From c1722cdfdbd08dce724be841e1918ba2d91c279f Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 26 Mar 2012 06:11:16 -0700 Subject: [PATCH] Fix permission mapping for change_profile onexec Bug #963756 The kernel has an extended test for change_profile when used with onexec, that allows it to only work against set executables. The parser is not correctly mapping change_profile for this test update the mapping so change_onexec will work when confined. Note: the parser does not currently support the extended syntax that the kernel test allows for, this just enables it to work for the generic case. Signed-off-by: John Johansen --- parser/immunix.h | 1 + parser/parser_regex.c | 27 +++-- tests/regression/apparmor/Makefile | 2 + tests/regression/apparmor/onexec.c | 58 +++++++++ tests/regression/apparmor/onexec.sh | 181 ++++++++++++++++++++++++++++ 5 files changed, 260 insertions(+), 9 deletions(-) create mode 100644 tests/regression/apparmor/onexec.c create mode 100644 tests/regression/apparmor/onexec.sh diff --git a/parser/immunix.h b/parser/immunix.h index 8dc157a14..ebb2d2ec6 100644 --- a/parser/immunix.h +++ b/parser/immunix.h @@ -61,6 +61,7 @@ #define AA_PTRACE_PERMS (AA_USER_PTRACE | AA_OTHER_PTRACE) #define AA_CHANGE_HAT (1 << 30) +#define AA_ONEXEC (1 << 30) #define AA_CHANGE_PROFILE (1 << 31) #define AA_SHARED_PERMS (AA_CHANGE_HAT | AA_CHANGE_PROFILE) diff --git a/parser/parser_regex.c b/parser/parser_regex.c index 8c34799a0..c77437239 100644 --- a/parser/parser_regex.c +++ b/parser/parser_regex.c @@ -510,19 +510,28 @@ static int process_dfa_entry(aare_ruleset_t *dfarules, struct cod_entry *entry) return FALSE; } if (entry->mode & AA_CHANGE_PROFILE) { + char *vec[3]; + char lbuf[PATH_MAX + 8]; + int index = 1; + + /* allow change_profile for all execs */ + vec[0] = "/[^\\x00]*"; + if (entry->namespace) { - char *vec[2]; - char lbuf[PATH_MAX + 8]; int pos; ptype = convert_aaregex_to_pcre(entry->namespace, 0, lbuf, PATH_MAX + 8, &pos); - vec[0] = lbuf; - vec[1] = tbuf; - if (!aare_add_rule_vec(dfarules, 0, AA_CHANGE_PROFILE, 0, 2, vec, dfaflags)) - return FALSE; - } else { - if (!aare_add_rule(dfarules, tbuf, 0, AA_CHANGE_PROFILE, 0, dfaflags)) - return FALSE; + vec[index++] = lbuf; } + vec[index++] = tbuf; + + /* regular change_profile rule */ + if (!aare_add_rule_vec(dfarules, 0, AA_CHANGE_PROFILE, 0, index - 1, &vec[1], dfaflags)) + return FALSE; + /* onexec rules - both rules are needed for onexec */ + if (!aare_add_rule_vec(dfarules, 0, AA_ONEXEC, 0, 1, vec, dfaflags)) + return FALSE; + if (!aare_add_rule_vec(dfarules, 0, AA_ONEXEC, 0, index, vec, dfaflags)) + return FALSE; } if (entry->mode & (AA_USER_PTRACE | AA_OTHER_PTRACE)) { int mode = entry->mode & (AA_USER_PTRACE | AA_OTHER_PTRACE); diff --git a/tests/regression/apparmor/Makefile b/tests/regression/apparmor/Makefile index b288626ff..2021f515f 100644 --- a/tests/regression/apparmor/Makefile +++ b/tests/regression/apparmor/Makefile @@ -8,6 +8,7 @@ SRC=access.c \ introspect.c \ changeprofile.c \ + onexec.c \ changehat.c \ changehat_fork.c \ changehat_misc.c \ @@ -110,6 +111,7 @@ TESTS=access \ introspect \ capabilities \ changeprofile \ + onexec \ changehat \ changehat_fork \ changehat_misc \ diff --git a/tests/regression/apparmor/onexec.c b/tests/regression/apparmor/onexec.c new file mode 100644 index 000000000..bcb52580e --- /dev/null +++ b/tests/regression/apparmor/onexec.c @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2002-2005 Novell/SUSE + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "changehat.h" + +int main(int argc, char *argv[]) +{ + int rc = 0; + + extern char **environ; + + if (argc < 3){ + fprintf(stderr, "usage: %s profile executable args\n", + argv[0]); + return 1; + } + + /* change profile if profile name != nochange */ + if (strcmp(argv[1], "nochange") != 0){ + rc = aa_change_onexec(argv[1]); + if (rc == -1){ + fprintf(stderr, "FAIL: change_onexec %s failed - %s\n", + argv[1], strerror(errno)); + exit(errno); + } + } + + /* stop after onexec and wait to for continue before exec so + * caller can introspect task */ + (void)kill(getpid(), SIGSTOP); + + (void)execve(argv[2], &argv[2], environ); + /* exec failed, kill outselves to flag parent */ + + rc = errno; + + fprintf(stderr, "FAIL: exec to '%s' failed\n", argv[2]); + + return rc; +} diff --git a/tests/regression/apparmor/onexec.sh b/tests/regression/apparmor/onexec.sh new file mode 100644 index 000000000..38d4632ae --- /dev/null +++ b/tests/regression/apparmor/onexec.sh @@ -0,0 +1,181 @@ +#! /bin/bash +# Copyright (C) 2012 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 onexec +#=DESCRIPTION +# Verifies basic file access permission checks for change_onexec +#=END + +pwd=`dirname $0` +pwd=`cd $pwd ; /bin/pwd` + +bin=$pwd + +. $bin/prologue.inc + +file=$tmpdir/file +subfile=$tmpdir/file2 +okperm=rw + +othertest="$pwd/rename" +subtest="sub" +fqsubbase="$pwd/onexec" +fqsubtest="$fqsubbase//$subtest" +subtest2="$pwd//sub2" +subtest3="$pwd//sub3" + +onexec="/proc/*/attr/exec" + +touch $file $subfile + +check_exec() +{ + local rc + local actual + actual=`cat /proc/$1/attr/exec 2>/dev/null` + rc=$? + + # /proc/$1/attr/exec returns invalid argument if onexec has not been called + if [ $rc -ne 0 ] ; then + if [ "$2" == "nochange" ] ; then + return 0 + fi + echo "ONEXEC - exec transition not set" + return $rc + fi + if [ "${actual% (*)}" != "$2" ] ; then + echo "ONEXEC - check exec '${actual% (*)}' != expected '$2'" + return 1 + fi + + return 0 +} + +check_current() +{ + local rc + local actual + actual=`cat /proc/$1/attr/current 2>/dev/null` + rc=$? + + # /proc/$1/attr/current return enoent if the onexec process already exited due to error + if [ $rc -ne 0 ] ; then + return $rc + fi + + if [ "${actual% (*)}" != "$2" ] ; then + echo "ONEXEC - check current '${actual% (*)}' != expected '$2'" + return 1 + fi + + return 0 +} + +do_test() +{ + local desc="$1" + local prof="$2" + local target_prof="$3" + local res="$4" + shift 4 + + #ignore prologue.inc error trapping that catches our subfn return values + + runtestbg "ONEXEC $desc ($prof -> $target_prof)" $res $target_prof "$@" + # check that transition does not happen before exec, and that transition + # is set + + if ! check_current $_pid $prof ; then + checktestfg + return + fi + + if ! check_exec $_pid $target_prof ; then + checktestfg + return + fi + + kill -CONT $_pid + + checktestbg +} + + +# ONEXEC from UNCONFINED - don't change profile +do_test "" unconfined nochange pass $bin/open $file + +# ONEXEC from UNCONFINED - target does NOT exist +genprofile image=$bin/rw $bin/open:rix $file:rw -- image=$bin/open +do_test "" unconfined noexist fail $bin/open $file + +# ONEXEC from UNCONFINED - change to rw profile, no exec profile to override +genprofile image=$bin/rw $bin/open:rix $file:rw +do_test "no px profile" unconfined $bin/rw pass $bin/open $file + +# ONEXEC from UNCONFINED - don't change profile, make sure exec profile is applied +genprofile image=$bin/rw $bin/open:px $file:rw -- image=$bin/open $file:rw +do_test "nochange px" unconfined nochange pass $bin/open $file + +# ONEXEC from UNCONFINED - change to rw profile, override regular exec profile, exec profile doesn't have perms +genprofile image=$bin/rw $bin/open:px $file:rw -- image=$bin/open +do_test "override px" unconfined $bin/rw pass $bin/open $file + +#------ + +# ONEXEC from CONFINED - don't change profile, open can't exec +genprofile 'change_profile->':$bin/rw $onexec:w +do_test "no px perm" $bin/onexec nochange fail $bin/open $file + +# ONEXEC from CONFINED - don't change profile, open is run unconfined +genprofile 'change_profile->':$bin/rw $bin/open:rux $onexec:w +do_test "nochange rux" $bin/onexec nochange pass $bin/open $file + +# ONEXEC from CONFINED - don't change profile, open is run confined without necessary perms +genprofile 'change_profile->':$bin/rw $onexec:w -- image=$bin/open $file:rw +do_test "nochange px - no px perm" $bin/onexec nochange fail $bin/open $file + +# ONEXEC from CONFINED - don't change profile, open is run confined without necessary perms +genprofile 'change_profile->':$bin/rw $bin/open:rpx $onexec:w -- image=$bin/open +do_test "nochange px - no file perm" $bin/onexec nochange fail $bin/open $file + +# ONEXEC from CONFINED - target does NOT exist +genprofile 'change_profile->':$bin/open $onexec:w -- image=$bin/rw $bin/open:rix $file:rw -- image=$bin/open +do_test "noexist px" $bin/onexec noexist fail $bin/open $file + +# ONEXEC from CONFINED - change to rw profile, no exec profile to override +genprofile 'change_profile->':$bin/rw $onexec:w -- image=$bin/rw $bin/open:rix $file:rw +do_test "change profile - override rix" $bin/onexec $bin/rw pass $bin/open $file + +# ONEXEC from CONFINED - change to rw profile, no exec profile to override +genprofile 'change_profile->':$bin/rw -- image=$bin/rw $bin/open:rix $file:rw +do_test "change profile - no onexec:w" $bin/onexec $bin/rw fail $bin/open $file + +# ONEXEC from CONFINED - don't change profile, make sure exec profile is applied +genprofile 'change_profile->':$bin/rw $onexec:w $bin/open:rpx -- image=$bin/rw $bin/open:rix $file:rw -- image=$bin/open $file:rw +do_test "nochange px" $bin/onexec nochange pass $bin/open $file + +# ONEXEC from CONFINED - change to rw profile, override regular exec profile, exec profile doesn't have perms +genprofile 'change_profile->':$bin/rw $onexec:w -- image=$bin/rw $bin/open:rix $file:rw -- image=$bin/open +do_test "override px" $bin/onexec $bin/rw pass $bin/open $file + +# ONEXEC from - change to rw profile, override regular exec profile, exec profile has perms, rw doesn't +genprofile 'change_profile->':$bin/rw $onexec:w -- image=$bin/rw $bin/open:rix -- image=$bin/open $file:rw +do_test "override px" $bin/onexec $bin/rw fail $bin/open $file + +# ONEXEC from COFINED - change to rw profile via glob rule, override exec profile, exec profile doesn't have perms +genprofile 'change_profile->':/** $onexec:w -- image=$bin/rw $bin/open:rix $file:rw -- image=$bin/open +do_test "glob override px" $bin/onexec $bin/rw pass $bin/open $file + +# ONEXEC from COFINED - change to exec profile via glob rule, override exec profile, exec profile doesn't have perms +genprofile 'change_profile->':/** $onexec:w -- image=$bin/rw $bin/open:rix $file:rw -- image=$bin/open +do_test "glob override px" $bin/onexec $bin/open fail $bin/open $file + +# ONEXEC from COFINED - change to exec profile via glob rule, override exec profile, exec profile has perms +genprofile 'change_profile->':/** $onexec:w -- image=$bin/rw $bin/open:rix $file:rw -- image=$bin/open $file:rw +do_test "glob override px" $bin/onexec $bin/rw pass $bin/open $file +