[apparmor] [PATCH 03/11] tests: Regression tests to verify AT_SECURE across exec transitions

Tyler Hicks tyhicks at canonical.com
Wed May 25 20:59:35 UTC 2016


The AT_SECURE value in the kernel's per-process auxiliary vector is what
signals to libc that the process' environment should be scrubbed. This
new set of regression tests checks the AT_SECURE value after performing
the various types of exec transitions that AppArmor supports (file rules
with different exec access modes and change_profile rules).

Different versions of the kernel handle AT_SECURE differently with
respect to change_profile rules. This change in behavior was introduced
in the AppArmor profile stacking kernel support and the tests are
conditionalized to account for this change.

Signed-off-by: Tyler Hicks <tyhicks at canonical.com>
---
 tests/regression/apparmor/Makefile     |   5 ++
 tests/regression/apparmor/at_secure.c  |  55 ++++++++++++
 tests/regression/apparmor/at_secure.sh | 153 +++++++++++++++++++++++++++++++++
 3 files changed, 213 insertions(+)
 create mode 100644 tests/regression/apparmor/at_secure.c
 create mode 100755 tests/regression/apparmor/at_secure.sh

diff --git a/tests/regression/apparmor/Makefile b/tests/regression/apparmor/Makefile
index f194396..8d75c69 100644
--- a/tests/regression/apparmor/Makefile
+++ b/tests/regression/apparmor/Makefile
@@ -70,6 +70,7 @@ endif # USE_SYSTEM
 CFLAGS += -g -O0 -Wall -Wstrict-prototypes
 
 SRC=access.c \
+    at_secure.c \
     introspect.c \
     changeprofile.c \
     onexec.c \
@@ -187,6 +188,7 @@ EXEC=$(SRC:%.c=%)
 
 TESTS=aa_exec \
       access \
+      at_secure \
       introspect \
       capabilities \
       changeprofile \
@@ -265,6 +267,9 @@ else # !USE_SYSTEM
 	cp uservars.inc.source uservars.inc
 endif # USE_SYSTEM
 
+at_secure: at_secure.c transition
+	${CC} ${CFLAGS} ${LDFLAGS} $< -o $@ ${LDLIBS}
+
 changehat_pthread: changehat_pthread.c changehat.h
 	${CC} ${CFLAGS} ${LDFLAGS} $< -o $@ ${LDLIBS} -pthread
 
diff --git a/tests/regression/apparmor/at_secure.c b/tests/regression/apparmor/at_secure.c
new file mode 100644
index 0000000..bfb80b8
--- /dev/null
+++ b/tests/regression/apparmor/at_secure.c
@@ -0,0 +1,55 @@
+/**
+ * Copyright (C) 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.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/auxv.h>
+
+int check_at_secure(unsigned long expected)
+{
+	unsigned long at_secure;
+
+	errno = 0;
+	at_secure = getauxval(AT_SECURE);
+	if (at_secure == 0 && errno != 0) {
+		perror("FAIL - getauxval");
+		return 1;
+	}
+
+	if (at_secure != expected) {
+		fprintf(stderr,
+			"FAIL - AT_SECURE value (%lu) did not match the expected value (%lu)\n",
+			at_secure, expected);
+		return 1;
+	}
+
+	printf("PASS\n");
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	unsigned long expected;
+
+	if (argc != 2) {
+		fprintf(stderr, "usage: %s EXPECTED_AT_SECURE\n", argv[0]);
+		return 1;
+	}
+
+	expected = strtoul(argv[1], NULL, 10);
+	return check_at_secure(expected);
+}
diff --git a/tests/regression/apparmor/at_secure.sh b/tests/regression/apparmor/at_secure.sh
new file mode 100755
index 0000000..7c507e7
--- /dev/null
+++ b/tests/regression/apparmor/at_secure.sh
@@ -0,0 +1,153 @@
+#! /bin/bash
+#	Copyright (C) 2016 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 at_secure
+#=DESCRIPTION
+# Verifies the AT_SECURE flag in the auxillary vector after an exec transition
+#=END
+
+pwd=`dirname $0`
+pwd=`cd $pwd ; /bin/pwd`
+
+bin=$pwd
+
+. $bin/prologue.inc
+
+settest transition
+at_secure=$pwd/at_secure
+test_prof=at_secure
+stacking_supported="$(kernel_features domain/stack || true)"
+
+onexec_default=1
+if [ "$stacking_supported" != "true" ]; then
+	# Pre-stacking kernels default to insecure exec transitions with
+	# change_profile rules that have an exec condition but don't have an
+	# "(un)safe" modifier.
+	onexec_default=0
+fi
+
+# Verify AT_SECURE after unconfined -> unconfined transition
+runchecktest "AT_SECURE (unconfined -> unconfined - change_onexec)" \
+	pass -O unconfined -- $at_secure 0
+runchecktest "AT_SECURE (unconfined -> unconfined - change_onexec) [NEGATIVE]" \
+	fail -O unconfined -- $at_secure 1
+
+# Verify AT_SECURE after unconfined -> confined transition
+genprofile image=$test_prof addimage:$at_secure
+runchecktest "AT_SECURE (unconfined -> confined - change_onexec)" \
+	pass -O $test_prof -- $at_secure 0
+runchecktest "AT_SECURE (unconfined -> confined - change_onexec) [NEGATIVE]" \
+	fail -O $test_prof -- $at_secure 1
+
+genprofile image=$at_secure
+runchecktest "AT_SECURE (unconfined -> confined - binary attachment)" \
+	pass -- $at_secure 0
+runchecktest "AT_SECURE (unconfined -> confined - binary attachment) [NEGATIVE]" \
+	fail -- $at_secure 1
+
+# Verify AT_SECURE after confined -> unconfined transition
+genprofile "change_profile:unconfined"
+runchecktest "AT_SECURE (confined -> unconfined - change_onexec)" \
+	pass -O unconfined -- $at_secure $onexec_default
+
+genprofile $at_secure:ux
+runchecktest "AT_SECURE (confined -> unconfined - ux)" \
+	pass -- $at_secure 0
+
+genprofile $at_secure:Ux
+runchecktest "AT_SECURE (confined -> unconfined - Ux)" \
+	pass -- $at_secure 1
+
+genprofile $at_secure:pux
+runchecktest "AT_SECURE (confined -> unconfined - pux fallback)" \
+	pass -- $at_secure 0
+
+genprofile $at_secure:PUx
+runchecktest "AT_SECURE (confined -> unconfined - PUx fallback)" \
+	pass -- $at_secure 1
+
+genprofile $at_secure:cux
+runchecktest "AT_SECURE (confined -> unconfined - cux fallback)" \
+	pass -- $at_secure 0
+
+genprofile $at_secure:CUx
+runchecktest "AT_SECURE (confined -> unconfined - CUx fallback)" \
+	pass -- $at_secure 1
+
+# Verify AT_SECURE after confined -> confined transition
+genprofile "change_profile:$test_prof" -- image=$test_prof addimage:$at_secure
+runchecktest "AT_SECURE (confined -> confined - change_onexec)" \
+	pass -O $test_prof -- $at_secure $onexec_default
+
+genprofile $at_secure:px -- image=$at_secure
+runchecktest "AT_SECURE (confined -> confined - px)" \
+	pass -- $at_secure 0
+
+genprofile $at_secure:Px -- image=$at_secure
+runchecktest "AT_SECURE (confined -> confined - Px)" \
+	pass -- $at_secure 1
+
+genprofile $at_secure:pux -- image=$at_secure
+runchecktest "AT_SECURE (confined -> confined - pux)" \
+	pass -- $at_secure 0
+
+genprofile $at_secure:PUx -- image=$at_secure
+runchecktest "AT_SECURE (confined -> confined - PUx)" \
+	pass -- $at_secure 1
+
+genprofile $at_secure:ix -- image=$at_secure
+runchecktest "AT_SECURE (confined -> confined - ix)" \
+	pass -- $at_secure 0
+
+genprofile $at_secure:pix -- image=$at_secure
+runchecktest "AT_SECURE (confined -> confined - pix)" \
+	pass -- $at_secure 0
+
+genprofile $at_secure:Pix -- image=$at_secure
+runchecktest "AT_SECURE (confined -> confined - Pix)" \
+	pass -- $at_secure 1
+
+genprofile $at_secure:cix -- image=$at_secure
+runchecktest "AT_SECURE (confined -> confined - cix fallback)" \
+	pass -- $at_secure 0
+
+genprofile $at_secure:Cix -- image=$at_secure
+runchecktest "AT_SECURE (confined -> confined - Cix fallback)" \
+	pass -- $at_secure 0
+
+# TODO: Adjust mkprofile.pl to allow child profiles so that cx and Cx can be
+# tested as well as the non-fallback cix and Cix cases
+
+if [ "$stacking_supported" != "true" ]; then
+	echo "Warning: kernel doesn't support stacking. Skipping tests..."
+else
+	removeprofile
+
+	# Verify AT_SECURE after unconfined -> &unconfined stacking transition
+	runchecktest "AT_SECURE (unconfined -> &unconfined - stack_onexec)" \
+		pass -o unconfined -- $at_secure 0
+	runchecktest "AT_SECURE (unconfined -> &unconfined - stack_onexec) [NEGATIVE]" \
+		fail -o unconfined -- $at_secure 1
+
+	# Verify AT_SECURE after unconfined -> &confined stacking transition
+	genprofile image=$test_prof addimage:$at_secure
+	runchecktest "AT_SECURE (unconfined -> &confined - stack_onexec)" \
+		pass -o $test_prof -- $at_secure 0
+	runchecktest "AT_SECURE (unconfined -> &confined - stack_onexec) [NEGATIVE]" \
+		fail -o $test_prof -- $at_secure 1
+
+	# Verify AT_SECURE after confined -> &unconfined stacking transition
+	genprofile "change_profile:&unconfined"
+	runchecktest "AT_SECURE (confined -> &unconfined - stack_onexec)" \
+		pass -o unconfined -- $at_secure $onexec_default
+
+	# Verify AT_SECURE after confined -> &confined stacking transition
+	genprofile "change_profile:&$test_prof" -- image=$test_prof addimage:$at_secure
+	runchecktest "AT_SECURE (confined -> &confined - stack_onexec)" \
+		pass -o $test_prof -- $at_secure $onexec_default
+fi
-- 
2.7.4




More information about the AppArmor mailing list