Message ID | 20210222023805.12846-1-nramas@linux.microsoft.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | IMA: Add test for selinux measurement | expand |
Hi Lakshmi, > +++ b/testcases/kernel/security/integrity/ima/tests/ima_selinux.sh ... > +validate_policy_capabilities() > +{ > + local measured_cap measured_value expected_value > + local result=1 > + local inx=7 > + > + # Policy capabilities flags start from "network_peer_controls" > + # in the measured SELinux state at offset 7 for 'awk' > + while [ $inx -lt 20 ]; do > + measured_cap=$(echo $1 | awk -F'[=;]' -v inx="$inx" '{print $inx}') > + inx=$(( $inx + 1 )) > + > + 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 TWARN "$measured_cap: expected: $expected_value, got: $digest" We rarely use TWARN in the tests, only when the error is not related to the test result. Otherwise we use TFAIL. The rest LGTM. Reviewed-by: Petr Vorel <pvorel@suse.cz> I did few formatting and style changes: https://github.com/pevik/ltp/commits/ima/selinux.v2.fixes (branch ima/selinux.v2.fixes), see diff below. As we discuss, I'm going tom merge test when patchset is merged in maintainers tree, please ping me. And ideally we should mention kernel commit hash as a comment in the test. Thanks a lot! Kind regards, Petr diff --git testcases/kernel/security/integrity/ima/tests/ima_selinux.sh testcases/kernel/security/integrity/ima/tests/ima_selinux.sh index e5060a5e3..ed758631b 100755 --- testcases/kernel/security/integrity/ima/tests/ima_selinux.sh +++ testcases/kernel/security/integrity/ima/tests/ima_selinux.sh @@ -13,16 +13,14 @@ TST_SETUP="setup" . ima_setup.sh FUNC_CRITICAL_DATA='func=CRITICAL_DATA' -REQUIRED_POLICY="^measure.*($FUNC_CRITICAL_DATA)" +REQUIRED_POLICY="^measure.*$FUNC_CRITICAL_DATA" setup() { - SELINUX_DIR=$(tst_get_selinux_dir) - if [ -z "$SELINUX_DIR" ]; then - tst_brk TCONF "SELinux is not enabled" - return - fi + tst_require_selinux_enabled require_ima_policy_content "$REQUIRED_POLICY" '-E' > $TST_TMPDIR/policy.txt + + SELINUX_DIR=$(tst_get_selinux_dir) } # Format of the measured SELinux state data. @@ -41,16 +39,16 @@ validate_policy_capabilities() # in the measured SELinux state at offset 7 for 'awk' while [ $inx -lt 20 ]; do measured_cap=$(echo $1 | awk -F'[=;]' -v inx="$inx" '{print $inx}') - inx=$(( $inx + 1 )) + inx=$(($inx + 1)) 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 + if [ "$measured_value" != "$expected_value" ]; then tst_res TWARN "$measured_cap: expected: $expected_value, got: $digest" result=0 fi - inx=$(( $inx + 1 )) + inx=$(($inx + 1)) done return $result @@ -109,7 +107,6 @@ test2() local initialized_value local enforced_value expected_enforced_value local checkreqprot_value expected_checkreqprot_value - local result tst_res TINFO "verifying SELinux state measurement" @@ -149,27 +146,25 @@ test2() measured_data=$(cat $state_file) enforced_value=$(echo $measured_data | awk -F'[=;]' '{print $4}') expected_enforced_value=$(cat $SELINUX_DIR/enforce) - if [ "$expected_enforced_value" != "$enforced_value" ];then + if [ "$expected_enforced_value" != "$enforced_value" ]; then tst_res TFAIL "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 + if [ "$expected_checkreqprot_value" != "$checkreqprot_value" ]; then tst_res TFAIL "checkreqprot: expected: $expected_checkreqprot_value, got: $checkreqprot_value" return fi initialized_value=$(echo $measured_data | awk -F'[=;]' '{print $2}') - if [ "$initialized_value" != "1" ];then + if [ "$initialized_value" != "1" ]; then tst_res TFAIL "initialized: expected 1, got: $initialized_value" return fi - validate_policy_capabilities $measured_data - result=$? - if [ $result = 0 ]; then + if validate_policy_capabilities $measured_data; then tst_res TFAIL "policy capabilities did not match" return fi
On 2/23/21 10:00 AM, Petr Vorel wrote: > >> +++ b/testcases/kernel/security/integrity/ima/tests/ima_selinux.sh > ... >> +validate_policy_capabilities() >> +{ >> + local measured_cap measured_value expected_value >> + local result=1 >> + local inx=7 >> + >> + # Policy capabilities flags start from "network_peer_controls" >> + # in the measured SELinux state at offset 7 for 'awk' >> + while [ $inx -lt 20 ]; do >> + measured_cap=$(echo $1 | awk -F'[=;]' -v inx="$inx" '{print $inx}') >> + inx=$(( $inx + 1 )) >> + >> + 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 TWARN "$measured_cap: expected: $expected_value, got: $digest" > We rarely use TWARN in the tests, only when the error is not related to the test result. > Otherwise we use TFAIL. ok - I will change it to TFAIL. > > The rest LGTM. > Reviewed-by: Petr Vorel <pvorel@suse.cz> > > I did few formatting and style changes: > https://github.com/pevik/ltp/commits/ima/selinux.v2.fixes > (branch ima/selinux.v2.fixes), see diff below. The changes look. Thanks Petr. I do have one comment - please see below. > > As we discuss, I'm going tom merge test when patchset is merged in maintainers tree, > please ping me. And ideally we should mention kernel commit hash as a comment in > the test. Will do. Thank you. > > Thanks a lot! > > Kind regards, > Petr > > diff --git testcases/kernel/security/integrity/ima/tests/ima_selinux.sh testcases/kernel/security/integrity/ima/tests/ima_selinux.sh > index e5060a5e3..ed758631b 100755 > --- testcases/kernel/security/integrity/ima/tests/ima_selinux.sh > +++ testcases/kernel/security/integrity/ima/tests/ima_selinux.sh > @@ -13,16 +13,14 @@ TST_SETUP="setup" > . ima_setup.sh > > FUNC_CRITICAL_DATA='func=CRITICAL_DATA' > -REQUIRED_POLICY="^measure.*($FUNC_CRITICAL_DATA)" > +REQUIRED_POLICY="^measure.*$FUNC_CRITICAL_DATA" > > setup() > { > - SELINUX_DIR=$(tst_get_selinux_dir) > - if [ -z "$SELINUX_DIR" ]; then > - tst_brk TCONF "SELinux is not enabled" > - return > - fi > + tst_require_selinux_enabled Please correct me if I have misunderstood this one: tst_require_selinux_enabled is checking if SELinux is enabled in "enforce" mode. Would this check fail if SELinux is enabled in "permissive" mode? For running the test, we just need SELinux to be enabled. I verify that by checking for the presence of SELINUX_DIR. thanks, -lakshmi > require_ima_policy_content "$REQUIRED_POLICY" '-E' > $TST_TMPDIR/policy.txt > + > + SELINUX_DIR=$(tst_get_selinux_dir) > } > > # Format of the measured SELinux state data. > @@ -41,16 +39,16 @@ validate_policy_capabilities() > # in the measured SELinux state at offset 7 for 'awk' > while [ $inx -lt 20 ]; do > measured_cap=$(echo $1 | awk -F'[=;]' -v inx="$inx" '{print $inx}') > - inx=$(( $inx + 1 )) > + inx=$(($inx + 1)) > > 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 > + if [ "$measured_value" != "$expected_value" ]; then > tst_res TWARN "$measured_cap: expected: $expected_value, got: $digest" > result=0 > fi > > - inx=$(( $inx + 1 )) > + inx=$(($inx + 1)) > done > > return $result > @@ -109,7 +107,6 @@ test2() > local initialized_value > local enforced_value expected_enforced_value > local checkreqprot_value expected_checkreqprot_value > - local result > > tst_res TINFO "verifying SELinux state measurement" > > @@ -149,27 +146,25 @@ test2() > measured_data=$(cat $state_file) > enforced_value=$(echo $measured_data | awk -F'[=;]' '{print $4}') > expected_enforced_value=$(cat $SELINUX_DIR/enforce) > - if [ "$expected_enforced_value" != "$enforced_value" ];then > + if [ "$expected_enforced_value" != "$enforced_value" ]; then > tst_res TFAIL "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 > + if [ "$expected_checkreqprot_value" != "$checkreqprot_value" ]; then > tst_res TFAIL "checkreqprot: expected: $expected_checkreqprot_value, got: $checkreqprot_value" > return > fi > > initialized_value=$(echo $measured_data | awk -F'[=;]' '{print $2}') > - if [ "$initialized_value" != "1" ];then > + if [ "$initialized_value" != "1" ]; then > tst_res TFAIL "initialized: expected 1, got: $initialized_value" > return > fi > > - validate_policy_capabilities $measured_data > - result=$? > - if [ $result = 0 ]; then > + if validate_policy_capabilities $measured_data; then > tst_res TFAIL "policy capabilities did not match" > return > fi >
> On 2/23/21 10:00 AM, Petr Vorel wrote: > > > +++ b/testcases/kernel/security/integrity/ima/tests/ima_selinux.sh > > ... > > > +validate_policy_capabilities() > > > +{ > > > + local measured_cap measured_value expected_value > > > + local result=1 > > > + local inx=7 > > > + > > > + # Policy capabilities flags start from "network_peer_controls" > > > + # in the measured SELinux state at offset 7 for 'awk' > > > + while [ $inx -lt 20 ]; do > > > + measured_cap=$(echo $1 | awk -F'[=;]' -v inx="$inx" '{print $inx}') > > > + inx=$(( $inx + 1 )) > > > + > > > + 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 TWARN "$measured_cap: expected: $expected_value, got: $digest" > > We rarely use TWARN in the tests, only when the error is not related to the test result. > > Otherwise we use TFAIL. > ok - I will change it to TFAIL. Thanks! But I've noticed that this error is handled twice, first in validate_policy_capabilities() as TWARN (or TFAIL) and then in test2(). Let's use TPASS/TFAIL in validate_policy_capabilities(): validate_policy_capabilities() { local measured_cap measured_value expected_value local inx=7 # Policy capabilities flags start from "network_peer_controls" # in the measured SELinux state at offset 7 for 'awk' while [ $inx -lt 20 ]; do measured_cap=$(echo $1 | awk -F'[=;]' -v inx="$inx" '{print $inx}') inx=$(($inx + 1)) 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" return fi inx=$(($inx + 1)) done tst_res TPASS "SELinux state measured correctly" } test2() { ... validate_policy_capabilities $measured_data } ... > > As we discuss, I'm going tom merge test when patchset is merged in maintainers tree, > > please ping me. And ideally we should mention kernel commit hash as a comment in > > the test. > Will do. Thank you. Thanks! ... > > +++ testcases/kernel/security/integrity/ima/tests/ima_selinux.sh > > @@ -13,16 +13,14 @@ TST_SETUP="setup" > > . ima_setup.sh > > FUNC_CRITICAL_DATA='func=CRITICAL_DATA' > > -REQUIRED_POLICY="^measure.*($FUNC_CRITICAL_DATA)" > > +REQUIRED_POLICY="^measure.*$FUNC_CRITICAL_DATA" > > setup() > > { > > - SELINUX_DIR=$(tst_get_selinux_dir) > > - if [ -z "$SELINUX_DIR" ]; then > > - tst_brk TCONF "SELinux is not enabled" > > - return > > - fi > > + tst_require_selinux_enabled > Please correct me if I have misunderstood this one: > tst_require_selinux_enabled is checking if SELinux is enabled in "enforce" > mode. Would this check fail if SELinux is enabled in "permissive" mode? > For running the test, we just need SELinux to be enabled. I verify that by > checking for the presence of SELINUX_DIR. Good catch. Your original version is correct (put it back into ima/selinux.v2.fixes). I didn't put a helper for it, because you need $SELINUX_DIR anyway. Thus removed tst_require_selinux_enabled() as not needed. I renamed tst_selinux_enabled() to tst_selinux_enforced() to make the purpose clearer (commit 82b598ea1 IMA: Add test for selinux measurement). I've updated branch ima/selinux.v2.fixes with all mentioned changes https://github.com/pevik/ltp/commits/ima/selinux.v2.fixes Kind regards, Petr > thanks, > -lakshmi
On 2/23/21 2:14 PM, Petr Vorel wrote: >> On 2/23/21 10:00 AM, Petr Vorel wrote: > > >>>> +++ b/testcases/kernel/security/integrity/ima/tests/ima_selinux.sh >>> ... >>>> +validate_policy_capabilities() >>>> +{ >>>> + local measured_cap measured_value expected_value >>>> + local result=1 >>>> + local inx=7 >>>> + >>>> + # Policy capabilities flags start from "network_peer_controls" >>>> + # in the measured SELinux state at offset 7 for 'awk' >>>> + while [ $inx -lt 20 ]; do >>>> + measured_cap=$(echo $1 | awk -F'[=;]' -v inx="$inx" '{print $inx}') >>>> + inx=$(( $inx + 1 )) >>>> + >>>> + 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 TWARN "$measured_cap: expected: $expected_value, got: $digest" >>> We rarely use TWARN in the tests, only when the error is not related to the test result. >>> Otherwise we use TFAIL. >> ok - I will change it to TFAIL. > Thanks! > But I've noticed that this error is handled twice, first in validate_policy_capabilities() > as TWARN (or TFAIL) and then in test2(). Let's use TPASS/TFAIL in > validate_policy_capabilities(): Sure - will make that change. > > validate_policy_capabilities() > { > local measured_cap measured_value expected_value > local inx=7 > > # Policy capabilities flags start from "network_peer_controls" > # in the measured SELinux state at offset 7 for 'awk' > while [ $inx -lt 20 ]; do > measured_cap=$(echo $1 | awk -F'[=;]' -v inx="$inx" '{print $inx}') > inx=$(($inx + 1)) > > 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" > return > fi > > inx=$(($inx + 1)) > done > > tst_res TPASS "SELinux state measured correctly" > } > > test2() > { > ... > validate_policy_capabilities $measured_data > } > > ... >>> As we discuss, I'm going tom merge test when patchset is merged in maintainers tree, >>> please ping me. And ideally we should mention kernel commit hash as a comment in >>> the test. >> Will do. Thank you. > Thanks! > > ... >>> +++ testcases/kernel/security/integrity/ima/tests/ima_selinux.sh >>> @@ -13,16 +13,14 @@ TST_SETUP="setup" >>> . ima_setup.sh >>> FUNC_CRITICAL_DATA='func=CRITICAL_DATA' >>> -REQUIRED_POLICY="^measure.*($FUNC_CRITICAL_DATA)" >>> +REQUIRED_POLICY="^measure.*$FUNC_CRITICAL_DATA" >>> setup() >>> { >>> - SELINUX_DIR=$(tst_get_selinux_dir) >>> - if [ -z "$SELINUX_DIR" ]; then >>> - tst_brk TCONF "SELinux is not enabled" >>> - return >>> - fi >>> + tst_require_selinux_enabled >> Please correct me if I have misunderstood this one: > >> tst_require_selinux_enabled is checking if SELinux is enabled in "enforce" >> mode. Would this check fail if SELinux is enabled in "permissive" mode? > >> For running the test, we just need SELinux to be enabled. I verify that by >> checking for the presence of SELINUX_DIR. > > Good catch. Your original version is correct (put it back into ima/selinux.v2.fixes). > I didn't put a helper for it, because you need $SELINUX_DIR anyway. > Thus removed tst_require_selinux_enabled() as not needed. Thanks > > I renamed tst_selinux_enabled() to tst_selinux_enforced() to make the purpose clearer > (commit 82b598ea1 IMA: Add test for selinux measurement). > > I've updated branch ima/selinux.v2.fixes with all mentioned changes > https://github.com/pevik/ltp/commits/ima/selinux.v2.fixes > Thanks again. I'll make my changes in this branch and post the patches later this week. -lakshmi
Hi Lakshmi, Mimi, > New functionality has been added in IMA to measure data that is > critical to the integrity of the system. SELinux uses this feature > to measure the hash of the SELinux policy loaded in kernel memory, > and the current state of various SELinux configuration. This new > functionality needs test automation in LTP. > Add test cases which verify that the IMA subsystem correctly > measures the data provided by SELinux. I finally merged this patchset, noted both kernel commits. Thanks for this test! Kind regards, Petr * fdd1ffe8a812 ("selinux: include a consumer of the new IMA critical data hook") (v5.12-rc1-dontuse) * 2554a48f4437 ("selinux: measure state and policy capabilities") (to be in v5.13
diff --git a/runtest/ima b/runtest/ima index 5f4b4a7a1..29caa034a 100644 --- a/runtest/ima +++ b/runtest/ima @@ -5,4 +5,5 @@ ima_tpm ima_tpm.sh ima_violations ima_violations.sh ima_keys ima_keys.sh ima_kexec ima_kexec.sh +ima_selinux ima_selinux.sh evm_overlay evm_overlay.sh diff --git a/testcases/kernel/security/integrity/ima/README.md b/testcases/kernel/security/integrity/ima/README.md index 68d046678..8f2249767 100644 --- a/testcases/kernel/security/integrity/ima/README.md +++ b/testcases/kernel/security/integrity/ima/README.md @@ -37,6 +37,25 @@ see example in `kexec.policy`. The test attempts to kexec the existing running kernel image. To kexec a different kernel image export `IMA_KEXEC_IMAGE=<pathname>`. +### IMA SELinux test + +To enable IMA to measure SELinux state and policy, `ima_selinux.sh` +requires a readable IMA policy, as well as a loaded measure policy with +`measure func=CRITICAL_DATA label=selinux`, +see example in `selinux.policy`. + +As well as what's required for the IMA tests, SELinux tests require reading +the IMA policy allowed in the kernel configuration: +``` +CONFIG_IMA_READ_POLICY=y +``` + +The following kernel configuration is also required. It enables compiling +the Linux Security Module (LSM) namely SELinux. +``` +CONFIG_SECURITY_SELINUX=y +``` + ## EVM tests `evm_overlay.sh` requires a builtin IMA appraise tcb policy (e.g. `ima_policy=appraise_tcb` diff --git a/testcases/kernel/security/integrity/ima/datafiles/Makefile b/testcases/kernel/security/integrity/ima/datafiles/Makefile index 47a470416..280175b17 100644 --- a/testcases/kernel/security/integrity/ima/datafiles/Makefile +++ b/testcases/kernel/security/integrity/ima/datafiles/Makefile @@ -26,6 +26,6 @@ top_srcdir ?= ../../../../../.. include $(top_srcdir)/include/mk/env_pre.mk -SUBDIRS := ima_kexec ima_keys ima_policy +SUBDIRS := ima_kexec ima_keys ima_policy ima_selinux include $(top_srcdir)/include/mk/generic_trunk_target.mk diff --git a/testcases/kernel/security/integrity/ima/datafiles/ima_selinux/Makefile b/testcases/kernel/security/integrity/ima/datafiles/ima_selinux/Makefile new file mode 100644 index 000000000..35088fdbc --- /dev/null +++ b/testcases/kernel/security/integrity/ima/datafiles/ima_selinux/Makefile @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) Linux Test Project, 2021 + +top_srcdir ?= ../../../../../../.. + +include $(top_srcdir)/include/mk/env_pre.mk + +INSTALL_DIR := testcases/data/ima_selinux +INSTALL_TARGETS := *.policy + +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/security/integrity/ima/datafiles/ima_selinux/selinux.policy b/testcases/kernel/security/integrity/ima/datafiles/ima_selinux/selinux.policy new file mode 100644 index 000000000..7cbe9352d --- /dev/null +++ b/testcases/kernel/security/integrity/ima/datafiles/ima_selinux/selinux.policy @@ -0,0 +1 @@ +measure func=CRITICAL_DATA label=selinux diff --git a/testcases/kernel/security/integrity/ima/tests/ima_selinux.sh b/testcases/kernel/security/integrity/ima/tests/ima_selinux.sh new file mode 100755 index 000000000..e5060a5e3 --- /dev/null +++ b/testcases/kernel/security/integrity/ima/tests/ima_selinux.sh @@ -0,0 +1,180 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2021 Microsoft Corporation +# Author: Lakshmi Ramasubramanian <nramas@linux.microsoft.com> +# +# Verify measurement of SELinux policy hash and state. + +TST_NEEDS_CMDS="awk cut grep tail" +TST_CNT=2 +TST_NEEDS_DEVICE=1 +TST_SETUP="setup" + +. ima_setup.sh + +FUNC_CRITICAL_DATA='func=CRITICAL_DATA' +REQUIRED_POLICY="^measure.*($FUNC_CRITICAL_DATA)" + +setup() +{ + SELINUX_DIR=$(tst_get_selinux_dir) + if [ -z "$SELINUX_DIR" ]; then + tst_brk TCONF "SELinux is not enabled" + return + fi + require_ima_policy_content "$REQUIRED_POLICY" '-E' > $TST_TMPDIR/policy.txt +} + +# Format of the measured SELinux state data. +# +# initialized=1;enforcing=0;checkreqprot=1; +# network_peer_controls=1;open_perms=1;extended_socket_class=1; +# always_check_network=0;cgroup_seclabel=1;nnp_nosuid_transition=1; +# genfs_seclabel_symlinks=0; +validate_policy_capabilities() +{ + local measured_cap measured_value expected_value + local result=1 + local inx=7 + + # Policy capabilities flags start from "network_peer_controls" + # in the measured SELinux state at offset 7 for 'awk' + while [ $inx -lt 20 ]; do + measured_cap=$(echo $1 | awk -F'[=;]' -v inx="$inx" '{print $inx}') + inx=$(( $inx + 1 )) + + 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 TWARN "$measured_cap: expected: $expected_value, got: $digest" + result=0 + fi + + inx=$(( $inx + 1 )) + done + + return $result +} + +# Trigger measurement of SELinux constructs and verify that +# the measured SELinux policy hash matches the hash of the policy +# loaded in kernel memory for SELinux. +test1() +{ + local policy_digest expected_policy_digest algorithm + local data_source_name="selinux" + local pattern="data_sources=[^[:space:]]*$data_source_name" + local tmp_file="$TST_TMPDIR/selinux_policy_tmp_file.txt" + + tst_res TINFO "verifying SELinux policy hash measurement" + + # Trigger a measurement by changing SELinux state + tst_update_selinux_state + + # Verify SELinux policy hash is measured and then validate that + # the measured policy hash matches the hash of the policy currently + # 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" + return + fi + + algorithm=$(echo "$line" | cut -d' ' -f4 | cut -d':' -f1) + policy_digest=$(echo "$line" | cut -d' ' -f6) + + expected_policy_digest="$(compute_digest $algorithm $SELINUX_DIR/policy)" || \ + 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" + return + fi + + tst_res TPASS "SELinux policy hash measured correctly" +} + +# Trigger measurement of SELinux constructs and verify that +# the measured SELinux state matches the current SELinux +# configuration. +test2() +{ + tst_check_cmds xxd || return + + local measured_data state_file="$TST_TMPDIR/selinux_state.txt" + local data_source_name="selinux" + local pattern="data_sources=[^[:space:]]*$data_source_name" + local tmp_file="$TST_TMPDIR/selinux_state_tmp_file.txt" + local digest expected_digest algorithm + local initialized_value + local enforced_value expected_enforced_value + local checkreqprot_value expected_checkreqprot_value + local result + + tst_res TINFO "verifying SELinux state measurement" + + # Trigger a measurement by changing SELinux state + tst_update_selinux_state + + # Verify SELinux state is measured and then validate the measured + # 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" + return + fi + + digest=$(echo "$line" | cut -d' ' -f4 | cut -d':' -f2) + algorithm=$(echo "$line" | cut -d' ' -f4 | cut -d':' -f1) + + echo "$line" | cut -d' ' -f6 | xxd -r -p > $state_file + + expected_digest="$(compute_digest $algorithm $state_file)" || \ + tst_brk TCONF "cannot compute digest for $algorithm" + + if [ "$digest" != "$expected_digest" ]; then + tst_res TFAIL "digest mismatch: expected: $expected_digest, got: $digest" + return + fi + + # SELinux state is measured as the following string + # initialized=1;enforcing=0;checkreqprot=1; + # Value of 0 indicates the state is ON, and 1 indicates OFF + # + # enforce and checkreqprot measurement can be verified by + # comparing the value of the file "enforce" and "checkreqprot" + # respectively in the SELinux directory. + # "initialized" is an internal state and should be set to 1 + # if enforce and checkreqprot are measured correctly. + measured_data=$(cat $state_file) + 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" + 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" + 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" + return + fi + + validate_policy_capabilities $measured_data + result=$? + if [ $result = 0 ]; then + tst_res TFAIL "policy capabilities did not match" + return + fi + + tst_res TPASS "SELinux state measured correctly" +} + +tst_run
New functionality has been added in IMA to measure data that is critical to the integrity of the system. SELinux uses this feature to measure the hash of the SELinux policy loaded in kernel memory, and the current state of various SELinux configuration. This new functionality needs test automation in LTP. Add test cases which verify that the IMA subsystem correctly measures the data provided by SELinux. Signed-off-by: Lakshmi Ramasubramanian <nramas@linux.microsoft.com> --- This patch is based on commit c7c4cd5e7f3b ("tst_security.sh: Add SELinux helpers") in https://github.com/pevik/ltp/commits/ima/selinux.v2.draft in branch ima/selinux.v2.draft. runtest/ima | 1 + .../kernel/security/integrity/ima/README.md | 19 ++ .../security/integrity/ima/datafiles/Makefile | 2 +- .../ima/datafiles/ima_selinux/Makefile | 11 ++ .../ima/datafiles/ima_selinux/selinux.policy | 1 + .../integrity/ima/tests/ima_selinux.sh | 180 ++++++++++++++++++ 6 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 testcases/kernel/security/integrity/ima/datafiles/ima_selinux/Makefile create mode 100644 testcases/kernel/security/integrity/ima/datafiles/ima_selinux/selinux.policy create mode 100755 testcases/kernel/security/integrity/ima/tests/ima_selinux.sh