On Monday, February 20, 2012 01:15:47 PM Marcelo Cerri wrote:
> This patch adds support for matching AVC records generated by AppArmor.
> With this patch auvirt matches AVC records based on AppArmor profile name
> generated by libvirt, which contains the guest's UUID, and based on target
> name ("name" field), which auvirt tries to correlate to resources assigned
> to the guests. ---

I added #ifdef WITH_APPARMOR in a couple places. You might want to check that 
it 
still works as expected.

-Steve


>  tools/auvirt/auvirt.c |  226
> ++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 225
> insertions(+), 1 deletions(-)
> 
> diff --git a/tools/auvirt/auvirt.c b/tools/auvirt/auvirt.c
> index a49a8b8..7c0e769 100644
> --- a/tools/auvirt/auvirt.c
> +++ b/tools/auvirt/auvirt.c
> @@ -894,7 +894,7 @@ int process_avc_selinux_context(auparse_state_t *au,
> const char *context) }
> 
>  /* AVC records are correlated to guest through the selinux context. */
> -int process_avc(auparse_state_t *au)
> +int process_avc_selinux(auparse_state_t *au)
>  {
>       const char **context;
>       const char *contexts[] = { "tcontext", "scontext", NULL };
> @@ -906,6 +906,230 @@ int process_avc(auparse_state_t *au)
>       return 0;
>  }
> 
> +int process_avc_apparmor_source(auparse_state_t *au)
> +{
> +     uid_t uid = -1;
> +     time_t time = 0;
> +     struct event *avc;
> +     const char *target;
> +
> +     /* Get the target object. */
> +     if (auparse_find_field(au, "name") == NULL) {
> +             if (debug) {
> +                     auparse_first_record(au);
> +                     fprintf(stderr, "Couldn't get the resource name from "
> +                                     "the AVC record: %s\n",
> +                                     auparse_get_record_text(au));
> +             }
> +             return 0;
> +     }
> +     target = auparse_interpret_field(au);
> +
> +     /* Loop backwards to find a guest session with the target object
> +      * assigned to. */
> +     struct list_node_t *it;
> +     struct event *res = NULL;
> +     for (it = events->tail; it; it = it->prev) {
> +             struct event *event = it->data;
> +             if (event->success) {
> +                     if (event->type == ET_DOWN) {
> +                             /* It's just possible to find a matching guest
> +                              * session in the current host session.
> +                              */
> +                             break;
> +                     } else if (event->type == ET_RES &&
> +                                event->end == 0 &&
> +                                event->res != NULL &&
> +                                strcmp(target, event->res) == 0) {
> +                             res = event;
> +                             break;
> +                     }
> +             }
> +     }
> +
> +     /* Check if a resource event was found. */
> +     if (res == NULL) {
> +             if (debug) {
> +                     fprintf(stderr, "Target object not found for AVC "
> +                                     "event.\n");
> +             }
> +             return 0;
> +     }
> +
> +     if (extract_virt_fields(au, NULL, &uid, &time, NULL, NULL))
> +             return 0;
> +
> +     avc = event_alloc();
> +     if (avc == NULL)
> +             return 1;
> +     avc->type = ET_AVC;
> +
> +     /* Guest info */
> +     avc->uuid = copy_str(res->uuid);
> +     avc->name = copy_str(res->name);
> +     memcpy(avc->proof, res->proof, sizeof(avc->proof));
> +
> +     /* AVC info */
> +     avc->start = time;
> +     avc->uid = uid;
> +     auparse_first_record(au);
> +     if (auparse_find_field(au, "apparmor")) {
> +             int i;
> +             avc->avc_result = copy_str(auparse_interpret_field(au));
> +             for (i = 0; avc->avc_result && avc->avc_result[i]; i++) {
> +                     avc->avc_result[i] = tolower(avc->avc_result[i]);
> +             }
> +     }
> +     if (auparse_find_field(au, "operation"))
> +             avc->avc_operation = copy_str(auparse_interpret_field(au));
> +     avc->target = copy_str(target);
> +     if (auparse_find_field(au, "comm"))
> +             avc->comm = copy_str(auparse_interpret_field(au));
> +
> +     add_proof(avc, au);
> +     if (list_append(events, avc) == NULL) {
> +             event_free(avc);
> +             return 1;
> +     }
> +     return 0;
> +}
> +
> +int process_avc_apparmor_target(auparse_state_t *au)
> +{
> +     uid_t uid;
> +     time_t time;
> +     const char *profile;
> +     struct event *avc;
> +
> +     /* Get profile associated with the AVC record */
> +     if (auparse_find_field(au, "profile") == NULL) {
> +             if (debug) {
> +                     auparse_first_record(au);
> +                     fprintf(stderr, "AppArmor profile not found for AVC "
> +                                     "record: %s\n",
> +                                     auparse_get_record_text(au));
> +             }
> +             return 0;
> +     }
> +     profile = auparse_interpret_field(au);
> +
> +     /* Break path to get just the basename */
> +     const char *basename = profile + strlen(profile);
> +     while (basename != profile && *basename != '/')
> +             basename--;
> +     if (*basename == '/')
> +             basename++;
> +
> +     /* Check if it is an apparmor profile generated by libvirt and get the
> +      * guest UUID from it */
> +     const char *prefix = "libvirt-";
> +     if (strncmp(prefix, basename, strlen(prefix)) != 0) {
> +             if (debug) {
> +                     fprintf(stderr, "Found a profile which is not "
> +                                     "generated by libvirt: %s\n", profile);
> +             }
> +             return 0;
> +     }
> +
> +     /* Try to find a valid guest session */
> +     const char *uuid = basename + strlen(prefix);
> +     struct list_node_t *it;
> +     struct event *machine_id = NULL;
> +     for (it = events->tail; it; it = it->prev) {
> +             struct event *event = it->data;
> +             if (event->success) {
> +                     if (event->uuid != NULL &&
> +                         strcmp(event->uuid, uuid) == 0) {
> +                             /* machine_id is used here instead of the start
> +                              * event because it is generated before any
> +                              * other event when a guest is started. So,
> +                              * it's possible to correlate AVC events that
> +                              * occurs during a guest start.
> +                              */
> +                             if (event->type == ET_MACHINE_ID) {
> +                                     machine_id = event;
> +                                     break;
> +                             } else if (event->type == ET_STOP) {
> +                                     break;
> +                             }
> +                     } else if (event->type == ET_DOWN) {
> +                             break;
> +                     }
> +             }
> +     }
> +     if (machine_id == NULL) {
> +             if (debug) {
> +                     fprintf(stderr, "Found an AVC record for an unknown "
> +                                     "guest.\n");
> +             }
> +             return 0;
> +     }
> +
> +     if (extract_virt_fields(au, NULL, &uid, &time, NULL, NULL))
> +             return 0;
> +
> +     avc = event_alloc();
> +     if (avc == NULL)
> +             return 1;
> +     avc->type = ET_AVC;
> +
> +     /* Guest info */
> +     avc->uuid = copy_str(machine_id->uuid);
> +     avc->name = copy_str(machine_id->name);
> +     memcpy(avc->proof, machine_id->proof, sizeof(avc->proof));
> +
> +     /* AVC info */
> +     avc->start = time;
> +     avc->uid = uid;
> +     auparse_first_record(au);
> +     if (auparse_find_field(au, "apparmor")) {
> +             int i;
> +             avc->avc_result = copy_str(auparse_interpret_field(au));
> +             for (i = 0; avc->avc_result && avc->avc_result[i]; i++) {
> +                     avc->avc_result[i] = tolower(avc->avc_result[i]);
> +             }
> +     }
> +     if (auparse_find_field(au, "operation"))
> +             avc->avc_operation = copy_str(auparse_interpret_field(au));
> +     if (auparse_find_field(au, "name"))
> +             avc->target = copy_str(auparse_interpret_field(au));
> +     if (auparse_find_field(au, "comm"))
> +             avc->comm = copy_str(auparse_interpret_field(au));
> +
> +     add_proof(avc, au);
> +     if (list_append(events, avc) == NULL) {
> +             event_free(avc);
> +             return 1;
> +     }
> +     return 0;
> +}
> +
> +/* AVC records are correlated to guest through the apparmor path name. */
> +int process_avc_apparmor(auparse_state_t *au)
> +{
> +     if (process_avc_apparmor_target(au))
> +             return 1;
> +     auparse_first_record(au);
> +     return process_avc_apparmor_source(au);
> +}
> +
> +int process_avc(auparse_state_t *au)
> +{
> +     /* Check if it is a SELinux AVC record */
> +     if (auparse_find_field(au, "tcontext")) {
> +             auparse_first_record(au);
> +             return process_avc_selinux(au);
> +     }
> +
> +     /* Check if it is an AppArmor AVC record */
> +     auparse_first_record(au);
> +     if (auparse_find_field(au, "apparmor")) {
> +             auparse_first_record(au);
> +             return process_avc_apparmor(au);
> +     }
> +     return 0;
> +}
> +
>  /* This function tries to correlate an anomaly record to a guest using the
> qemu * pid or the selinux context. */
>  int process_anom(auparse_state_t *au)

--
Linux-audit mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/linux-audit

Reply via email to