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 <[email protected]>
---
 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 100755 tests/regression/apparmor/onexec.sh

diff --git a/parser/immunix.h b/parser/immunix.h
index 8dc157a..ebb2d2e 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 8c34799..c774372 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 b288626..2021f51 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 0000000..bcb5258
--- /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 <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <linux/unistd.h>
+
+#include <sys/apparmor.h>
+#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 100755
index 0000000..38d4632
--- /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
+
-- 
1.7.9.1


-- 
AppArmor mailing list
[email protected]
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/apparmor

Reply via email to