* [PATCH 0/2] Improvements to AVC record matching
@ 2012-02-20 18:15 Marcelo Cerri
2012-02-20 18:15 ` [PATCH 1/2] auvirt: Improve matching of AVC records generated by SELinux Marcelo Cerri
2012-02-20 18:15 ` [PATCH 2/2] auvirt: Add support for AVC records generated by AppArmor Marcelo Cerri
0 siblings, 2 replies; 5+ messages in thread
From: Marcelo Cerri @ 2012-02-20 18:15 UTC (permalink / raw)
To: linux-audit; +Cc: gcwilson, bryntcor
This set of patches is intended to improve how auvirt matches AVC records.
Currently, auvirt just matches AVC records generated by SELinux that have a
guest context as target context.
With the first patch, auvirt will also match records that have a guest context
as source context, which means that denied actions performed by a guest will
also be matched.
The second patch adds similar support for AVC records generated by AppArmor.
With this patch, auvirt will match AVC records generated due to an AppArmor
profile generated by libvirt to a guest. It will also match AVC records which
the target is one of the resources assigned to a guest.
Marcelo Cerri (2):
auvirt: Improve matching of AVC records generated by SELinux
auvirt: Add support for AVC records generated by AppArmor
tools/auvirt/auvirt.c | 276 +++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 256 insertions(+), 20 deletions(-)
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/2] auvirt: Improve matching of AVC records generated by SELinux
2012-02-20 18:15 [PATCH 0/2] Improvements to AVC record matching Marcelo Cerri
@ 2012-02-20 18:15 ` Marcelo Cerri
2012-02-28 23:19 ` Steve Grubb
2012-02-20 18:15 ` [PATCH 2/2] auvirt: Add support for AVC records generated by AppArmor Marcelo Cerri
1 sibling, 1 reply; 5+ messages in thread
From: Marcelo Cerri @ 2012-02-20 18:15 UTC (permalink / raw)
To: linux-audit; +Cc: gcwilson, bryntcor
With this patch, auvirt also matches AVC denials performed by the guest and
generated by SELinux.
---
tools/auvirt/auvirt.c | 52 ++++++++++++++++++++++++++++++------------------
1 files changed, 32 insertions(+), 20 deletions(-)
diff --git a/tools/auvirt/auvirt.c b/tools/auvirt/auvirt.c
index 9b71a3c..a49a8b8 100644
--- a/tools/auvirt/auvirt.c
+++ b/tools/auvirt/auvirt.c
@@ -87,10 +87,10 @@ struct event {
/* Fields specific for machine id events: */
char *seclevel;
/* Fields specific for avc events: */
+ char *avc_result;
+ char *avc_operation;
char *target;
char *comm;
- char *seresult;
- char *seperms;
char *context;
/* Fields to print proof information: */
struct record_id proof[4];
@@ -123,11 +123,11 @@ void event_free(struct event *event)
free(event->reason);
free(event->res_type);
free(event->res);
+ free(event->avc_result);
+ free(event->avc_operation);
free(event->seclevel);
free(event->target);
free(event->comm);
- free(event->seresult);
- free(event->seperms);
free(event->cgroup_class);
free(event->cgroup_detail);
free(event->cgroup_acl);
@@ -468,7 +468,7 @@ int process_machine_id_event(auparse_state_t *au)
seclevel = get_seclevel(auparse_find_field(au, "vm-ctx"));
if (seclevel == NULL) {
if (debug)
- fprintf(stderr, "security context not found for "
+ fprintf(stderr, "Security context not found for "
"MACHINE_ID event.\n");
}
@@ -592,7 +592,7 @@ int add_stop_guest_event(auparse_state_t *au)
}
if (start == NULL) {
if (debug) {
- fprintf(stderr, "Couldn't find the correlated start i"
+ fprintf(stderr, "Couldn't find the correlated start "
"record to the stop event.\n");
}
return 0;
@@ -824,19 +824,18 @@ struct event *get_machine_id_by_seclevel(const char *seclevel)
return machine_id;
}
-/* AVC records are correlated to guest through the selinux context. */
-int process_avc(auparse_state_t *au)
+int process_avc_selinux_context(auparse_state_t *au, const char *context)
{
const char *target, *seclevel;
struct event *machine_id, *avc;
uid_t uid;
time_t time;
- seclevel = get_seclevel(auparse_find_field(au, "tcontext"));
+ seclevel = get_seclevel(auparse_find_field(au, context));
if (seclevel == NULL) {
if (debug) {
- fprintf(stderr, "Security context not found for "
- "AVC event.\n");
+ fprintf(stderr, "Security context not found "
+ "for AVC event.\n");
}
return 0;
}
@@ -847,8 +846,8 @@ int process_avc(auparse_state_t *au)
machine_id = get_machine_id_by_seclevel(seclevel);
if (machine_id == NULL) {
if (debug) {
- fprintf(stderr, "Couldn't get the security level from "
- "the AVC event.\n");
+ fprintf(stderr, "Couldn't get the security "
+ "level from the AVC event.\n");
}
return 0;
}
@@ -868,19 +867,19 @@ int process_avc(auparse_state_t *au)
avc->uid = uid;
avc->seclevel = copy_str(seclevel);
auparse_first_record(au);
- avc->seresult = copy_str(auparse_find_field(au, "seresult"));
- avc->seperms = copy_str(auparse_find_field(au, "seperms"));
+ avc->avc_result = copy_str(auparse_find_field(au, "seresult"));
+ avc->avc_operation = copy_str(auparse_find_field(au, "seperms"));
if (auparse_find_field(au, "comm"))
avc->comm = copy_str(auparse_interpret_field(au));
if (auparse_find_field(au, "name"))
avc->target = copy_str(auparse_interpret_field(au));
/* get the context related to the permission that was denied. */
- if (avc->seperms) {
+ if (avc->avc_operation) {
const char *ctx = NULL;
- if (strcmp("relabelfrom", avc->seperms) == 0) {
+ if (strcmp("relabelfrom", avc->avc_operation) == 0) {
ctx = auparse_find_field(au, "scontext");
- } else if (strcmp("relabelto", avc->seperms) == 0) {
+ } else if (strcmp("relabelto", avc->avc_operation) == 0) {
ctx = auparse_find_field(au, "tcontext");
}
avc->context = copy_str(ctx);
@@ -894,6 +893,19 @@ int process_avc(auparse_state_t *au)
return 0;
}
+/* AVC records are correlated to guest through the selinux context. */
+int process_avc(auparse_state_t *au)
+{
+ const char **context;
+ const char *contexts[] = { "tcontext", "scontext", NULL };
+
+ for (context = contexts; context && *context; context++) {
+ if (process_avc_selinux_context(au, *context))
+ return 1;
+ }
+ 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)
@@ -1152,8 +1164,8 @@ void print_event(struct event *event)
} else if (event->type == ET_MACHINE_ID) {
printf("\t%s", N(event->seclevel));
} else if (event->type == ET_AVC) {
- printf("\t%-12.12s", N(event->seperms));
- printf("\t%-10.10s", N(event->seresult));
+ printf("\t%-12.12s", N(event->avc_operation));
+ printf("\t%-10.10s", N(event->avc_result));
printf("\t%s\t%s\t%s", N(event->comm), N(event->target),
N(event->context));
}
--
1.7.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/2] auvirt: Add support for AVC records generated by AppArmor
2012-02-20 18:15 [PATCH 0/2] Improvements to AVC record matching Marcelo Cerri
2012-02-20 18:15 ` [PATCH 1/2] auvirt: Improve matching of AVC records generated by SELinux Marcelo Cerri
@ 2012-02-20 18:15 ` Marcelo Cerri
2012-02-28 23:28 ` Steve Grubb
1 sibling, 1 reply; 5+ messages in thread
From: Marcelo Cerri @ 2012-02-20 18:15 UTC (permalink / raw)
To: linux-audit; +Cc: gcwilson, bryntcor
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.
---
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)
--
1.7.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] auvirt: Improve matching of AVC records generated by SELinux
2012-02-20 18:15 ` [PATCH 1/2] auvirt: Improve matching of AVC records generated by SELinux Marcelo Cerri
@ 2012-02-28 23:19 ` Steve Grubb
0 siblings, 0 replies; 5+ messages in thread
From: Steve Grubb @ 2012-02-28 23:19 UTC (permalink / raw)
To: linux-audit; +Cc: gcwilson, bryntcor
On Monday, February 20, 2012 01:15:46 PM Marcelo Cerri wrote:
> With this patch, auvirt also matches AVC denials performed by the guest and
> generated by SELinux.
Applied.
-Steve
> tools/auvirt/auvirt.c | 52
> ++++++++++++++++++++++++++++++------------------ 1 files changed, 32
> insertions(+), 20 deletions(-)
>
> diff --git a/tools/auvirt/auvirt.c b/tools/auvirt/auvirt.c
> index 9b71a3c..a49a8b8 100644
> --- a/tools/auvirt/auvirt.c
> +++ b/tools/auvirt/auvirt.c
> @@ -87,10 +87,10 @@ struct event {
> /* Fields specific for machine id events: */
> char *seclevel;
> /* Fields specific for avc events: */
> + char *avc_result;
> + char *avc_operation;
> char *target;
> char *comm;
> - char *seresult;
> - char *seperms;
> char *context;
> /* Fields to print proof information: */
> struct record_id proof[4];
> @@ -123,11 +123,11 @@ void event_free(struct event *event)
> free(event->reason);
> free(event->res_type);
> free(event->res);
> + free(event->avc_result);
> + free(event->avc_operation);
> free(event->seclevel);
> free(event->target);
> free(event->comm);
> - free(event->seresult);
> - free(event->seperms);
> free(event->cgroup_class);
> free(event->cgroup_detail);
> free(event->cgroup_acl);
> @@ -468,7 +468,7 @@ int process_machine_id_event(auparse_state_t *au)
> seclevel = get_seclevel(auparse_find_field(au, "vm-ctx"));
> if (seclevel == NULL) {
> if (debug)
> - fprintf(stderr, "security context not found for "
> + fprintf(stderr, "Security context not found for "
> "MACHINE_ID event.\n");
> }
>
> @@ -592,7 +592,7 @@ int add_stop_guest_event(auparse_state_t *au)
> }
> if (start == NULL) {
> if (debug) {
> - fprintf(stderr, "Couldn't find the correlated start i"
> + fprintf(stderr, "Couldn't find the correlated start "
> "record to the stop event.\n");
> }
> return 0;
> @@ -824,19 +824,18 @@ struct event *get_machine_id_by_seclevel(const char
> *seclevel) return machine_id;
> }
>
> -/* AVC records are correlated to guest through the selinux context. */
> -int process_avc(auparse_state_t *au)
> +int process_avc_selinux_context(auparse_state_t *au, const char *context)
> {
> const char *target, *seclevel;
> struct event *machine_id, *avc;
> uid_t uid;
> time_t time;
>
> - seclevel = get_seclevel(auparse_find_field(au, "tcontext"));
> + seclevel = get_seclevel(auparse_find_field(au, context));
> if (seclevel == NULL) {
> if (debug) {
> - fprintf(stderr, "Security context not found for "
> - "AVC event.\n");
> + fprintf(stderr, "Security context not found "
> + "for AVC event.\n");
> }
> return 0;
> }
> @@ -847,8 +846,8 @@ int process_avc(auparse_state_t *au)
> machine_id = get_machine_id_by_seclevel(seclevel);
> if (machine_id == NULL) {
> if (debug) {
> - fprintf(stderr, "Couldn't get the security level from "
> - "the AVC event.\n");
> + fprintf(stderr, "Couldn't get the security "
> + "level from the AVC event.\n");
> }
> return 0;
> }
> @@ -868,19 +867,19 @@ int process_avc(auparse_state_t *au)
> avc->uid = uid;
> avc->seclevel = copy_str(seclevel);
> auparse_first_record(au);
> - avc->seresult = copy_str(auparse_find_field(au, "seresult"));
> - avc->seperms = copy_str(auparse_find_field(au, "seperms"));
> + avc->avc_result = copy_str(auparse_find_field(au, "seresult"));
> + avc->avc_operation = copy_str(auparse_find_field(au, "seperms"));
> if (auparse_find_field(au, "comm"))
> avc->comm = copy_str(auparse_interpret_field(au));
> if (auparse_find_field(au, "name"))
> avc->target = copy_str(auparse_interpret_field(au));
>
> /* get the context related to the permission that was denied. */
> - if (avc->seperms) {
> + if (avc->avc_operation) {
> const char *ctx = NULL;
> - if (strcmp("relabelfrom", avc->seperms) == 0) {
> + if (strcmp("relabelfrom", avc->avc_operation) == 0) {
> ctx = auparse_find_field(au, "scontext");
> - } else if (strcmp("relabelto", avc->seperms) == 0) {
> + } else if (strcmp("relabelto", avc->avc_operation) == 0) {
> ctx = auparse_find_field(au, "tcontext");
> }
> avc->context = copy_str(ctx);
> @@ -894,6 +893,19 @@ int process_avc(auparse_state_t *au)
> return 0;
> }
>
> +/* AVC records are correlated to guest through the selinux context. */
> +int process_avc(auparse_state_t *au)
> +{
> + const char **context;
> + const char *contexts[] = { "tcontext", "scontext", NULL };
> +
> + for (context = contexts; context && *context; context++) {
> + if (process_avc_selinux_context(au, *context))
> + return 1;
> + }
> + 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)
> @@ -1152,8 +1164,8 @@ void print_event(struct event *event)
> } else if (event->type == ET_MACHINE_ID) {
> printf("\t%s", N(event->seclevel));
> } else if (event->type == ET_AVC) {
> - printf("\t%-12.12s", N(event->seperms));
> - printf("\t%-10.10s", N(event->seresult));
> + printf("\t%-12.12s", N(event->avc_operation));
> + printf("\t%-10.10s", N(event->avc_result));
> printf("\t%s\t%s\t%s", N(event->comm), N(event->target),
> N(event->context));
> }
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] auvirt: Add support for AVC records generated by AppArmor
2012-02-20 18:15 ` [PATCH 2/2] auvirt: Add support for AVC records generated by AppArmor Marcelo Cerri
@ 2012-02-28 23:28 ` Steve Grubb
0 siblings, 0 replies; 5+ messages in thread
From: Steve Grubb @ 2012-02-28 23:28 UTC (permalink / raw)
To: linux-audit; +Cc: gcwilson, bryntcor
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)
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2012-02-28 23:28 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-02-20 18:15 [PATCH 0/2] Improvements to AVC record matching Marcelo Cerri
2012-02-20 18:15 ` [PATCH 1/2] auvirt: Improve matching of AVC records generated by SELinux Marcelo Cerri
2012-02-28 23:19 ` Steve Grubb
2012-02-20 18:15 ` [PATCH 2/2] auvirt: Add support for AVC records generated by AppArmor Marcelo Cerri
2012-02-28 23:28 ` Steve Grubb
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox