On 2014-05-06 19:20:32, Tyler Hicks wrote: > Bug: https://bugs.launchpad.net/bugs/1235478 > > This is a test to check the label on file descriptors returned from > socketpair(). > > In its simple form, it simply calls socketpair() and checks the > labels on both fds. > > In its complex form, it has the ability to do the simple test, then set > up an exec transition using aa_change_onexec(), and re-exec itself to > check the labeling after the file descriptors have been passed across an > exec transition. > > The complex form is meant to test revalidation at exec. AppArmor > currently keeps the original labeling in place across the exec > transition. > > Note that this test does not currently test read/write access to the > file descriptors. It only checks the label, as returned by > aa_getpeercon(2). > > Signed-off-by: Tyler Hicks <[email protected]> > --- > tests/regression/apparmor/Makefile | 2 + > tests/regression/apparmor/socketpair.c | 192 > ++++++++++++++++++++++++++++++++ > tests/regression/apparmor/socketpair.sh | 90 +++++++++++++++ > 3 files changed, 284 insertions(+) > create mode 100644 tests/regression/apparmor/socketpair.c > create mode 100755 tests/regression/apparmor/socketpair.sh > > diff --git a/tests/regression/apparmor/Makefile > b/tests/regression/apparmor/Makefile > index 08afdf6..55f59a3 100644 > --- a/tests/regression/apparmor/Makefile > +++ b/tests/regression/apparmor/Makefile > @@ -97,6 +97,7 @@ SRC=access.c \ > rename.c \ > readdir.c \ > rw.c \ > + socketpair.c \ > symlink.c \ > syscall_mknod.c \ > swap.c \ > @@ -174,6 +175,7 @@ TESTS=access \ > rename \ > readdir \ > rw \ > + socketpair \ > swap \ > sd_flags \ > setattr \ > diff --git a/tests/regression/apparmor/socketpair.c > b/tests/regression/apparmor/socketpair.c > new file mode 100644 > index 0000000..9a64ba7 > --- /dev/null > +++ b/tests/regression/apparmor/socketpair.c > @@ -0,0 +1,192 @@ > +/* > + * Copyright (C) 2014 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> > + > +#define NO_MODE "(null)" > + > +#define ENV_FD0 "_SOCKETPAIR_FD0" > +#define ENV_FD1 "_SOCKETPAIR_FD1" > + > +static int get_socketpair(int pair[2]) > +{ > + char *fd0, *fd1; > + > + fd0 = getenv(ENV_FD0); > + fd1 = getenv(ENV_FD1); > + > + if (fd0 && fd1) { > + pair[0] = atoi(fd0); > + pair[1] = atoi(fd1); > + } else { > + if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) < 0) { > + perror("FAIL - socketpair"); > + return 1; > + } > + } > + > + return 0; > +} > + > +static int verify_confinement_context(int fd, const char *fd_name, > + const char *expected_con, > + const char *expected_mode) > +{ > + char *con, *mode; > + int rc; > + > + rc = aa_getpeercon(fd, &con, &mode); > + if (rc < 0) { > + fprintf(stderr, "FAIL - %s: aa_getpeercon(%d, , ): %m", > + fd_name, fd); > + return 1; > + } > + > + if (!mode) > + mode = NO_MODE; > + > + if (strcmp(con, expected_con)) { > + fprintf(stderr, > + "FAIL - %s: con \"%s\" != expected_con \"%s\"\n", > + fd_name, con, expected_con); > + rc = 2; > + goto out; > + } > + > + if (strcmp(mode, expected_mode)) { > + fprintf(stderr, > + "FAIL - %s: mode \"%s\" != expected_mode \"%s\"\n", > + fd_name, mode, expected_mode); > + rc = 3; > + goto out; > + } > + > + rc = 0; > +out: > + free(con); > + return rc; > +} > + > +static int reexec(int pair[2], int argc, char **argv) > +{ > + char *new_profile; > + char fd_str[32]; > + > + /* Less than 4 arguments means that no <CHANGE_ONEXEC> args exist */ > + if (argc < 4) > + return 0; > + > + /** > + * Save off the first <CHANGE_ONEXEC> arg and then shift all preceeding > + * args by one to effectively pop off the first <CHANGE_ONEXEC> > + */ > + new_profile = argv[3]; > + argv[3] = argv[2]; > + argv[2] = argv[1]; > + argv[1] = argv[0]; > + argv++; > + > + if (aa_change_onexec(new_profile) < 0) { > + perror("FAIL - aa_change_onexec"); > + return 1; > + } > + > + snprintf(fd_str, sizeof(fd_str), "%d", pair[0]); > + if (setenv(ENV_FD0, fd_str, 1) < 0) { > + perror("FAIL - setenv"); > + return 2; > + } > + > + snprintf(fd_str, sizeof(fd_str), "%d", pair[1]); > + if (setenv(ENV_FD1, fd_str, 1) < 0) { > + perror("FAIL - setenv"); > + return 3; > + } > + > + execv(argv[0], argv); > + > + perror("FAIL - execv"); > + return 4; > +} > + > +int main(int argc, char **argv) > +{ > + char *expected_con, *expected_mode; > + int pair[2], rc; > + > + if (argc < 3) { > + fprintf(stderr, > + "FAIL - usage: %s <CON> <MODE> [<CHANGE_ONEXEC> > ...]\n\n" > + " <CON>\t\tThe expected confinement context\n" > + " <MODE>\tThe expected confinement mode\n" > + " <CHANGE_ONEXEC>\tThe profile to change to on > exec\n\n" > + "This program gets a socket pair and then verifies \n" > + "the confinement context and mode of each file \n" > + "descriptor. If there is no expected mode string, \n" > + "<MODE> should be \"%s\".\n\n" > + "Multiple <CHANGE_ONEXEC> profiles can be specified \n" > + "and the test will run normally for the first pair, \n" > + "then call aa_change_onexec() to rexec itself under \n" > + "the next <CHANGE_ONEXEC> and verify the passed in \n" > + "socket pairs still have the correct labeling.\n" , > + argv[0], NO_MODE); > + exit(1); > + } > + > + /** > + * If ENV_FD0 and ENV_FD1 are set, they'll point to fds that were > + * passed in. If they're not set, call socketpair(). > + */ > + if (get_socketpair(pair)) > + exit(2); > + > + expected_con = argv[1]; > + expected_mode = argv[2]; > + > + if (verify_confinement_context(pair[0], "pair[0]", > + expected_con, expected_mode)) { > + rc = 3; > + goto out; > + } > + > + if (verify_confinement_context(pair[1], "pair[1]", > + expected_con, expected_mode)) { > + rc = 4; > + goto out; > + } > + > + if (reexec(pair, argc, argv)) { > + rc = 5; > + goto out; > + } > + > + printf("PASS\n"); > + rc = 0; > +out: > + close(pair[0]); > + close(pair[1]); > + exit(rc); > +} > + > diff --git a/tests/regression/apparmor/socketpair.sh > b/tests/regression/apparmor/socketpair.sh > new file mode 100755 > index 0000000..9e6a145 > --- /dev/null > +++ b/tests/regression/apparmor/socketpair.sh > @@ -0,0 +1,90 @@ > +#! /bin/bash > +# Copyright (C) 2014 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 socketpair > +#=DESCRIPTION > +# This test verifies that the fds returned from the socketpair syscall are > +# correctly labeled > +#=END > + > +pwd=`dirname $0` > +pwd=`cd $pwd ; /bin/pwd` > + > +bin=$pwd > + > +. $bin/prologue.inc > + > +do_test() > +{ > + local desc="SOCKETPAIR ($1)" > + shift > + > + runchecktest "$desc" "$@" > +} > + > +exec="/proc/*/attr/exec:w" > +np1="new_profile_1" > +np2="new_profile_2" > + > +# Ensure everything works as expected when unconfined > +do_test "unconfined" pass "unconfined" "(null)" > + > +# Test the test > +do_test "unconfined bad con" fail "uncon" "(null)" > +do_test "unconfined bad mode" fail "unconfined" "(null)XXX" > + > +# Ensure correct labeling under confinement > +genprofile > +do_test "confined" pass "$test" "enforce" > + > +# Test the test > +do_test "confined bad con" fail "/bad${test}" "enforce" > +do_test "confined bad mode" fail "$test" "inforce" > + > +# Ensure correct mode when using the complain flag > +genprofile flag:complain > +do_test "complain" pass "$test" "complain" > + > +# Test the test > +genprofile flag:complain > +do_test "complain bad mode" fail "$test" "enforce" > + > +# Ensure correct mode when using the audit flag > +genprofile flag:audit > +do_test "complain" pass "$test" "enforce" > + > +# Ensure correct labeling after passing fd pair across exec > +genprofile $exec 'change_profile->':$np1 -- image=$np1 addimage:$test > +do_test "confined exec transition" pass "$test" "enforce" "$np1" > + > +# Ensure correct labeling after passing fd pair across a no-transition exec > +# NOTE: The test still calls aa_change_onexec(), so change_profile -> $test > +# is still needed > +genprofile $exec 'change_profile->':$test > +do_test "confined exec no transition" pass "$test" "enforce" "$test" > + > +# Ensure correct complain mode after passing fd pair across exec > +genprofile flag:complain $exec 'change_profile->':$np1 -- \ > + image=$np1 addimage:$test > +do_test "confined exec transition from complain" pass "$test" "complain" > "$np1" > + > +# Ensure correct enforce mode after passing fd pair across exec > +genprofile $exec 'change_profile->':$np1 -- \ > + image=$np1 addimage:$test flag:complain > +do_test "confined exec transition to complain" pass "$test" "enforce" "$np1" > + > +# Ensure correct labeling after passing fd pair across 2 execs > +gp_args="$exec change_profile->:$np1 -- \ > + image=$np1 addimage:$test $exec change_profile->:$np2 -- \ > + image=$np2 addimage:$test" > +genprofile $gp_args > +do_test "confined 2 exec transitions" pass "$test" "enforce" "$np1" "$np2" > + > +# Test the test > +do_test "confined 2 exec transitions bad con" fail "$test" "enforce" "$np1" > "$np1" > +do_test "confined 2 exec transitions bad mode" fail "$test" "complain" > "$np1" "$np2"
Lets add these two oddballs while we're at it. diff --git a/tests/regression/apparmor/socketpair.sh b/tests/regression/apparmor/socketpair.sh index 9e6a145..8af3be2 100755 --- a/tests/regression/apparmor/socketpair.sh +++ b/tests/regression/apparmor/socketpair.sh @@ -88,3 +88,11 @@ do_test "confined 2 exec transitions" pass "$test" "enforce" "$np1" "$np2" # Test the test do_test "confined 2 exec transitions bad con" fail "$test" "enforce" "$np1" "$np1" do_test "confined 2 exec transitions bad mode" fail "$test" "complain" "$np1" "$np2" + +# Ensure correct labeling after passing fd pair across exec to unconfined +genprofile $exec 'change_profile->':unconfined +do_test "confined exec transition to unconfined" pass "$test" "enforce" "unconfined" + +# Ensure correct labeling after passing fd pair across exec from unconfined +genprofile image=$np1 addimage:$test +do_test "unconfined exec transition ton confined" pass "unconfined" "(null)" "$np1"
signature.asc
Description: Digital signature
-- AppArmor mailing list [email protected] Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/apparmor
