On 09/26/2013 04:08 PM, Tyler Hicks wrote: > This is a regression test to load a profile, query it from userspace > using aa_query_label(), and then verify the results. > > The query interface is tested by the dbus mediation regression tests, > but this test helps in finding bugs specific to AppArmor, which may > possibly be caused by the parser, kernel, and/or libapparmor. > > Signed-off-by: Tyler Hicks <[email protected]> yea tests! Okay I think I've been through this enough to give it an ack
thanks ty Acked-by: John Johansen <[email protected]> > --- > tests/regression/apparmor/Makefile | 2 + > tests/regression/apparmor/prologue.inc | 9 ++ > tests/regression/apparmor/query_label.c | 180 +++++++++++++++++++++++++++ > tests/regression/apparmor/query_label.sh | 207 > +++++++++++++++++++++++++++++++ > 4 files changed, 398 insertions(+) > create mode 100644 tests/regression/apparmor/query_label.c > create mode 100644 tests/regression/apparmor/query_label.sh > > diff --git a/tests/regression/apparmor/Makefile > b/tests/regression/apparmor/Makefile > index bf0c0b1..370690f 100644 > --- a/tests/regression/apparmor/Makefile > +++ b/tests/regression/apparmor/Makefile > @@ -51,6 +51,7 @@ SRC=access.c \ > ptrace.c \ > ptrace_helper.c \ > pwrite.c \ > + query_label.c \ > rename.c \ > readdir.c \ > rw.c \ > @@ -145,6 +146,7 @@ TESTS=access \ > pipe \ > ptrace \ > pwrite \ > + query_label \ > regex \ > rename \ > readdir \ > diff --git a/tests/regression/apparmor/prologue.inc > b/tests/regression/apparmor/prologue.inc > index 84ad777..b50d3d5 100755 > --- a/tests/regression/apparmor/prologue.inc > +++ b/tests/regression/apparmor/prologue.inc > @@ -36,6 +36,15 @@ required_features() > done > } > > +requires_query_interface() > +{ > + if [ ! -e "/sys/kernel/security/apparmor/.access" ] > + then > + echo "Kernel query interface not supported. Skipping tests ..." > + exit 0 > + fi > +} > + > fatalerror() > { > # global _fatal > diff --git a/tests/regression/apparmor/query_label.c > b/tests/regression/apparmor/query_label.c > new file mode 100644 > index 0000000..be945cb > --- /dev/null > +++ b/tests/regression/apparmor/query_label.c > @@ -0,0 +1,180 @@ > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <sys/apparmor.h> > + > +#define OPT_EXPECT "--expect=" > +#define OPT_EXPECT_LEN strlen(OPT_EXPECT) > + > +#define OPT_LABEL "--label=" > +#define OPT_LABEL_LEN strlen(OPT_LABEL) > + > +#define OPT_TYPE_DBUS "--dbus=" > +#define OPT_TYPE_DBUS_LEN strlen(OPT_TYPE_DBUS) > + > +static char *progname = NULL; > + > +void usage(void) > +{ > + fprintf(stderr, "Usage: %s --expect=EXPECTED --label=LABEL > --CLASS=PERMS QUERY...\n\n", > + progname); > + fprintf(stderr, " EXPECTED\tA comma separated list of allow, audit, > and/or anything.\n"); > + fprintf(stderr, "\t\t\"anything\" is a special keyword that matches any > condition\n"); > + fprintf(stderr, "\t\tand cannot be used with other keywords. > Additionally,\n"); > + fprintf(stderr, "\t\tEXPECTED can be empty to indicate neither, allow > or audit,\n"); > + fprintf(stderr, "\t\tin the results.\n"); > + fprintf(stderr, " LABEL\t\tThe AppArmor label to use in the query\n"); > + fprintf(stderr, " CLASS\t\tThe rule class and may consist of:\n"); > + fprintf(stderr, "\t\t dbus\n"); > + fprintf(stderr, " PERMS\t\tA comma separated list of permissions. > Possibilities\n"); > + fprintf(stderr, "\t\tfor the supported rule classes are:\n"); > + fprintf(stderr, "\t\t dbus: send,receive,bind\n"); > + fprintf(stderr, "\t\tAdditionaly, PERMS can be empty to indicate an > empty mask\n"); > + exit(1); > +} > + > +static int parse_expected(int *should_allow, int *should_audit, char > *expected) > +{ > + char *expect; > + > + *should_allow = *should_audit = 0; > + > + expect = strtok(expected, ","); > + while (expect) { > + if (!strcmp(expect, "allow")) { > + *should_allow = 1; > + } else if (!strcmp(expect, "audit")) { > + *should_audit = 1; > + } else if (!strcmp(expect, "anything")) { > + *should_allow = *should_audit = -1; > + } else { > + fprintf(stderr, "FAIL: unknown expect: %s\n", expect); > + return 1; > + } > + > + expect = strtok(NULL, ","); > + } > + > + return 0; > +} > + > +static int parse_dbus_perms(uint32_t *mask, char *perms) > +{ > + char *perm; > + > + *mask = 0; > + > + perm = strtok(perms, ","); > + while (perm) { > + if (!strcmp(perm, "send")) > + *mask |= AA_DBUS_SEND; > + else if (!strcmp(perm, "receive")) > + *mask |= AA_DBUS_RECEIVE; > + else if (!strcmp(perm, "bind")) > + *mask |= AA_DBUS_BIND; > + else { > + fprintf(stderr, "FAIL: unknown perm: %s\n", perm); > + return 1; > + } > + > + perm = strtok(NULL, ","); > + } > + > + return 0; > +} > + > +static ssize_t build_query(char **qstr, const char *label, int class, > + int argc, char **argv) > +{ > + int size, label_size, i; > + char *buffer, *to; > + > + label_size = strlen(label); > + size = label_size + 1; > + for (i = 0; i < argc; i++) { > + if (argv[i]) > + size += strlen(argv[i]); > + } > + > + buffer = malloc(size + argc + 1 + AA_QUERY_CMD_LABEL_SIZE); > + if (!buffer) > + return -1; > + > + to = buffer + AA_QUERY_CMD_LABEL_SIZE; > + strcpy(to, label); > + to += label_size; > + *(to)++ = '\0'; > + *(to)++ = class; > + > + for (i = 0; i < argc; to++, i++) { > + char *arg = argv[i]; > + > + if (!arg) > + arg = ""; > + to = stpcpy(to, arg); > + } > + *qstr = buffer; > + > + /* don't include trailing \0 in size */ > + return size + argc + AA_QUERY_CMD_LABEL_SIZE; > +} > + > +int main(int argc, char **argv) > +{ > + char *label, *class_str, *query; > + int class, should_allow, allowed, should_audit, audited, rc; > + uint32_t mask; > + ssize_t query_len; > + > + progname = argv[0]; > + > + if (argc < 5) > + usage(); > + > + if (!strncmp(argv[1], OPT_EXPECT, OPT_EXPECT_LEN)) { > + rc = parse_expected(&should_allow, &should_audit, > + argv[1] + OPT_EXPECT_LEN); > + if (rc) > + usage(); > + } > + > + if (!strncmp(argv[2], OPT_LABEL, OPT_LABEL_LEN)) > + label = argv[2] + OPT_LABEL_LEN; > + else > + usage(); > + > + class_str = argv[3]; > + if (!strncmp(class_str, OPT_TYPE_DBUS, OPT_TYPE_DBUS_LEN)) { > + class = AA_CLASS_DBUS; > + rc = parse_dbus_perms(&mask, class_str + OPT_TYPE_DBUS_LEN); > + if (rc) > + usage(); > + } else { > + fprintf(stderr, "FAIL: unknown rule class: %s\n", class_str); > + usage(); > + } > + > + query_len = build_query(&query, label, class, argc - 4, argv + 4); > + if (query_len < 0) { > + fprintf(stderr, "FAIL: failed to allocate memory for query > string\n"); > + exit(1); > + } > + > + rc = aa_query_label(mask, query, query_len, &allowed, &audited); > + free(query); > + if (rc < 0) { > + fprintf(stderr, "FAIL: failed to perform query: %m\n"); > + exit(1); > + } > + > + if ((should_allow == -1 && should_audit == -1) || > + (allowed == should_allow && audited == should_audit)) { > + printf("PASS\n"); > + } else { > + fprintf(stderr, "FAIL: the access should %sbe allowed and > should %sbe audited\n", > + allowed ? "" : "not ", audited ? "" : "not "); > + exit(1); > + } > + > + exit(0); > +} > diff --git a/tests/regression/apparmor/query_label.sh > b/tests/regression/apparmor/query_label.sh > new file mode 100644 > index 0000000..92e588e > --- /dev/null > +++ b/tests/regression/apparmor/query_label.sh > @@ -0,0 +1,207 @@ > +#! /bin/bash > +# Copyright (C) 2013 Canonical, Ltd. > +# > +# This program is free software; you can redistribute it and/or > +# modify it under the terms of the GNU General Public License as > +# published by the Free Software Foundation, version 2 of the > +# License. > + > +#=NAME query_label > +#=DESCRIPTION > +# This test verifies the results returned from aa_query_label() > +#=END > + > +pwd=`dirname $0` > +pwd=`cd $pwd ; /bin/pwd` > + > +bin=$pwd > + > +. $bin/prologue.inc > +requires_query_interface > + > +settest query_label > + > +expect="" > +perms="" > +label="--label=$test" > + > +dbus_send="--dbus=send" > +dbus_receive="--dbus=receive" > +dbus_bind="--dbus=bind" > +dbus_send_receive="--dbus=send,receive" > +dbus_all="--dbus=send,receive,bind" > +dbus_none="--dbus=" > + > +dbus_msg_query="session com.foo.bar /usr/bin/bar /com/foo/bar com.foo.bar > Method" > +dbus_svc_query="session com.foo.baz" > + > +# Generate a profile for $test, granting all file access and anything > specified > +# in $@ > +genqueryprofile() > +{ > + genprofile --stdin <<EOF > +$test { > + file, > + $@ > +} > +EOF > +} > + > +# Generate the --expect parameter for query_label. Example usage: > +# `expect audit` would generate --expect=audit > +# `expect allow audit` would generate --expect=allow,audit > +# `expect` would generate --expect= > +expect() > +{ > + local old=$IFS > + > + IFS="," > + expect=$(printf "%s=%s" "--expect" "$*") > + IFS=$old > +} > + > +# Generate the --CLASS=PERMS parameter query_label. Example usage: > +# `perms dbus send` would generate --dbus=send > +# `perms dbus send bind` would generate --dbus=send,bind > +# `perms dbus` would generate --dbus= > +perms() > +{ > + local old=$IFS > + local class=$1 > + > + shift > + IFS="," > + perms=$(printf "%s%s=%s" "--" "$class" "$*") > + IFS=$old > +} > + > +# Gather up the globals ($expect, $label, $perms) and call runchecktest > +# @1: the test description > +# @2: pass or fail > +# @3: the query string > +querytest() > +{ > + local desc=$1 > + local pf=$2 > + > + shift > + shift > + runchecktest "$desc" "$pf" "$expect" "$label" "$perms" $* > +} > + > +# Check querying of a label that the kernel doesn't know about > +# aa_query_label() should return an error > +expect anything > +perms dbus send > +querytest "QUERY no profile loaded" fail $dbus_msg_query > + > +# Check querying with an empty mask - aa_query_label() should error out > +genqueryprofile "dbus," > +expect anything > +perms dbus # no perms > +querytest "QUERY empty mask" fail $dbus_msg_query > + > +# Check dbus - allowed without auditing > +genqueryprofile "dbus," > +expect allow > +perms dbus send > +querytest "QUERY dbus (msg send)" pass $dbus_msg_query > +perms dbus receive > +querytest "QUERY dbus (msg receive)" pass $dbus_msg_query > +perms dbus send receive > +querytest "QUERY dbus (msg send & receive)" pass $dbus_msg_query > +perms dbus bind > +querytest "QUERY dbus (svc)" pass $dbus_svc_query > + > +# Check deny dbus - denied without auditing > +genqueryprofile "deny dbus," > +expect # neither allow, nor audit > +perms dbus send > +querytest "QUERY deny dbus (msg send)" pass $dbus_msg_query > +perms dbus receive > +querytest "QUERY deny dbus (msg receive)" pass $dbus_msg_query > +perms dbus send receive > +querytest "QUERY deny dbus (msg send & receive)" pass $dbus_msg_query > +perms dbus bind > +querytest "QUERY deny dbus (svc)" pass $dbus_svc_query > + > +# Check audit dbus - allowed, but audited > +genqueryprofile "audit dbus," > +expect allow audit > +perms dbus send > +querytest "QUERY audit dbus (msg send)" pass $dbus_msg_query > +perms dbus receive > +querytest "QUERY audit dbus (msg receive)" pass $dbus_msg_query > +perms dbus send receive > +querytest "QUERY audit dbus (msg send & receive)" pass $dbus_msg_query > +perms dbus bind > +querytest "QUERY audit dbus (svc)" pass $dbus_svc_query > + > +# Check audit deny dbus - explicit deny without auditing > +genqueryprofile "audit deny dbus," > +expect audit > +perms dbus send > +querytest "QUERY audit deny dbus (msg send)" pass $dbus_msg_query > +perms dbus receive > +querytest "QUERY audit deny dbus (msg receive)" pass $dbus_msg_query > +perms dbus send receive > +querytest "QUERY audit deny dbus (msg send & receive)" pass $dbus_msg_query > +perms dbus bind > +querytest "QUERY audit deny dbus (svc)" pass $dbus_svc_query > + > +# Check dbus send - ensure that receive and bind bits aren't set > +genqueryprofile "dbus send," > +expect allow > +perms dbus send > +querytest "QUERY dbus send (msg send)" pass $dbus_msg_query > +perms dbus receive > +querytest "QUERY dbus send (msg receive)" fail $dbus_msg_query > +perms dbus send receive > +querytest "QUERY dbus send (msg send & receive)" fail $dbus_msg_query > +perms dbus bind > +querytest "QUERY dbus send (msg bind)" fail $dbus_msg_query > +perms dbus send bind > +querytest "QUERY dbus send (msg send & bind)" fail $dbus_msg_query > + > +# Check dbus receive - ensure that send and bind bits aren't set > +genqueryprofile "dbus receive," > +expect allow > +perms dbus receive > +querytest "QUERY dbus receive (msg receive)" pass $dbus_msg_query > +perms dbus send > +querytest "QUERY dbus receive (msg send)" fail $dbus_msg_query > +perms dbus send receive > +querytest "QUERY dbus receive (msg send & receive)" fail $dbus_msg_query > +perms dbus bind > +querytest "QUERY dbus receive (msg bind)" fail $dbus_msg_query > +perms dbus receive bind > +querytest "QUERY dbus receive (msg receive & bind)" fail $dbus_msg_query > + > +# Check dbus bind - ensure that send and receive bits aren't set > +genqueryprofile "dbus bind," > +expect allow > +perms dbus bind > +querytest "QUERY dbus bind (svc bind)" pass $dbus_svc_query > +perms dbus send > +querytest "QUERY dbus bind (svc send)" fail $dbus_svc_query > +perms dbus send bind > +querytest "QUERY dbus bind (svc send & bind)" fail $dbus_svc_query > +perms dbus receive > +querytest "QUERY dbus bind (svc receive)" fail $dbus_svc_query > +perms dbus receive bind > +querytest "QUERY dbus bind (svc receive & bind)" fail $dbus_svc_query > + > +# Check dbus - ensure that send and receive bits aren't set in service > queries > +# and the bind bit isn't set in message queries > +genqueryprofile "dbus," > +expect allow > +perms dbus send receive > +querytest "QUERY dbus (msg send & receive)" pass $dbus_msg_query > +perms dbus bind > +querytest "QUERY dbus (msg bind)" fail $dbus_msg_query > +perms dbus bind > +querytest "QUERY dbus (svc bind)" pass $dbus_svc_query > +perms dbus send > +querytest "QUERY dbus (svc send)" fail $dbus_svc_query > +perms dbus receive > +querytest "QUERY dbus (svc receive)" fail $dbus_svc_query > -- AppArmor mailing list [email protected] Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/apparmor
