xref: /aosp_15_r20/external/ltp/testcases/kernel/security/integrity/ima/tests/ima_selinux.sh (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1#!/bin/sh
2# SPDX-License-Identifier: GPL-2.0-or-later
3# Copyright (c) 2021 Microsoft Corporation
4# Author: Lakshmi Ramasubramanian <[email protected]>
5#
6# Verify measurement of SELinux policy hash and state.
7#
8# Relevant kernel commits:
9# * fdd1ffe8a812 ("selinux: include a consumer of the new IMA critical data hook")
10# * 2554a48f4437 ("selinux: measure state and policy capabilities")
11
12TST_NEEDS_CMDS="awk cut grep tail"
13TST_CNT=2
14TST_SETUP="setup"
15
16FUNC_CRITICAL_DATA='func=CRITICAL_DATA'
17REQUIRED_POLICY="^measure.*$FUNC_CRITICAL_DATA"
18
19setup()
20{
21	SELINUX_DIR=$(tst_get_selinux_dir)
22	[ "$SELINUX_DIR" ] || tst_brk TCONF "SELinux is not enabled"
23
24	require_ima_policy_content "$REQUIRED_POLICY" '-E' > $TST_TMPDIR/policy.txt
25}
26
27# Format of the measured SELinux state data.
28#
29# initialized=1;enforcing=0;checkreqprot=1;
30# network_peer_controls=1;open_perms=1;extended_socket_class=1;
31# always_check_network=0;cgroup_seclabel=1;nnp_nosuid_transition=1;
32# genfs_seclabel_symlinks=0;
33validate_policy_capabilities()
34{
35	local measured_cap measured_value expected_value
36	local inx=7
37
38	# Policy capabilities flags start from "network_peer_controls"
39	# in the measured SELinux state at offset 7 for 'awk'
40	while [ $inx -lt 20 ]; do
41		measured_cap=$(echo $1 | awk -F'[=;]' -v inx="$inx" '{print $inx}')
42		inx=$(($inx + 1))
43
44		measured_value=$(echo $1 | awk -F'[=;]' -v inx="$inx" '{print $inx}')
45		expected_value=$(cat "$SELINUX_DIR/policy_capabilities/$measured_cap")
46		if [ "$measured_value" != "$expected_value" ]; then
47			tst_res TFAIL "$measured_cap: expected: $expected_value, got: $digest"
48			return
49		fi
50
51		inx=$(($inx + 1))
52	done
53
54	tst_res TPASS "SELinux state measured correctly"
55}
56
57# Trigger measurement of SELinux constructs and verify that
58# the measured SELinux policy hash matches the hash of the policy
59# loaded in kernel memory for SELinux.
60test1()
61{
62	local policy_digest expected_policy_digest algorithm
63	local data_source_name="selinux"
64	local pattern="data_sources=[^[:space:]]*$data_source_name"
65	local tmp_file="$TST_TMPDIR/selinux_policy_tmp_file.txt"
66
67	tst_res TINFO "verifying SELinux policy hash measurement"
68
69	# Trigger a measurement by changing SELinux state
70	tst_update_selinux_state
71
72	# Verify SELinux policy hash is measured and then validate that
73	# the measured policy hash matches the hash of the policy currently
74	# in kernel memory for SELinux
75	line=$(grep -E "selinux-policy-hash" $ASCII_MEASUREMENTS | tail -1)
76	if [ -z "$line" ]; then
77		tst_res TFAIL "SELinux policy hash not measured"
78		return
79	fi
80
81	algorithm=$(echo "$line" | cut -d' ' -f4 | cut -d':' -f1)
82	policy_digest=$(echo "$line" | cut -d' ' -f6)
83
84	expected_policy_digest="$(compute_digest $algorithm $SELINUX_DIR/policy)" || \
85		tst_brk TCONF "cannot compute digest for $algorithm"
86
87	if [ "$policy_digest" != "$expected_policy_digest" ]; then
88		tst_res TFAIL "Digest mismatch: expected: $expected_policy_digest, got: $policy_digest"
89		return
90	fi
91
92	tst_res TPASS "SELinux policy hash measured correctly"
93}
94
95# Trigger measurement of SELinux constructs and verify that
96# the measured SELinux state matches the current SELinux
97# configuration.
98test2()
99{
100	local measured_data state_file="$TST_TMPDIR/selinux_state.txt"
101	local data_source_name="selinux"
102	local pattern="data_sources=[^[:space:]]*$data_source_name"
103	local tmp_file="$TST_TMPDIR/selinux_state_tmp_file.txt"
104	local digest expected_digest algorithm
105	local initialized_value
106	local enforced_value expected_enforced_value
107	local checkreqprot_value expected_checkreqprot_value
108
109	tst_res TINFO "verifying SELinux state measurement"
110
111	# Trigger a measurement by changing SELinux state
112	tst_update_selinux_state
113
114	# Verify SELinux state is measured and then validate the measured
115	# state matches that currently set for SELinux
116	line=$(grep -E "selinux-state" $ASCII_MEASUREMENTS | tail -1)
117	if [ -z "$line" ]; then
118		tst_res TFAIL "SELinux state not measured"
119		return
120	fi
121
122	digest=$(echo "$line" | cut -d' ' -f4 | cut -d':' -f2)
123	algorithm=$(echo "$line" | cut -d' ' -f4 | cut -d':' -f1)
124
125	echo "$line" | cut -d' ' -f6 | tst_hexdump -d > $state_file
126
127	expected_digest="$(compute_digest $algorithm $state_file)" || \
128	tst_brk TCONF "cannot compute digest for $algorithm"
129
130	if [ "$digest" != "$expected_digest" ]; then
131		tst_res TFAIL "digest mismatch: expected: $expected_digest, got: $digest"
132		return
133	fi
134
135	# SELinux state is measured as the following string
136	#   initialized=1;enforcing=0;checkreqprot=1;
137	# Value of 0 indicates the state is ON, and 1 indicates OFF
138	#
139	# enforce and checkreqprot measurement can be verified by
140	# comparing the value of the file "enforce" and "checkreqprot"
141	# respectively in the SELinux directory.
142	# "initialized" is an internal state and should be set to 1
143	# if enforce and checkreqprot are measured correctly.
144	measured_data=$(cat $state_file)
145	enforced_value=$(echo $measured_data | awk -F'[=;]' '{print $4}')
146	expected_enforced_value=$(cat $SELINUX_DIR/enforce)
147	if [ "$expected_enforced_value" != "$enforced_value" ]; then
148		tst_res TFAIL "enforce: expected: $expected_enforced_value, got: $enforced_value"
149		return
150	fi
151
152	checkreqprot_value=$(echo $measured_data | awk -F'[=;]' '{print $6}')
153	expected_checkreqprot_value=$(cat $SELINUX_DIR/checkreqprot)
154	if [ "$expected_checkreqprot_value" != "$checkreqprot_value" ]; then
155		tst_res TFAIL "checkreqprot: expected: $expected_checkreqprot_value, got: $checkreqprot_value"
156		return
157	fi
158
159	initialized_value=$(echo $measured_data | awk -F'[=;]' '{print $2}')
160	if [ "$initialized_value" != "1" ]; then
161		tst_res TFAIL "initialized: expected 1, got: $initialized_value"
162		return
163	fi
164
165	validate_policy_capabilities $measured_data
166}
167
168. ima_setup.sh
169tst_run
170