On 05/25/2016 01:59 PM, Tyler Hicks wrote: > This test will soon be made to do more than just stack a new profile. > It will be extended to allow for changing to a new profile and, > therefore, be renamed. > > Signed-off-by: Tyler Hicks <[email protected]>
Acked-by: John Johansen <[email protected]> > --- > tests/regression/apparmor/Makefile | 4 +- > tests/regression/apparmor/exec_stack.sh | 2 +- > tests/regression/apparmor/stacking.c | 337 > ------------------------------ > tests/regression/apparmor/stackonexec.sh | 2 +- > tests/regression/apparmor/stackprofile.sh | 2 +- > tests/regression/apparmor/transition.c | 337 > ++++++++++++++++++++++++++++++ > 6 files changed, 342 insertions(+), 342 deletions(-) > delete mode 100644 tests/regression/apparmor/stacking.c > create mode 100644 tests/regression/apparmor/transition.c > > diff --git a/tests/regression/apparmor/Makefile > b/tests/regression/apparmor/Makefile > index ca9a294..87f756a 100644 > --- a/tests/regression/apparmor/Makefile > +++ b/tests/regression/apparmor/Makefile > @@ -168,7 +168,7 @@ ifdef USE_SYSTEM > endif > > ifneq (,$(shell pkg-config --atleast-version 2.10.95 libapparmor && echo > TRUE)) > - SRC+=stacking.c > + SRC+=transition.c > CONDITIONAL_TESTS+=exec_stack stackonexec stackprofile > else > $(warning ${nl}\ > @@ -177,7 +177,7 @@ ifdef USE_SYSTEM > > ************************************************************************${nl}) > endif > else > - SRC+=aa_policy_cache.c stacking.c > + SRC+=aa_policy_cache.c transition.c > CONDITIONAL_TESTS+=exec_stack aa_policy_cache stackonexec stackprofile > endif > > diff --git a/tests/regression/apparmor/exec_stack.sh > b/tests/regression/apparmor/exec_stack.sh > index ef12015..2423dea 100755 > --- a/tests/regression/apparmor/exec_stack.sh > +++ b/tests/regression/apparmor/exec_stack.sh > @@ -20,7 +20,7 @@ bin=$pwd > . $bin/prologue.inc > > requires_kernel_features domain/stack > -settest stacking > +settest transition > > file=$tmpdir/file > otherfile=$tmpdir/file2 > diff --git a/tests/regression/apparmor/stacking.c > b/tests/regression/apparmor/stacking.c > deleted file mode 100644 > index ac1afce..0000000 > --- a/tests/regression/apparmor/stacking.c > +++ /dev/null > @@ -1,337 +0,0 @@ > -/* > - * Copyright (C) 2014-2016 Canonical, Ltd. > - * > - * This program is free software; you can redistribute it and/or > - * modify it under the terms of version 2 of the GNU General Public > - * License published by the Free Software Foundation. > - * > - * This program is distributed in the hope that it will be useful, > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > - * GNU General Public License for more details. > - * > - * You should have received a copy of the GNU General Public License > - * along with this program; if not, contact Canonical Ltd. > - */ > - > -#define _GNU_SOURCE > - > -#include <errno.h> > -#include <stdio.h> > -#include <stdlib.h> > -#include <string.h> > -#include <sys/apparmor.h> > -#include <sys/socket.h> > -#include <sys/types.h> > -#include <unistd.h> > - > -#include "changehat.h" /* for do_open() */ > - > -#define STACK_DELIM "//&" > -#define STACK_DELIM_LEN strlen(STACK_DELIM) > - > -#define NO_MODE "(null)" > - > -static void file_io(const char *file) > -{ > - int rc = do_open(file); > - > - if (rc != 0) > - exit(rc); > -} > - > -struct single_label { > - const char *label; > - size_t len; > -}; > - > -#define MAX_LABELS 32 > - > -struct compound_label { > - size_t num_labels; > - struct single_label labels[MAX_LABELS]; > -}; > - > -/** > - * Initializes @sl by parsing @compound_label. Returns a pointer to the > - * location of the next label in the compound label string, which should be > - * passed in as @compound_label the next time that next_label() is called. > NULL > - * is returned when there are no more labels in @compound_label. > - */ > -static const char *next_label(struct single_label *sl, > - const char *compound_label) > -{ > - const char *delim; > - > - if (!compound_label || compound_label[0] == '\0') > - return NULL; > - > - delim = strstr(compound_label, STACK_DELIM); > - if (!delim) { > - sl->label = compound_label; > - sl->len = strlen(sl->label); > - return sl->label + sl->len; > - } > - > - sl->label = compound_label; > - sl->len = delim - sl->label; > - return delim + STACK_DELIM_LEN; > -} > - > -/* Returns true if the compound label was constructed successfully */ > -static bool compound_label_init(struct compound_label *cl, > - const char *compound_label) > -{ > - memset(cl, 0, sizeof(*cl)); > - while ((compound_label = next_label(&cl->labels[cl->num_labels], > - compound_label))) { > - cl->num_labels++; > - > - if (cl->num_labels == MAX_LABELS) > - return false; > - } > - > - return true; > -} > - > -/* Returns true if the compound label contains the single label */ > -static bool compound_label_contains(struct compound_label *cl, > - struct single_label *sl) > -{ > - bool matched = false; > - size_t i; > - > - for (i = 0; !matched && i < cl->num_labels; i++) { > - if (cl->labels[i].len != sl->len) > - continue; > - > - if (strncmp(cl->labels[i].label, sl->label, sl->len)) > - continue; > - > - matched = true; > - } > - > - return matched; > -} > - > -/* Returns true if the two compound labels contain the same label sets */ > -static bool compound_labels_equal(struct compound_label *cl1, > - struct compound_label *cl2) > -{ > - size_t i; > - > - if (cl1->num_labels != cl2->num_labels) > - return false; > - > - for (i = 0; i < cl1->num_labels; i++) { > - if (!compound_label_contains(cl2, &cl1->labels[i])) > - return false; > - } > - > - return true; > -} > - > -/** > - * Verifies that the current confinement context matches the expected > context. > - * > - * Either @expected_label or @expected_mode can be NULL if their values > should > - * not be verified. If a NULL mode is expected, as what happens when an > - * unconfined process calls aa_getcon(2), then @expected_mode should be equal > - * to NO_MODE. > - */ > -static void verify_confinement_context(const char *expected_label, > - const char *expected_mode) > -{ > - char *label, *mode; > - int expected_rc, rc; > - bool null_expected_mode = expected_mode ? > - strcmp(NO_MODE, expected_mode) == 0 : false; > - > - rc = aa_getcon(&label, &mode); > - if (rc < 0) { > - int err = errno; > - fprintf(stderr, "FAIL - aa_getcon: %m"); > - exit(err); > - } > - > - if (expected_label) { > - struct compound_label cl, expected_cl; > - > - if (!compound_label_init(&cl, label)) { > - fprintf(stderr, "FAIL - could not parse current > compound label: %s\n", > - label); > - rc = EINVAL; > - goto err; > - } > - > - if (!compound_label_init(&expected_cl, expected_label)) { > - fprintf(stderr, "FAIL - could not parse expected > compound label: %s\n", > - expected_label); > - rc = EINVAL; > - goto err; > - } > - > - if (!compound_labels_equal(&cl, &expected_cl)) { > - fprintf(stderr, "FAIL - label \"%s\" != expected_label > \"%s\"\n", > - label, expected_label); > - rc = EINVAL; > - goto err; > - } > - } > - > - if (expected_mode && > - ((!mode && !null_expected_mode) || > - (mode && strcmp(mode, expected_mode)))) { > - fprintf(stderr, "FAIL - mode \"%s\" != expected_mode \"%s\"\n", > - mode, expected_mode); > - rc = EINVAL; > - goto err; > - } > - > - expected_rc = expected_label ? strlen(expected_label) : strlen(label); > - > - /** > - * Add the expected bytes following the returned label string: > - * > - * ' ' + '(' + mode + ')' > - */ > - if (expected_mode && !null_expected_mode) > - expected_rc += 1 + 1 + strlen(expected_mode) + 1; > - else if (mode) > - expected_rc += 1 + 1 + strlen(mode) + 1; > - > - expected_rc++; /* Trailing NUL terminator */ > - > - if (rc != expected_rc) { > - fprintf(stderr, "FAIL - rc (%d) != expected_rc (%d)\n", > - rc, expected_rc); > - rc = EINVAL; > - goto err; > - } > - > - return; > -err: > - free(label); > - exit(EINVAL); > -} > - > -static void stack_onexec(const char *label) > -{ > - if (aa_stack_onexec(label) != 0) { > - int err = errno; > - perror("FAIL - aa_stack_onexec"); > - exit(err); > - } > -} > - > -static void stack_profile(const char *label) > -{ > - if (aa_stack_profile(label) != 0) { > - int err = errno; > - perror("FAIL - aa_stack_profile"); > - exit(err); > - } > -} > - > -static void exec(const char *prog, char **argv) > -{ > - int err; > - > - execv(prog, argv); > - err = errno; > - perror("FAIL - execv"); > - exit(err); > -} > - > -static void usage(const char *prog) > -{ > - fprintf(stderr, > - "%s: [-o <LABEL> | -p <LABEL>] [-l <LABEL>] [-m <MODE>] [-f > <FILE>] [-- ... [-- ...]]\n" > - " -o <LABEL>\tCall aa_stack_onexec(LABEL)\n" > - " -p <LABEL>\tCall aa_stack_profile(LABEL)\n" > - " -l <LABEL>\tVerify that aa_getcon() returns LABEL\n" > - " -m <MODE>\tVerify that aa_getcon() returns MODE. Set to > \"%s\" if a NULL mode is expected.\n" > - " -f <FILE>\tOpen FILE and attempt to write to and read from > it\n\n" > - "If \"--\" is encountered, execv() will be called using the > following argument\n" > - "as the program to execute and passing it all of the arguments > following the\n" > - "program name.\n", prog, NO_MODE); > - exit(EINVAL); > -} > - > -struct options { > - const char *file; > - const char *expected_label; > - const char *expected_mode; > - const char *stack_onexec; > - const char *stack_profile; > - const char *exec; > - char **exec_argv; > -}; > - > -static void parse_opts(int argc, char **argv, struct options *opts) > -{ > - int o; > - > - memset(opts, 0, sizeof(*opts)); > - while ((o = getopt(argc, argv, "f:l:m:o:p:")) != -1) { > - switch (o) { > - case 'f': /* file */ > - opts->file = optarg; > - break; > - case 'l': /* expected label */ > - opts->expected_label = optarg; > - break; > - case 'm': /* expected mode */ > - opts->expected_mode = optarg; > - break; > - case 'o': /* aa_stack_onexec */ > - opts->stack_onexec = optarg; > - break; > - case 'p': /* aa_stack_profile */ > - opts->stack_profile = optarg; > - break; > - default: /* '?' */ > - usage(argv[0]); > - } > - } > - > - /* Can only specify one or the other */ > - if (opts->stack_onexec && opts->stack_profile) { > - usage(argv[0]); > - } > - > - if (optind < argc) { > - /* Ensure that the previous option was "--" */ > - if (optind == 0 || strcmp("--", argv[optind - 1])) > - usage(argv[0]); > - > - opts->exec = argv[optind]; > - opts->exec_argv = &argv[optind]; > - } > -} > - > -int main(int argc, char **argv) > -{ > - struct options opts; > - > - parse_opts(argc, argv, &opts); > - > - if (opts.stack_onexec) > - stack_onexec(opts.stack_onexec); > - else if (opts.stack_profile) > - stack_profile(opts.stack_profile); > - > - if (opts.file) > - file_io(opts.file); > - > - if (opts.expected_label || opts.expected_mode) > - verify_confinement_context(opts.expected_label, > - opts.expected_mode); > - > - if (opts.exec) > - exec(opts.exec, opts.exec_argv); > - > - printf("PASS\n"); > - exit(0); > -} > - > diff --git a/tests/regression/apparmor/stackonexec.sh > b/tests/regression/apparmor/stackonexec.sh > index 7bad824..565fbfc 100755 > --- a/tests/regression/apparmor/stackonexec.sh > +++ b/tests/regression/apparmor/stackonexec.sh > @@ -20,7 +20,7 @@ bin=$pwd > . $bin/prologue.inc > > requires_kernel_features domain/stack > -settest stacking > +settest transition > > file=$tmpdir/file > otherfile=$tmpdir/file2 > diff --git a/tests/regression/apparmor/stackprofile.sh > b/tests/regression/apparmor/stackprofile.sh > index 7f248a1..efe8a7c 100755 > --- a/tests/regression/apparmor/stackprofile.sh > +++ b/tests/regression/apparmor/stackprofile.sh > @@ -20,7 +20,7 @@ bin=$pwd > . $bin/prologue.inc > > requires_kernel_features domain/stack > -settest stacking > +settest transition > > file=$tmpdir/file > otherfile=$tmpdir/file2 > diff --git a/tests/regression/apparmor/transition.c > b/tests/regression/apparmor/transition.c > new file mode 100644 > index 0000000..ac1afce > --- /dev/null > +++ b/tests/regression/apparmor/transition.c > @@ -0,0 +1,337 @@ > +/* > + * Copyright (C) 2014-2016 Canonical, Ltd. > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of version 2 of the GNU General Public > + * License published by the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, contact Canonical Ltd. > + */ > + > +#define _GNU_SOURCE > + > +#include <errno.h> > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <sys/apparmor.h> > +#include <sys/socket.h> > +#include <sys/types.h> > +#include <unistd.h> > + > +#include "changehat.h" /* for do_open() */ > + > +#define STACK_DELIM "//&" > +#define STACK_DELIM_LEN strlen(STACK_DELIM) > + > +#define NO_MODE "(null)" > + > +static void file_io(const char *file) > +{ > + int rc = do_open(file); > + > + if (rc != 0) > + exit(rc); > +} > + > +struct single_label { > + const char *label; > + size_t len; > +}; > + > +#define MAX_LABELS 32 > + > +struct compound_label { > + size_t num_labels; > + struct single_label labels[MAX_LABELS]; > +}; > + > +/** > + * Initializes @sl by parsing @compound_label. Returns a pointer to the > + * location of the next label in the compound label string, which should be > + * passed in as @compound_label the next time that next_label() is called. > NULL > + * is returned when there are no more labels in @compound_label. > + */ > +static const char *next_label(struct single_label *sl, > + const char *compound_label) > +{ > + const char *delim; > + > + if (!compound_label || compound_label[0] == '\0') > + return NULL; > + > + delim = strstr(compound_label, STACK_DELIM); > + if (!delim) { > + sl->label = compound_label; > + sl->len = strlen(sl->label); > + return sl->label + sl->len; > + } > + > + sl->label = compound_label; > + sl->len = delim - sl->label; > + return delim + STACK_DELIM_LEN; > +} > + > +/* Returns true if the compound label was constructed successfully */ > +static bool compound_label_init(struct compound_label *cl, > + const char *compound_label) > +{ > + memset(cl, 0, sizeof(*cl)); > + while ((compound_label = next_label(&cl->labels[cl->num_labels], > + compound_label))) { > + cl->num_labels++; > + > + if (cl->num_labels == MAX_LABELS) > + return false; > + } > + > + return true; > +} > + > +/* Returns true if the compound label contains the single label */ > +static bool compound_label_contains(struct compound_label *cl, > + struct single_label *sl) > +{ > + bool matched = false; > + size_t i; > + > + for (i = 0; !matched && i < cl->num_labels; i++) { > + if (cl->labels[i].len != sl->len) > + continue; > + > + if (strncmp(cl->labels[i].label, sl->label, sl->len)) > + continue; > + > + matched = true; > + } > + > + return matched; > +} > + > +/* Returns true if the two compound labels contain the same label sets */ > +static bool compound_labels_equal(struct compound_label *cl1, > + struct compound_label *cl2) > +{ > + size_t i; > + > + if (cl1->num_labels != cl2->num_labels) > + return false; > + > + for (i = 0; i < cl1->num_labels; i++) { > + if (!compound_label_contains(cl2, &cl1->labels[i])) > + return false; > + } > + > + return true; > +} > + > +/** > + * Verifies that the current confinement context matches the expected > context. > + * > + * Either @expected_label or @expected_mode can be NULL if their values > should > + * not be verified. If a NULL mode is expected, as what happens when an > + * unconfined process calls aa_getcon(2), then @expected_mode should be equal > + * to NO_MODE. > + */ > +static void verify_confinement_context(const char *expected_label, > + const char *expected_mode) > +{ > + char *label, *mode; > + int expected_rc, rc; > + bool null_expected_mode = expected_mode ? > + strcmp(NO_MODE, expected_mode) == 0 : false; > + > + rc = aa_getcon(&label, &mode); > + if (rc < 0) { > + int err = errno; > + fprintf(stderr, "FAIL - aa_getcon: %m"); > + exit(err); > + } > + > + if (expected_label) { > + struct compound_label cl, expected_cl; > + > + if (!compound_label_init(&cl, label)) { > + fprintf(stderr, "FAIL - could not parse current > compound label: %s\n", > + label); > + rc = EINVAL; > + goto err; > + } > + > + if (!compound_label_init(&expected_cl, expected_label)) { > + fprintf(stderr, "FAIL - could not parse expected > compound label: %s\n", > + expected_label); > + rc = EINVAL; > + goto err; > + } > + > + if (!compound_labels_equal(&cl, &expected_cl)) { > + fprintf(stderr, "FAIL - label \"%s\" != expected_label > \"%s\"\n", > + label, expected_label); > + rc = EINVAL; > + goto err; > + } > + } > + > + if (expected_mode && > + ((!mode && !null_expected_mode) || > + (mode && strcmp(mode, expected_mode)))) { > + fprintf(stderr, "FAIL - mode \"%s\" != expected_mode \"%s\"\n", > + mode, expected_mode); > + rc = EINVAL; > + goto err; > + } > + > + expected_rc = expected_label ? strlen(expected_label) : strlen(label); > + > + /** > + * Add the expected bytes following the returned label string: > + * > + * ' ' + '(' + mode + ')' > + */ > + if (expected_mode && !null_expected_mode) > + expected_rc += 1 + 1 + strlen(expected_mode) + 1; > + else if (mode) > + expected_rc += 1 + 1 + strlen(mode) + 1; > + > + expected_rc++; /* Trailing NUL terminator */ > + > + if (rc != expected_rc) { > + fprintf(stderr, "FAIL - rc (%d) != expected_rc (%d)\n", > + rc, expected_rc); > + rc = EINVAL; > + goto err; > + } > + > + return; > +err: > + free(label); > + exit(EINVAL); > +} > + > +static void stack_onexec(const char *label) > +{ > + if (aa_stack_onexec(label) != 0) { > + int err = errno; > + perror("FAIL - aa_stack_onexec"); > + exit(err); > + } > +} > + > +static void stack_profile(const char *label) > +{ > + if (aa_stack_profile(label) != 0) { > + int err = errno; > + perror("FAIL - aa_stack_profile"); > + exit(err); > + } > +} > + > +static void exec(const char *prog, char **argv) > +{ > + int err; > + > + execv(prog, argv); > + err = errno; > + perror("FAIL - execv"); > + exit(err); > +} > + > +static void usage(const char *prog) > +{ > + fprintf(stderr, > + "%s: [-o <LABEL> | -p <LABEL>] [-l <LABEL>] [-m <MODE>] [-f > <FILE>] [-- ... [-- ...]]\n" > + " -o <LABEL>\tCall aa_stack_onexec(LABEL)\n" > + " -p <LABEL>\tCall aa_stack_profile(LABEL)\n" > + " -l <LABEL>\tVerify that aa_getcon() returns LABEL\n" > + " -m <MODE>\tVerify that aa_getcon() returns MODE. Set to > \"%s\" if a NULL mode is expected.\n" > + " -f <FILE>\tOpen FILE and attempt to write to and read from > it\n\n" > + "If \"--\" is encountered, execv() will be called using the > following argument\n" > + "as the program to execute and passing it all of the arguments > following the\n" > + "program name.\n", prog, NO_MODE); > + exit(EINVAL); > +} > + > +struct options { > + const char *file; > + const char *expected_label; > + const char *expected_mode; > + const char *stack_onexec; > + const char *stack_profile; > + const char *exec; > + char **exec_argv; > +}; > + > +static void parse_opts(int argc, char **argv, struct options *opts) > +{ > + int o; > + > + memset(opts, 0, sizeof(*opts)); > + while ((o = getopt(argc, argv, "f:l:m:o:p:")) != -1) { > + switch (o) { > + case 'f': /* file */ > + opts->file = optarg; > + break; > + case 'l': /* expected label */ > + opts->expected_label = optarg; > + break; > + case 'm': /* expected mode */ > + opts->expected_mode = optarg; > + break; > + case 'o': /* aa_stack_onexec */ > + opts->stack_onexec = optarg; > + break; > + case 'p': /* aa_stack_profile */ > + opts->stack_profile = optarg; > + break; > + default: /* '?' */ > + usage(argv[0]); > + } > + } > + > + /* Can only specify one or the other */ > + if (opts->stack_onexec && opts->stack_profile) { > + usage(argv[0]); > + } > + > + if (optind < argc) { > + /* Ensure that the previous option was "--" */ > + if (optind == 0 || strcmp("--", argv[optind - 1])) > + usage(argv[0]); > + > + opts->exec = argv[optind]; > + opts->exec_argv = &argv[optind]; > + } > +} > + > +int main(int argc, char **argv) > +{ > + struct options opts; > + > + parse_opts(argc, argv, &opts); > + > + if (opts.stack_onexec) > + stack_onexec(opts.stack_onexec); > + else if (opts.stack_profile) > + stack_profile(opts.stack_profile); > + > + if (opts.file) > + file_io(opts.file); > + > + if (opts.expected_label || opts.expected_mode) > + verify_confinement_context(opts.expected_label, > + opts.expected_mode); > + > + if (opts.exec) > + exec(opts.exec, opts.exec_argv); > + > + printf("PASS\n"); > + exit(0); > +} > + > -- AppArmor mailing list [email protected] Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/apparmor
