[PATCH ima-evm-utils] Add ima_policy_check.awk and ima_policy_check.test

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Roberto Sassu <roberto.sassu@xxxxxxxxxx>

Add the awk script to check for possible interference of a rule added by a
test with the existing IMA policy (policy replacement at the first policy
load is not taken into account).

The script expects the rule to be added to be the first, and the existing
IMA policy to be after.

Rules are considered as interfering if they don't overlap, or they overlap
but they have the same action and same policy options with the same values.

Combinations of MMAP_CHECK and MMAP_CHECK_REQPROT hooks are always
considered as interfering, due to the different behavior of those hooks.

Finally add a test, to ensure that the awk script behaves as expected.

Signed-off-by: Roberto Sassu <roberto.sassu@xxxxxxxxxx>
---
 tests/Makefile.am           |   2 +-
 tests/ima_policy_check.awk  | 142 ++++++++++++++++
 tests/ima_policy_check.test | 319 ++++++++++++++++++++++++++++++++++++
 3 files changed, 462 insertions(+), 1 deletion(-)
 create mode 100755 tests/ima_policy_check.awk
 create mode 100755 tests/ima_policy_check.test

diff --git a/tests/Makefile.am b/tests/Makefile.am
index a0463b7b5b5..9a7d8a1f989 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -2,7 +2,7 @@ check_SCRIPTS =
 TESTS = $(check_SCRIPTS)
 
 check_SCRIPTS += ima_hash.test sign_verify.test boot_aggregate.test \
-		 fsverity.test portable_signatures.test
+		 fsverity.test portable_signatures.test ima_policy_check.test
 
 .PHONY: check_logs
 check_logs:
diff --git a/tests/ima_policy_check.awk b/tests/ima_policy_check.awk
new file mode 100755
index 00000000000..bb39153c182
--- /dev/null
+++ b/tests/ima_policy_check.awk
@@ -0,0 +1,142 @@
+#! /usr/bin/awk -f
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (C) 2023 Roberto Sassu <roberto.sassu@xxxxxxxxxx>
+#
+# Check possible interference of a new rule with the existing IMA policy.
+
+# Documentation/ABI/testing/ima_policy (Linux kernel)
+# base:	[[func=] [mask=] [fsmagic=] [fsuuid=] [fsname=]
+#	[uid=] [euid=] [gid=] [egid=]
+#	[fowner=] [fgroup=]]
+# lsm:	[[subj_user=] [subj_role=] [subj_type=]
+#	[obj_user=] [obj_role=] [obj_type=]]
+# option:	[digest_type=] [template=] [permit_directio]
+#		[appraise_type=] [appraise_flag=]
+#		[appraise_algos=] [keyrings=]
+#
+# Non interference if:
+# - non-overlapping rules (different values for policy keywords)
+# - overlapping rules with same action and same policy options
+#
+# Rules overlap if they have different policy keywords or same policy keywords
+# and same values.
+#
+# The same policy options and value requirement is needed as otherwise tests
+# might match an overlapping rule with undesired/missing policy options.
+#
+# Rules with MMAP_CHECK and MMAP_CHECK_REQPROT are considered as an exception.
+# They overlap, despite they have a different name. In addition, combinations of
+# them are reported as interference, since they are matched depending on
+# external factors, not inferrable from the policy (a MMAP_CHECK rule might
+# cause a measurement, while a MMAP_CHECK_REQPROT one might not).
+#
+# More/less specific rules are considered as overlapping.
+#
+# Overlapping rules must have the same policy options, or tests might match
+# policy rules set by other tests with undesired policy options.
+
+BEGIN {
+	keywords_str="func mask fsmagic fsuuid fsname uid euid gid egid fowner fgroup subj_user subj_role subj_type obj_user obj_role obj_type";
+	split(keywords_str, keywords_array, " ");
+	options_str="digest_type template permit_directio appraise_type appraise_flag appraise_algos keyrings";
+	split(options_str, options_array, " ");
+	key_type_unknown=0;
+	key_type_keyword=1;
+	key_type_option=2;
+	for (keyword in keywords_array)
+		key_types[keywords_array[keyword]]=key_type_keyword;
+	for (option in options_array)
+		key_types[options_array[option]]=key_type_option;
+	new_rule=1;
+	mmap_check_interference=0;
+}
+{
+	if (new_rule) {
+		new_rule_action=$1;
+		# Strip dont_ from the action of the new rule.
+		new_rule_action_sub=new_rule_action;
+		gsub(/dont_/, "", new_rule_action_sub);
+	} else {
+		current_action=$1;
+		# Strip dont_ from the action of the current rule.
+		current_action_sub=current_action;
+		gsub(/dont_/, "", current_action_sub);
+		# Unrelated action, ignore.
+		if (new_rule_action_sub != current_action_sub) {
+			next;
+		}
+		# Store policy options of the new rule into an array, to compare with the options of the current rule.
+		delete new_rule_extra_options;
+		for (key in new_rule_array) {
+			if (key_types[key] == key_type_option) {
+				new_rule_extra_options[key]=new_rule_array[key];
+			}
+		}
+		current_rule_extra_options=0;
+	}
+	for (i=2; i<=NF; i++) {
+		# Parse key/value pair.
+		split($i, key_value_array, "=");
+		key=key_value_array[1];
+		value=key_value_array[2];
+		if (key == "func") {
+			# Normalize values of IMA hooks.
+			if (value == "FILE_MMAP") {
+				value="MMAP_CHECK";
+			} else if (value == "PATH_CHECK") {
+				value="FILE_CHECK";
+			}
+		}
+		# Store key/value pair from the new rule into an array.
+		if (new_rule) {
+			# Check if the key is valid.
+			if (key_types[key] == key_type_unknown) {
+				exit 1;
+			}
+			new_rule_array[key]=value;
+		} else {
+			if (key_types[key] == key_type_keyword) {
+				# No overlap and no operators, no interference.
+				if (key in new_rule_array && new_rule_array[key] != value && value !~ /^[<,>,^]/) {
+					# Exception: MMAP_CHECK and MMAP_CHECK_REQPROT overlap and have different behavior, interference if overlap (cannot be determined yet).
+					if (key == "func" && new_rule_array[key] ~ /MMAP_CHECK/ && value ~ /MMAP_CHECK/) {
+						mmap_check_interference=1;
+						continue;
+					}
+					next;
+				}
+			} else if (key_types[key] == key_type_option) {
+				# Possible overlap and different policy options, interference if overlap (cannot be determined yet).
+				if (!(key in new_rule_extra_options)) {
+					current_rule_extra_options=1;
+				# Possible overlap, same policy option and same value, current option can be deleted from the new_rule_extra_options array.
+				} else if (new_rule_extra_options[key] == value) {
+					delete new_rule_extra_options[key];
+				}
+				# Possible overlap and same policy option but with different value, interference if overlap (cannot be determined yet).
+			}
+		}
+	}
+	# Always ok to parse a new rule.
+	if (new_rule) {
+		new_rule=0;
+		next;
+	}
+	# Overlap and different related action, interference.
+	if (current_action != new_rule_action) {
+		exit 1;
+	}
+	# Overlap and different policy options or different option values, interference.
+	for (key in new_rule_extra_options) {
+		exit 1;
+	}
+	if (current_rule_extra_options) {
+		exit 1;
+	}
+	# Overlap and MMAP_CHECK/MMAP_CHECK_REQPROT, interference.
+	if (mmap_check_interference) {
+		exit 1;
+	}
+	# Overlap with same related action and same policy options, ok.
+}
diff --git a/tests/ima_policy_check.test b/tests/ima_policy_check.test
new file mode 100755
index 00000000000..f1e79ca451f
--- /dev/null
+++ b/tests/ima_policy_check.test
@@ -0,0 +1,319 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (C) 2023 Roberto Sassu <roberto.sassu@xxxxxxxxxx>
+#
+# Test for ima_policy_check.awk
+
+trap '_report_exit_and_cleanup' SIGINT SIGTERM EXIT
+
+cd "$(dirname "$0")" || exit 1
+. ./functions.sh
+
+export PATH=$PWD:$PATH
+
+# Base VERBOSE on the environment variable, if set.
+VERBOSE="${VERBOSE:-0}"
+
+check_interference() {
+	echo -e "\nTest: $1"
+	echo "New rule: $2"
+	echo "IMA policy: $3"
+
+	if [ "$TFAIL" != "yes" ]; then
+		echo -n "Result (expect no interference): "
+	else
+		echo -n "Result (expect interference): "
+	fi
+
+	if ! echo -e "$2\n$3" | ima_policy_check.awk; then
+		if [ "$TFAIL" != "yes" ]; then
+			echo "${RED}interference${NORM}"
+		else
+			echo "${GREEN}interference${NORM}"
+		fi
+		return "$FAIL"
+	fi
+
+	if [ "$TFAIL" != "yes" ]; then
+		echo "${GREEN}no interference${NORM}"
+	else
+		echo "${RED}no interference${NORM}"
+	fi
+	return "$OK"
+}
+
+# Basic check.
+desc="empty IMA policy"
+rule="measure func=FILE_CHECK"
+ima_policy=""
+expect_pass check_interference "$desc" "$rule" "$ima_policy"
+
+# Wrong new rule.
+desc="Wrong new rule"
+rule="measure fun=FILE_CHECK"
+ima_policy=""
+expect_fail check_interference "$desc" "$rule" "$ima_policy"
+
+# Unrelated/related actions.
+desc="unrelated actions measure/appraise"
+rule="measure func=FILE_CHECK"
+ima_policy="appraise func=FILE_CHECK"
+expect_pass check_interference "$desc" "$rule" "$ima_policy"
+
+desc="unrelated actions appraise/measure"
+rule="appraise func=FILE_CHECK"
+ima_policy="measure func=FILE_CHECK"
+expect_pass check_interference "$desc" "$rule" "$ima_policy"
+
+desc="unrelated actions appraise/dont_measure"
+rule="appraise func=FILE_CHECK"
+ima_policy="dont_measure func=FILE_CHECK"
+expect_pass check_interference "$desc" "$rule" "$ima_policy"
+
+desc="related actions measure/dont_measure"
+rule="measure func=FILE_CHECK"
+ima_policy="dont_measure func=FILE_CHECK"
+expect_fail check_interference "$desc" "$rule" "$ima_policy"
+
+desc="related actions dont_measure/measure"
+rule="measure func=FILE_CHECK"
+ima_policy="dont_measure func=FILE_CHECK"
+expect_fail check_interference "$desc" "$rule" "$ima_policy"
+
+desc="related actions dont_appraise/appraise"
+rule="dont_appraise func=FILE_CHECK"
+ima_policy="appraise func=FILE_CHECK"
+expect_fail check_interference "$desc" "$rule" "$ima_policy"
+
+# Unrelated rules by different values for policy keywords.
+desc="same action, unrelated by func"
+rule="measure func=FILE_CHECK"
+ima_policy="measure func=MMAP_CHECK"
+expect_pass check_interference "$desc" "$rule" "$ima_policy"
+
+desc="different action, unrelated by func"
+rule="measure func=FILE_CHECK"
+ima_policy="dont_measure func=MMAP_CHECK"
+expect_pass check_interference "$desc" "$rule" "$ima_policy"
+
+desc="different action, unrelated by mask"
+rule="measure func=FILE_CHECK mask=MAY_EXEC"
+ima_policy="dont_measure func=FILE_CHECK mask=MAY_READ"
+expect_pass check_interference "$desc" "$rule" "$ima_policy"
+
+desc="different action, unrelated by fowner"
+rule="measure func=FILE_CHECK fowner=1 mask=MAY_EXEC"
+ima_policy="dont_measure func=FILE_CHECK mask=MAY_EXEC fowner=0"
+expect_pass check_interference "$desc" "$rule" "$ima_policy"
+
+# Unrelated rules with different policy options.
+desc="different action, unrelated by fowner, different policy options"
+rule="measure func=FILE_CHECK fowner=1 mask=MAY_EXEC"
+ima_policy="dont_measure func=FILE_CHECK mask=MAY_EXEC fowner=0 permit_directio"
+expect_pass check_interference "$desc" "$rule" "$ima_policy"
+
+desc="same action, unrelated by fowner, different policy options"
+rule="measure func=FILE_CHECK fowner=1 mask=MAY_EXEC"
+ima_policy="measure func=FILE_CHECK mask=MAY_EXEC fowner=0 permit_directio"
+expect_pass check_interference "$desc" "$rule" "$ima_policy"
+
+# Related rules by different policy keywords.
+desc="same action, add with uid, existing with func, no policy options"
+rule="measure uid=0"
+ima_policy="measure func=FILE_CHECK"
+expect_pass check_interference "$desc" "$rule" "$ima_policy"
+
+desc="different action, add with uid, existing with func, no policy options"
+rule="measure uid=0"
+ima_policy="dont_measure func=FILE_CHECK"
+expect_fail check_interference "$desc" "$rule" "$ima_policy"
+
+desc="same action, add with uid, existing with func, different policy options"
+rule="measure uid=0 permit_directio"
+ima_policy="measure func=FILE_CHECK"
+expect_fail check_interference "$desc" "$rule" "$ima_policy"
+
+desc="same action, add with uid, existing with func, different policy options"
+rule="measure uid=0"
+ima_policy="measure func=FILE_CHECK permit_directio"
+expect_fail check_interference "$desc" "$rule" "$ima_policy"
+
+desc="same action, add with uid, existing with func, same policy options"
+rule="measure uid=0 permit_directio"
+ima_policy="measure func=FILE_CHECK permit_directio"
+expect_pass check_interference "$desc" "$rule" "$ima_policy"
+
+# Related rules by same policy keywords and same value, with policy options.
+desc="same action, add with func, existing with func, same policy options"
+rule="measure func=FILE_CHECK permit_directio"
+ima_policy="measure func=FILE_CHECK permit_directio"
+expect_pass check_interference "$desc" "$rule" "$ima_policy"
+
+desc="same action, add with func, existing with func, different policy options"
+rule="measure func=FILE_CHECK"
+ima_policy="measure func=FILE_CHECK permit_directio"
+expect_fail check_interference "$desc" "$rule" "$ima_policy"
+
+desc="same action, add with func, existing with func, different policy options"
+rule="measure func=FILE_CHECK permit_directio"
+ima_policy="measure func=FILE_CHECK"
+expect_fail check_interference "$desc" "$rule" "$ima_policy"
+
+desc="different action, add with func, existing with func, no policy options"
+rule="measure func=FILE_CHECK"
+ima_policy="dont_measure func=FILE_CHECK"
+expect_fail check_interference "$desc" "$rule" "$ima_policy"
+
+desc="different action, add with func, existing with func, no policy options"
+rule="dont_measure func=FILE_CHECK"
+ima_policy="measure func=FILE_CHECK"
+expect_fail check_interference "$desc" "$rule" "$ima_policy"
+
+desc="different action, add with func, existing with func, same policy options"
+rule="dont_measure func=FILE_CHECK permit_directio"
+ima_policy="measure func=FILE_CHECK permit_directio"
+expect_fail check_interference "$desc" "$rule" "$ima_policy"
+
+desc="different action, add with func, existing with func, same policy options"
+rule="measure func=FILE_CHECK permit_directio"
+ima_policy="dont_measure func=FILE_CHECK permit_directio"
+expect_fail check_interference "$desc" "$rule" "$ima_policy"
+
+# Related rules by same policy keywords and different value but with unsupported operator.
+desc="different action, add with func and uid, existing with func and different uid"
+rule="dont_measure func=FILE_CHECK uid=>0"
+ima_policy="measure func=FILE_CHECK uid=>1"
+expect_fail check_interference "$desc" "$rule" "$ima_policy"
+
+desc="same action, add with func and uid, existing with func and different uid"
+rule="measure func=FILE_CHECK uid=>0"
+ima_policy="measure func=FILE_CHECK uid=>1"
+expect_pass check_interference "$desc" "$rule" "$ima_policy"
+
+desc="same action, add with func and uid, existing with func and different uid, different policy options"
+rule="measure func=FILE_CHECK uid=>0 permit_directio"
+ima_policy="measure func=FILE_CHECK uid=>1"
+expect_fail check_interference "$desc" "$rule" "$ima_policy"
+
+desc="same action, add with func and uid, existing with func and different uid, same policy options"
+rule="measure func=FILE_CHECK uid=>0 permit_directio"
+ima_policy="measure func=FILE_CHECK uid=>1 permit_directio"
+expect_pass check_interference "$desc" "$rule" "$ima_policy"
+
+# Related rules by subset/superset policy keywords.
+desc="different action, add with func and uid, existing with func"
+rule="dont_measure func=FILE_CHECK uid=0"
+ima_policy="measure func=FILE_CHECK"
+expect_fail check_interference "$desc" "$rule" "$ima_policy"
+
+desc="same action, add with func and uid, existing with func"
+rule="measure func=FILE_CHECK uid=0"
+ima_policy="measure func=FILE_CHECK"
+expect_pass check_interference "$desc" "$rule" "$ima_policy"
+
+desc="same action, add with func and uid, existing with func"
+rule="dont_measure func=FILE_CHECK uid=0"
+ima_policy="dont_measure func=FILE_CHECK"
+expect_pass check_interference "$desc" "$rule" "$ima_policy"
+
+desc="same action, add with func and uid, existing with func, different policy options"
+rule="measure func=FILE_CHECK uid=0"
+ima_policy="measure func=FILE_CHECK permit_directio"
+expect_fail check_interference "$desc" "$rule" "$ima_policy"
+
+desc="same action, add with func and uid, existing with func, same policy options"
+rule="measure func=FILE_CHECK uid=0 permit_directio"
+ima_policy="measure func=FILE_CHECK permit_directio"
+expect_pass check_interference "$desc" "$rule" "$ima_policy"
+
+desc="same action, add with func, existing with func and uid, same policy options (multiple)"
+rule="measure func=FILE_CHECK uid=0 permit_directio appraise_type=imasig"
+ima_policy="measure func=FILE_CHECK permit_directio appraise_type=imasig"
+expect_pass check_interference "$desc" "$rule" "$ima_policy"
+
+desc="different action, add with func, existing with func and uid"
+rule="dont_measure func=FILE_CHECK"
+ima_policy="measure func=FILE_CHECK uid=0"
+expect_fail check_interference "$desc" "$rule" "$ima_policy"
+
+desc="same action, add with func, existing with func and uid"
+rule="measure func=FILE_CHECK"
+ima_policy="measure func=FILE_CHECK uid=0"
+expect_pass check_interference "$desc" "$rule" "$ima_policy"
+
+desc="same action, add with func, existing with func and uid"
+rule="dont_measure func=FILE_CHECK"
+ima_policy="dont_measure func=FILE_CHECK uid=0"
+expect_pass check_interference "$desc" "$rule" "$ima_policy"
+
+desc="same action, add with func and uid, existing with func, different policy options"
+rule="measure func=FILE_CHECK"
+ima_policy="measure func=FILE_CHECK uid=0 permit_directio"
+expect_fail check_interference "$desc" "$rule" "$ima_policy"
+
+desc="same action, add with func, existing with func and uid, same policy options"
+rule="measure func=FILE_CHECK permit_directio"
+ima_policy="measure func=FILE_CHECK uid=0 permit_directio"
+expect_pass check_interference "$desc" "$rule" "$ima_policy"
+
+desc="same action, add with func, existing with func and uid, same policy options (multiple)"
+rule="measure func=FILE_CHECK permit_directio appraise_type=imasig"
+ima_policy="measure func=FILE_CHECK uid=0 permit_directio appraise_type=imasig"
+expect_pass check_interference "$desc" "$rule" "$ima_policy"
+
+# Different policy options in a non-overlapping rule.
+desc="same action, add with func, existing with func and uid, no policy options"
+rule="measure func=FILE_CHECK uid=1"
+ima_policy="measure func=FILE_CHECK permit_directio uid=0"
+expect_pass check_interference "$desc" "$rule" "$ima_policy"
+
+# Same policy option with different value in an overlapping rule.
+desc="same action, add with func, existing with func and uid, same policy option with different value"
+rule="measure func=FILE_CHECK permit_directio appraise_type=imasig"
+ima_policy="measure func=FILE_CHECK uid=0 permit_directio appraise_type=sigv3"
+expect_fail check_interference "$desc" "$rule" "$ima_policy"
+
+# Same policy option with different value in an non-overlapping rule.
+desc="same action, add with func and uid, existing with func and different uid, same policy option with different value"
+rule="measure func=FILE_CHECK uid=1 permit_directio appraise_type=imasig"
+ima_policy="measure func=FILE_CHECK uid=0 permit_directio appraise_type=sigv3"
+expect_pass check_interference "$desc" "$rule" "$ima_policy"
+
+# Same policy option with different value in an non-overlapping rule, uid is the last.
+desc="same action, add with func and uid, existing with func and different uid, same policy option with different value"
+rule="measure func=FILE_CHECK permit_directio appraise_type=imasig uid=1"
+ima_policy="measure func=FILE_CHECK permit_directio appraise_type=sigv3 uid=0"
+expect_pass check_interference "$desc" "$rule" "$ima_policy"
+
+# MMAP_CHECK and MMAP_CHECK_REQPROT hooks.
+desc="same action, MMAP_CHECK and MMAP_CHECK_REQPROT hooks"
+rule="measure func=MMAP_CHECK"
+ima_policy="measure func=MMAP_CHECK_REQPROT"
+expect_fail check_interference "$desc" "$rule" "$ima_policy"
+
+desc="different action, MMAP_CHECK and MMAP_CHECK_REQPROT hooks"
+rule="measure func=MMAP_CHECK"
+ima_policy="dont_measure func=MMAP_CHECK_REQPROT"
+expect_fail check_interference "$desc" "$rule" "$ima_policy"
+
+desc="same action, MMAP_CHECK and MMAP_CHECK_REQPROT hooks, overlapping rules and IMA policy more specific"
+rule="measure func=MMAP_CHECK"
+ima_policy="measure func=MMAP_CHECK_REQPROT uid=0"
+expect_fail check_interference "$desc" "$rule" "$ima_policy"
+
+desc="same action, MMAP_CHECK and MMAP_CHECK_REQPROT hooks, non-overlapping rules"
+rule="measure func=MMAP_CHECK uid=1"
+ima_policy="measure func=MMAP_CHECK_REQPROT uid=0"
+expect_pass check_interference "$desc" "$rule" "$ima_policy"
+
+desc="same action, same hook MMAP_CHECK"
+rule="measure func=MMAP_CHECK"
+ima_policy="measure func=MMAP_CHECK"
+expect_pass check_interference "$desc" "$rule" "$ima_policy"
+
+# Hook aliases.
+desc="different action, FILE_CHECK hook and its alias"
+rule="measure func=FILE_CHECK"
+ima_policy="dont_measure func=PATH_CHECK"
+expect_fail check_interference "$desc" "$rule" "$ima_policy"
-- 
2.25.1




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux Kernel]     [Linux Kernel Hardening]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]

  Powered by Linux