diff mbox series

[v3,05/10] IMA: Read required policy from file

Message ID 20250114112915.610297-6-pvorel@suse.cz (mailing list archive)
State New
Headers show
Series LTP tests: load predefined policy, enhancements | expand

Commit Message

Petr Vorel Jan. 14, 2025, 11:29 a.m. UTC
Previously snipped of required policy was as a string or regexp.
Loading required policy from file allows to move code to ima_setup.sh.
This is a preparation for loading IMA policy from file.

Check can be done on one or both:
1) IMA builtin policy (based on /proc/cmdline)
2) IMA policy content (actual content of /sys/kernel/security/ima/policy)

When missing CONFIG_IMA_READ_POLICY=y on required policy convert: test, but convert TFAIL => TCONF.

Signed-off-by: Petr Vorel <pvorel@suse.cz>
---
 .../security/integrity/ima/tests/ima_kexec.sh | 19 ++----
 .../security/integrity/ima/tests/ima_keys.sh  | 47 ++++---------
 .../integrity/ima/tests/ima_measurements.sh   |  8 ++-
 .../integrity/ima/tests/ima_selinux.sh        | 22 +++---
 .../security/integrity/ima/tests/ima_setup.sh | 68 ++++++++++++++-----
 .../integrity/ima/tests/ima_violations.sh     |  8 ++-
 6 files changed, 92 insertions(+), 80 deletions(-)
diff mbox series

Patch

diff --git a/testcases/kernel/security/integrity/ima/tests/ima_kexec.sh b/testcases/kernel/security/integrity/ima/tests/ima_kexec.sh
index 3446bc24bf..95e6186bb5 100755
--- a/testcases/kernel/security/integrity/ima/tests/ima_kexec.sh
+++ b/testcases/kernel/security/integrity/ima/tests/ima_kexec.sh
@@ -1,7 +1,7 @@ 
 #!/bin/sh
 # SPDX-License-Identifier: GPL-2.0-or-later
 # Copyright (c) 2020 Microsoft Corporation
-# Copyright (c) 2020 Petr Vorel <pvorel@suse.cz>
+# Copyright (c) 2020-2025 Petr Vorel <pvorel@suse.cz>
 # Author: Lachlan Sneff <t-josne@linux.microsoft.com>
 #
 # Verify that kexec cmdline is measured correctly.
@@ -14,7 +14,7 @@  TST_SETUP="setup"
 TST_MIN_KVER="5.3"
 
 IMA_KEXEC_IMAGE="${IMA_KEXEC_IMAGE:-/boot/vmlinuz-$(uname -r)}"
-REQUIRED_POLICY='^measure.*func=KEXEC_CMDLINE'
+REQUIRED_POLICY_CONTENT='kexec.policy'
 
 measure()
 {
@@ -46,11 +46,6 @@  setup()
 	if [ ! -f "$IMA_KEXEC_IMAGE" ]; then
 		tst_brk TCONF "kernel image not found, specify path in \$IMA_KEXEC_IMAGE"
 	fi
-
-	if check_policy_readable; then
-		require_ima_policy_content "$REQUIRED_POLICY"
-		policy_readable=1
-	fi
 }
 
 kexec_failure_hint()
@@ -79,7 +74,6 @@  kexec_test()
 {
 	local param="$1"
 	local cmdline="$2"
-	local res=TFAIL
 	local kexec_cmd
 
 	kexec_cmd="$param=$cmdline"
@@ -97,13 +91,10 @@  kexec_test()
 
 	ROD kexec -su
 	if ! measure "$cmdline"; then
-		if [ "$policy_readable" != 1 ]; then
-			tst_res TWARN "policy not readable, it might not contain required policy '$REQUIRED_POLICY'"
-			res=TBROK
-		fi
-		tst_brk $res "unable to find a correct measurement"
+		tst_res $IMA_FAIL "unable to find a correct measurement"
+	else
+		tst_res TPASS "kexec cmdline was measured correctly"
 	fi
-	tst_res TPASS "kexec cmdline was measured correctly"
 }
 
 test()
diff --git a/testcases/kernel/security/integrity/ima/tests/ima_keys.sh b/testcases/kernel/security/integrity/ima/tests/ima_keys.sh
index ff32eb6c43..a2e9c77738 100755
--- a/testcases/kernel/security/integrity/ima/tests/ima_keys.sh
+++ b/testcases/kernel/security/integrity/ima/tests/ima_keys.sh
@@ -1,7 +1,7 @@ 
 #!/bin/sh
 # SPDX-License-Identifier: GPL-2.0-or-later
 # Copyright (c) 2020 Microsoft Corporation
-# Copyright (c) 2020-2021 Petr Vorel <pvorel@suse.cz>
+# Copyright (c) 2020-2025 Petr Vorel <pvorel@suse.cz>
 # Author: Lachlan Sneff <t-josne@linux.microsoft.com>
 #
 # Verify that keys are measured correctly based on policy.
@@ -12,38 +12,24 @@  TST_SETUP=setup
 TST_CLEANUP=cleanup
 TST_MIN_KVER="5.6"
 
-FUNC_KEYCHECK='func=KEY_CHECK'
-REQUIRED_POLICY="^measure.*$FUNC_KEYCHECK"
+REQUIRED_POLICY_CONTENT='keycheck.policy'
 
 setup()
 {
-	require_ima_policy_content "$REQUIRED_POLICY" '-E' > $TST_TMPDIR/policy.txt
-	require_valid_policy_template
-}
+	local line
 
-cleanup()
-{
-	tst_is_num $KEYRING_ID && keyctl clear $KEYRING_ID
-}
+	require_policy_readable
 
-require_valid_policy_template()
-{
 	while read line; do
-	if echo $line | grep -q 'template=' && ! echo $line | grep -q 'template=ima-buf'; then
-		tst_brk TCONF "only template=ima-buf can be specified for KEY_CHECK"
-	fi
-	done < $TST_TMPDIR/policy.txt
+		if echo $line | grep -q 'template=' && ! echo $line | grep -q 'template=ima-buf'; then
+			tst_brk TCONF "only template=ima-buf can be specified for KEY_CHECK"
+		fi
+	done < $IMA_POLICY
 }
 
-check_keys_policy()
+cleanup()
 {
-	local pattern="$1"
-
-	if ! grep -E "$pattern" $TST_TMPDIR/policy.txt; then
-		tst_res TCONF "IMA policy must specify $pattern, $FUNC_KEYCHECK"
-		return 1
-	fi
-	return 0
+	tst_is_num $KEYRING_ID && keyctl clear $KEYRING_ID
 }
 
 # Based on https://lkml.org/lkml/2019/12/13/564.
@@ -51,12 +37,10 @@  check_keys_policy()
 test1()
 {
 	local keycheck_lines i keyrings templates
-	local pattern='keyrings=[^[:space:]]+'
 	local test_file="file.txt" tmp_file="file2.txt"
 
 	tst_res TINFO "verify key measurement for keyrings and templates specified in IMA policy"
 
-	check_keys_policy "$pattern" > $tmp_file || return
 	keycheck_lines=$(cat $tmp_file)
 	keyrings=$(for i in $keycheck_lines; do echo "$i" | grep "keyrings" | \
 		sed "s/\./\\\./g" | cut -d'=' -f2; done | sed ':a;N;$!ba;s/\n/|/g')
@@ -87,7 +71,7 @@  test1()
 		fi
 
 		if [ "$digest" != "$expected_digest" ]; then
-			tst_res TFAIL "incorrect digest was found for $keyring keyring"
+			tst_res $IMA_FAIL "incorrect digest was found for $keyring keyring"
 			return
 		fi
 	done
@@ -105,13 +89,10 @@  test2()
 
 	local cert_file="$TST_DATAROOT/x509_ima.der"
 	local keyring_name="key_import_test"
-	local pattern="keyrings=[^[:space:]]*$keyring_name"
 	local temp_file="file.txt"
 
 	tst_res TINFO "verify measurement of certificate imported into a keyring"
 
-	check_keys_policy "$pattern" >/dev/null || return
-
 	KEYRING_ID=$(keyctl newring $keyring_name @s) || \
 		tst_brk TBROK "unable to create a new keyring"
 
@@ -126,19 +107,19 @@  test2()
 		tst_hexdump -d > $temp_file
 
 	if [ ! -s $temp_file ]; then
-		tst_res TFAIL "keyring $keyring_name not found in $ASCII_MEASUREMENTS"
+		tst_res $IMA_FAIL "keyring $keyring_name not found in $ASCII_MEASUREMENTS"
 		return
 	fi
 
 	if ! openssl x509 -in $temp_file -inform der > /dev/null; then
-		tst_res TFAIL "logged certificate is not a valid x509 certificate"
+		tst_res $IMA_FAIL "logged certificate is not a valid x509 certificate"
 		return
 	fi
 
 	if cmp -s $temp_file $cert_file; then
 		tst_res TPASS "logged certificate matches the original"
 	else
-		tst_res TFAIL "logged certificate does not match original"
+		tst_res $IMA_FAIL "logged certificate does not match original"
 	fi
 }
 
diff --git a/testcases/kernel/security/integrity/ima/tests/ima_measurements.sh b/testcases/kernel/security/integrity/ima/tests/ima_measurements.sh
index ca9d73b4aa..41d53aa03b 100755
--- a/testcases/kernel/security/integrity/ima/tests/ima_measurements.sh
+++ b/testcases/kernel/security/integrity/ima/tests/ima_measurements.sh
@@ -11,6 +11,7 @@  TST_NEEDS_CMDS="awk cut sed"
 TST_SETUP="setup"
 TST_CNT=3
 REQUIRED_BUILTIN_POLICY="tcb"
+REQUIRED_POLICY_CONTENT='tcb.policy'
 
 setup()
 {
@@ -70,6 +71,7 @@  test3()
 	local user="nobody"
 	local dir="$PWD/user"
 	local file="$dir/test.txt"
+	local cmd="grep $file $ASCII_MEASUREMENTS"
 
 	# Default policy does not measure user files
 	tst_res TINFO "verify not measuring user files"
@@ -87,7 +89,11 @@  test3()
 	sudo -n -u $user sh -c "echo $(cat /proc/uptime) user file > $file; cat $file > /dev/null"
 	cd ..
 
-	EXPECT_FAIL "grep $file $ASCII_MEASUREMENTS"
+	if tst_rod "$cmd" 2> /dev/null; then
+		tst_res TPASS "$cmd failed as expected"
+	else
+		tst_res $IMA_FAIL "$cmd passed unexpectedly"
+	fi
 }
 
 . ima_setup.sh
diff --git a/testcases/kernel/security/integrity/ima/tests/ima_selinux.sh b/testcases/kernel/security/integrity/ima/tests/ima_selinux.sh
index 75f9ba84e4..45fd741b5f 100755
--- a/testcases/kernel/security/integrity/ima/tests/ima_selinux.sh
+++ b/testcases/kernel/security/integrity/ima/tests/ima_selinux.sh
@@ -1,6 +1,7 @@ 
 #!/bin/sh
 # SPDX-License-Identifier: GPL-2.0-or-later
 # Copyright (c) 2021 Microsoft Corporation
+# Copyright (c) Linux Test Project, 2021-2025
 # Author: Lakshmi Ramasubramanian <nramas@linux.microsoft.com>
 #
 # Verify measurement of SELinux policy hash and state.
@@ -14,15 +15,12 @@  TST_CNT=2
 TST_SETUP="setup"
 TST_MIN_KVER="5.12"
 
-FUNC_CRITICAL_DATA='func=CRITICAL_DATA'
-REQUIRED_POLICY="^measure.*$FUNC_CRITICAL_DATA"
+REQUIRED_POLICY_CONTENT='selinux.policy'
 
 setup()
 {
 	SELINUX_DIR=$(tst_get_selinux_dir)
 	[ "$SELINUX_DIR" ] || tst_brk TCONF "SELinux is not enabled"
-
-	require_ima_policy_content "$REQUIRED_POLICY" '-E' > $TST_TMPDIR/policy.txt
 }
 
 # Format of the measured SELinux state data.
@@ -45,7 +43,7 @@  validate_policy_capabilities()
 		measured_value=$(echo $1 | awk -F'[=;]' -v inx="$inx" '{print $inx}')
 		expected_value=$(cat "$SELINUX_DIR/policy_capabilities/$measured_cap")
 		if [ "$measured_value" != "$expected_value" ]; then
-			tst_res TFAIL "$measured_cap: expected: $expected_value, got: $digest"
+			tst_res $IMA_FAIL "$measured_cap: expected: $expected_value, got: $digest"
 			return
 		fi
 
@@ -75,7 +73,7 @@  test1()
 	# in kernel memory for SELinux
 	line=$(grep -E "selinux-policy-hash" $ASCII_MEASUREMENTS | tail -1)
 	if [ -z "$line" ]; then
-		tst_res TFAIL "SELinux policy hash not measured"
+		tst_res $IMA_FAIL "SELinux policy hash not measured"
 		return
 	fi
 
@@ -86,7 +84,7 @@  test1()
 		tst_brk TCONF "cannot compute digest for $algorithm"
 
 	if [ "$policy_digest" != "$expected_policy_digest" ]; then
-		tst_res TFAIL "Digest mismatch: expected: $expected_policy_digest, got: $policy_digest"
+		tst_res $IMA_FAIL "Digest mismatch: expected: $expected_policy_digest, got: $policy_digest"
 		return
 	fi
 
@@ -116,7 +114,7 @@  test2()
 	# state matches that currently set for SELinux
 	line=$(grep -E "selinux-state" $ASCII_MEASUREMENTS | tail -1)
 	if [ -z "$line" ]; then
-		tst_res TFAIL "SELinux state not measured"
+		tst_res $IMA_FAIL "SELinux state not measured"
 		return
 	fi
 
@@ -129,7 +127,7 @@  test2()
 	tst_brk TCONF "cannot compute digest for $algorithm"
 
 	if [ "$digest" != "$expected_digest" ]; then
-		tst_res TFAIL "digest mismatch: expected: $expected_digest, got: $digest"
+		tst_res $IMA_FAIL "digest mismatch: expected: $expected_digest, got: $digest"
 		return
 	fi
 
@@ -146,20 +144,20 @@  test2()
 	enforced_value=$(echo $measured_data | awk -F'[=;]' '{print $4}')
 	expected_enforced_value=$(cat $SELINUX_DIR/enforce)
 	if [ "$expected_enforced_value" != "$enforced_value" ]; then
-		tst_res TFAIL "enforce: expected: $expected_enforced_value, got: $enforced_value"
+		tst_res $IMA_FAIL "enforce: expected: $expected_enforced_value, got: $enforced_value"
 		return
 	fi
 
 	checkreqprot_value=$(echo $measured_data | awk -F'[=;]' '{print $6}')
 	expected_checkreqprot_value=$(cat $SELINUX_DIR/checkreqprot)
 	if [ "$expected_checkreqprot_value" != "$checkreqprot_value" ]; then
-		tst_res TFAIL "checkreqprot: expected: $expected_checkreqprot_value, got: $checkreqprot_value"
+		tst_res $IMA_FAIL "checkreqprot: expected: $expected_checkreqprot_value, got: $checkreqprot_value"
 		return
 	fi
 
 	initialized_value=$(echo $measured_data | awk -F'[=;]' '{print $2}')
 	if [ "$initialized_value" != "1" ]; then
-		tst_res TFAIL "initialized: expected 1, got: $initialized_value"
+		tst_res $IMA_FAIL "initialized: expected 1, got: $initialized_value"
 		return
 	fi
 
diff --git a/testcases/kernel/security/integrity/ima/tests/ima_setup.sh b/testcases/kernel/security/integrity/ima/tests/ima_setup.sh
index 2a578ceb45..af5584951c 100644
--- a/testcases/kernel/security/integrity/ima/tests/ima_setup.sh
+++ b/testcases/kernel/security/integrity/ima/tests/ima_setup.sh
@@ -19,6 +19,9 @@  SYSFS="/sys"
 UMOUNT=
 TST_FS_TYPE="ext3"
 
+IMA_FAIL="TFAIL"
+IMA_BROK="TBROK"
+
 # TODO: find support for rmd128 rmd256 rmd320 wp256 wp384 tgr128 tgr160
 compute_digest()
 {
@@ -85,21 +88,9 @@  require_policy_writable()
 check_ima_policy_content()
 {
 	local pattern="$1"
-	local grep_params="${2--q}"
 
 	check_policy_readable || return 1
-	grep $grep_params "$pattern" $IMA_POLICY
-}
-
-require_ima_policy_content()
-{
-	local pattern="$1"
-	local grep_params="${2--q}"
-
-	require_policy_readable
-	if ! grep $grep_params "$pattern" $IMA_POLICY; then
-		tst_brk TCONF "IMA policy does not specify '$pattern'"
-	fi
+	grep -q "$pattern" $IMA_POLICY
 }
 
 check_ima_policy_cmdline()
@@ -158,6 +149,51 @@  print_ima_config()
 	tst_res TINFO "/proc/cmdline: $(cat /proc/cmdline)"
 }
 
+# Check for required
+# 1) IMA builtin policy (based on /proc/cmdline)
+# 2) IMA policy content (actual content of /sys/kernel/security/ima/policy)
+# When missing CONFIG_IMA_READ_POLICY=y on required policy convert: test, but convert TFAIL => TCONF.
+# $REQUIRED_POLICY_CONTENT: file with required IMA policy
+# $REQUIRED_BUILTIN_POLICY: IMA policy specified as kernel cmdline
+verify_ima_policy()
+{
+	local check_content line
+	local file="$TST_DATAROOT/$REQUIRED_POLICY_CONTENT"
+
+	if [ -z "$REQUIRED_POLICY_CONTENT" -a -z "$REQUIRED_BUILTIN_POLICY" ]; then
+		return 0
+	fi
+
+	if [ -n "$REQUIRED_POLICY_CONTENT" ]; then
+		check_content=1
+		if [ -n "$REQUIRED_BUILTIN_POLICY" ] && check_ima_policy_cmdline "$REQUIRED_BUILTIN_POLICY"; then
+			tst_res TINFO "booted with IMA policy: $REQUIRED_BUILTIN_POLICY"
+			return 0
+		fi
+	elif [ -n "$REQUIRED_BUILTIN_POLICY" ]; then
+		require_ima_policy_cmdline "$REQUIRED_BUILTIN_POLICY"
+	fi
+
+	if [ "$check_content" = 1 ]; then
+		[ -e $file ] || tst_brk TBROK "policy file '$file' does not exist (LTPROOT=$LTPROOT)"
+		tst_res TINFO "test requires IMA policy:"
+		cat $file
+		if check_policy_readable; then
+			# check IMA policy content
+			while read line; do
+				if ! grep -q "$line" $IMA_POLICY; then
+					tst_brk TCONF "missing required policy '$line'"
+				fi
+				IMA_POLICY_CHECKED=1
+			done < $file
+		else
+			tst_res TINFO "policy is not readable, failure will be treated as TCONF"
+			IMA_FAIL="TCONF"
+			IMA_BROK="TCONF"
+		fi
+	fi
+}
+
 ima_setup()
 {
 	SECURITYFS="$(mount_helper securityfs $SYSFS/kernel/security)"
@@ -180,9 +216,7 @@  ima_setup()
 		cd "$TST_MNTPOINT"
 	fi
 
-	if [ "$REQUIRED_BUILTIN_POLICY" ]; then
-		require_ima_policy_cmdline "$REQUIRED_BUILTIN_POLICY"
-	fi
+	verify_ima_policy
 
 	[ -n "$TST_SETUP_CALLER" ] && $TST_SETUP_CALLER
 }
@@ -290,7 +324,7 @@  ima_check()
 		algorithm=$(cat tmp | cut -d'|' -f1)
 		digest=$(cat tmp | cut -d'|' -f2)
 	else
-		tst_brk TBROK "failed to get algorithm/digest for '$test_file'"
+		tst_brk $IMA_BROK "failed to get algorithm/digest for '$test_file'"
 	fi
 
 	tst_res TINFO "computing digest for $algorithm algorithm"
diff --git a/testcases/kernel/security/integrity/ima/tests/ima_violations.sh b/testcases/kernel/security/integrity/ima/tests/ima_violations.sh
index b2b597ad08..1852e8bc74 100755
--- a/testcases/kernel/security/integrity/ima/tests/ima_violations.sh
+++ b/testcases/kernel/security/integrity/ima/tests/ima_violations.sh
@@ -1,7 +1,7 @@ 
 #!/bin/sh
 # SPDX-License-Identifier: GPL-2.0-or-later
 # Copyright (c) 2009 IBM Corporation
-# Copyright (c) 2018-2020 Petr Vorel <pvorel@suse.cz>
+# Copyright (c) 2018-2025 Petr Vorel <pvorel@suse.cz>
 # Author: Mimi Zohar <zohar@linux.ibm.com>
 #
 # Test whether ToMToU and open_writer violations invalidatethe PCR and are logged.
@@ -10,6 +10,8 @@  TST_SETUP="setup"
 TST_CLEANUP="cleanup"
 TST_CNT=3
 
+REQUIRED_POLICY_CONTENT='violations.policy'
+
 setup()
 {
 	FILE="test.txt"
@@ -83,11 +85,11 @@  validate()
 				tst_sleep 1s
 			fi
 		else
-			tst_res TFAIL "$search violation not added"
+			tst_res $IMA_FAIL "$search violation not added"
 			return
 		fi
 	done
-	tst_res TFAIL "$search not found in $LOG"
+	tst_res $IMA_FAIL "$search not found in $LOG"
 }
 
 test1()