From: Steve Grubb <sgrubb@redhat.com>
To: linux-audit@redhat.com
Cc: gcwilson@us.ibm.com, bryntcor@us.ibm.com
Subject: Re: [PATCH 2/2] auvirt: Add support for AVC records generated by AppArmor
Date: Tue, 28 Feb 2012 18:28:33 -0500 [thread overview]
Message-ID: <201202281828.34194.sgrubb@redhat.com> (raw)
In-Reply-To: <1329761747-27905-3-git-send-email-mhcerri@linux.vnet.ibm.com>
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)
prev parent reply other threads:[~2012-02-28 23:28 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
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 message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=201202281828.34194.sgrubb@redhat.com \
--to=sgrubb@redhat.com \
--cc=bryntcor@us.ibm.com \
--cc=gcwilson@us.ibm.com \
--cc=linux-audit@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.