diff mbox series

[v3,ima-evm-utils,4/4] Add simple tests to check EVM HMAC calculation

Message ID 20230616192358.314906-5-roberto.sassu@huaweicloud.com (mailing list archive)
State New, archived
Headers show
Series Simple EVM HMAC calculation tests | expand

Commit Message

Roberto Sassu June 16, 2023, 7:23 p.m. UTC
From: Roberto Sassu <roberto.sassu@huawei.com>

Add a simple test to ensure that the kernel and evmctl provide the same
result for the HMAC calculation. Do it with SELinux or Smack, whichever is
available (if the UML kernel is used, the test is done with both LSMs).

Also add another test to evaluate the HMAC on a directory for which Smack
added the SMACK64TRANSMUTE xattr.

The second test fails without the kernel patch 'smack: Set the
SMACK64TRANSMUTE xattr in smack_inode_init_security()', as Smack uses
__vfs_setxattr() to set SMACK64TRANSMUTE, which does not go through EVM,
and makes the HMAC invalid.

Require (unless the UML kernel is used) that the TST_EVM_CHANGE_MODE
environment variable is set to 1, so that users acknowledge that they are
initializing EVM with a well-known HMAC key, which can introduce obvious
security concerns.

Finally, enable SELinux, the EVM additional xattrs, and encrypted keys with
user-decrypted data in the kernel configuration for CI, and set
TST_EVM_CHANGE_MODE to 1 in the Github Action workflow.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
 .github/workflows/ci.yml |   1 +
 kernel-configs/base      |   6 +-
 kernel-configs/integrity |   1 +
 tests/Makefile.am        |   2 +-
 tests/evm_hmac.test      | 281 +++++++++++++++++++++++++++++++++++++++
 tests/functions.sh       |   6 +
 6 files changed, 295 insertions(+), 2 deletions(-)
 create mode 100755 tests/evm_hmac.test

Comments

Mimi Zohar June 23, 2023, 11:42 a.m. UTC | #1
Hi Roberto,

On Fri, 2023-06-16 at 21:23 +0200, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
> 
> Add a simple test to ensure that the kernel and evmctl provide the same
> result for the HMAC calculation. Do it with SELinux or Smack, whichever is
> available (if the UML kernel is used, the test is done with both LSMs).
> 
> Also add another test to evaluate the HMAC on a directory for which Smack
> added the SMACK64TRANSMUTE xattr.
> 
> The second test fails without the kernel patch 'smack: Set the
> SMACK64TRANSMUTE xattr in smack_inode_init_security()', as Smack uses
> __vfs_setxattr() to set SMACK64TRANSMUTE, which does not go through EVM,
> and makes the HMAC invalid.
> 
> Require (unless the UML kernel is used) that the TST_EVM_CHANGE_MODE
> environment variable is set to 1, so that users acknowledge that they are
> initializing EVM with a well-known HMAC key, which can introduce obvious
> security concerns.
> 
> Finally, enable SELinux, the EVM additional xattrs, and encrypted keys with
> user-decrypted data in the kernel configuration for CI, and set
> TST_EVM_CHANGE_MODE to 1 in the Github Action workflow.
> 
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>

The simple SELinux and Smack tests are working properly without kernel
changes.  Even the Smack transmute test is working is proplery
returning an error message, but is followed by a kernel panic.

Possibly missing patches:
 - smack: Set the SMACK64TRANSMUTE xattr in smack_inode_init_security

   14.620000][    T1] Kernel panic - not syncing: Attempted to kill
init! exitcode=0x00000100
[   14.620000][    T1] CPU: 0 PID: 1 Comm: evm_hmac.test Not tainted
6.4.0-rc2-dont-use-g95526d13038c #1
[   14.620000][    T1] Stack:
[   14.620000][    T1]  60900a17 e1803be0 e1803c20 606f7598
[   14.620000][    T1]  63240701 60043a50 60900a17 00000000
[   14.620000][    T1]  60dfc308 00000000 e1803c60 60762e4b
[   14.620000][    T1] Call Trace:
[   14.620000][    T1]  [<6072ad82>] ? _printk+0x0/0x98
[   14.620000][    T1]  [<6072274d>] show_stack.cold+0x9d/0xf4
[   14.620000][    T1]  [<606f7598>] ? dump_stack_print_info+0xd8/0xf0
[   14.620000][    T1]  [<60043a50>] ? um_set_signals+0x0/0x60
[   14.620000][    T1]  [<60762e4b>] dump_stack_lvl+0x66/0x9a
[   14.620000][    T1]  [<607715d0>] ? _raw_spin_unlock_irq+0x0/0x60
[   14.620000][    T1]  [<60762e9d>] dump_stack+0x1e/0x20
[   14.620000][    T1]  [<6072429d>] panic+0x1a6/0x3a6
[   14.620000][    T1]  [<607240f7>] ? panic+0x0/0x3a6
[   14.620000][    T1]  [<600aec6a>] ? lock_release+0xca/0x180
[   14.620000][    T1]  [<60043a50>] ? um_set_signals+0x0/0x60
[   14.620000][    T1]  [<60764fe0>] ?
debug_lockdep_rcu_enabled+0x0/0x50
[   14.620000][    T1]  [<60043a9f>] ? um_set_signals+0x4f/0x60
[   14.620000][    T1]  [<60764fe0>] ?
debug_lockdep_rcu_enabled+0x0/0x50
[   14.620000][    T1]  [<60043a50>] ? um_set_signals+0x0/0x60
[   14.620000][    T1]  [<60064d79>] ? exit_signals+0x139/0x500
[   14.620000][    T1]  [<60771210>] ? _raw_spin_lock_irq+0x0/0xd0
[   14.620000][    T1]  [<607715d0>] ? _raw_spin_unlock_irq+0x0/0x60
[   14.620000][    T1]  [<607249c0>] make_task_dead.cold+0x0/0x9d
[   14.620000][    T1]  [<600557e7>] do_group_exit+0x47/0xe0
[   14.620000][    T1]  [<6004a0f0>] ? get_fp_registers+0x0/0x80
[   14.620000][    T1]  [<6005589a>] sys_exit_group+0x1a/0x20
[   14.620000][    T1]  [<600302a0>] handle_syscall+0xa0/0xd0
[   14.620000][    T1]  [<60046969>] handle_trap+0xe9/0x1a0
[   14.620000][    T1]  [<6004a0f0>] ? get_fp_registers+0x0/0x80
[   14.620000][    T1]  [<6004709f>] userspace+0x29f/0x530
[   14.620000][    T1]  [<6002c374>] new_thread_handler+0xb4/0xc0
./functions.sh: line 72:  8546 Aborted                 (core dumped)
"$@"
=================================
 Run with FAILEARLY=1 ./evm_hmac.test _cleanup_env cleanup
 To stop after first failure
Roberto Sassu June 23, 2023, 11:45 a.m. UTC | #2
On Fri, 2023-06-23 at 07:42 -0400, Mimi Zohar wrote:
> Hi Roberto,
> 
> On Fri, 2023-06-16 at 21:23 +0200, Roberto Sassu wrote:
> > From: Roberto Sassu <roberto.sassu@huawei.com>
> > 
> > Add a simple test to ensure that the kernel and evmctl provide the same
> > result for the HMAC calculation. Do it with SELinux or Smack, whichever is
> > available (if the UML kernel is used, the test is done with both LSMs).
> > 
> > Also add another test to evaluate the HMAC on a directory for which Smack
> > added the SMACK64TRANSMUTE xattr.
> > 
> > The second test fails without the kernel patch 'smack: Set the
> > SMACK64TRANSMUTE xattr in smack_inode_init_security()', as Smack uses
> > __vfs_setxattr() to set SMACK64TRANSMUTE, which does not go through EVM,
> > and makes the HMAC invalid.
> > 
> > Require (unless the UML kernel is used) that the TST_EVM_CHANGE_MODE
> > environment variable is set to 1, so that users acknowledge that they are
> > initializing EVM with a well-known HMAC key, which can introduce obvious
> > security concerns.
> > 
> > Finally, enable SELinux, the EVM additional xattrs, and encrypted keys with
> > user-decrypted data in the kernel configuration for CI, and set
> > TST_EVM_CHANGE_MODE to 1 in the Github Action workflow.
> > 
> > Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> 
> The simple SELinux and Smack tests are working properly without kernel
> changes.  Even the Smack transmute test is working is proplery
> returning an error message, but is followed by a kernel panic.
> 
> Possibly missing patches:
>  - smack: Set the SMACK64TRANSMUTE xattr in smack_inode_init_security

Hi Mimi

that means that the test is failing.

A UML kernel panic is used to signal to the caller that a test in that
environment failed.

It is expected that the test fails, Smack updates its xattr with
__vfs_setxattr() which does not involve EVM checking and updating the
HMAC.

Thanks

Roberto

>    14.620000][    T1] Kernel panic - not syncing: Attempted to kill
> init! exitcode=0x00000100
> [   14.620000][    T1] CPU: 0 PID: 1 Comm: evm_hmac.test Not tainted
> 6.4.0-rc2-dont-use-g95526d13038c #1
> [   14.620000][    T1] Stack:
> [   14.620000][    T1]  60900a17 e1803be0 e1803c20 606f7598
> [   14.620000][    T1]  63240701 60043a50 60900a17 00000000
> [   14.620000][    T1]  60dfc308 00000000 e1803c60 60762e4b
> [   14.620000][    T1] Call Trace:
> [   14.620000][    T1]  [<6072ad82>] ? _printk+0x0/0x98
> [   14.620000][    T1]  [<6072274d>] show_stack.cold+0x9d/0xf4
> [   14.620000][    T1]  [<606f7598>] ? dump_stack_print_info+0xd8/0xf0
> [   14.620000][    T1]  [<60043a50>] ? um_set_signals+0x0/0x60
> [   14.620000][    T1]  [<60762e4b>] dump_stack_lvl+0x66/0x9a
> [   14.620000][    T1]  [<607715d0>] ? _raw_spin_unlock_irq+0x0/0x60
> [   14.620000][    T1]  [<60762e9d>] dump_stack+0x1e/0x20
> [   14.620000][    T1]  [<6072429d>] panic+0x1a6/0x3a6
> [   14.620000][    T1]  [<607240f7>] ? panic+0x0/0x3a6
> [   14.620000][    T1]  [<600aec6a>] ? lock_release+0xca/0x180
> [   14.620000][    T1]  [<60043a50>] ? um_set_signals+0x0/0x60
> [   14.620000][    T1]  [<60764fe0>] ?
> debug_lockdep_rcu_enabled+0x0/0x50
> [   14.620000][    T1]  [<60043a9f>] ? um_set_signals+0x4f/0x60
> [   14.620000][    T1]  [<60764fe0>] ?
> debug_lockdep_rcu_enabled+0x0/0x50
> [   14.620000][    T1]  [<60043a50>] ? um_set_signals+0x0/0x60
> [   14.620000][    T1]  [<60064d79>] ? exit_signals+0x139/0x500
> [   14.620000][    T1]  [<60771210>] ? _raw_spin_lock_irq+0x0/0xd0
> [   14.620000][    T1]  [<607715d0>] ? _raw_spin_unlock_irq+0x0/0x60
> [   14.620000][    T1]  [<607249c0>] make_task_dead.cold+0x0/0x9d
> [   14.620000][    T1]  [<600557e7>] do_group_exit+0x47/0xe0
> [   14.620000][    T1]  [<6004a0f0>] ? get_fp_registers+0x0/0x80
> [   14.620000][    T1]  [<6005589a>] sys_exit_group+0x1a/0x20
> [   14.620000][    T1]  [<600302a0>] handle_syscall+0xa0/0xd0
> [   14.620000][    T1]  [<60046969>] handle_trap+0xe9/0x1a0
> [   14.620000][    T1]  [<6004a0f0>] ? get_fp_registers+0x0/0x80
> [   14.620000][    T1]  [<6004709f>] userspace+0x29f/0x530
> [   14.620000][    T1]  [<6002c374>] new_thread_handler+0xb4/0xc0
> ./functions.sh: line 72:  8546 Aborted                 (core dumped)
> "$@"
> =================================
>  Run with FAILEARLY=1 ./evm_hmac.test _cleanup_env cleanup
>  To stop after first failure
>
Mimi Zohar June 23, 2023, 2:30 p.m. UTC | #3
On Fri, 2023-06-23 at 13:45 +0200, Roberto Sassu wrote:
> On Fri, 2023-06-23 at 07:42 -0400, Mimi Zohar wrote:
> > Hi Roberto,
> > 
> > On Fri, 2023-06-16 at 21:23 +0200, Roberto Sassu wrote:
> > > From: Roberto Sassu <roberto.sassu@huawei.com>
> > > 
> > > Add a simple test to ensure that the kernel and evmctl provide the same
> > > result for the HMAC calculation. Do it with SELinux or Smack, whichever is
> > > available (if the UML kernel is used, the test is done with both LSMs).
> > > 
> > > Also add another test to evaluate the HMAC on a directory for which Smack
> > > added the SMACK64TRANSMUTE xattr.
> > > 
> > > The second test fails without the kernel patch 'smack: Set the
> > > SMACK64TRANSMUTE xattr in smack_inode_init_security()', as Smack uses
> > > __vfs_setxattr() to set SMACK64TRANSMUTE, which does not go through EVM,
> > > and makes the HMAC invalid.
> > > 
> > > Require (unless the UML kernel is used) that the TST_EVM_CHANGE_MODE
> > > environment variable is set to 1, so that users acknowledge that they are
> > > initializing EVM with a well-known HMAC key, which can introduce obvious
> > > security concerns.
> > > 
> > > Finally, enable SELinux, the EVM additional xattrs, and encrypted keys with
> > > user-decrypted data in the kernel configuration for CI, and set
> > > TST_EVM_CHANGE_MODE to 1 in the Github Action workflow.
> > > 
> > > Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> > 
> > The simple SELinux and Smack tests are working properly without kernel
> > changes.  Even the Smack transmute test is working is proplery
> > returning an error message, but is followed by a kernel panic.
> > 
> > Possibly missing patches:
> >  - smack: Set the SMACK64TRANSMUTE xattr in smack_inode_init_security
> 
> Hi Mimi
> 
> that means that the test is failing.
> 
> A UML kernel panic is used to signal to the caller that a test in that
> environment failed.

Thank you for the clarification.  That explains why I couldn't
reproduce it locally.  Including a traceback like this though is kind
of ugly.
diff mbox series

Patch

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e3dcf3dbc0a..54dbca5e5d7 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -152,6 +152,7 @@  jobs:
               TSS: ibmtss
               TST_ENV: um
               TST_KERNEL: ../linux
+              TST_EVM_CHANGE_MODE: 1
 
           - container: "centos:7"
             env:
diff --git a/kernel-configs/base b/kernel-configs/base
index 7acbd5b3b2a..a3cec34bc58 100644
--- a/kernel-configs/base
+++ b/kernel-configs/base
@@ -46,11 +46,13 @@  CONFIG_TMPFS_XATTR=y
 CONFIG_CONFIGFS_FS=y
 CONFIG_KEYS=y
 CONFIG_ENCRYPTED_KEYS=y
+CONFIG_USER_DECRYPTED_DATA=y
 CONFIG_SECURITY=y
 CONFIG_SECURITYFS=y
 CONFIG_SECURITY_NETWORK=y
 CONFIG_SECURITY_PATH=y
-CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity,bpf"
+CONFIG_SECURITY_SMACK=y
+CONFIG_LSM="lockdown,yama,loadpin,safesetid,selinux,smack,bpf"
 CONFIG_CRYPTO_AEAD2=y
 CONFIG_CRYPTO_SKCIPHER=y
 CONFIG_CRYPTO_SKCIPHER2=y
@@ -211,3 +213,5 @@  CONFIG_9P_FS_POSIX_ACL=y
 CONFIG_9P_FS_SECURITY=y
 CONFIG_ETHERNET=n
 CONFIG_WLAN=n
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_DEVELOP=y
diff --git a/kernel-configs/integrity b/kernel-configs/integrity
index a7e01e19466..2e104d205ba 100644
--- a/kernel-configs/integrity
+++ b/kernel-configs/integrity
@@ -27,3 +27,4 @@  CONFIG_EVM_ATTR_FSUUID=y
 CONFIG_EVM_ADD_XATTRS=y
 CONFIG_EVM_LOAD_X509=y
 CONFIG_EVM_X509_PATH="/etc/keys/x509_evm.der"
+CONFIG_EVM_EXTRA_SMACK_XATTRS=y
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 03aa5b76088..a28f671398f 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -3,7 +3,7 @@  TESTS = $(check_SCRIPTS)
 
 check_SCRIPTS += ima_hash.test sign_verify.test boot_aggregate.test \
 		 fsverity.test portable_signatures.test ima_policy_check.test \
-		 mmap_check.test
+		 mmap_check.test evm_hmac.test
 
 check_PROGRAMS := test_mmap
 
diff --git a/tests/evm_hmac.test b/tests/evm_hmac.test
new file mode 100755
index 00000000000..fe0ee218dd0
--- /dev/null
+++ b/tests/evm_hmac.test
@@ -0,0 +1,281 @@ 
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (C) 2023 Roberto Sassu <roberto.sassu@huawei.com>
+#
+# Check if the kernel and evmctl provide the same result for HMAC calculation.
+
+trap '_report_exit_and_cleanup _cleanup_env cleanup' SIGINT SIGTERM SIGSEGV EXIT
+
+# Base VERBOSE on the environment variable, if set.
+VERBOSE="${VERBOSE:-0}"
+TST_EVM_CHANGE_MODE="${TST_EVM_CHANGE_MODE:-0}"
+IMA_UUID="28b23254-9467-44c0-b6ba-34b12e85a26f"
+
+PATCHES=(
+'KEYS: encrypted: fix key instantiation with user-provided data'
+'KEYS: encrypted: Instantiate key with user-provided decrypted data'
+'smack: Set the SMACK64TRANSMUTE xattr in smack_inode_init_security()'
+)
+
+# From security/integrity/evm/evm.h in kernel source directory
+(( EVM_INIT_HMAC=0x0001 ))
+
+cd "$(dirname "$0")" || exit 1
+export PATH=$PWD/../src:$PATH
+export LD_LIBRARY_PATH=$LD_LIBRARY_PATH
+. ./functions.sh
+_require evmctl
+
+cleanup() {
+	if [ "$g_loop_mounted" = "1" ]; then
+		popd > /dev/null || exit "$FAIL"
+		umount "$g_mountpoint"
+	fi
+
+	if [ -n "$g_dev" ]; then
+		losetup -d "$g_dev"
+	fi
+
+	if [ -n "$g_image" ]; then
+		rm -f "$g_image"
+	fi
+
+	if [ -n "$g_mountpoint" ]; then
+		rm -Rf "$g_mountpoint"
+	fi
+}
+
+get_xattr() {
+	local format="hex"
+
+	if [ "$1" = "security.selinux" ]; then
+		format="text"
+	fi
+
+	getfattr -n "$1" -e "$format" -d "$2" 2> /dev/null | awk -F "=" '$1 == "'"$1"'" {if ("'"$format"'" == "hex") v=substr($2, 3); else { split($2, temp, "\""); v=temp[2] }; print v}'
+}
+
+# Compare HMAC calculated by the kernel with that calculated by evmctl.
+compare_xattr() {
+	local algo=$1
+	local path=$2
+	local evm_xattr evm_xattr_evmctl true_digest
+
+	evm_xattr="$(get_xattr security.evm "$path")"
+	true_digest=$("$algo"sum /bin/true | awk '{print $1}')
+	# evm_xattr has an extra byte at the beginning for the xattr type.
+	if [ "${#evm_xattr}" != $(( ${#true_digest} + 2 )) ]; then
+		echo "${RED}Unexpected size of security.evm for $path${NORM}"
+		return "$FAIL"
+	fi
+
+	evm_xattr_evmctl="$(evmctl hmac --smack -v -n "$path" --uuid="$IMA_UUID" -a "$algo" --hmackey "$g_hmackey" 2>&1 | awk -F " " '$1 == "hmac:" {print $2}')"
+	if [ "$evm_xattr" != "02$evm_xattr_evmctl" ]; then
+		echo "${RED}$path security.evm mismatch between the kernel and evmctl${NORM}"
+		return "$FAIL"
+	fi
+
+	return "$OK"
+}
+
+# The purpose of this test is to verify if the kernel and evmctl produce the
+# same HMAC.
+check_evm_hmac() {
+	echo "Test: ${FUNCNAME[0]} (evm_hash: $1, evm_value: $g_evm_value, algo: $1, fs: $2, lsm: $3)"
+
+	if ! grep -q "$3" < /sys/kernel/security/lsm; then
+		echo "${CYAN}$3 LSM not active${NORM}"
+		return "$SKIP"
+	fi
+
+	if [ "$3" = "selinux" ] && [ -n "$TST_ENV" ]; then
+		if [ -z "$(command -v load_policy 2> /dev/null)" ]; then
+			echo "${CYAN}Cannot find load_policy${NORM}"
+			return "$SKIP"
+		fi
+
+		if ! load_policy -i; then
+			echo "${RED}SELinux policy loading failed${NORM}"
+			return "$FAIL"
+		else
+			# Undo selinuxfs mount done by load_policy (sysfs cannot be mounted twice, procfs works but causes umount warning)
+			umount /sys/fs/selinux
+		fi
+	fi
+
+	if ! touch test-file; then
+		echo "${RED}Cannot create test-file${NORM}"
+		return "$FAIL"
+	fi
+
+	compare_xattr "$1" test-file
+	return $?
+}
+
+cleanup_evm_hmac() {
+	rm -f test-file
+}
+
+# The purpose of this test is to verify that SMACK64TRANSMUTE is successfully
+# set on a newly created directory, and that the HMAC on that directory is valid.
+check_evm_hmac_transmute() {
+	echo "Test: ${FUNCNAME[0]} (evm_hash: $1, evm_value: $g_evm_value, algo: $1, fs: $2, lsm: $3)"
+
+	if ! grep -q "$3" < /sys/kernel/security/lsm; then
+		echo "${CYAN}$3 LSM not active${NORM}"
+		return "$SKIP"
+	fi
+
+	if [ ! -f /sys/kernel/security/integrity/evm/evm_xattrs ] ||
+	   ! grep -q SMACK64TRANSMUTE < /sys/kernel/security/integrity/evm/evm_xattrs; then
+		echo "${CYAN}Set CONFIG_EVM_ADD_XATTRS=y and CONFIG_EVM_EXTRA_SMACK_XATTRS=y in the kernel configuration${NORM}"
+		exit "$SKIP"
+	fi
+
+	# Add a Smack rule for transmuting of test-dir/test-dir2
+	if ! echo "_ system rwxatl" > /sys/fs/smackfs/load2; then
+		echo "${RED}Cannot set Smack policy${NORM}"
+		return "$FAIL"
+	fi
+
+	# Smack adds security.SMACK64=_.
+	if ! mkdir test-dir; then
+		echo "${RED}Cannot create test-dir${NORM}"
+		return "$FAIL"
+	fi
+
+	# Change the directory label so that transmuting happens.
+	if ! setfattr -n security.SMACK64 -v system test-dir; then
+		echo "${RED}Cannot set security.SMACK64 on test-dir${NORM}"
+		return "$FAIL"
+	fi
+
+	# Add the transmute xattr so that transmuting happens.
+	if ! setfattr -n security.SMACK64TRANSMUTE -v TRUE test-dir; then
+		echo "${RED}Cannot set security.SMACK64TRANSMUTE on test-dir${NORM}"
+		return "$FAIL"
+	fi
+
+	compare_xattr "$1" test-dir
+	result=$?
+
+	if [ "$result" -ne "$OK" ]; then
+		return "$result"
+	fi
+
+	# Smack adds security.SMACK64=system and security.SMACK64TRANSMUTE=TRUE.
+	if ! mkdir test-dir/test-dir2; then
+		echo "${RED}Cannot create test-dir/test-dir2${NORM}"
+		return "$FAIL"
+	fi
+
+	compare_xattr "$1" test-dir/test-dir2
+	return $?
+}
+
+cleanup_evm_hmac_transmute() {
+	rm -Rf test-dir
+}
+
+if [ $$ -ne 1 ]; then
+	# Run in the new environment if TST_ENV is set.
+
+	# SElinux enabled
+	_run_env "$TST_KERNEL" "$PWD/$(basename "$0")" "TST_ENV=$TST_ENV TST_KERNEL=$TST_KERNEL PATH=$PATH LD_LIBRARY_PATH=$LD_LIBRARY_PATH VERBOSE=$VERBOSE TST_LIST=check_evm_hmac security=selinux enforcing=0"
+
+	# Smack enabled
+	_run_env "$TST_KERNEL" "$PWD/$(basename "$0")" "TST_ENV=$TST_ENV TST_KERNEL=$TST_KERNEL PATH=$PATH LD_LIBRARY_PATH=$LD_LIBRARY_PATH VERBOSE=$VERBOSE security=smack"
+
+	# Exit from the creator of the new environment.
+	_exit_env "$TST_KERNEL"
+fi
+
+# Mount filesystems in the new environment.
+_init_env
+
+# Assume that the EVM mode can be changed in a new environment.
+if [ -z "$TST_ENV" ] && [ "$TST_EVM_CHANGE_MODE" -eq 0 ]; then
+	echo "${CYAN}TST_EVM_CHANGE_MODE env variable must be set to 1${NORM}"
+	exit "$SKIP"
+fi
+
+g_lsm_init_xattr=$(awk '$1 ~ /(smack|selinux)/' < /sys/kernel/security/lsm)
+if [ -z "$g_lsm_init_xattr" ]; then
+	echo "${CYAN}Either Smack or SELinux must be active in the system for security.evm to be set${NORM}"
+	exit "$SKIP"
+fi
+
+g_mountpoint="$(mktemp -d)"
+g_image="$(mktemp)"
+
+if [ -z "$g_mountpoint" ]; then
+	echo "${RED}Mountpoint directory not created${NORM}"
+	exit "$FAIL"
+fi
+
+if [ "$(whoami)" != "root" ]; then
+	echo "${CYAN}This script must be executed as root${NORM}"
+	exit "$SKIP"
+fi
+
+if ! evmctl -h | grep -q hmackey; then
+	echo "${CYAN}Missing HMAC support, run: ./configure --enable-debug${NORM}"
+	exit "$SKIP"
+fi
+
+if ! dd if=/dev/zero of="$g_image" bs=1M count=10 &> /dev/null; then
+	echo "${RED}Cannot create test image${NORM}"
+	exit "$FAIL"
+fi
+
+g_dev="$(losetup -f "$g_image" --show)"
+if [ -z "$g_dev" ]; then
+	echo "${RED}Cannot create loop device${NORM}"
+	exit "$FAIL"
+fi
+
+if ! mkfs.ext4 -U $IMA_UUID -b 4096 "$g_dev" &> /dev/null; then
+	echo "${RED}Cannot format $g_dev${NORM}"
+	exit "$FAIL"
+fi
+
+if ! mount "$g_dev" "$g_mountpoint"; then
+	echo "${RED}Cannot mount loop device${NORM}"
+	exit "$FAIL"
+fi
+
+g_loop_mounted=1
+chmod 777 "$g_mountpoint"
+pushd "$g_mountpoint" > /dev/null || exit "$FAIL"
+
+if [ -f /sys/kernel/security/evm ]; then
+	g_evm_value=$(cat /sys/kernel/security/evm)
+fi
+
+g_hmackey_data="abcdefABCDEF1234567890aaaaaaaaaaabcdefABCDEF1234567890aaaaaaaaaa"
+
+g_hmackey="$(mktemp)"
+echo $g_hmackey_data | xxd -r -p > "$g_hmackey"
+
+if [ -n "$g_evm_value" ] && [ $((g_evm_value & EVM_INIT_HMAC)) -ne $EVM_INIT_HMAC ]; then
+	g_evm_id="$(keyctl add encrypted evm-key "new enc32 user:kmk 32 $g_hmackey_data" @u)"
+	if ! echo "$EVM_INIT_HMAC" | tee /sys/kernel/security/evm &> /dev/null; then
+		# Retry with sudo -i, to force search in the root user keyring.
+		if ! echo "$EVM_INIT_HMAC" | sudo -i tee /sys/kernel/security/evm &> /dev/null; then
+			keyctl unlink "$g_evm_id"
+			echo "${RED}Failed to initialize EVM${NORM}"
+			exit "$FAIL"
+		fi
+	fi
+
+	g_evm_value=$(cat /sys/kernel/security/evm)
+fi
+
+expect_pass_if '0 1' check_evm_hmac sha1 ext4 selinux
+cleanup_evm_hmac
+expect_pass_if '0 1' check_evm_hmac sha1 ext4 smack
+cleanup_evm_hmac
+
+expect_pass_if '2' check_evm_hmac_transmute sha1 ext4 smack
+cleanup_evm_hmac_transmute
diff --git a/tests/functions.sh b/tests/functions.sh
index ed06040b394..35e925cc963 100755
--- a/tests/functions.sh
+++ b/tests/functions.sh
@@ -434,6 +434,9 @@  _init_env() {
   mount -t proc proc /proc
   mount -t sysfs sysfs /sys
   mount -t securityfs securityfs /sys/kernel/security
+  if grep -q smack < /sys/kernel/security/lsm; then
+    mount -t smackfs smackfs /sys/fs/smackfs
+  fi
 
   if [ -n "$(command -v haveged 2> /dev/null)" ]; then
     $(command -v haveged) -w 1024 &> /dev/null
@@ -455,6 +458,9 @@  _cleanup_env() {
 
   $1
 
+  if grep -q smack < /sys/kernel/security/lsm; then
+    umount /sys/fs/smackfs
+  fi
   umount /sys/kernel/security
   umount /sys
   umount /proc