linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/7] evmtest: Regression testing Integrity Subsystem
@ 2018-08-14 18:05 David Jacobson
  2018-08-14 18:05 ` [PATCH 2/7] evmtest: test appraisal on policy loading with signature David Jacobson
                   ` (6 more replies)
  0 siblings, 7 replies; 9+ messages in thread
From: David Jacobson @ 2018-08-14 18:05 UTC (permalink / raw)
  To: linux-integrity, linux-kernel; +Cc: David Jacobson, Petr Vorel, David Jacobson

As the existing IMA/EVM features of the kernel mature, and new features are
being added, the number of kernel configuration options (Kconfig) and
methods for loading policies have been increasing. Rigorous testing of
the various IMA/EVM features is needed to ensure correct behavior and to
help avoid regressions.

Currently, only IMA-measurement can be tested (via LTP), a feature
introduced in Linux 2.6.30. Since then, IMA has grown to support
IMA-appraisal and IMA-audit. There are no LTP modules to test either of
these features.

This patchset introduces evmtest — a stand alone tool for regression
testing IMA. evmtest can be used to validate individual behaviors by
exercising execve, kexec, module load, and other LSM hooks.  evmtest
uses a combination of invalid signatures, invalid hashes, and unsigned
files to check that IMA-Appraisal catches all cases a running policy has
set. evmtest can also be used to validate that the kernel is properly
configured. For example, there are a number of Kconfig options that need
to be set, in addition to a local CA certificate being built-in or
memory reserved for embedding the certificate post-build.  evmtest
output is consistent. Consistent output allows evmtest to be plugged
into a testing framework/harness. Testing frameworks (such as xfstests)
require deterministic output. XFStests runs a test and compares its
output to a predefined value, created by running the test script under
conditions where it passes. evmtest provides output that can easily be
integrated with xfstests. All tests have a verbose mode (-v) that
outputs more information for debugging purposes.

New tests can be defined by placing them in the functions/ directory.
An "example_test.sh" script is provided for reference.

Example 1:
Successful example test output
$ evmtest runtest example_test -e /bin/bash
[*] Starting test: example_test
[*] TEST: PASSED

Example 1a: successful verbose example test output
$ evmtest runtest example_test -e /bin/bash -v
[*] Starting test: example_test
[*] Example file exists
[*] TEST: PASSED

Example 1b: failed verbose example test output
$ evmtest runtest example_test -e /bin/foo -v
[*] Starting test: example_test
[!] Example file does not exist
[!] TEST: FAILED

SYNOPSIS:
evmtest [runtest|help] test_name [test options]
options:
	-h,--help	Displays a help message
	-v,--verbose	Verbose logging for debugging

Signed-off-by: David Jacobson <davidj@linux.ibm.com>
---
 Makefile.am                         |   5 +-
 configure.ac                        |   1 +
 evmtest/INSTALL                     |  11 ++
 evmtest/Makefile.am                 |  23 ++++
 evmtest/README                      | 190 ++++++++++++++++++++++++++
 evmtest/evmtest                     |  74 ++++++++++
 evmtest/files/common.sh             |  49 +++++++
 evmtest/files/load_policy.sh        |  38 ++++++
 evmtest/functions/example_test.sh   |  75 ++++++++++
 evmtest/functions/r_env_validate.sh | 205 ++++++++++++++++++++++++++++
 10 files changed, 670 insertions(+), 1 deletion(-)
 create mode 100644 evmtest/INSTALL
 create mode 100644 evmtest/Makefile.am
 create mode 100644 evmtest/README
 create mode 100755 evmtest/evmtest
 create mode 100755 evmtest/files/common.sh
 create mode 100755 evmtest/files/load_policy.sh
 create mode 100755 evmtest/functions/example_test.sh
 create mode 100755 evmtest/functions/r_env_validate.sh

diff --git a/Makefile.am b/Makefile.am
index dba408d..0cb4111 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -36,4 +36,7 @@ rmman:
 
 doc: evmctl.1.html rmman evmctl.1
 
-.PHONY: $(tarname)
+evmtest:
+	$(MAKE) -C evmtest
+
+.PHONY: $(tarname) evmtest
diff --git a/configure.ac b/configure.ac
index a5b4288..59ec1d1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -52,6 +52,7 @@ EVMCTL_MANPAGE_DOCBOOK_XSL
 AC_CONFIG_FILES([Makefile
 		src/Makefile
 		packaging/ima-evm-utils.spec
+		evmtest/Makefile
 		])
 AC_OUTPUT
 
diff --git a/evmtest/INSTALL b/evmtest/INSTALL
new file mode 100644
index 0000000..699853e
--- /dev/null
+++ b/evmtest/INSTALL
@@ -0,0 +1,11 @@
+Installation Instructions
+-------------------------
+
+Basic Installation
+------------------
+
+From the root directory of ima-evm-utils, run the commands: `./autogen.sh`
+followed by `./configure`. `cd` to evmtest directory, execute `make`, and
+`sudo make install`.
+For details on how to use `evmtest` See the installed manpage or the README.
+There is an evmtest.html provided as well.
diff --git a/evmtest/Makefile.am b/evmtest/Makefile.am
new file mode 100644
index 0000000..388ead1
--- /dev/null
+++ b/evmtest/Makefile.am
@@ -0,0 +1,23 @@
+prefix=@prefix@
+datarootdir=@datarootdir@
+exec_prefix=@exec_prefix@
+bindir=@bindir@
+
+all: evmtest.1
+
+evmtest.1:
+	asciidoc -d manpage -b docbook -o evmtest.1.xsl README
+	asciidoc INSTALL
+	xsltproc --nonet -o $@ $(MANPAGE_DOCBOOK_XSL) evmtest.1.xsl
+	asciidoc -o evmtest.html README
+	rm -f evmtest.1.xsl
+install:
+	install -m 755 evmtest $(bindir)
+	install -d $(datarootdir)/evmtest/files/
+	install -d $(datarootdir)/evmtest/functions/
+	install -D $$(find ./files/ -not -type d)  $(datarootdir)/evmtest/files/
+	install -D ./functions/* $(datarootdir)/evmtest/functions/
+	cp evmtest.1 $(datarootdir)/man/man1
+	mandb -q
+
+.PHONY: install evmtest.1
diff --git a/evmtest/README b/evmtest/README
new file mode 100644
index 0000000..ac0c175
--- /dev/null
+++ b/evmtest/README
@@ -0,0 +1,190 @@
+evmtest(1)
+==========
+
+
+NAME
+----
+
+evmtest - IMA Regression Testing Utility
+
+SYNOPSIS
+--------
+evmtest <command> [OPTIONS]
+
+DESCRIPTION
+-----------
+
+evmtest can be used to verify various functionalities of IMA. It can also be
+used to check a kernel's configuration and validate compatibility with IMA.
+
+COMMANDS
+--------
+
+ runtest <test name> - Run a specific test
+ runall <configuration> - Run all tests
+
+OPTIONS
+-------
+ -v,--verbose			Verbose mode
+ -h,--help			Display help message
+ -i,--image			Kernel image
+ -k,--key			An IMA key
+ -c,--config			Kconfig for kernel build
+ -b,--kernel_build_directory    The path to a kernel build dir
+ --vm				Validate compatibility with a virtual machine
+
+
+
+
+BACKGROUND
+----------
+The Linux kernel needs to be configured properly with a key embedded into the
+kernel and loaded onto the `.builtin_trusted_keys` keyring at boot in order to
+run evmtest.
+
+=== 1. Confirming the kernel is properly configured with IMA enabled.
+
+A number of Kconfig options need to be configured to enable IMA and permit
+evmtest to validate IMA's functionality. (For directions on building a Linux
+kernel with IMA enabled, refer to the wiki[1].)
+To validate the kernel configuration based on its compatibility with IMA, use
+`evmtest runtest r_env_validate`. This can be called with the path to the kernel
+build as an argument, or the -r (--running) flag to validate the running
+kernel's configuration. To use the --running flag, IKCONFIG must be enabled as
+a Kconfig option, either builtin or as a module. An optional argument for this
+script is "--vm". This will check settings related to running the build in a
+virtual machine.
+
+
+=== 2. Creating a local CA Certificate
+
+IMA relies on two keyrings: `.builtin_trusted_keys` and `.ima.`
+`.builtin_trusted_keys` contains the certificate of the ephemeral key generated
+at build time to sign kernel modules. This section will describe the process of
+generating an "IMA local-CA key" to be placed on the same keyring as the
+kernel module signing key. The purpose of the IMA local CA key is to sign keys
+that will be placed on  the `.ima` keyring. These keys will then be used to sign
+files, kernel images, policies, and kernel modules.
+
+TIP: `man evmctl [GENERATE TRUSTED KEYS]` contains the exact commands needed to
+generate the IMA CA keypair, and IMA keypair used for signing files.
+
+Following these instructions should produce these three files:
+
+* `ima-local-ca.x509` - This will be placed on the .builtin_trusted_keys keyring
+
+* `ima-local-ca.priv` - This will be used in signing the IMA key
+
+* `ima-local-ca.pem`  - This will be placed on the  IMA Trusted keyring
+
+The process for creating an IMA key is described in the same section.
+
+Some distribution kernels reserve memory for inserting a certificate post-build.
+The directions in section 3a do not require rebuilding the kernel, just
+resigning it. For kernels which do not reserve memory for a certificate, see
+section 3b.
+
+
+=== 3a. Inserting a local CA certificate post build into the kernel.
+
+The first method for adding a key to the the .builtin_trusted_keys keyring is
+adding it to the kernel post-build. The following Kconfig options must be set.
+-------------
+CONFIG_SYSTEM_EXTRA_CERTIFICATE=y
+CONFIG_SYSTEM_TRUSTED_KEYRING=y
+CONFIG_SYSTEM_TRUSTED_KEYS=" "
+-------------
+Navigate to the build, and:
+
+`scripts/insert-sys-cert -b vmlinux -c <path to ima-local-ca.pem>`
+
+Delete both:
+
+* arch/x86/boot/compressed/vmlinux
+
+* arch/x86/boot/bzImage
+
+Remake, install, and sign the kernel.
+When prompted for a key size, allot 4096 bytes.
+
+Boot, the key loading should be visible through dmesg.
+
+
+===  3b. Kernel build method for including a local CA certificate.
+
+The second method for adding a key to the .builtin_trusted_keys keyring is
+to include the certificate during the build. Set these Kconfig options:
+-------------
+CONFIG_SYSTEM_TRUSTED_KEYRING=y
+CONFIG_SYSTEM_TRUSTED_KEYS="<path to ima-local-ca.pem>"
+-------------
+Continue the build as normal, sign, and boot. The key loading should be visible
+through dmesg.
+
+
+=== 4. Boot options for running IMA
+
+When running IMA, and specifically evmtest, it is important to have the
+correct boot options. Boot with: `module.sig_enforce=1`. This tells the kernel
+to prevent the loading of any unsigned modules.
+
+When running evmtest, the kernel should be booted with no policy, however,
+for debugging purposes it may be to useful to boot with:
+`ima_policy=tcb`
+This instructs IMA to load a policy which measures all program's exec'd, files
+mmap'd for exec by any user, and all files opened for read by root (fowner=0).
+More documentation is available in the IMA docs.
+evmtest appends the policy during runtime to test specific behavior. For this
+reason, the builtin policy specified on the boot command line should not be
+replaced with a custom policy during boot.
+
+
+=== 5. Loading a certificate on the IMA trusted keyring
+
+(For key creation, see documentation in man evmctl.)
+
+Depending on the distribution, dracut may be enabled to load keys on the IMA
+keyring. Place the IMA keys in: `/etc/ima/keys`
+Reboot, and assuming dracut is enabled to load IMA keys, the key loading should
+be visible in dmesg. The key should also be visible on the `.ima` keyring.
+Verify using keyctl (`keyctl show %keyring:.ima`) or by cat'ing `/proc/keys`
+
+
+=== FAQ
+For questions regarding IMA see the IMA wiki.
+
+=== 1. What additional settings are needed when testing in a virtual machine?
+
+When building for a virtual machine, use the following Kconfig options:
+------------------
+CONFIG_BLK_MQ_VIRTIO=y
+CONFIG_MEMORY_BALLOON=y
+CONFIG_VIRTIO_BLK=y
+CONFIG_SCSI_VIRTIO=y
+CONFIG_HW_RANDOM_VIRTIO=y
+CONFIG_VIRTIO=y
+CONFIG_VIRTIO_MENU=y
+CONFIG_VIRTIO_PCI=y
+CONFIG_VIRTIO_PCI_LEGACY=y
+CONFIG_VIRTIO_BALLOON=y
+-------------------------
+
+=== 2. How can an IMA key be loaded without rebuilding dracut?
+
+First, get the `.ima` keyring ID:
+-------------------------
+keyctl show %keyring:.ima
+-------------------------
+The ID is the number that appears before the keyring description.
+------------------------------------------------
+evmctl import <path to ima key> <.ima keyring ID>
+------------------------------------------------
+This process can be scripted and added to startup/login
+
+== Reference
+
+1. https://sourceforge.net/p/linux-ima/wiki/Home/
+
+Author
+------
+David Jacobson - davidj@linux.ibm.com
diff --git a/evmtest/evmtest b/evmtest/evmtest
new file mode 100755
index 0000000..dfe39a9
--- /dev/null
+++ b/evmtest/evmtest
@@ -0,0 +1,74 @@
+#!/bin/bash
+
+# Initial set up
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # Current directory
+# Useful for development
+
+
+# Check to see if we're installed or not
+evmtest=$(type -p evmtest) # Find in path
+if [[ -e "${evmtest}" ]]; then
+	_evmdir=$(dirname ${evmtest})
+	prefix=${_evmdir%%/bin}
+	EVMDIR=${prefix}/share/evmtest
+else
+	EVMDIR=$DIR
+fi
+
+source $EVMDIR/files/common.sh
+usage (){
+	echo "Usage: evmtest [[runtest] <test_name>] [options]"
+	echo ""
+	echo "Tests may be called directly by cd'ing to the evmtest directory:"
+	echo "$ cd $EVMDIR/functions"
+	echo "$ ./<test_name>.sh [arg1] .. [arg2]"
+	echo "Options:"
+	echo "	-h,--help	Displays this help message"
+	echo "Tests available: [R] = Must be run as root"
+	echo ""
+
+	for test in $EVMDIR/functions/*.sh; do
+		test_name=${test/.sh/}
+		test_name=${test_name#$EVMDIR/functions/}
+		if [[ $test_name == r_* ]]; then # r_ = root test
+			root_required="[R]"
+		else
+			root_required="[ ]"
+		fi
+		echo "$root_required $test_name"
+		root_required="" # Reset
+	done
+}
+
+runtest (){
+	local test_name=$1
+	shift # Drop test_name
+
+	if [[ ! -e $EVMDIR/functions/$test_name.sh ]]; then
+		echo "[!] Test: "$test_name" not found"
+		usage
+		exit 1
+	else
+		# Invoke test & pass args, let the test parse args itself
+		($EVMDIR/functions/$test_name.sh $@)
+	fi
+}
+
+if [[ "$#" == 0 ]]; then
+	usage
+	exit 1
+elif [[ "$1" == "-h" || $1 == "--help" || $1 == "help" ]]; then
+	usage
+	exit 0
+elif [[ "$1" == "runtest" ]]; then
+	if [[ -z $2 ]]; then
+		echo "[!] Provide a test"
+		exit
+	else
+		shift # Drop runtest
+		runtest $@
+		exit $?
+	fi
+else
+	usage
+fi
diff --git a/evmtest/files/common.sh b/evmtest/files/common.sh
new file mode 100755
index 0000000..0fc3fd7
--- /dev/null
+++ b/evmtest/files/common.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+
+# This is the EVMTest common.sh file
+# This is sourced at the top of a test file to provide common variables,
+# paths, and functions.
+
+function EVMTEST_forbid_root {
+	if [[ $UID == 0 ]]; then
+		echo "[!] This test should not be run as root"
+		exit 1
+	fi
+}
+
+function EVMTEST_require_root {
+	if [[ $UID != 0 ]]; then
+		echo "[!] This test must be run as root"
+		exit 1
+	fi
+}
+
+# verbose_output function - will only echo output if verbose is true
+# otherwise, output is muted
+function v_out {
+	[ "$VERBOSE" != "0" ] && { echo "[*] $@" ; return ; }
+}
+
+# Function to fail a test
+function fail {
+	if [[ $VERBOSE != 0 ]]; then
+		if [[ ! -z "$@" ]]; then
+			echo "[!] $@"
+		fi
+	fi
+	echo "[*] TEST: FAILED"
+	exit 1
+}
+
+function begin {
+	echo "[*] Starting test: $TEST"
+}
+
+function passed {
+	echo "[*] TEST: PASSED"
+	exit 0
+}
+# Everything exported should be prefixed with EVMTEST_
+EVMTEST_SECFS_EXISTS=`findmnt securityfs`
+EVMTEST_SECFS=`findmnt -f -n securityfs -o TARGET`
+EVMTEST_BOOT_OPTS=`cat /proc/cmdline`
diff --git a/evmtest/files/load_policy.sh b/evmtest/files/load_policy.sh
new file mode 100755
index 0000000..e22ea21
--- /dev/null
+++ b/evmtest/files/load_policy.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )/.."
+source $ROOT/files/common.sh
+EVMTEST_require_root
+
+#This script loads the IMA policy either by replacing the builtin
+#policies specified on the boot command line or by appending the policy
+#rules to the existing custom policy.
+
+# This program assumes that the running kernel has been compiled with
+# CONFIG_IMA_WRITE_POLICY=y
+# To validate this, run env_validate <path_to_kernel_build>
+# Otherwise, this will fail
+
+if [[ "$#" !=  1 || "$1" == "-h" ]]; then
+	echo "load_policy - load an IMA policy."
+	echo "Usage: load_pol <policy pathname>"
+	exit
+fi
+
+IMA_POLICY_LOCATION=$EVMTEST_SECFS/ima/policy
+EVMTEST_POLICY_LOCATION="$( cd "$( dirname "${BASH_SOURCE[0]}" )" \
+	>/dev/null && pwd )/policies"
+if [[ ! -e $EVMTEST_POLICY_LOCATION/$1 ]]; then
+	echo "[!] Policy: $1 not found, ensure it is in files/policies"
+	exit 1
+fi
+TO_LOAD=$EVMTEST_POLICY_LOCATION/$1
+echo $TO_LOAD > $IMA_POLICY_LOCATION
+if [[ $? != 0 ]]; then
+	echo "[!] Load failed - see dmesg"
+	exit 1
+else
+	echo "[*] Policy update completed"
+fi
+
+exit 0
diff --git a/evmtest/functions/example_test.sh b/evmtest/functions/example_test.sh
new file mode 100755
index 0000000..d0cd4bc
--- /dev/null
+++ b/evmtest/functions/example_test.sh
@@ -0,0 +1,75 @@
+#!/bin/bash
+# Author: David Jacobson <davidj@linux.ibm.com>
+TEST="example_test"
+
+ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )/.."
+source $ROOT/files/common.sh
+VERBOSE=0
+
+# This is an example test for documentation purposes.
+# This test describes the outline of evmtest test files.
+
+# Each file starts with a $TEST variable that gives the name of the test.
+# The next line should have the test author.
+# There are then the three bootstrap lines that follow
+# The first finds the current location of the script, so the needed files can
+# be found relative to it. The second line imports functions and variables
+# that are useful for writing tests. The third sets the output to silent.
+# After that, there is a 2-3 line description of the test.
+# Tests which require root should start with r_
+
+usage () {
+	echo ""
+	echo "example_test -e <example_file> [-vh]"
+	echo ""
+	echo "  This test is an example of how to structure an evmtest."
+	echo ""
+	echo "  -e,--example_file  Any file"
+	echo "  -v,--verbose    Verbose testing"
+	echo "  -h,--help       Displays this help message"
+	echo ""
+}
+
+# Define the usage
+TEMP=`getopt -o 'e:hv' -l 'example_file:,help,verbose' -n\
+	'example_test' -- "$@"`
+# letter followed by : means an argument is taken
+eval set -- "$TEMP"
+while true ; do
+	case "$1" in
+		-h|--help) usage; exit 0 ; shift;;
+		-e|--example_file) EXAMPLE_FILE=$2; shift 2;;
+		-v|--verbose)   VERBOSE=1; shift;;
+		--) shift; break;;
+		*) echo "[*] Unrecognized option $1"; exit 1 ;;
+	esac
+done
+
+# All arguments can be parsed like the above.
+# To require an argument, check that it has been defined. If it has not,
+# display usage and exit.
+if [[ -z $EXAMPLE_FILE ]]; then
+	usage
+	exit 1
+fi
+
+# Define how the test should be run:
+# The two options are: EVMTEST_forbid_root and EVMTEST_require_root
+EVMTEST_forbid_root
+
+# This function outputs that the test is starting:
+begin
+
+# Do whatever testing needs to be done
+if [[ -e $EXAMPLE_FILE ]]; then
+	# Output data for logging / debugging:
+	# [*] = Informative
+	# [!] = Attention Required
+	v_out "Example file exists"
+else
+	# Some condition failed, fail the test
+	fail "Example file does not exist"
+fi
+
+# If all has gone well until here - the test has passed
+passed
diff --git a/evmtest/functions/r_env_validate.sh b/evmtest/functions/r_env_validate.sh
new file mode 100755
index 0000000..19eb0f5
--- /dev/null
+++ b/evmtest/functions/r_env_validate.sh
@@ -0,0 +1,205 @@
+#!/bin/bash
+
+TEST="r_env_validate"
+ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )/.."
+source $ROOT/files/common.sh
+VM_VALIDATE=0
+VERBOSE=0
+CONFIG_FILE=""
+# This test serves to validate a kernel build for running with EVMTEST
+# optional argument for validating compatibility with a VM
+
+usage () {
+	echo ""
+	echo "env_validate [-c <config>]|-r] [-vh]"
+	echo ""
+	echo "	This test will validate that a kernel build is compatible with"
+	echo "	evmtest, and is configured correctly. It can be pointed toward"
+	echo "	a build directory where a .config file is provided, or it can"
+	echo "	attempt to pull the config out of a running kernel."
+	echo ""
+	echo "	-c,--config	Kernel config file"
+	echo "	-r,--running	Will attempt to pull running config"
+	echo "	-V,--vm		Will validate that build is vm compatible"
+	echo "	-v,--verbose	Verbose testing [Do not use in test harness]"
+	echo "	-h,--help	Displays this help message"
+	echo ""
+
+}
+
+TEMP=`getopt -o 'hc:rVv' -l 'help,config:,running,vm,verbose' -n\
+		 'env_validate' -- "$@"`
+eval set -- "$TEMP"
+
+while true ; do
+	case "$1" in
+	-h|--help) usage; exit 0 ;;
+	-c|--config) CONFIG=$2; shift 2;;
+	-r|--running) RUNNING=1; shift;;
+	-V|--vm) VM_VALIDATE=1; shift;;
+	-v|--verbose)	VERBOSE=1; shift;;
+	--) shift; break;;
+	*) echo "[*] Unrecognized option $1"; exit 1 ;;
+	esac
+done
+
+# One must be defined
+if [[ -z $CONFIG && -z $RUNNING ]]; then
+	usage
+	exit 1
+# But not both
+elif [[ ! -z $CONFIG && ! -z $RUNNING ]]; then
+	usage
+	exit 1
+fi
+
+INVALID_DEFINITION=() # Variables that aren't assigned correctly
+NOT_DEFINED=() # Variables that need to be defined
+
+function validate {
+	# Test that a variable is defined, and that it has a certain
+	# value
+
+	eval value='$'$1
+	if [[ -z "$value" ]]; then
+		NOT_DEFINED+=( "$1" )
+	elif [[ "$value" != "$2" ]]; then
+		INVALID_DEFINITION+=( "$1" )
+	fi
+}
+
+function validate_defined {
+	# Test that a variable is defined - don't care specifically what that
+	# value is
+
+	eval value='$'$1
+	if [[ -z $value ]]; then
+		NOT_DEFINED+=( "$1" )
+	fi
+}
+
+begin
+
+# If we want to pull the running config
+if [[ ! -z $RUNNING ]]; then
+	EVMTEST_require_root
+	# If we are pulling the running config - root will be required
+	v_out "Trying to find running kernel configuration..."
+	CONFIG_FILE=`mktemp`
+	if [[ -f /proc/config.gz ]]; then
+		v_out "Located kernel config in /proc/config.gz"
+		gunzip -c /proc/config.gz > $CONFIG_FILE
+		v_out "Placed config in $CONFIG_FILE"
+	else
+		v_out "Trying to load configs module to expose config"
+		if [[ -e "/lib/modules/`uname -r`/kernel/kernel/configs.ko" ]];
+		then
+			modprobe configs &>> /dev/null
+
+			gunzip -c /proc/config.gz > $CONFIG_FILE
+		else
+
+			v_out "Could not load configs - kernel may not have"
+			v_out "compiled with ability to get config. Rebuild"
+			v_out "with CONFIG_IKCONFIG enabled."
+			v_out "modprobe loaded configs - reattempting read"
+		fi
+	fi
+fi
+
+if [[ ! -z $CONFIG ]]; then
+	CONFIG_FILE=$CONFIG
+fi
+
+if [[ ! -f $CONFIG_FILE ]]; then
+	fail "Could not find config file"
+fi
+
+v_out "Parsing .config file..."
+# Not safe to source .config file - this is a safer way of reading in variables
+IFS=$'\n'
+for line in $(grep -v -E "#" $CONFIG_FILE); do
+	declare $line
+done
+
+
+# Set all desired values below here
+v_out "Validating keyring configuration..."
+# Keyring configuration
+validate "CONFIG_SYSTEM_EXTRA_CERTIFICATE" "y"
+validate_defined "CONFIG_SYSTEM_EXTRA_CERTIFICATE_SIZE"
+validate "CONFIG_SYSTEM_TRUSTED_KEYRING" "y"
+validate_defined "CONFIG_SYSTEM_TRUSTED_KEYS"
+
+v_out "Validating integrity configuration..."
+# Integrity configuration
+validate "CONFIG_INTEGRITY" "y"
+validate "CONFIG_INTEGRITY_SIGNATURE" "y"
+validate "CONFIG_INTEGRITY_ASYMMETRIC_KEYS" "y"
+validate "CONFIG_INTEGRITY_TRUSTED_KEYRING" "y"
+validate "CONFIG_INTEGRITY_AUDIT" "y"
+
+v_out "Validating IMA configuration..."
+# IMA configuration
+validate "CONFIG_IMA" "y"
+validate "CONFIG_IMA_MEASURE_PCR_IDX" "10"
+validate "CONFIG_IMA_LSM_RULES" "y"
+validate "CONFIG_IMA_SIG_TEMPLATE" "y"
+validate_defined "CONFIG_IMA_DEFAULT_TEMPLATE"
+validate_defined "CONFIG_IMA_DEFAULT_HASH_SHA256"
+validate_defined "CONFIG_IMA_DEFAULT_HASH"
+validate "CONFIG_IMA_WRITE_POLICY" "y"
+validate "CONFIG_IMA_READ_POLICY" "y"
+validate "CONFIG_IMA_APPRAISE" "y"
+validate "CONFIG_IMA_TRUSTED_KEYRING" "y"
+validate "CONFIG_IMA_LOAD_X509" "y"
+validate_defined "CONFIG_IMA_X509_PATH"
+
+v_out "Validating module signing configuration..."
+# Module signing configuration
+validate_defined "CONFIG_MODULE_SIG_KEY"
+validate "CONFIG_MODULE_SIG" "y"
+
+if [[ $VM_VALIDATE == 1 ]]; then
+	v_out "Validating VM configuration"
+
+	validate "CONFIG_BLK_MQ_VIRTIO" "y"
+	validate "CONFIG_MEMORY_BALLOON" "y"
+	validate "CONFIG_VIRTIO_BLK" "y"
+	validate "CONFIG_SCSI_VIRTIO" "y"
+	validate "CONFIG_HW_RANDOM_VIRTIO" "y"
+	validate "CONFIG_VIRTIO" "y"
+	validate "CONFIG_VIRTIO_MENU" "y"
+	validate "CONFIG_VIRTIO_PCI" "y"
+	validate "CONFIG_VIRTIO_PCI_LEGACY" "y"
+	validate "CONFIG_VIRTIO_BALLOON" "y"
+fi
+
+if [ ${#INVALID_DEFINITION[@]} != 0 ]; then
+	v_out "The following configuration variables have the wrong value"
+	for var in "${INVALID_DEFINITION[@]}"; do
+		eval value='$'$var
+		v_out "$var ($value)"
+	done
+fi
+
+if [ ${#NOT_DEFINED[@]} != 0 ]; then
+	v_out "The following configuration variables need to be defined"
+	for var in "${NOT_DEFINED[@]}"; do
+		v_out $var
+	done
+
+fi
+
+[[ "${#NOT_DEFINED[@]}" -eq 0 ]] && [[ "${#INVALID_DEFINITION[@]}" -eq 0 ]]
+code=$?
+
+if [[ ! -z $RUNNING ]]; then
+	rm $CONFIG_FILE
+fi
+
+if [[ $code == 0 ]]; then
+	passed
+else
+	fail
+fi
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/7] evmtest: test appraisal on policy loading with signature
  2018-08-14 18:05 [PATCH 1/7] evmtest: Regression testing Integrity Subsystem David Jacobson
@ 2018-08-14 18:05 ` David Jacobson
  2018-08-14 18:05 ` [PATCH 3/7] evmtest: test kernel module loading David Jacobson
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: David Jacobson @ 2018-08-14 18:05 UTC (permalink / raw)
  To: linux-integrity, linux-kernel; +Cc: David Jacobson, Petr Vorel, David Jacobson

IMA can be configured to require signatures on policies before loading
them. This test verifies that IMA correctly validates signatures, and
rejects policies that lack signatures or have been signed by an
unauthorized party (i.e. certificate is not on the appropriate keyring).

This test requires root privileges in order to write to securityfs
files.

Signed-off-by: David Jacobson <davidj@linux.ibm.com>
---
 evmtest/Makefile.am                          |  4 +-
 evmtest/files/Notes                          | 25 ++++++
 evmtest/files/bad_privkey_ima.pem            | 16 ++++
 evmtest/files/policies/signed_policy         |  2 +
 evmtest/files/policies/unknown_signed_policy |  1 +
 evmtest/files/policies/unsigned_policy       |  1 +
 evmtest/functions/r_policy_sig.sh            | 93 ++++++++++++++++++++
 7 files changed, 141 insertions(+), 1 deletion(-)
 create mode 100644 evmtest/files/Notes
 create mode 100644 evmtest/files/bad_privkey_ima.pem
 create mode 100644 evmtest/files/policies/signed_policy
 create mode 100644 evmtest/files/policies/unknown_signed_policy
 create mode 100644 evmtest/files/policies/unsigned_policy
 create mode 100755 evmtest/functions/r_policy_sig.sh

diff --git a/evmtest/Makefile.am b/evmtest/Makefile.am
index 388ead1..b537e78 100644
--- a/evmtest/Makefile.am
+++ b/evmtest/Makefile.am
@@ -14,9 +14,11 @@ evmtest.1:
 install:
 	install -m 755 evmtest $(bindir)
 	install -d $(datarootdir)/evmtest/files/
+	install -d $(datarootdir)/evmtest/files/policies
 	install -d $(datarootdir)/evmtest/functions/
-	install -D $$(find ./files/ -not -type d)  $(datarootdir)/evmtest/files/
+	install -D $$(find ./files/ -not -type d -not -path "./files/policies/*")  $(datarootdir)/evmtest/files/
 	install -D ./functions/* $(datarootdir)/evmtest/functions/
+	install -D ./files/policies/* $(datarootdir)/evmtest/files/policies/
 	cp evmtest.1 $(datarootdir)/man/man1
 	mandb -q
 
diff --git a/evmtest/files/Notes b/evmtest/files/Notes
new file mode 100644
index 0000000..6b75263
--- /dev/null
+++ b/evmtest/files/Notes
@@ -0,0 +1,25 @@
+This file contains a description of the contents of this directory.
+
+1. bad_privkey_ima.pem
+
+This file was generated such that its corresponding public key could be placed
+on the IMA Trusted Keyring, however, it has not. Therefore, any policy (or file)
+signed by this key cannot be verified, and is untrusted.
+
+2. basic_mod.ko
+
+This is a kernel module that logs (to dmesg) the syscall that was used to load
+it.
+
+3. common.sh
+
+This file contains useful functions and variables for evmtest scripts.
+
+4. load_policy.sh
+
+This is a script to load policies. The first time this is called, it will
+replace the existing policy. Subsequent calls will append the running policy.
+
+5. policies/
+
+This is a directory that contains IMA policies with self explanatory names.
diff --git a/evmtest/files/bad_privkey_ima.pem b/evmtest/files/bad_privkey_ima.pem
new file mode 100644
index 0000000..dcc0e24
--- /dev/null
+++ b/evmtest/files/bad_privkey_ima.pem
@@ -0,0 +1,16 @@
+-----BEGIN PRIVATE KEY-----
+MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMOnki6OKMHExpH1
+IWgUlPWWSbsDpW1lpqXMj0/ZWo9xU5W2xZC53TVArUGOImQ5PcMNkw1VcHhKbFKO
+jYT0gEE0Sv+VbePiEnhUheFOWUxNNFE3DVQaOpBN0OzsUCSGX9RKIIwkIAwJkvWA
+MHzR4ZPQGGM9hMJKhEvlTG4PP96LAgMBAAECgYBKVKVCrptpUhqmZNx2MCuPSbNl
+KzNz5kRzhM2FZmvzRvicTj2siBA0JQgteZQzQ1PlgIi3bhg2ev/ANYwqUMFQWZv9
+zm5d4P7Zsdyle15MDTSrQIaroeb1nbfNvaB0L4D4Inv0p6ksyIFp7TR5MLVenC5k
+bxfESVWVPDseiAFKUQJBAPQ/x3LmnT0RiMeX6quCGAON7DGpV5KFwL97luWO6vH+
+qZ2W1/J0UxTbruv7rA+tj3ZXpdNOxfmq+JStY0jrJV0CQQDNEUqomnA183rX0dv8
+MWyOPmX0Z9SMSTRvflNRW85Bzbosq68uLTq3qOBj+td9zUlopsLpJlfF0Vc+moff
+uq0HAkEAi/Sz47oTZXfTqZL6TBZ6jibXrck8PeBYhyBZYebX55ymMn/J88sGBFCx
+VdVbTYyFRSmKAqADv0FhuUf1OUZMnQJAOayjUsgcxw+zfP+I32UHIvppslOBc/Mi
+zDi7Niab2+YAdo/StSoDWaQld/kUok0aWFSOfQRLq1c1MmZD0KiwAQJANY0LopqG
+pxACc4/QawxtBoV1a8j5Zui8LZPRtKwjkA30Nq8fOufzMuBeJIlLap45uD1xC7St
+bsPWG5+uz18e5w==
+-----END PRIVATE KEY-----
diff --git a/evmtest/files/policies/signed_policy b/evmtest/files/policies/signed_policy
new file mode 100644
index 0000000..87828f0
--- /dev/null
+++ b/evmtest/files/policies/signed_policy
@@ -0,0 +1,2 @@
+measure func=POLICY_CHECK
+appraise func=POLICY_CHECK appraise_type=imasig
diff --git a/evmtest/files/policies/unknown_signed_policy b/evmtest/files/policies/unknown_signed_policy
new file mode 100644
index 0000000..1f8f8f4
--- /dev/null
+++ b/evmtest/files/policies/unknown_signed_policy
@@ -0,0 +1 @@
+audit func=POLICY_CHECK
diff --git a/evmtest/files/policies/unsigned_policy b/evmtest/files/policies/unsigned_policy
new file mode 100644
index 0000000..1f8f8f4
--- /dev/null
+++ b/evmtest/files/policies/unsigned_policy
@@ -0,0 +1 @@
+audit func=POLICY_CHECK
diff --git a/evmtest/functions/r_policy_sig.sh b/evmtest/functions/r_policy_sig.sh
new file mode 100755
index 0000000..7462c0a
--- /dev/null
+++ b/evmtest/functions/r_policy_sig.sh
@@ -0,0 +1,93 @@
+#!/bin/bash
+TEST="r_policy_sig"
+# Author: David Jacobson <davidj@linux.ibm.com>
+
+ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )/.."
+source $ROOT/files/common.sh
+
+VERBOSE=0
+POLICY_LOAD=$ROOT/files/load_policy.sh
+# This test validates that IMA measures and appraises policies.
+usage() {
+	echo ""
+	echo "policy_sig -k <key> [-vh]"
+	echo ""
+	echo "  This test must be run as root"
+	echo ""
+	echo "  This test verifies that IMA prevents the loading of unsigned"
+	echo "	policies"
+	echo ""
+	echo "  -k,--key    	The key for the certificate on the IMA keyring"
+	echo "  -h,--help       Display this help message"
+	echo "  -v,--verbose    Verbose logging"
+}
+
+TEMP=`getopt -o 'k:hv' -l 'key:,help,verbose' -n 'r_policy_sig' -- "$@"`
+eval set -- "$TEMP"
+
+while true ; do
+	case "$1" in
+	-h|--help) usage; exit 0; shift;;
+	-k|--key) IMA_KEY=$2; shift 2;;
+	-v|--verbose) VERBOSE=1; shift;;
+	--) shift; break;;
+	*) echo "[*] Unrecognized option $1"; exit 1 ;;
+	esac
+done
+
+if [[ -z $IMA_KEY ]]; then
+	usage
+	exit 1
+fi
+
+EVMTEST_require_root
+
+begin
+v_out "Attempting to read current policy..."
+cat $EVMTEST_SECFS/ima/policy &>> /dev/null # Don't need to output it
+
+if [[ $? != 0 ]]; then
+	fail "Could not read running policy - did you run env_validate?"
+fi
+v_out "Policy is readable"
+
+v_out "Signing policy with provided key..."
+evmctl ima_sign -f $ROOT/files/policies/signed_policy -k $IMA_KEY
+if [[ $? != 0 ]]; then
+	fail "Failed to sign policy - check key file"
+fi
+
+v_out "Loading policy..."
+$POLICY_LOAD signed_policy &>> /dev/null
+if [[ $? != 0 ]]; then
+	fail "Failed to write policy - did you run env_validate?"
+fi
+v_out "Loaded"
+
+v_out "Attempting to load unsigned policy..."
+$POLICY_LOAD unsigned_policy &>> /dev/null
+if [[ $? != 1 ]]; then
+	fail "Failed to reject unsigned policy"
+fi
+
+v_out "IMA Blocked unsigned policy"
+
+v_out "Signing policy with invalid key..."
+evmctl ima_sign -f $ROOT/files/policies/unknown_signed_policy \
+	-k $ROOT/files/bad_privkey_ima.pem &>> /dev/null
+v_out "Attempting to load policy signed by invalid key..."
+$POLICY_LOAD unknown_signed_policy &>> /dev/null
+
+if [[ $? != 1 ]]; then
+	fail "Failed to reject policy signed by unknown key"
+fi
+
+v_out "IMA blocked policy signed by unknown key"
+
+v_out "Removing security.ima attribute from policies..."
+setfattr -x security.ima $ROOT/files/policies/unsigned_policy &>> /dev/null
+setfattr -x security.ima $ROOT/files/policies/unknown_signed_policy \
+	&>> /dev/null
+v_out "Done"
+
+passed
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 3/7] evmtest: test kernel module loading
  2018-08-14 18:05 [PATCH 1/7] evmtest: Regression testing Integrity Subsystem David Jacobson
  2018-08-14 18:05 ` [PATCH 2/7] evmtest: test appraisal on policy loading with signature David Jacobson
@ 2018-08-14 18:05 ` David Jacobson
  2018-08-14 18:05 ` [PATCH 4/7] evmtest: test kexec signature policy David Jacobson
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: David Jacobson @ 2018-08-14 18:05 UTC (permalink / raw)
  To: linux-integrity, linux-kernel; +Cc: David Jacobson, Petr Vorel, David Jacobson

The Linux kernel supports two methods of loading kernel modules -
init_module and finit_module syscalls. This test verifies loading kernel
modules with both syscalls, first without an IMA policy, and
subsequently with an IMA policy (that restricts module loading to signed
modules).

This test requires the kernel to be configured with the
"CONFIG_MODULE_SIG" option, but not with "CONFIG_MODULE_SIG_FORCE".  For
this reason, the test requires that  "module.sig_enforce=1" is supplied
as a boot option to the kernel.

Signed-off-by: David Jacobson <davidj@linux.ibm.com>

Changelog:
---
 evmtest/Makefile.am                         |  11 +-
 evmtest/files/policies/kernel_module_policy |   2 +
 evmtest/functions/r_kmod_sig.sh             | 225 ++++++++++++++++++++
 evmtest/src/Makefile                        |   5 +
 evmtest/src/basic_mod.c                     |  36 ++++
 evmtest/src/kern_mod_loader.c               | 131 ++++++++++++
 6 files changed, 407 insertions(+), 3 deletions(-)
 create mode 100644 evmtest/files/policies/kernel_module_policy
 create mode 100755 evmtest/functions/r_kmod_sig.sh
 create mode 100644 evmtest/src/Makefile
 create mode 100644 evmtest/src/basic_mod.c
 create mode 100644 evmtest/src/kern_mod_loader.c

diff --git a/evmtest/Makefile.am b/evmtest/Makefile.am
index b537e78..6be0596 100644
--- a/evmtest/Makefile.am
+++ b/evmtest/Makefile.am
@@ -3,7 +3,7 @@ datarootdir=@datarootdir@
 exec_prefix=@exec_prefix@
 bindir=@bindir@
 
-all: evmtest.1
+all: src evmtest.1
 
 evmtest.1:
 	asciidoc -d manpage -b docbook -o evmtest.1.xsl README
@@ -11,7 +11,10 @@ evmtest.1:
 	xsltproc --nonet -o $@ $(MANPAGE_DOCBOOK_XSL) evmtest.1.xsl
 	asciidoc -o evmtest.html README
 	rm -f evmtest.1.xsl
-install:
+src:
+	cd src && make
+
+install: src
 	install -m 755 evmtest $(bindir)
 	install -d $(datarootdir)/evmtest/files/
 	install -d $(datarootdir)/evmtest/files/policies
@@ -19,7 +22,9 @@ install:
 	install -D $$(find ./files/ -not -type d -not -path "./files/policies/*")  $(datarootdir)/evmtest/files/
 	install -D ./functions/* $(datarootdir)/evmtest/functions/
 	install -D ./files/policies/* $(datarootdir)/evmtest/files/policies/
+	cp ./src/basic_mod.ko $(datarootdir)/evmtest/files/
+	cp ./src/kern_mod_loader $(datarootdir)/evmtest/files
 	cp evmtest.1 $(datarootdir)/man/man1
 	mandb -q
 
-.PHONY: install evmtest.1
+.PHONY: src install evmtest.1
diff --git a/evmtest/files/policies/kernel_module_policy b/evmtest/files/policies/kernel_module_policy
new file mode 100644
index 0000000..8096e18
--- /dev/null
+++ b/evmtest/files/policies/kernel_module_policy
@@ -0,0 +1,2 @@
+measure func=MODULE_CHECK
+appraise func=MODULE_CHECK appraise_type=imasig
diff --git a/evmtest/functions/r_kmod_sig.sh b/evmtest/functions/r_kmod_sig.sh
new file mode 100755
index 0000000..43ab9df
--- /dev/null
+++ b/evmtest/functions/r_kmod_sig.sh
@@ -0,0 +1,225 @@
+#!/bin/bash
+# Author: David Jacobson <davidj@linux.ibm.com>
+TEST="r_kmod_sig"
+BUILD_DIR=""
+ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )/.."
+source $ROOT/files/common.sh
+
+VERBOSE=0
+# This test validates that IMA prevents the loading of unsigned
+# kernel modules
+# There is no way to tell how the Kernel was compiled, so the boot command:
+# module.sig_enable=1 is required for this test. This is equivalent to
+# compiling with CONFIG_MODULE_SIG_FORCE
+
+SIG_ENFORCE_CMD="module.sig_enforce=1"
+POLICY_LOAD=$ROOT/files/load_policy.sh
+
+usage(){
+	echo ""
+	echo "kmod_sig [-b kernel_build_directory] -k <ima_key> [-v]"
+	echo "	This test verifies that IMA prevents the loading of an"
+	echo "	unsigned kernel module with a policy appraising MODULE_CHECK"
+	echo ""
+	echo "	This test must be run as root"
+	echo ""
+	echo "	-b,--kernel_build_directory	The path to a kernel build dir"
+	echo "	-k,--key			IMA key"
+	echo "	-v,--verbose			Verbose logging"
+	echo "	-h,--help			Display this help message"
+}
+
+TEMP=`getopt -o 'b:k:hv' -l 'kernel_build_directory:,key:,help,verbose'\
+	-n 'r_kmod_sig' -- "$@"`
+eval set -- "$TEMP"
+
+while true ; do
+	case "$1" in
+	-h|--help) usage; exit 0 ;;
+	-b|--kernel_build_directory) BUILD_DIR=$2; shift 2;;
+	-k|--key) IMA_KEY=$2; shift 2;;
+	-v|--verbose)	VERBOSE=1; shift;;
+	--) shift; break;;
+	*) echo "[*] Unrecognized option $1"; exit 1 ;;
+	esac
+done
+
+if [[ -z $IMA_KEY ]]; then
+	echo "[!] Please provide an IMA key."
+	usage
+	exit 1
+fi
+
+if [[ -z $BUILD_DIR ]]; then
+	v_out "No build directory provided, searching..."
+	BUILD_DIR="/lib/modules/`uname -r`/build"
+	if [[ ! -e $BUILD_DIR ]]; then
+		echo "[!] Could not find build tree. Please specify with -b"
+		exit 1
+	else
+		v_out "Found - using: `readlink -f $BUILD_DIR`"
+	fi
+fi
+
+EVMTEST_require_root
+
+begin
+
+if [[ ! -d "$BUILD_DIR" ]]; then
+	fail "Could not find kernel build path"
+fi
+
+if [[ ! -e "$IMA_KEY" ]]; then
+	fail "Could not find IMA key"
+fi
+
+v_out "Unloading test module if loaded..."
+rmmod basic_mod &>> /dev/null
+
+mod_load=$ROOT/files/kern_mod_loader
+
+if [[ ! $EVMTEST_BOOT_OPTS = *$SIG_ENFORCE_CMD* ]]; then
+	v_out "Test requires running with kernel command: $SIG_ENFORCE_CMD"
+	fail "Booted with options: $EVMTEST_BOOT_OPTS"
+else
+	v_out "Booted with correct configuration..."
+fi
+
+# This test may have been run before - remove the security attribute so we can
+# test again
+v_out "Removing security attribute if it exists..."
+setfattr -x security.ima $ROOT/files/basic_mod.ko &>> /dev/null
+
+v_out "Removing appended signature if present..."
+strip --strip-debug $ROOT/files/basic_mod.ko
+
+v_out "Signing policy before loading..."
+evmctl ima_sign -f $ROOT/files/policies/kernel_module_policy -k $IMA_KEY
+
+if [[ $? != 0 ]]; then
+	fail "failed to sign policy - check key"
+fi
+
+v_out "Setting policy to prevent loading unsigned kernel modules..."
+$POLICY_LOAD kernel_module_policy &>> /dev/null
+
+if [[ $? != 0 ]]; then
+	fail "Could not write policy - is the supplied key correct?"
+fi
+
+# First attempt to find hash algo
+hash_alg=`grep CONFIG_MODULE_SIG_HASH $BUILD_DIR/.config|awk -F "=" \
+	'{print $2}'| tr -d "\""`
+# Need to read the config a little more to determine how to sign module...
+if [[ -z $hash_alg ]]; then
+	v_out "Could not determine hash algorithm used on module signing"
+	v_out "Checking for other Kconfig variables..."
+	hash_opts=`grep CONFIG_MODULE_SIG $BUILD_DIR/.config`
+
+	# All possible hashes from:
+	# https://www.kernel.org/doc/html/v4.17/admin-guide/module-signing.html
+	case $hash_opts in
+	*"CONFIG_MODULE_SIG_SHA1=y"*)
+		hash_alg="sha1"
+		;;
+	*"CONFIG_MODULE_SIG_SHA224"*)
+		hash_alg="sha224"
+		;;
+	*"CONFIG_MODULE_SIG_SHA256"*)
+		hash_alg="sha256"
+		;;
+	*"CONFIG_MODULE_SIG_SHA384"*)
+		hash_alg="sha384"
+		;;
+	*"CONFIG_MODULE_SIG_SHA512"*)
+		hash_alg="sha512"
+		;;
+	*)
+		fail "Could not determine hash"
+		;;
+	esac
+fi
+
+v_out "Using: $hash_alg"
+
+v_out "Looking for signing key..."
+if [[ ! -e $BUILD_DIR/certs/signing_key.pem ]]; then
+	v_out "signing_key.pem not in certs/ finding location via Kconfig";
+	key_location=`grep MODULE_SIG_KEY $BUILD_DIR/.config`
+	if [[ -z $key_location ]]; then
+		fail "Could not determine key location"
+	fi
+	# Parse from .config
+	key_location=${key_location/CONFIG_MODULE_SIG_KEY=/}
+	# Drop quotes
+	key_location=${key_location//\"}
+	# Drop .pem
+	key_location=${key_location/.pem}
+	sig_key=$key_location
+
+else
+	sig_key=$BUILD_DIR/certs/signing_key
+fi
+
+v_out "Found key: $sig_key"
+
+v_out "Signing module [appended signature]..."
+
+$BUILD_DIR/scripts/sign-file $hash_alg $sig_key.pem \
+	$sig_key.x509 $ROOT/files/basic_mod.ko
+
+if [[ $? != 0 ]]; then
+	fail "Signing failed - please ensure sign-file is in scripts/"
+fi
+
+v_out "Attempting to load signed module with init_mod [should pass] ..."
+$mod_load $ROOT/files/basic_mod.ko init_module &>> /dev/null
+if [[ $? != 0 ]]; then
+	fail "Failed to load using init_module - check key used to sign module"
+fi
+v_out "Module loaded..."
+
+v_out "Unloading module..."
+rmmod basic_mod &>> /dev/null
+
+v_out "Attempting to load signed module with finit_mod [should fail]..."
+$mod_load $ROOT/files/basic_mod.ko finit_module &>> /dev/null
+# Several of these are piped to /dev/null - the text output doesn't matter here
+# the return code is kept
+if [[ $? == 0 ]]; then
+	fail
+fi
+v_out "Module loading blocked..."
+
+v_out "Signing file [extended file attribute]..."
+evmctl ima_sign -k $IMA_KEY -f $ROOT/files/basic_mod.ko
+
+if [[ $? != 0 ]]; then
+	fail "Error signing module - check keys"
+fi
+
+v_out "Attempting to load module with finit_mod [should pass]..."
+$mod_load $ROOT/files/basic_mod.ko finit_module &>> /dev/null
+
+v_out "Removing signature(s)..."
+
+setfattr -x security.ima $ROOT/files/basic_mod.ko &>> /dev/null
+strip --strip-debug $ROOT/files/basic_mod.ko
+
+v_out "Signing with unknown key..."
+evmctl ima_sign -f $ROOT/files/basic_mod.ko &>> /dev/null
+$mod_load $ROOT/files/basic_mod.ko finit_module &>> /dev/null
+if [[ $? == 0 ]]; then
+	fail "Allowed module to load with wrong signature"
+fi
+
+v_out "Prevented loading with finit_module"
+
+$mod_load $ROOT/files/basic_mod.ko init_module &>> /dev/null
+
+if [[ $? == 0 ]]; then
+	fail "Allowed module to load with wrong signature"
+fi
+v_out "Prevented loading with init_module"
+
+passed
diff --git a/evmtest/src/Makefile b/evmtest/src/Makefile
new file mode 100644
index 0000000..4c3f33d
--- /dev/null
+++ b/evmtest/src/Makefile
@@ -0,0 +1,5 @@
+obj-m += basic_mod.o
+
+all:
+	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
+	$(CC) kern_mod_loader.c -o kern_mod_loader
diff --git a/evmtest/src/basic_mod.c b/evmtest/src/basic_mod.c
new file mode 100644
index 0000000..7c49c74
--- /dev/null
+++ b/evmtest/src/basic_mod.c
@@ -0,0 +1,36 @@
+/*
+ * Basic kernel module
+ *
+ * Copyright (C) 2018 IBM
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+/*
+ * evmtest_load_type is a flag passed when loading the module, it indicates
+ * which syscall is being used. It should be either init_module or finit_module
+ * When loaded, evmtest_load_type is outputted to the kernel's message buffer
+ */
+static char *evmtest_load_type;
+
+module_param(evmtest_load_type, charp, 000);
+MODULE_PARM_DESC(evmtest_load_type, "Which syscall is loading this module.");
+
+static int __init basic_module_init(void)
+{
+	printk(KERN_INFO "EVMTEST: LOADED MODULE (%s)\n", evmtest_load_type);
+	return 0;
+}
+
+static void __exit basic_module_cleanup(void)
+{
+	printk(KERN_INFO "EVMTEST: UNLOADED MODULE (%s)\n", evmtest_load_type);
+}
+
+module_init(basic_module_init);
+module_exit(basic_module_cleanup);
+
+MODULE_AUTHOR("David Jacobson");
+MODULE_DESCRIPTION("Kernel module for testing IMA signatures");
+MODULE_LICENSE("GPL");
diff --git a/evmtest/src/kern_mod_loader.c b/evmtest/src/kern_mod_loader.c
new file mode 100644
index 0000000..fdb9ab1
--- /dev/null
+++ b/evmtest/src/kern_mod_loader.c
@@ -0,0 +1,131 @@
+/*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+/*
+ * finit_module - load a kernel module using the finit_module syscall
+ * @fd: File Descriptor of the kernel module to be loaded
+ */
+int finit_module(int fd)
+{
+	return syscall(__NR_finit_module, fd,
+			"evmtest_load_type=finit_module", 0);
+}
+
+/*
+ * init_module - load a kernel module using the init_module syscall
+ * @fd: File Descriptor of the kernel module to be loaded
+ *
+ * Adapted explanation from: https://github.com/cirosantilli/
+ * linux-kernel-module-cheat/blob/
+ * 91583552ba2c2d547c8577ac888ab9f851642b25/kernel_module/user/
+ * myinsmod.c
+ */
+int init_module(int fd)
+{
+
+	struct stat st;
+
+	int mod = fstat(fd, &st);
+
+	if (mod != 0) {
+		printf("[!] Failed to load module\n");
+		return -1;
+	}
+
+	size_t im_size = st.st_size;
+	void *im = malloc(im_size);
+
+	if (im == NULL) {
+		printf("[!] Failed to load module - MALLOC NULL\n");
+		return -1;
+	}
+	read(fd, im, im_size);
+	close(fd);
+
+	int loaded = syscall(__NR_init_module, im, im_size,
+			     "evmtest_load_type=init_module");
+	free(im);
+
+	return loaded;
+}
+
+/*
+ * display_help - print out a help message to the user
+ */
+void display_help(void)
+{
+	printf("kern_mod_loader: Usage\n");
+	printf("kern_mod_loader <path> <finit_module|init_module>\n");
+}
+
+int main(int argc, char **argv)
+{
+
+	int ret;
+	int uid = getuid();
+
+	if (argc != 3) {
+		printf("[*] Please supply a path and load type\n");
+		printf("kern_mod_loader <path> <init_module|finit_module>\n");
+		return -1;
+	}
+
+	/* Root is required to try and load kernel modules */
+	if (uid != 0) {
+		printf("[!] kern_mod_loader must be run as root\n");
+		return -1;
+	}
+
+	int fd = open(argv[1], O_RDONLY);
+	if (fd == -1) {
+		printf("[!] Could not open file for read.\n");
+		return -1;
+	}
+
+	if (strncmp(argv[2], "finit_module", 12) == 0) {
+		printf("[*] Using finit_module syscall...\n");
+		ret = finit_module(fd);
+
+	} else if (strncmp(argv[2], "init_module", 11) == 0) {
+		printf("[*] Using init_module syscall...\n");
+		ret = init_module(fd);
+	} else {
+		printf("[!] Please use a valid syscall...\n");
+		return -1;
+	}
+
+	switch (ret) {
+	case 0:
+		printf("[*] Module loaded successfully.\n");
+		return ret;
+	case -1:
+		printf("[!] Could not load module\n");
+		printf("[!] This may be intended behavior\n");
+		return ret;
+	default:
+		printf("[!] Unknown error\n.");
+		return ret;
+	}
+}
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 4/7] evmtest: test kexec signature policy
  2018-08-14 18:05 [PATCH 1/7] evmtest: Regression testing Integrity Subsystem David Jacobson
  2018-08-14 18:05 ` [PATCH 2/7] evmtest: test appraisal on policy loading with signature David Jacobson
  2018-08-14 18:05 ` [PATCH 3/7] evmtest: test kernel module loading David Jacobson
@ 2018-08-14 18:05 ` David Jacobson
  2018-08-14 18:05 ` [PATCH 5/7] evmtest: validate boot record David Jacobson
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: David Jacobson @ 2018-08-14 18:05 UTC (permalink / raw)
  To: linux-integrity, linux-kernel; +Cc: David Jacobson, Petr Vorel, David Jacobson

With secure boot enabled, the bootloader verifies the kernel image's
signature before transferring control to it. With Linux as the
bootloader running with secure boot enabled, kexec needs to verify the
kernel image's signature.

This patch defined a new test named "kexec_sig", which first attempts to
kexec an unsigned kernel image with an IMA policy that requires
signatures on any kernel image. Then, the test attempts to kexec the
signed kernel image, which should succeed.

Signed-off-by: David Jacobson <davidj@linux.ibm.com>
---
 evmtest/files/policies/kexec_policy |   3 +
 evmtest/functions/r_kexec_sig.sh    | 156 ++++++++++++++++++++++++++++
 2 files changed, 159 insertions(+)
 create mode 100644 evmtest/files/policies/kexec_policy
 create mode 100755 evmtest/functions/r_kexec_sig.sh

diff --git a/evmtest/files/policies/kexec_policy b/evmtest/files/policies/kexec_policy
new file mode 100644
index 0000000..dc00fa7
--- /dev/null
+++ b/evmtest/files/policies/kexec_policy
@@ -0,0 +1,3 @@
+appraise func=KEXEC_KERNEL_CHECK appraise_type=imasig
+measure func=KEXEC_KERNEL_CHECK
+audit func=KEXEC_KERNEL_CHECK
diff --git a/evmtest/functions/r_kexec_sig.sh b/evmtest/functions/r_kexec_sig.sh
new file mode 100755
index 0000000..e1295b9
--- /dev/null
+++ b/evmtest/functions/r_kexec_sig.sh
@@ -0,0 +1,156 @@
+#!/bin/bash
+# Author: David Jacobson <davidj@linux.ibm.com>
+TEST="r_kexec_sig"
+ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )/.."
+source $ROOT/files/common.sh
+VERBOSE=0
+POLICY_LOAD=$ROOT/files/load_policy.sh
+
+# This test validates that IMA measures and appraises signatures on kernel
+# images when trying to kexec, if the current policy requires that.
+usage() {
+	echo ""
+	echo "kexec_sig -k <key> [-i <kernel_image]"
+	echo "	[-vh]"
+	echo ""
+	echo "	This test must be run as root"
+	echo "	Note: kexec may require PECOFF signature"
+	echo ""
+	echo "	This test will check that IMA prevents kexec-ing to "
+	echo "	unsigned kernel image."
+	echo ""
+	echo "	-k,--key	The key for the certificate on the IMA keyring"
+	echo "	-i,--image	An unsigned kernel image"
+	echo "	-h,--help	Display this help message"
+	echo "	-v,--verbose	Verbose logging"
+}
+
+TEMP=`getopt -o 'k:i:hv' -l 'key:,image:,help,verbose' -n 'r_kexec_sig' -- "$@"`
+eval set -- "$TEMP"
+
+while true ; do
+	case "$1" in
+	-h|--help) usage; exit 0 ; shift;;
+	-i|--image) KERNEL_IMAGE=$2; shift 2;;
+	-k|--key) IMA_KEY=$2; shift 2;;
+	-v|--verbose) VERBOSE=1; shift;;
+	--) shift; break;;
+	*) echo "[*] Unrecognized option $1"; exit 1;;
+	esac
+done
+
+if [[ -z $IMA_KEY ]]; then
+	usage
+	exit 1
+else
+	if [[ ! -e $IMA_KEY ]]; then
+		fail "Please provide valid keys"
+	fi
+fi
+
+# If the user doesn't provide a kernel image for kexec, get the current
+if [[ -z $KERNEL_IMAGE ]]; then
+	v_out "No kernel provided, looking for running kernel"
+	RUNNING_KERNEL=`uname -r`
+	if [[ -e /boot/vmlinuz-$RUNNING_KERNEL ]]; then
+		KERNEL_IMAGE=/boot/vmlinuz-$RUNNING_KERNEL
+		TEMP_LOCATION=`mktemp`
+		v_out "Found kernel in: $KERNEL_IMAGE"
+		v_out "Copying kernel to $TEMP_LOCATION"
+		cp $KERNEL_IMAGE $TEMP_LOCATION
+		KERNEL_IMAGE=$TEMP_LOCATION
+	fi
+else
+	# If a kernel has been provided, ensure it exists
+	if [[ ! -e $KERNEL_IMAGE ]]; then
+		fail "Kernel image not found..."
+	else
+		v_out "Valid Kernel provided, continuing"
+	fi
+fi
+
+EVMTEST_require_root
+
+begin
+
+v_out "Writing file hash on kernel image"
+evmctl ima_hash -a sha256 -f $KERNEL_IMAGE
+
+
+v_out "Attempting to sign policy..."
+evmctl ima_sign -f $ROOT/files/policies/kexec_policy -k $IMA_KEY
+
+v_out "Loading kexec policy..."
+$POLICY_LOAD kexec_policy &>> /dev/null
+
+if [[ $? != 0 ]]; then
+	fail "Could not update policy - verify keys"
+fi
+
+v_out "Testing kexec (using kexec_file_load) on unsigned image..."
+# -s uses the kexec_file_load syscall
+kexec -s -l $KERNEL_IMAGE &>> /dev/null
+loaded_unsigned=$?
+if [[ $loaded_unsigned != 0 ]]; then # Permission denied (IMA)
+	v_out "Correctly prevented kexec of an unsigned image"
+else
+	kexec -s -u
+	fail "kexec loaded instead of rejecting. Unloading and exiting."
+fi
+
+v_out "Testing kexec (using kexec_load) on unsigned image..."
+kexec -l $KERNEL_IMAGE &>> /dev/null
+if [[ $? == 0 ]]; then
+	kexec -u
+	fail "Kexec loaded unsigned image - unloading"
+else
+	v_out "Correctly prevented kexec of an unsigned image"
+fi
+
+# On some systems this prevents resigning the kernel image
+
+#v_out "Signing image with invalid key..."
+#evmctl ima_sign -f $KERNEL_IMAGE -k $ROOT/files/bad_privkey_ima.pem
+#kexec -s -l $KERNEL_IMAGE &>> /dev/null
+#loaded_bad_signature=$?
+
+#if [[ $loaded_bad_signature == 0 ]]; then
+#	kexec -u
+#	fail "Kernel image signed by invalid party was allowed to load.\
+#		Unloaded"
+#fi
+
+#v_out "Correctly prevented loading of kernel signed by unknown key"
+
+v_out "Signing kernel image with provided key..."
+evmctl ima_sign -f $KERNEL_IMAGE -k $IMA_KEY
+
+v_out "Attempting to kexec signed image using kexec_file_load..."
+kexec -s -l $KERNEL_IMAGE &>> /dev/null
+
+loaded_signed=$?
+if [[ $loaded_signed != 0 ]]; then
+	fail "kexec rejected a signed image - possibly due to PECOFF signature"
+else
+	v_out "kexec correctly loaded signed image...unloading"
+fi
+
+kexec -s -u
+
+v_out "Attempting kexec_load on signed kernel... [should fail]"
+kexec -l $KERNEL_IMAGE &>> /dev/null
+
+if [[ $? == 0 ]]; then
+	kexec -u
+	fail "Signed image was allowed to load without file descriptor for\
+		appraisal. Unloading."
+fi
+
+v_out "Correctly prevented loading"
+
+v_out "Cleaning up..."
+if [[ ! -z $TEMP_LOCATION ]]; then
+	rm $TEMP_LOCATION
+fi
+
+passed
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 5/7] evmtest: validate boot record
  2018-08-14 18:05 [PATCH 1/7] evmtest: Regression testing Integrity Subsystem David Jacobson
                   ` (2 preceding siblings ...)
  2018-08-14 18:05 ` [PATCH 4/7] evmtest: test kexec signature policy David Jacobson
@ 2018-08-14 18:05 ` David Jacobson
  2018-08-14 18:05 ` [PATCH 6/7] evmtest: test the preservation of extended attributes David Jacobson
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: David Jacobson @ 2018-08-14 18:05 UTC (permalink / raw)
  To: linux-integrity, linux-kernel; +Cc: David Jacobson, Petr Vorel, David Jacobson

The first record in the IMA runtime measurement list is the boot
aggregate - a hash of PCRs 0-7. This test calculates the boot aggregate
based off the PCRs and compares it to IMA's boot aggregate.

Dependencies: a TPM, IBMTSS2.

Signed-off-by: David Jacobson <davidj@linux.ibm.com>
---
 evmtest/functions/r_validate_boot_record.sh | 140 ++++++++++++++++++++
 1 file changed, 140 insertions(+)
 create mode 100755 evmtest/functions/r_validate_boot_record.sh

diff --git a/evmtest/functions/r_validate_boot_record.sh b/evmtest/functions/r_validate_boot_record.sh
new file mode 100755
index 0000000..421cbf1
--- /dev/null
+++ b/evmtest/functions/r_validate_boot_record.sh
@@ -0,0 +1,140 @@
+#!/bin/bash
+# Author: David Jacobson <davidj@linux.ibm.com>
+TEST="r_validate_boot_record"
+
+ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )/.."
+source $ROOT/files/common.sh
+
+TPM_VERSION="2.0" # DEFAULT
+VERBOSE=0
+TSS_DIR=`locate ibmtpm20tss | head -1`
+EVENT_EXTEND=$TSS_DIR/utils12/eventextend
+LD_LIBRARY_PATH=$TSS_DIR/utils:$TSS_DIR/utils12
+MEASUREMENT_FILE=$EVMTEST_SECFS/tpm0/binary_bios_measurements
+# This test validates the eventlog against the hardware PCRs in the TPM, and
+# the boot aggregate against IMA.
+
+usage (){
+	echo "r_validate_boot_record [-hv]"
+	echo ""
+	echo "	This test must be run as root"
+	echo ""
+	echo "	This test will attempt to validate PCRs 0-7 in the TPM"
+	echo "	It will also validate the boot_aggregate based those PCRs"
+	echo "	against what IMA has recorded"
+	echo ""
+	echo "	-h,--help	Display this help message"
+	echo "	-v,--verbose	Verbose logging"
+}
+
+
+TEMP=`getopt -o 'hv' -l 'help,verbose' -n 'r_validate_boot_record' -- "$@"`
+eval set -- "$TEMP"
+
+while true ; do
+	case "$1" in
+	-h|--help) usage; exit; shift;;
+	-v|--verbose) VERBOSE=1; shift;;
+	--) shift; break;;
+	*) echo "[*] Unrecognized option $1"; exit 1 ;;
+	esac
+done
+
+EVMTEST_require_root
+
+echo "[*] Starting test: $TEST"
+
+v_out "Checking if securityfs is mounted..."
+if [[ -z $EVMTEST_SECFS_EXISTS ]]; then
+	fail "securityfs not found..."
+fi
+
+v_out "Verifying TPM is present..."
+if [[ ! -d $EVMTEST_SECFS/tpm0 ]]; then
+	fail "Could not locate TPM in $EVMTEST_SECFS"
+fi
+
+v_out "TPM found..."
+
+v_out "Checking if system supports reading event log..."
+
+if [[ ! -f $EVMTEST_SECFS/tpm0/binary_bios_measurements ]]; then
+		fail "Kernel does not support reading BIOS measurements,
+		please update to at least 4.16.0"
+fi
+
+
+
+v_out "Verifying TPM Version"
+if [[ -e /sys/class/tpm/tpm0/device/caps ]]; then
+	contains_12=`grep 'TCG version: 1.2' /sys/class/tpm/tpm0/device/caps`
+	if [[ -z $contains12 ]]; then
+		v_out "TPM 1.2"
+		TPM_VERSION="1.2"
+	fi
+else
+	v_out "TPM 2.0"
+fi
+
+v_out "Checking if system supports reading PCRs..."
+
+if [[ ! -d $TSS_DIR ]]; then
+	fail "Could not find TSS2, please install using the package and
+	 try again"
+fi
+
+v_out "Grabbing PCR values..."
+pcrs=() # array to store the Hardware PCR values
+sim_pcrs=() # What PCRs should be according to the event log
+halg=$(grep boot_aggregate $EVMTEST_SECFS/ima/ascii_runtime_measurements|\
+		sed -n 's/.*\(sha[^:]*\):.*/\1/p')
+
+for ((i=0; i<=7; i++)); do
+	if [[ $TPM_VERSION == "1.2" ]]; then
+		pcrs[i]=`TPM_INTERFACE_TYPE=dev $TSS_DIR/utils12/pcrread \
+			-ha $i -ns`
+	else
+		pcrs[i]=`TPM_INTERFACE_TYPE=dev $TSS_DIR/utils/pcrread \
+			-ha $i -halg $halg -ns`
+	fi
+done
+
+tss_out=`LD_LIBRARY_PATH=$LD_LIBRARY_PATH $EVENT_EXTEND -if \
+				$MEASUREMENT_FILE -sim -ns`
+for ((y=2; y<=9; y++)); do
+	# Parse TSS output - first strip away PCR, then split on :, then
+	# remove leading whitespace
+	x=`echo $tss_out | awk -v y=$y -F 'PCR' '{print $y}'`
+	x=`echo "$x" | awk -F ":" '{print $2}' | sed -e 's/^[ \t]*//'`
+	index=$((y-2))
+	sim_pcrs[$index]=$x
+done
+
+v_out "Validating PCRs.."
+for ((i=0; i<=7; i++)); do
+	v_out "SIM PCR [$i]: ${sim_pcrs[$i]}"
+	v_out "TPM PCR [$i]: ${pcrs[$i]}"
+	if [[  "${pcrs[$i]}" = "${sim_pcrs[$i]}" ]]; then
+		v_out "PCRs are incorrect..."
+		fail "Mismatch at PCR "$i" "
+	else
+		v_out "PCR $i validated..."
+	fi
+done
+
+
+v_out "Validating Boot Aggregate..."
+tss_boot_agg=`echo $tss_out | awk -F "boot aggregate:" '{print $2}'| tr -d " "`
+ima_boot_agg=`grep boot_aggregate \
+$EVMTEST_SECFS/ima/ascii_runtime_measurements|cut -d ":" -f2|cut -d " " -f1`
+v_out "TSS BOOT AGG: $tss_boot_agg"
+v_out "IMA BOOT AGG: $ima_boot_agg"
+
+if [ "$tss_boot_agg" != "$ima_boot_agg" ]; then
+	fail "Boot Aggregate is inconsistent"
+else
+	v_out "Boot Aggregate validated"
+fi
+
+echo "[*] TEST: PASSED"
+exit 0
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 6/7] evmtest: test the preservation of extended attributes
  2018-08-14 18:05 [PATCH 1/7] evmtest: Regression testing Integrity Subsystem David Jacobson
                   ` (3 preceding siblings ...)
  2018-08-14 18:05 ` [PATCH 5/7] evmtest: validate boot record David Jacobson
@ 2018-08-14 18:05 ` David Jacobson
  2018-08-14 18:05 ` [PATCH 7/7] emvtest: Add ability to run all tests David Jacobson
  2018-08-14 18:29 ` [PATCH 1/7] evmtest: Regression testing Integrity Subsystem James Morris
  6 siblings, 0 replies; 9+ messages in thread
From: David Jacobson @ 2018-08-14 18:05 UTC (permalink / raw)
  To: linux-integrity, linux-kernel; +Cc: David Jacobson, Petr Vorel, David Jacobson

IMA supports file signatures by storing information in a security.ima
extended file attribute. This test ensures that the attribute is
preserved when a file is copied.  This test requires root because only
root can write "security." xattrs to files.

Signed-off-by: David Jacobson <davidj@linux.ibm.com>
---
 evmtest/functions/r_xattr_preserve.sh | 74 +++++++++++++++++++++++++++
 1 file changed, 74 insertions(+)
 create mode 100755 evmtest/functions/r_xattr_preserve.sh

diff --git a/evmtest/functions/r_xattr_preserve.sh b/evmtest/functions/r_xattr_preserve.sh
new file mode 100755
index 0000000..e7f0e2a
--- /dev/null
+++ b/evmtest/functions/r_xattr_preserve.sh
@@ -0,0 +1,74 @@
+#!/bin/bash
+# Author: David Jacobson <davidj@linux.ibm.com>
+TEST="r_xattr_preserve"
+ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )/.."
+source $ROOT/files/common.sh
+
+VERBOSE=0
+# This test ensures that extended file attributes are preserved when a file is
+# moved with the correct flag
+
+usage (){
+	echo ""
+	echo "xattr_preserve [-hv]"
+	echo ""
+	echo "This test must be run as root"
+	echo ""
+	echo "	This test ensures that extended file attributes (specifically"
+	echo "	security.ima labels) are preserved when copying"
+	echo "Options"
+	echo "  -h,--help       Display this help message"
+	echo "  -v,--verbose    Verbose logging"
+}
+
+TEMP=`getopt -o 'hv' -l 'help,verbose' -n 'r_xattr_preserve' -- "$@"`
+eval set -- "$TEMP"
+
+while true ; do
+	case "$1" in
+	-h|--help) usage; exit; shift;;
+	-v|--verbose) VERBOSE=1; shift;;
+	--) shift; break;;
+	*) echo "[*] Unrecognized option $1"; exit 1;;
+	esac
+done
+
+EVMTEST_require_root
+
+begin
+
+LOCATION_1=`mktemp`
+LOCATION_2=`mktemp -u` # Doesn't create the file
+v_out "Labeling file..."
+
+evmctl ima_hash $LOCATION_1
+initial_ima_label=`getfattr -m ^security.ima -e hex \
+	--dump $LOCATION_1 2> /dev/null`
+
+initial_hash=`echo $initial_ima_label | awk -F '=' '{print $2}'`
+
+if [[ $initial_ima_label = *"security.ima"* ]]; then
+	v_out "Found hash on initial file... "
+else
+	fail "Hash not found on initial file"
+fi
+
+initial_hash=`echo $initial_ima_label | awk -F '=' '{print $2}'`
+
+v_out "Copying file..."
+cp --preserve=xattr $LOCATION_1 $LOCATION_2
+v_out "Checking if extended attribute has been preserved..."
+
+
+second_ima_label=`getfattr -m ^security.ima -e hex \
+	--dump $LOCATION_2 2> /dev/null`
+second_hash=`echo $second_ima_label | awk -F '=' '{print $2}'`
+if [[ "$initial_hash" != "$second_hash" ]]; then
+	fail "security.ima xattr was not preserved!"
+else
+	v_out "Extended attribute was preserved during copy"
+fi
+v_out "Cleaning up..."
+rm $LOCATION_1 $LOCATION_2
+
+passed
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 7/7] emvtest: Add ability to run all tests
  2018-08-14 18:05 [PATCH 1/7] evmtest: Regression testing Integrity Subsystem David Jacobson
                   ` (4 preceding siblings ...)
  2018-08-14 18:05 ` [PATCH 6/7] evmtest: test the preservation of extended attributes David Jacobson
@ 2018-08-14 18:05 ` David Jacobson
  2018-08-14 18:29 ` [PATCH 1/7] evmtest: Regression testing Integrity Subsystem James Morris
  6 siblings, 0 replies; 9+ messages in thread
From: David Jacobson @ 2018-08-14 18:05 UTC (permalink / raw)
  To: linux-integrity, linux-kernel; +Cc: David Jacobson, Petr Vorel, David Jacobson

evmtest tests functionality of different IMA-Appraisal policies.

To simplify testing, this patch defines an evmtest config file.  This
allows for running all tests at once, rather than invoking each test
individually. Variables can be set once rather than specifying
parameters at runtime on the command line.

Signed-off-by: David Jacobson <davidj@linux.ibm.com>
---
 evmtest/README       | 19 +++++++++++++++--
 evmtest/evmtest      | 51 +++++++++++++++++++++++++++++++++++++++++++-
 evmtest/example.conf | 14 ++++++++++++
 3 files changed, 81 insertions(+), 3 deletions(-)
 create mode 100644 evmtest/example.conf

diff --git a/evmtest/README b/evmtest/README
index ac0c175..6f1c5c8 100644
--- a/evmtest/README
+++ b/evmtest/README
@@ -20,8 +20,8 @@ used to check a kernel's configuration and validate compatibility with IMA.
 COMMANDS
 --------
 
- runtest <test name> - Run a specific test
- runall <configuration> - Run all tests
+ runtest <test name> 	 - Run a specific test
+ runall  <configuration> - Run all tests
 
 OPTIONS
 -------
@@ -34,7 +34,21 @@ OPTIONS
  --vm				Validate compatibility with a virtual machine
 
 
+CONFIGURATION FILE
+------------------
+
+The `example.conf` provides a skeleton configuration file, where the only
+variable that *must* be defined is `IMA_KEY`.
+
+* `IMA_KEY` - The private key for the certificate on the IMA Trusted Keyring
 
+* `KBUILD_DIR` - Should point to a kernel build tree. If not provided, the test
+will use `/lib/modules/$(uname -r)/build`.
+
+* `KERN_IMAGE` - Should point towards an unsigned kernel image. If not provided,
+the test will attempt to use the running kernel.
+
+* `VERBOSE` - If set to 1, will add -v to all tests run
 
 BACKGROUND
 ----------
@@ -42,6 +56,7 @@ The Linux kernel needs to be configured properly with a key embedded into the
 kernel and loaded onto the `.builtin_trusted_keys` keyring at boot in order to
 run evmtest.
 
+
 === 1. Confirming the kernel is properly configured with IMA enabled.
 
 A number of Kconfig options need to be configured to enable IMA and permit
diff --git a/evmtest/evmtest b/evmtest/evmtest
index dfe39a9..74c829c 100755
--- a/evmtest/evmtest
+++ b/evmtest/evmtest
@@ -17,7 +17,7 @@ fi
 
 source $EVMDIR/files/common.sh
 usage (){
-	echo "Usage: evmtest [[runtest] <test_name>] [options]"
+	echo "Usage: evmtest [[runtest|runall] <test_name|config>] [options]"
 	echo ""
 	echo "Tests may be called directly by cd'ing to the evmtest directory:"
 	echo "$ cd $EVMDIR/functions"
@@ -69,6 +69,55 @@ elif [[ "$1" == "runtest" ]]; then
 		runtest $@
 		exit $?
 	fi
+elif [[ "$1" == "runall" ]]; then
+	if [[ -z $2 || ! -e $2 ]]; then
+		echo "evmtest runall <config file>"
+		echo "[!] Please provide a config file"
+		exit 1
+	fi
+	source $2 # Load in config
+	if [[ $VERBOSE -eq 1 ]]; then
+		V="-v"
+	fi
+
+	# Key is not optional
+	if [[ -z $IMA_KEY ]]; then
+		echo "[*] Please correct your config file"
+		exit 1
+	fi
+
+	EVMTEST_require_root
+	FAIL=0
+	echo "[*] Running tests..."
+	# 1
+	$EVMDIR/functions/r_env_validate.sh -r $V
+
+	# 2
+	if [[ -z $KERN_IMAGE ]]; then
+		$EVMDIR/functions/r_kexec_sig.sh -k $IMA_KEY $V
+	else
+		$EVMDIR/functions/r_kexec_sig.sh -k $IMA_KEY -i $KERN_IMAGE $V
+	fi
+	FAIL=$((FAIL+$?))
+	# 3
+	if [[ -z $KBUILD_DIR ]]; then
+		$EVMDIR/functions/r_kmod_sig.sh -k $IMA_KEY $V
+	else
+		$EVMDIR/functions/r_kmod_sig.sh -b $KBUILD_DIR -k $IMA_KEY $V
+	fi
+	FAIL=$((FAIL+$?))
+	# 4
+	$EVMDIR/functions/r_policy_sig.sh -k $IMA_KEY $V
+	FAIL=$((FAIL+$?))
+	# 5
+	$EVMDIR/functions/r_validate_boot_record.sh $V
+	FAIL=$((FAIL+$?))
+	# 6
+	$EVMDIR/functions/r_xattr_preserve.sh $V
+	FAIL=$((FAIL+$?))
+	echo "..."
+	echo "[*] TESTS PASSED: $((6-FAIL))"
+	echo "[*] TESTS FAILED: $FAIL"
 else
 	usage
 fi
diff --git a/evmtest/example.conf b/evmtest/example.conf
new file mode 100644
index 0000000..fd1c8fe
--- /dev/null
+++ b/evmtest/example.conf
@@ -0,0 +1,14 @@
+# This is an example config file
+# There are three variables that can be set when using evmtest runall
+
+#Set this to 1 for verbose output
+VERBOSE=0
+# Path to the private key for the IMA Trusted Keyring
+# This is required
+IMA_KEY=/path/to/your/ima_key
+
+# If this is not provided, tests will run but attempt to copy the running kernel
+KERN_IMAGE=/path/to/unsigned/kernel_image
+
+# If this is not defined, tests will try to find build tree
+KBUILD_DIR=/path/to/kernel/build/tree
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/7] evmtest: Regression testing Integrity Subsystem
  2018-08-14 18:05 [PATCH 1/7] evmtest: Regression testing Integrity Subsystem David Jacobson
                   ` (5 preceding siblings ...)
  2018-08-14 18:05 ` [PATCH 7/7] emvtest: Add ability to run all tests David Jacobson
@ 2018-08-14 18:29 ` James Morris
  2018-08-22 11:21   ` Dmitry Kasatkin
  6 siblings, 1 reply; 9+ messages in thread
From: James Morris @ 2018-08-14 18:29 UTC (permalink / raw)
  To: David Jacobson; +Cc: linux-integrity, linux-kernel, David Jacobson, Petr Vorel

[-- Attachment #1: Type: text/plain, Size: 315 bytes --]

On Tue, 14 Aug 2018, David Jacobson wrote:

> This patchset introduces evmtest — a stand alone tool for regression
> testing IMA. 

Nice!

I usually run the SELinux testsuite as a general sanity check of LSM 
before pushing to Linus, and I'll also run this once it's merged.

-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/7] evmtest: Regression testing Integrity Subsystem
  2018-08-14 18:29 ` [PATCH 1/7] evmtest: Regression testing Integrity Subsystem James Morris
@ 2018-08-22 11:21   ` Dmitry Kasatkin
  0 siblings, 0 replies; 9+ messages in thread
From: Dmitry Kasatkin @ 2018-08-22 11:21 UTC (permalink / raw)
  To: James Morris; +Cc: davidj, linux-integrity, linux-kernel, david, pvorel

Hi,

I will have a look to patches.

Thanks,
Dmitry

On Tue, Aug 14, 2018 at 9:34 PM James Morris <jmorris@namei.org> wrote:
>
> On Tue, 14 Aug 2018, David Jacobson wrote:
>
> > This patchset introduces evmtest — a stand alone tool for regression
> > testing IMA.
>
> Nice!
>
> I usually run the SELinux testsuite as a general sanity check of LSM
> before pushing to Linus, and I'll also run this once it's merged.
>
> --
> James Morris
> <jmorris@namei.org>



-- 
Thanks,
Dmitry

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2018-08-22 11:21 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-08-14 18:05 [PATCH 1/7] evmtest: Regression testing Integrity Subsystem David Jacobson
2018-08-14 18:05 ` [PATCH 2/7] evmtest: test appraisal on policy loading with signature David Jacobson
2018-08-14 18:05 ` [PATCH 3/7] evmtest: test kernel module loading David Jacobson
2018-08-14 18:05 ` [PATCH 4/7] evmtest: test kexec signature policy David Jacobson
2018-08-14 18:05 ` [PATCH 5/7] evmtest: validate boot record David Jacobson
2018-08-14 18:05 ` [PATCH 6/7] evmtest: test the preservation of extended attributes David Jacobson
2018-08-14 18:05 ` [PATCH 7/7] emvtest: Add ability to run all tests David Jacobson
2018-08-14 18:29 ` [PATCH 1/7] evmtest: Regression testing Integrity Subsystem James Morris
2018-08-22 11:21   ` Dmitry Kasatkin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).