* [PATCH v2 2/8] evmtest: test loading IMA policies
2019-03-22 8:34 [PATCH v2 1/8] evmtest: Regression testing integrity subsystem djacobs7
@ 2019-03-22 8:34 ` djacobs7
2019-03-22 8:34 ` [PATCH v2 3/8] evmtest: test kernel module loading djacobs7
` (6 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: djacobs7 @ 2019-03-22 8:34 UTC (permalink / raw)
To: linux-integrity, linux-kernel; +Cc: zohar, pvorel, vt, David Jacobson
From: David Jacobson <djacobs7@binghamton.edu>
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 <djacobs7@binghamton.edu>
Changelog:
* Placed policy_sig on list of tests
* make sure key exists
* shellcheck compliant
* Update makefiles with tests instead of functions
* removed begin
* removed long opts
* Notes file is updated in correct patch
* restructure to use functions
* reword usage
* reworded patch title
* Fixed changes in Notes
* renamed key
* Cut down on functions
---
evmtest/Makefile.am | 6 +-
evmtest/README | 1 +
evmtest/evmtest | 1 +
evmtest/files/Notes | 16 +++
evmtest/files/policies/signed_policy | 2 +
evmtest/files/policies/unknown_signed_policy | 1 +
evmtest/files/policies/unsigned_policy | 1 +
evmtest/tests/policy_sig.sh | 110 +++++++++++++++++++
evmtest/unknown_privkey_ima.pem | 16 +++
9 files changed, 153 insertions(+), 1 deletion(-)
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/tests/policy_sig.sh
create mode 100644 evmtest/unknown_privkey_ima.pem
diff --git a/evmtest/Makefile.am b/evmtest/Makefile.am
index e74feaf..496a5de 100644
--- a/evmtest/Makefile.am
+++ b/evmtest/Makefile.am
@@ -14,9 +14,13 @@ evmtest.1:
install:
install -m 755 evmtest $(bindir)
install -d $(datarootdir)/evmtest/files/
+ install -d $(datarootdir)/evmtest/files/policies
install -d $(datarootdir)/evmtest/tests/
- 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 ./tests/* $(datarootdir)/evmtest/tests/
+ install -D ./files/policies/* $(datarootdir)/evmtest/files/policies/
cp evmtest.1 $(datarootdir)/man/man1
mandb -q
diff --git a/evmtest/README b/evmtest/README
index 5a44070..480f426 100644
--- a/evmtest/README
+++ b/evmtest/README
@@ -38,6 +38,7 @@ TEST NAMES
env_validate - verify kernel build
example_test - example test
+ policy_sig - verify loading IMA policies
Introduction
diff --git a/evmtest/evmtest b/evmtest/evmtest
index d579d03..9902e61 100755
--- a/evmtest/evmtest
+++ b/evmtest/evmtest
@@ -28,6 +28,7 @@ usage (){
# placement of a script in tests/
echo "[R] env_validate"
echo "[ ] examples_test"
+ echo "[R] policy_sig"
echo ""
echo "Note: Tests may be run directly from the \"tests\" directory"
diff --git a/evmtest/files/Notes b/evmtest/files/Notes
index f20a272..8aa2670 100644
--- a/evmtest/files/Notes
+++ b/evmtest/files/Notes
@@ -3,3 +3,19 @@ This file contains a description of the contents of this directory.
1. common.sh
This file contains useful functions and variables for evmtest scripts.
+
+2. 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 additional rules to
+the existing policy.
+
+3. policies/
+
+This is a directory that contains IMA policies with self explanatory names.
+
+4. unknown_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.
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/tests/policy_sig.sh b/evmtest/tests/policy_sig.sh
new file mode 100755
index 0000000..174d111
--- /dev/null
+++ b/evmtest/tests/policy_sig.sh
@@ -0,0 +1,110 @@
+#!/bin/bash
+TEST="policy_sig"
+# Author: David Jacobson <davidj@linux.ibm.com>
+
+ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )/.."
+#shellcheck source=/usr/local/share/evmtest/files/common.sh
+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 first loads a policy requiring all subsequent"
+ echo " policies to be signed, and verifies that only signed policies"
+ echo " may then be loaded."
+ echo ""
+ echo " Loading policy rules requires root privilege. This test must be"
+ echo " executed as root."
+ echo ""
+ echo " -k The key for the certificate on the IMA keyring"
+ echo " -h Display this help message"
+ echo " -v Verbose logging"
+}
+
+parse_args () {
+ TEMP=$(getopt -o 'k:hv' -n 'policy_sig' -- "$@")
+ eval set -- "$TEMP"
+
+ while true ; do
+ case "$1" in
+ -h) usage; exit 0; shift;;
+ -k) IMA_KEY=$2; shift 2;;
+ -v) VERBOSE=1; shift;;
+ --) shift; break;;
+ *) echo "[*] Unrecognized option $1"; exit 1 ;;
+ esac
+ done
+
+ if [ -z "$IMA_KEY" ]; then
+ usage
+ exit 1
+ fi
+
+ if [ ! -f "$IMA_KEY" ]; then
+ cleanup
+ fail "Missing key"
+ fi
+}
+
+load_signed_policy () {
+ v_out "Signing policy with provided key..."
+ if ! evmctl ima_sign -f "$POLICY_PATH" -k "$IMA_KEY" &>> /dev/null; then
+ cleanup
+ fail "Failed to sign policy - check key file"
+ fi
+
+ v_out "Loading policy..."
+ if ! "$POLICY_LOAD" signed_policy &>> /dev/null; then
+ cleanup
+ fail "Failed to write policy. "
+ fi
+ v_out "Loaded"
+}
+
+load_unsigned_policy () {
+ v_out "Attempting to load unsigned policy..."
+ if "$POLICY_LOAD" unsigned_policy &>> /dev/null; then
+ cleanup
+ fail "Failed to reject unsigned policy"
+ fi
+
+ v_out "IMA Blocked unsigned policy"
+}
+
+load_unknown_key_policy () {
+ v_out "Signing policy with invalid key..."
+ evmctl ima_sign -f "$ROOT"/files/policies/unknown_signed_policy \
+ -k "$ROOT"/files/unknown_privkey_ima.pem &>> /dev/null
+
+ v_out "Attempting to load policy signed by invalid key..."
+ if "$POLICY_LOAD" unknown_signed_policy &>> /dev/null; then
+ cleanup
+ fail "Failed to reject policy signed by unknown key"
+ fi
+
+ v_out "IMA blocked policy signed by unknown key"
+}
+
+cleanup () {
+ 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"
+}
+
+POLICY_PATH="$ROOT"/files/policies/signed_policy
+
+EVMTEST_require_root
+echo "[*] Starting test: $TEST"
+parse_args "$@"
+load_signed_policy
+load_unsigned_policy
+load_unknown_key_policy
+cleanup
+passed
diff --git a/evmtest/unknown_privkey_ima.pem b/evmtest/unknown_privkey_ima.pem
new file mode 100644
index 0000000..dcc0e24
--- /dev/null
+++ b/evmtest/unknown_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-----
--
2.20.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v2 3/8] evmtest: test kernel module loading
2019-03-22 8:34 [PATCH v2 1/8] evmtest: Regression testing integrity subsystem djacobs7
2019-03-22 8:34 ` [PATCH v2 2/8] evmtest: test loading IMA policies djacobs7
@ 2019-03-22 8:34 ` djacobs7
2019-03-22 8:34 ` [PATCH v2 4/8] evmtest: test kexec signature policy djacobs7
` (5 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: djacobs7 @ 2019-03-22 8:34 UTC (permalink / raw)
To: linux-integrity, linux-kernel; +Cc: zohar, pvorel, vt, David Jacobson
From: David Jacobson <djacobs7@binghamton.edu>
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 <djacobs7@binghamton.edu>
Changelog:
* kernel_build_directory -> build_directory
* Added kmod_sig to test list
* shellcheck compliant
* move from functions to tests
* clean up for readability
* redid order of loading and pushing policy
* added policy check
* checkbashisms complaint
* removed begin
* removed long opts
* Notes file updated in appropriate patch
* Restructured with functions
* Renamed to simple_modload, can now be used in other areas
---
evmtest/Makefile.am | 11 +-
evmtest/README | 11 +
evmtest/evmtest | 1 +
evmtest/files/Notes | 5 +
evmtest/files/policies/kernel_module_policy | 2 +
evmtest/src/Makefile | 5 +
evmtest/src/basic_mod.c | 36 +++
evmtest/src/simple_modload.c | 151 ++++++++++
evmtest/tests/kmod_sig.sh | 288 ++++++++++++++++++++
evmtest/tests/policy_sig.sh | 1 -
10 files changed, 507 insertions(+), 4 deletions(-)
create mode 100644 evmtest/files/policies/kernel_module_policy
create mode 100644 evmtest/src/Makefile
create mode 100644 evmtest/src/basic_mod.c
create mode 100644 evmtest/src/simple_modload.c
create mode 100755 evmtest/tests/kmod_sig.sh
diff --git a/evmtest/Makefile.am b/evmtest/Makefile.am
index 496a5de..74a8199 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
@@ -21,7 +24,9 @@ install:
$(datarootdir)/evmtest/files/
install -D ./tests/* $(datarootdir)/evmtest/tests/
install -D ./files/policies/* $(datarootdir)/evmtest/files/policies/
+ cp ./src/basic_mod.ko $(datarootdir)/evmtest/files/
+ cp ./src/basic_modload $(datarootdir)/evmtest/files
cp evmtest.1 $(datarootdir)/man/man1
mandb -q
-.PHONY: install evmtest.1
+.PHONY: src install evmtest.1
diff --git a/evmtest/README b/evmtest/README
index 480f426..8c63630 100644
--- a/evmtest/README
+++ b/evmtest/README
@@ -39,6 +39,7 @@ TEST NAMES
env_validate - verify kernel build
example_test - example test
policy_sig - verify loading IMA policies
+ policy_sig - test IMA-appraise on policies
Introduction
@@ -172,6 +173,9 @@ IMA's behavior is dependent on its policy. The policy defines which
files are measured, appraised, and audited. Without a policy, IMA does
not do anything.
+When running evmtest, boot with: module.sig_enforce=1. This tells the kernel to
+prevent the loading of any unsigned modules.
+
=== Methods for defining policy rules
@@ -213,6 +217,13 @@ As the regression tests mature and additional tests are defined, the
regression tests will not make policy assumptions.
+=== Require kernel module appended signatures
+
+Most kernels are configured with CONFIG_MODULE_SIG enabled but without
+CONFIG_MODULE_SIG_FORCE. For testing purposes, require kernel module appended
+signatures by specifying `module.sig_enforce=1` on the boot command line.
+
+
FAQ
---
=== 1. How can an IMA key be loaded without rebuilding dracut?
diff --git a/evmtest/evmtest b/evmtest/evmtest
index 9902e61..49b162d 100755
--- a/evmtest/evmtest
+++ b/evmtest/evmtest
@@ -28,6 +28,7 @@ usage (){
# placement of a script in tests/
echo "[R] env_validate"
echo "[ ] examples_test"
+ echo "[R] kmod_sig"
echo "[R] policy_sig"
echo ""
diff --git a/evmtest/files/Notes b/evmtest/files/Notes
index 8aa2670..574f5d8 100644
--- a/evmtest/files/Notes
+++ b/evmtest/files/Notes
@@ -19,3 +19,8 @@ This is a directory that contains IMA policies with self explanatory names.
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.
+
+5. basic_mod.ko
+
+This is a kernel module that logs (to dmesg) the syscall that was used to load
+it.
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/src/Makefile b/evmtest/src/Makefile
new file mode 100644
index 0000000..2d66ece
--- /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) simple_modload.c -o simple_modload
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/simple_modload.c b/evmtest/src/simple_modload.c
new file mode 100644
index 0000000..42510f0
--- /dev/null
+++ b/evmtest/src/simple_modload.c
@@ -0,0 +1,151 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#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>
+#include <getopt.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;
+}
+
+/*
+ * usage - print out a help message to the user
+ */
+void usage(void)
+{
+ printf("Usage: simple_modload <-p pathname> <-o | -n>\n");
+ printf(" -p,--path pathname of kernel module\n");
+ printf(" -o,--old old syscall (INIT_MODULE)\n");
+ printf(" -n,--new new syscall (FINIT_MODULE)\n");
+}
+
+int main(int argc, char **argv)
+{
+
+ int ret;
+ int uid = getuid();
+ char * path;
+ char old = 0;
+ char new = 0;
+
+ // For getopt
+ char * opt_path = 0;
+ int next;
+
+ const char * const short_opts = "p:on";
+ const struct option long_opts[] =
+ {
+ { "path", 1, NULL, 'p' },
+ { "old", 0, NULL, 'o' },
+ { "new", 0, NULL, 'n' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ while (1) {
+ next = getopt_long(argc, argv, short_opts, long_opts, NULL);
+
+ if (next == -1) {
+ break;
+ }
+
+ switch (next) {
+ case 'p' :
+ opt_path=optarg;
+ int size = strlen(opt_path) + 1;
+ path=(char *)malloc(sizeof(char) * size);
+ strcpy(path,opt_path);
+ break;
+
+ case 'o' :
+ old = 1;
+ break;
+
+ case 'n' :
+ new = 1;
+ break;
+
+ case '?' :
+ case -1 :
+ break;
+
+ default :
+ return -1;
+ }
+ }
+
+ if ( (old && new) || !(old || new) || path == NULL) {
+ usage();
+ return -1;
+ }
+
+ /* Root is required to try and load kernel modules */
+ if (uid != 0) {
+ printf("[!] simple_modload must be run as root\n");
+ return -1;
+ }
+
+ int fd = open(path, O_RDONLY);
+ if (fd == -1) {
+ printf("[!] Could not open file for read.\n");
+ return -1;
+ }
+
+ if (old == 1) {
+ ret = init_module(fd);
+ } else {
+ ret = finit_module(fd);
+ }
+
+ return ret;
+}
diff --git a/evmtest/tests/kmod_sig.sh b/evmtest/tests/kmod_sig.sh
new file mode 100755
index 0000000..0ebbaf3
--- /dev/null
+++ b/evmtest/tests/kmod_sig.sh
@@ -0,0 +1,288 @@
+#!/bin/bash
+# Author: David Jacobson <davidj@linux.ibm.com>
+TEST="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
+
+# The boot command line option module.sig_enforce=1 is equivalent to
+# compiling with CONFIG_MODULE_SIG_FORCE enabled.
+
+usage(){
+ echo ""
+ echo "kmod_sig [-b 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 The path to a kernel build dir"
+ echo " -k IMA key"
+ echo " -v Verbose logging"
+ echo " -h Display this help message"
+}
+
+parse_args () {
+ TEMP=$(getopt -o 'b:k:hv' -n 'kmod_sig' -- "$@")
+ eval set -- "$TEMP"
+
+ while true ; do
+ case "$1" in
+ -h) usage; exit 0 ;;
+ -b) BUILD_DIR=$2; shift 2;;
+ -k) IMA_KEY=$2; shift 2;;
+ -v) 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
+}
+
+
+set_build_tree_location () {
+ if [ -z "$BUILD_DIR" ]; then
+ BUILD_DIR="/lib/modules/$(uname -r)/build"
+ if [ ! -e "$BUILD_DIR" ]; then
+ echo "[!] Could not find build tree. Specify with -b"
+ exit 1
+ else
+ v_out "No build tree provided."\
+ "Found - using: $(readlink -f "$BUILD_DIR")"
+ fi
+ fi
+
+
+ if [ ! -d "$BUILD_DIR" ]; then
+ fail "Could not find kernel build path"
+ fi
+}
+
+check_key () {
+ if [ ! -e "$IMA_KEY" ]; then
+ fail "Could not find IMA key"
+ fi
+}
+
+check_policy () {
+ already_run="IMA policy already contains MODULE_CHECK"
+ if [ -e "$EVMTEST_SECFS"/ima/policy ]; then
+ POLICY=$(mktemp -u)
+ cp "$EVMTEST_SECFS"/ima/policy "$POLICY"
+ if grep -q "MODULE_CHECK" "$POLICY"; then
+ rm "$POLICY"
+ fail "$already_run"
+ fi
+ rm "$POLICY"
+ fi
+}
+
+unload_module () {
+ v_out "Unloading test module if loaded..."
+ rmmod basic_mod &>> /dev/null
+}
+
+
+
+check_boot_opts () {
+ if ! printf '%s' "$EVMTEST_BOOT_OPTS" | grep -E -q "$SIG_ENFORCE_CMD";
+ then
+ v_out "Run 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
+remove_xattr_appended_sig () {
+ v_out "Removing security attribute and appended signature if present"
+ setfattr -x security.ima "$ROOT"/files/basic_mod.ko &>> /dev/null
+ strip --strip-debug "$ROOT"/files/basic_mod.ko
+}
+
+check_hash_algo () {
+ # 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 more to determine how to sign module...
+ if [ -z "$hash_alg" ]; then
+ v_out "Could not determine hash algorithm used on module"\
+ "signing. 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 "Found hash algo: $hash_alg"
+}
+
+check_signing_key () {
+ v_out "Looking for signing key..."
+ if [ ! -e "$BUILD_DIR"/certs/signing_key.pem ]; then
+ v_out "signing_key.pem not in certs/ finding 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"
+}
+
+sign_appended_signature () {
+ v_out "Signing module [appended signature]..."
+
+ if ! "$BUILD_DIR"/scripts/sign-file "$hash_alg" "$sig_key".pem \
+ "$sig_key".x509 "$ROOT"/files/basic_mod.ko; then
+ fail "Signing failed - please ensure sign-file is in scripts/"
+ fi
+}
+
+check_appended_signature_init_mod () {
+ v_out "Attempting to load signed (appended) module with INIT_MODULE"\
+ " syscall [should pass]"
+ if ! "$mod_load" -p "$ROOT"/files/basic_mod.ko -o &>> /dev/null;
+ then
+ fail "Failed to load using init_module - check key"
+ fi
+
+ v_out "Module loaded - unloading"
+ rmmod basic_mod &>> /dev/null
+}
+
+check_appended_signature_finit_mod () {
+ v_out "Attempting to load signed (appended) module with FINIT_MODULE"\
+ " syscall [should pass]"
+ if ! "$mod_load" -p "$ROOT"/files/basic_mod.ko -n &>> /dev/null;
+ then
+ fail "Failed to load module"
+ fi
+
+ v_out "Module loaded - unloading"
+ rmmod basic_mod &>> /dev/null
+}
+
+update_policy () {
+ if ! evmctl ima_sign -f "$POLICY_PATH" -k "$IMA_KEY"; then
+ fail "Failed to sign policy - check key"
+ fi
+
+ v_out "Signing and loading policy to prevent loading unsigned kernel"\
+ " modules..."
+ if ! "$POLICY_LOAD" kernel_module_policy &>> /dev/null; then
+ fail "Could not write policy - is the supplied key correct?"
+ fi
+}
+
+check_appended_signature_init_mod_IMA () {
+ v_out "Attempting to load signed (appended) module with FINIT_MODULE "\
+ "syscall [should fail]"
+ if "$mod_load" -p "$ROOT"/files/basic_mod.ko -n &>> /dev/null;
+ then
+ rmmod_basic_mod &>> /dev/null
+ fail "FINIT_MODULE loaded module without xattr. Unloading"
+ fi
+ v_out "Prevented module without file attribute from loading"
+}
+
+sign_xattr () {
+ v_out "Signing file [extended file attribute]..."
+ if ! evmctl ima_sign -k "$IMA_KEY" -f "$ROOT"/files/basic_mod.ko; then
+ fail "Error signing module - check keys"
+ fi
+}
+
+check_xattr_finit_mod () {
+ v_out "Attempting to load module with FINIT_MODULE syscall"\
+ " [should pass]"
+ "$mod_load" -p "$ROOT"/files/basic_mod.ko -n &>> /dev/null
+}
+
+check_unknown_key () {
+ v_out "Signing with unknown key..."
+ evmctl ima_sign -f "$ROOT"/files/basic_mod.ko &>> /dev/null
+ if "$mod_load" -p "$ROOT"/files/basic_mod.ko -n &>> /dev/null;
+ then
+ fail "Allowed module to load with wrong signature"
+ fi
+
+ v_out "Prevented loading module signed by unknown key using"\
+ " FINIT_MODULE syscall"
+
+ if "$mod_load" -p "$ROOT"/files/basic_mod.ko -o &>> /dev/null;
+ then
+ fail "Allowed module to load with wrong signature"
+ fi
+
+ v_out "Prevented loading module signed by unknown key using"\
+ " INIT_MODULE syscall"
+}
+
+mod_load="$ROOT"/files/simple_modload
+SIG_ENFORCE_CMD="module.sig_enforce=1"
+POLICY_LOAD="$ROOT"/files/load_policy.sh
+POLICY_PATH="$ROOT"/files/policies/kernel_module_policy
+
+EVMTEST_require_root
+echo "[*] Starting test: $TEST"
+parse_args "$@"
+set_build_tree_location
+check_key
+check_policy
+unload_module
+check_boot_opts
+remove_xattr_appended_sig
+check_hash_algo
+check_signing_key
+sign_appended_signature
+check_appended_signature_init_mod
+check_appended_signature_finit_mod
+update_policy
+check_appended_signature_init_mod_IMA
+sign_xattr
+check_xattr_finit_mod
+remove_xattr_appended_sig
+passed
diff --git a/evmtest/tests/policy_sig.sh b/evmtest/tests/policy_sig.sh
index 174d111..ac56d0a 100755
--- a/evmtest/tests/policy_sig.sh
+++ b/evmtest/tests/policy_sig.sh
@@ -3,7 +3,6 @@ TEST="policy_sig"
# Author: David Jacobson <davidj@linux.ibm.com>
ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )/.."
-#shellcheck source=/usr/local/share/evmtest/files/common.sh
source "$ROOT"/files/common.sh
VERBOSE=0
--
2.20.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v2 4/8] evmtest: test kexec signature policy
2019-03-22 8:34 [PATCH v2 1/8] evmtest: Regression testing integrity subsystem djacobs7
2019-03-22 8:34 ` [PATCH v2 2/8] evmtest: test loading IMA policies djacobs7
2019-03-22 8:34 ` [PATCH v2 3/8] evmtest: test kernel module loading djacobs7
@ 2019-03-22 8:34 ` djacobs7
2019-03-22 8:34 ` [PATCH v2 5/8] evmtest: validate boot record djacobs7
` (4 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: djacobs7 @ 2019-03-22 8:34 UTC (permalink / raw)
To: linux-integrity, linux-kernel; +Cc: zohar, pvorel, vt, David Jacobson
From: David Jacobson <djacobs7@binghamton.edu>
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 <djacobs7@binghamton.edu>
Changelog:
* Added policy_sig to test list
* shellcheck compliant
* move from functions to tests
* suggestions from Mimi
* checkbashisms complaint
* removed begin
* removed long opts
* restructed to use functions
---
evmtest/README | 3 +-
evmtest/evmtest | 1 +
evmtest/files/policies/kexec_policy | 3 +
evmtest/tests/kexec_sig.sh | 167 ++++++++++++++++++++++++++++
4 files changed, 173 insertions(+), 1 deletion(-)
create mode 100644 evmtest/files/policies/kexec_policy
create mode 100755 evmtest/tests/kexec_sig.sh
diff --git a/evmtest/README b/evmtest/README
index 8c63630..91c8cda 100644
--- a/evmtest/README
+++ b/evmtest/README
@@ -39,7 +39,8 @@ TEST NAMES
env_validate - verify kernel build
example_test - example test
policy_sig - verify loading IMA policies
- policy_sig - test IMA-appraise on policies
+ kexec_sig - test IMA-appraise on kexec image loading
+ kmod_sig - test IMA-appraise on kernel module loading
Introduction
diff --git a/evmtest/evmtest b/evmtest/evmtest
index 49b162d..cd5e238 100755
--- a/evmtest/evmtest
+++ b/evmtest/evmtest
@@ -28,6 +28,7 @@ usage (){
# placement of a script in tests/
echo "[R] env_validate"
echo "[ ] examples_test"
+ echo "[R] kexec_sig"
echo "[R] kmod_sig"
echo "[R] policy_sig"
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/tests/kexec_sig.sh b/evmtest/tests/kexec_sig.sh
new file mode 100755
index 0000000..3a9459d
--- /dev/null
+++ b/evmtest/tests/kexec_sig.sh
@@ -0,0 +1,167 @@
+#!/bin/bash
+# Author: David Jacobson <davidj@linux.ibm.com>
+TEST="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 ""
+ echo " This test validates that IMA prevents kexec-ing to an"
+ echo " unsigned kernel image."
+ echo ""
+ echo ""
+ echo " -k The key for the certificate on the IMA keyring"
+ echo " -i An unsigned kernel image"
+ echo " -h Display this help message"
+ echo " -v Verbose logging"
+ echo ""
+ echo " Note: kexec may require PECOFF signature"
+}
+
+parse_args () {
+ TEMP=$(getopt -o 'k:i:hv' -n 'kexec_sig' -- "$@")
+ eval set -- "$TEMP"
+
+ while true ; do
+ case "$1" in
+ -h) usage; exit 0 ; shift;;
+ -i) KERNEL_IMAGE=$2; shift 2;;
+ -k) IMA_KEY=$2; shift 2;;
+ -v) 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
+get_image () {
+ 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 "Copying kernel ($KERNEL_IMAGE) to $TEMP_LOCATION"
+ cp "$KERNEL_IMAGE" "$TEMP_LOCATION"
+ KERNEL_IMAGE="$TEMP_LOCATION"
+ fi
+ else
+ if [ ! -e "$KERNEL_IMAGE" ]; then
+ fail "Kernel image not found..."
+ else
+ v_out "Valid Kernel provided, continuing"
+ fi
+ fi
+}
+
+write_hash () {
+ v_out "Writing file hash on kernel image"
+ evmctl ima_hash -a sha256 -f "$KERNEL_IMAGE"
+}
+
+load_policy () {
+ v_out "Attempting to sign policy..."
+ evmctl ima_sign -f "$ROOT"/files/policies/kexec_policy -k "$IMA_KEY"
+
+ v_out "Loading kexec policy..."
+ if ! "$POLICY_LOAD" kexec_policy &>> /dev/null; then
+ fail "Could not update policy - verify keys"
+ fi
+}
+
+check_unsigned_KEXEC_FILE_LOAD () {
+ v_out "Testing loading an unsigned kernel image using KEXEC_FILE_LOAD"\
+ "syscall"
+ # -s uses the kexec_file_load syscall
+ if ! kexec -s -l "$KERNEL_IMAGE" &>> /dev/null; then
+ v_out "Correctly prevented kexec of an unsigned image"
+ else
+ kexec -s -u
+ fail "kexec loaded instead of rejecting. Unloading and exiting."
+ fi
+}
+
+check_unsigned_KEXEC_LOAD () {
+ v_out "Testing loading an unsigned kernel image using KEXEC_LOAD"\
+ "syscall"
+ if kexec -l "$KERNEL_IMAGE" &>> /dev/null; then
+ kexec -u
+ fail "Kexec loaded unsigned image - unloading"
+ else
+ v_out "Correctly prevented kexec of an unsigned image"
+ fi
+}
+
+sign_image () {
+ v_out "Signing kernel image with provided key..."
+ evmctl ima_sign -f "$KERNEL_IMAGE" -k "$IMA_KEY"
+}
+
+check_signed_KEXEC_FILE_LOAD () {
+ v_out "Testing loading a signed kernel image using KEXEC_FILE_LOAD"\
+ "syscall"
+ if ! kexec -s -l "$KERNEL_IMAGE" &>> /dev/null; 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
+}
+
+check_signed_KEXEC_LOAD () {
+ v_out "Testing loading a signed kernel image \
+ (without file descriptor) using KEXEC_LOAD syscall"
+
+ if kexec -l "$KERNEL_IMAGE" &>> /dev/null; then
+ kexec -u
+ fail "Signed image was allowed to load without file descriptor"\
+ "for appraisal. Unloading."
+ fi
+
+ v_out "Correctly prevented loading"
+}
+
+cleanup () {
+v_out "Cleaning up..."
+if [ -n "$TEMP_LOCATION" ]; then
+ rm "$TEMP_LOCATION"
+fi
+}
+
+
+EVMTEST_require_root
+echo "[*] Starting test: $TEST"
+parse_args "$@"
+get_image
+write_hash
+load_policy
+check_unsigned_KEXEC_FILE_LOAD
+check_unsigned_KEXEC_LOAD
+sign_image
+check_signed_KEXEC_FILE_LOAD
+check_signed_KEXEC_LOAD
+cleanup
+passed
--
2.20.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v2 5/8] evmtest: validate boot record
2019-03-22 8:34 [PATCH v2 1/8] evmtest: Regression testing integrity subsystem djacobs7
` (2 preceding siblings ...)
2019-03-22 8:34 ` [PATCH v2 4/8] evmtest: test kexec signature policy djacobs7
@ 2019-03-22 8:34 ` djacobs7
2019-03-22 8:34 ` [PATCH v2 6/8] evmtest: test the preservation of extended attributes djacobs7
` (3 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: djacobs7 @ 2019-03-22 8:34 UTC (permalink / raw)
To: linux-integrity, linux-kernel; +Cc: zohar, pvorel, vt, David Jacobson
From: David Jacobson <djacobs7@binghamton.edu>
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 <djacobs7@binghamton.edu>
Changelog:
* Added boot_aggregate to test list
* shellcheck compliant
* minor fixes
* move from functions to tests
* redid tss parsing
* checkbashisms complaint
* remove begin
* removed long opts
* restructured to use functions
* added changes from Mimi to work with new TSS
* removed searching for TSS locations
---
evmtest/README | 1 +
evmtest/evmtest | 1 +
evmtest/tests/boot_aggregate.sh | 140 ++++++++++++++++++++++++++++++++
3 files changed, 142 insertions(+)
create mode 100755 evmtest/tests/boot_aggregate.sh
diff --git a/evmtest/README b/evmtest/README
index 91c8cda..b2d37e2 100644
--- a/evmtest/README
+++ b/evmtest/README
@@ -36,6 +36,7 @@ OPTIONS
TEST NAMES
----------
+ boot_aggregate - verify the IMA boot-aggregate
env_validate - verify kernel build
example_test - example test
policy_sig - verify loading IMA policies
diff --git a/evmtest/evmtest b/evmtest/evmtest
index cd5e238..3c967f9 100755
--- a/evmtest/evmtest
+++ b/evmtest/evmtest
@@ -26,6 +26,7 @@ usage (){
# Any test should be added here manually
# The reason this is manual is to prevent the accidental / malicious
# placement of a script in tests/
+ echo "[R] boot_aggregate"
echo "[R] env_validate"
echo "[ ] examples_test"
echo "[R] kexec_sig"
diff --git a/evmtest/tests/boot_aggregate.sh b/evmtest/tests/boot_aggregate.sh
new file mode 100755
index 0000000..adecfeb
--- /dev/null
+++ b/evmtest/tests/boot_aggregate.sh
@@ -0,0 +1,140 @@
+#!/bin/bash
+# Author: David Jacobson <davidj@linux.ibm.com>
+TEST="boot_aggregate"
+
+ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )/.."
+source "$ROOT"/files/common.sh
+
+VERBOSE=0
+TPM_VERSION="2.0"
+# This test validates the eventlog against the hardware PCRs in the TPM, and
+# the boot aggregate against IMA.
+
+usage (){
+ echo "boot_aggregate [-hv]"
+ echo ""
+ echo " This test must be run as root"
+ echo ""
+ echo " This test validates PCRs 0-7 in the TPM"
+ echo " It also validates the boot_aggregate based those PCRs"
+ echo " against what IMA has recorded"
+ echo ""
+ echo " -h Display this help message"
+ echo " -v Verbose logging"
+}
+
+parse_args () {
+ TEMP=$(getopt -o 'hv' -n 'boot_aggregate' -- "$@")
+ eval set -- "$TEMP"
+
+ while true ; do
+ case "$1" in
+ -h) usage; exit; shift;;
+ -v) VERBOSE=1; shift;;
+ --) shift; break;;
+ *) echo "[*] Unrecognized option $1"; exit 1 ;;
+ esac
+ done
+}
+
+check_requirements () {
+ 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
+ TPM_VERSION="1.2"
+ fi
+}
+
+check_pcrs () {
+ v_out "Grabbing PCR values..."
+ local pcrs=() # array to store the Hardware PCR values
+ local sim_pcrs=() # What PCRs should be according to the event log
+ local eventextend=tsseventextend
+ local pcrread="tsspcrread -halg sha1"
+ local eventlog=/sys/kernel/security/tpm0/binary_bios_measurements
+
+ if [ "$TPM_VERSION" == "1.2" ]; then
+ eventextend=tss1eventextend
+ pcrread=tss1pcrread
+ fi
+
+ for ((i=0; i<=7; i++)); do
+ pcrs[i]=$(TPM_INTERFACE_TYPE=dev $pcrread -ha "$i" -ns)
+ done
+
+ local output=$(mktemp -u)
+ "$eventextend" -if "$eventlog" -sim -ns > "$output"
+
+ # Some PTT's are using TPM 1.2 event log format. Retry on failure.
+ if [ $? -ne 0 ]; then
+ eventextend=tss1eventextend
+ "$eventextend" -if "$eventlog" -sim -ns > "$output"
+ fi
+
+ IFS=$'\n' read -d '' -r -a lines < "$output"
+ rm "$output"
+
+ for line in "${lines[@]}"
+ do
+ :
+ sim_pcrs+=( "$(echo "$line" | cut -d ':' -f2 | \
+ tr -d '[:space:]')" )
+ if printf '%s' "$line" | grep -E -q "boot aggregate"; then
+ tss_agg=$(echo "$line" | cut -d ':' -f2 | \
+ tr -d '[:space:]')
+ fi
+ 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
+}
+
+check_boot_aggregate () {
+ v_out "Validating Boot Aggregate..."
+ ima_agg=$(grep boot_aggregate \
+ "$EVMTEST_SECFS"/ima/ascii_runtime_measurements| head -1 | cut \
+ -d ":" -f2|cut -d " " -f1)
+ v_out "TSS BOOT AGG: $tss_agg"
+ v_out "IMA BOOT AGG: $ima_agg"
+
+ if [ "$tss_agg" != "$ima_agg" ]; then
+ fail "Boot Aggregate is inconsistent"
+ else
+ v_out "Boot Aggregate validated"
+ fi
+}
+
+EVMTEST_require_root
+echo "[*] Starting test: $TEST"
+parse_args "$@"
+check_requirements
+check_pcrs
+check_boot_aggregate
+passed
--
2.20.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v2 6/8] evmtest: test the preservation of extended attributes
2019-03-22 8:34 [PATCH v2 1/8] evmtest: Regression testing integrity subsystem djacobs7
` (3 preceding siblings ...)
2019-03-22 8:34 ` [PATCH v2 5/8] evmtest: validate boot record djacobs7
@ 2019-03-22 8:34 ` djacobs7
2019-03-22 8:34 ` [PATCH v2 7/8] emvtest: Add ability to run all tests djacobs7
` (2 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: djacobs7 @ 2019-03-22 8:34 UTC (permalink / raw)
To: linux-integrity, linux-kernel; +Cc: zohar, pvorel, vt, David Jacobson
From: David Jacobson <djacobs7@binghamton.edu>
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 <djacobs7@binghamton.edu>
Changelog:
* Clean ups suggested via mailing list
* getfattr used correctly
* more information about which file is created
* added xattr_preserve to test list
* shellcheck compliant
* move from functions to tests
* checkbashisms complaint
* remove begin
* removed long opts
* restructured using functions
---
evmtest/README | 1 +
evmtest/evmtest | 1 +
evmtest/tests/xattr_preserve.sh | 81 +++++++++++++++++++++++++++++++++
3 files changed, 83 insertions(+)
create mode 100755 evmtest/tests/xattr_preserve.sh
diff --git a/evmtest/README b/evmtest/README
index b2d37e2..4dddbc0 100644
--- a/evmtest/README
+++ b/evmtest/README
@@ -42,6 +42,7 @@ TEST NAMES
policy_sig - verify loading IMA policies
kexec_sig - test IMA-appraise on kexec image loading
kmod_sig - test IMA-appraise on kernel module loading
+ xattr_preserve - test metadata preservation on file move
Introduction
diff --git a/evmtest/evmtest b/evmtest/evmtest
index 3c967f9..18cb98d 100755
--- a/evmtest/evmtest
+++ b/evmtest/evmtest
@@ -32,6 +32,7 @@ usage (){
echo "[R] kexec_sig"
echo "[R] kmod_sig"
echo "[R] policy_sig"
+ echo "[R] xattr_preserve"
echo ""
echo "Note: Tests may be run directly from the \"tests\" directory"
diff --git a/evmtest/tests/xattr_preserve.sh b/evmtest/tests/xattr_preserve.sh
new file mode 100755
index 0000000..61f6ded
--- /dev/null
+++ b/evmtest/tests/xattr_preserve.sh
@@ -0,0 +1,81 @@
+#!/bin/bash
+# Author: David Jacobson <davidj@linux.ibm.com>
+TEST="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 requires root privileges to write security xattrs"
+ echo ""
+ echo " This test ensures that extended file attributes (specifically"
+ echo " security.ima labels) are preserved when copying"
+ echo "Options"
+ echo " -h Display this help message"
+ echo " -v Verbose logging"
+}
+
+parse_args () {
+ TEMP=$(getopt -o 'hv' -n 'xattr_preserve' -- "$@")
+ eval set -- "$TEMP"
+
+ while true ; do
+ case "$1" in
+ -h) usage; exit; shift;;
+ -v) VERBOSE=1; shift;;
+ --) shift; break;;
+ *) echo "[*] Unrecognized option $1"; exit 1;;
+ esac
+ done
+}
+
+check_xattr_preserve () {
+ LOCATION_1=$(mktemp)
+ LOCATION_2=$(mktemp -u) # Doesn't create the file
+
+ v_out "Creating and labeling file $LOCATION_1..."
+
+ evmctl ima_hash "$LOCATION_1"
+
+ initial_ima_label=$(getfattr --absolute-names -n security.ima \
+ "$LOCATION_1")
+ initial_hash=$(echo "$initial_ima_label" | awk -F '=' '{print $2}')
+ if printf '%s' "$initial_ima_label" | grep -E -q "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 to $LOCATION_2..."
+ cp --preserve=xattr "$LOCATION_1" "$LOCATION_2"
+ v_out "Checking if extended attribute has been preserved..."
+
+
+ second_ima_label=$(getfattr --absolute-names -n security.ima \
+ "$LOCATION_2")
+ 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
+}
+
+cleanup () {
+ v_out "Cleaning up..."
+ rm "$LOCATION_1" "$LOCATION_2"
+}
+
+EVMTEST_require_root
+echo "[*] Starting test: $TEST"
+check_xattr_preserve
+cleanup
+passed
--
2.20.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v2 7/8] emvtest: Add ability to run all tests
2019-03-22 8:34 [PATCH v2 1/8] evmtest: Regression testing integrity subsystem djacobs7
` (4 preceding siblings ...)
2019-03-22 8:34 ` [PATCH v2 6/8] evmtest: test the preservation of extended attributes djacobs7
@ 2019-03-22 8:34 ` djacobs7
2019-03-22 8:34 ` [PATCH v2 8/8] evmtest: virtual machine compatibility djacobs7
2019-03-22 12:18 ` [PATCH v2 1/8] evmtest: Regression testing integrity subsystem Petr Vorel
7 siblings, 0 replies; 9+ messages in thread
From: djacobs7 @ 2019-03-22 8:34 UTC (permalink / raw)
To: linux-integrity, linux-kernel; +Cc: zohar, pvorel, vt, David Jacobson
From: David Jacobson <djacobs7@binghamton.edu>
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 <djacobs7@binghamton.edu>
changelog:
* removed [OPTIONS] for runall
* added CONFIGURATION PATHNAME -> configuration file
* shellcheck compliant
---
evmtest/README | 31 +++++++++++++++++++++++++-
evmtest/evmtest | 52 ++++++++++++++++++++++++++++++++++++++++++++
evmtest/example.conf | 14 ++++++++++++
3 files changed, 96 insertions(+), 1 deletion(-)
create mode 100644 evmtest/example.conf
diff --git a/evmtest/README b/evmtest/README
index 4dddbc0..d202559 100644
--- a/evmtest/README
+++ b/evmtest/README
@@ -13,6 +13,7 @@ SYNOPSIS
evmtest runtest <test name> [OPTIONS]
+evmtest runall <configuration pathname>
DESCRIPTION
-----------
@@ -34,7 +35,7 @@ OPTIONS
TEST NAMES
-----------
+---------
boot_aggregate - verify the IMA boot-aggregate
env_validate - verify kernel build
@@ -45,6 +46,34 @@ TEST NAMES
xattr_preserve - test metadata preservation on file move
+
+CONFIGURATION PATHNAME
+----------------------
+
+The configuration pathname should point to the runall configuration file.
+
+
+=== Configuration File
+
+The evmtest configuration file allows all tests to be run by executing a single
+command. The configuration file contains all the options that needed for
+various tests and allows tests to be run non-interactively, so they can be
+integrated in a larger testing suite.
+
+The `example.conf` file provides a skeleton configuration file, where the only
+variable that *must* be defined is `IMA_KEY`. Defaults are described below.
+
+* `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
+
+
Introduction
------------
diff --git a/evmtest/evmtest b/evmtest/evmtest
index 18cb98d..d6f46f5 100755
--- a/evmtest/evmtest
+++ b/evmtest/evmtest
@@ -16,6 +16,7 @@ source "$EVMDIR"/files/common.sh
usage (){
echo "Usage:"
echo " evmtest runtest <test name> [OPTIONS]"
+ echo " evmtest runall <configuration file>"
echo ""
echo "Options:"
echo " -h Displays this help message"
@@ -67,6 +68,57 @@ 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"/tests/env_validate.sh -r "$V"
+ FAIL=$((FAIL+$?))
+ # 2
+ if [ -z "$KERN_IMAGE" ]; then
+ "$EVMDIR"/tests/kexec_sig.sh -k "$IMA_KEY" "$V"
+ else
+ "$EVMDIR"/tests/kexec_sig.sh -k "$IMA_KEY" -i \
+ "$KERN_IMAGE" "$V"
+ fi
+ FAIL=$((FAIL+$?))
+ # 3
+ if [ -z "$KBUILD_DIR" ]; then
+ "$EVMDIR"/tests/kmod_sig.sh -k "$IMA_KEY" "$V"
+ else
+ "$EVMDIR"/tests/kmod_sig.sh -b "$KBUILD_DIR" \
+ -k "$IMA_KEY" "$V"
+ fi
+ FAIL=$((FAIL+$?))
+ # 4
+ "$EVMDIR"/tests/policy_sig.sh -k "$IMA_KEY" "$V"
+ FAIL=$((FAIL+$?))
+ # 5
+ "$EVMDIR"/tests/boot_aggregate.sh "$V"
+ FAIL=$((FAIL+$?))
+ # 6
+ "$EVMDIR"/tests/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.20.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v2 8/8] evmtest: virtual machine compatibility
2019-03-22 8:34 [PATCH v2 1/8] evmtest: Regression testing integrity subsystem djacobs7
` (5 preceding siblings ...)
2019-03-22 8:34 ` [PATCH v2 7/8] emvtest: Add ability to run all tests djacobs7
@ 2019-03-22 8:34 ` djacobs7
2019-03-22 12:18 ` [PATCH v2 1/8] evmtest: Regression testing integrity subsystem Petr Vorel
7 siblings, 0 replies; 9+ messages in thread
From: djacobs7 @ 2019-03-22 8:34 UTC (permalink / raw)
To: linux-integrity, linux-kernel; +Cc: zohar, pvorel, vt, David Jacobson
From: David Jacobson <djacobs7@binghamton.edu>
Regression testing kernels is a task that is often virtualized. This
patch adds functionality to evmtest that enables a developer to
determine if their kernel build is suitable for running in a virtual
machine.
Signed-off-by: David Jacobson <djacobs7@binghamton.edu>
changelog:
* shellcheck compliant
* updated patch to work with function restructure
---
evmtest/tests/env_validate.sh | 23 +++++++++++++++++++++--
1 file changed, 21 insertions(+), 2 deletions(-)
diff --git a/evmtest/tests/env_validate.sh b/evmtest/tests/env_validate.sh
index c630a23..09b1a87 100755
--- a/evmtest/tests/env_validate.sh
+++ b/evmtest/tests/env_validate.sh
@@ -4,12 +4,13 @@
TEST="env_validate"
ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )/.."
source "$ROOT"/files/common.sh
+VM_VALIDATE=0
VERBOSE=0
CONFIG_FILE=""
usage () {
echo ""
- echo "env_validate [-c <config>]|-r] [-vh]"
+ echo "env_validate [-c <config>]|-r] [--vm] [-vh]"
echo ""
echo " This test validates that a kernel is properly configured, "
echo " based on either the provided config file or the builtin"
@@ -18,12 +19,13 @@ usage () {
echo " -c Kernel config file"
echo " -r Will attempt to pull running config"
echo " -v Verbose testing"
+ echo " --vm Will validate that the build is VM compatible"
echo " -h Displays this help message"
echo ""
}
parse_args () {
- TEMP=$(getopt -o 'hc:rv' -n 'env_validate' -- "$@")
+ TEMP=$(getopt -o 'hc:rv' -l "vm" -n 'env_validate' -- "$@")
eval set -- "$TEMP"
while true ; do
@@ -32,6 +34,7 @@ parse_args () {
-c) CONFIG="$2"; shift 2;;
-r) RUNNING=1; shift;;
-v) VERBOSE=1; shift;;
+ --vm) VM_VALIDATE=1; shift;;
--) shift; break;;
*) echo "[*] Unrecognized option $1"; exit 1 ;;
esac
@@ -154,6 +157,22 @@ check_config () {
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 Kconfig variables are incorrectly defined:"
for var in "${INVALID_DEFINITION[@]}"; do
--
2.20.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v2 1/8] evmtest: Regression testing integrity subsystem
2019-03-22 8:34 [PATCH v2 1/8] evmtest: Regression testing integrity subsystem djacobs7
` (6 preceding siblings ...)
2019-03-22 8:34 ` [PATCH v2 8/8] evmtest: virtual machine compatibility djacobs7
@ 2019-03-22 12:18 ` Petr Vorel
7 siblings, 0 replies; 9+ messages in thread
From: Petr Vorel @ 2019-03-22 12:18 UTC (permalink / raw)
To: djacobs7; +Cc: linux-integrity, linux-kernel, zohar, vt
Hi David,
> $ 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
...
> Changelog:
...
> * checkbashishms compliant
Not yet :). I noticed using
source (should be .)
== (should be =)
${BASH_SOURCE[0]} (should be $0)
$UID (should be $(id -u)
bash redirection &>> (should be >/dev/null 2>&1)
+= (should be VAR="${VAR}foo")
and bash shebang.
Could you please fix that?
...
> +++ b/evmtest/evmtest
> @@ -0,0 +1,67 @@
> +#!/bin/bash
Can we, please, use /bin/sh and not-expect bash?
Portability matters.
> +source "$EVMDIR"/files/common.sh
> +usage (){
> + echo "Usage:"
> + echo " evmtest runtest <test name> [OPTIONS]"
> + echo ""
Can be just echo. Maybe using cat might be better than many echos:
cat <<EOF
Usage:
\tevmtest runtest <test name> [OPTIONS]
...
EOF
Kind regards,
Petr
^ permalink raw reply [flat|nested] 9+ messages in thread