ff1ba812c0
Change-Id: I68dc653708a33536b69ede4f032457ab951c24dd
247 lines
8.2 KiB
Diff
247 lines
8.2 KiB
Diff
From 43dfb08aa6e053bcf1cf5696ea6bc3b9b2aa3d53 Mon Sep 17 00:00:00 2001
|
|
Message-Id: <43dfb08aa6e053bcf1cf5696ea6bc3b9b2aa3d53.1527544850.git.Jim.Somerville@windriver.com>
|
|
In-Reply-To: <b6ceef1c915827b50ce3f76da4dc47f3eb768b44.1527544850.git.Jim.Somerville@windriver.com>
|
|
References: <b6ceef1c915827b50ce3f76da4dc47f3eb768b44.1527544850.git.Jim.Somerville@windriver.com>
|
|
From: Kam Nasim <kam.nasim@windriver.com>
|
|
Date: Wed, 4 Oct 2017 14:02:10 -0400
|
|
Subject: [PATCH 23/26] US103091: IMA: System Configuration
|
|
|
|
Normally (if trusted integrity keyring is disabled), the _ima keyring
|
|
needs to be created by user space (specifically systemd), but that has
|
|
the added disadvantage of requiring the IMA public key to reside on the
|
|
file system as opposed to being compiled in. Somebody could render some
|
|
serious Grade A damage by corrupting this public key on the FS.
|
|
Crippling the system if IMA 'enforce' action is enabled.
|
|
|
|
We will therefore create the IMA keyring inside the kernel and load the
|
|
IMA public key as a compiled data blob, similar to how the Kernel loads
|
|
trusted X509 keys into the system truststore (.system_keyring)
|
|
|
|
Signed-off-by: Jim Somerville <Jim.Somerville@windriver.com>
|
|
---
|
|
.gitignore | 1 +
|
|
include/keys/system_keyring.h | 2 ++
|
|
kernel/Makefile | 42 ++++++++++++++++++++--
|
|
kernel/ima_certificate.S | 20 +++++++++++
|
|
kernel/system_keyring.c | 82 +++++++++++++++++++++++++++++++++++++++++++
|
|
5 files changed, 145 insertions(+), 2 deletions(-)
|
|
create mode 100644 kernel/ima_certificate.S
|
|
|
|
diff --git a/.gitignore b/.gitignore
|
|
index f73f35f..7148219 100644
|
|
--- a/.gitignore
|
|
+++ b/.gitignore
|
|
@@ -106,3 +106,4 @@ localversion
|
|
|
|
# Red Hat key security
|
|
kernel/x509_certificate_list
|
|
+kernel/ima_x509_certificate
|
|
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
|
|
index 0e49b3c..6b2da90 100644
|
|
--- a/include/keys/system_keyring.h
|
|
+++ b/include/keys/system_keyring.h
|
|
@@ -34,4 +34,6 @@ static inline struct key *get_system_trusted_keyring(void)
|
|
|
|
#endif /* CONFIG_SYSTEM_TRUSTED_KEYRING */
|
|
|
|
+extern struct key *ima_keyring;
|
|
+
|
|
#endif /* _KEYS_SYSTEM_KEYRING_H */
|
|
diff --git a/kernel/Makefile b/kernel/Makefile
|
|
index 44a82c1..000b9a8 100644
|
|
--- a/kernel/Makefile
|
|
+++ b/kernel/Makefile
|
|
@@ -57,7 +57,7 @@ obj-$(CONFIG_QUEUED_SPINLOCKS) += qspinlock.o
|
|
obj-$(CONFIG_QUEUED_RWLOCKS) += qrwlock.o qrwlock_gen.o
|
|
obj-$(CONFIG_LOCK_SPIN_ON_OWNER) += osq_lock.o
|
|
obj-$(CONFIG_UID16) += uid16.o
|
|
-obj-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += system_keyring.o system_certificates.o
|
|
+obj-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += system_keyring.o system_certificates.o ima_certificate.o
|
|
obj-$(CONFIG_MODULES) += module.o
|
|
obj-$(CONFIG_MODULE_SIG) += module_signing.o
|
|
obj-$(CONFIG_MODULE_SIG_UEFI) += modsign_uefi.o
|
|
@@ -197,7 +197,45 @@ targets += $(obj)/.x509.list
|
|
$(obj)/.x509.list:
|
|
@echo $(X509_CERTIFICATES) >$@
|
|
|
|
-clean-files := x509_certificate_list .x509.list
|
|
+
|
|
+###############################################################################
|
|
+#
|
|
+# We will roll in the IMA X.509 certificate and pull it in the kernel
|
|
+# so that it gets loaded into the _ima keyring during boot.
|
|
+#
|
|
+# Ideally, this should have been treated similar to other .x509 certificates
|
|
+# (X509_CERTIFICATES), but those all get loaded into the system trusted keyring
|
|
+# and since the canonical pathnames are not available in the x509_certificate_list
|
|
+# compiled data blob, there is no way to isolate the IMA certificate from the
|
|
+# rest. Therefore we treat the IMA certificate as a seperate blob all together.
|
|
+#
|
|
+# We look in the source root for the IMA certificate, of name "ima_signing_key.pub"
|
|
+#
|
|
+###############################################################################
|
|
+IMA_X509_CERTIFICATE := $(srctree)/ima_signing_key.pub
|
|
+
|
|
+ifneq ($(wildcard $(obj)/.x509.ima),)
|
|
+ifneq ($(shell cat $(obj)/.x509.ima),$(IMA_X509_CERTIFICATE))
|
|
+$(info IMA: X.509 certificate changed)
|
|
+$(shell rm $(obj)/.x509.ima)
|
|
+endif
|
|
+endif
|
|
+
|
|
+kernel/ima_certificate.o: $(obj)/ima_x509_certificate
|
|
+
|
|
+quiet_cmd_imacert = CERTS $@
|
|
+ cmd_imacert = cat $(IMA_X509_CERTIFICATE) >$@ $(foreach IMA_X509,$(IMA_X509_CERTIFICATE),; echo " - Including cert $(IMA_X509)")
|
|
+
|
|
+targets += $(obj)/ima_x509_certificate
|
|
+$(obj)/ima_x509_certificate: $(IMA_X509_CERTIFICATE) $(obj)/.x509.ima
|
|
+ $(call if_changed,imacert)
|
|
+
|
|
+targets += $(obj)/.x509.ima
|
|
+$(obj)/.x509.ima:
|
|
+ @echo $(IMA_X509_CERTIFICATE) >$@
|
|
+
|
|
+
|
|
+clean-files := x509_certificate_list .x509.list ima_x509_certificate .x509.ima
|
|
endif
|
|
|
|
ifeq ($(CONFIG_MODULE_SIG),y)
|
|
diff --git a/kernel/ima_certificate.S b/kernel/ima_certificate.S
|
|
new file mode 100644
|
|
index 0000000..0c665dd
|
|
--- /dev/null
|
|
+++ b/kernel/ima_certificate.S
|
|
@@ -0,0 +1,20 @@
|
|
+#include <linux/export.h>
|
|
+#include <linux/init.h>
|
|
+
|
|
+ __INITRODATA
|
|
+
|
|
+ .align 8
|
|
+ .globl VMLINUX_SYMBOL(ima_system_certificate)
|
|
+VMLINUX_SYMBOL(ima_system_certificate):
|
|
+__cert_list_start:
|
|
+ .incbin "kernel/ima_x509_certificate"
|
|
+__cert_list_end:
|
|
+
|
|
+ .align 8
|
|
+ .globl VMLINUX_SYMBOL(ima_system_certificate_size)
|
|
+VMLINUX_SYMBOL(ima_system_certificate_size):
|
|
+#ifdef CONFIG_64BIT
|
|
+ .quad __cert_list_end - __cert_list_start
|
|
+#else
|
|
+ .long __cert_list_end - __cert_list_start
|
|
+#endif
|
|
diff --git a/kernel/system_keyring.c b/kernel/system_keyring.c
|
|
index c15e93f..92beb15 100644
|
|
--- a/kernel/system_keyring.c
|
|
+++ b/kernel/system_keyring.c
|
|
@@ -23,10 +23,15 @@ EXPORT_SYMBOL_GPL(system_trusted_keyring);
|
|
#ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING
|
|
struct key *system_blacklist_keyring;
|
|
#endif
|
|
+struct key *ima_keyring;
|
|
+EXPORT_SYMBOL_GPL(ima_keyring);
|
|
|
|
extern __initconst const u8 system_certificate_list[];
|
|
extern __initconst const unsigned long system_certificate_list_size;
|
|
|
|
+extern __initconst const u8 ima_system_certificate[];
|
|
+extern __initconst const unsigned long ima_system_certificate_size;
|
|
+
|
|
/*
|
|
* Load the compiled-in keys
|
|
*/
|
|
@@ -57,6 +62,27 @@ static __init int system_trusted_keyring_init(void)
|
|
|
|
set_bit(KEY_FLAG_TRUSTED_ONLY, &system_blacklist_keyring->flags);
|
|
#endif
|
|
+ /* Normally (if trusted integrity keyring is disabled), the _ima
|
|
+ * keyring needs to be created by user space but that has the
|
|
+ * added disadvantage of requiring the IMA public key to reside on
|
|
+ * the file system as opposed to being compiled in.
|
|
+ * We will therefore form a _ima keyring here and load build
|
|
+ * the IMA X.509 certificate
|
|
+ *
|
|
+ * N.B: The IMA keyring only allows root userspace view & read ops
|
|
+ */
|
|
+ pr_notice("Initializing system IMA keyring\n");
|
|
+
|
|
+ ima_keyring = keyring_alloc("_ima",
|
|
+ KUIDT_INIT(0), KGIDT_INIT(0),
|
|
+ current_cred(),
|
|
+ ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
|
|
+ KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH),
|
|
+ KEY_ALLOC_NOT_IN_QUOTA, NULL);
|
|
+ if (IS_ERR(ima_keyring))
|
|
+ panic("Can't allocate system IMA keyring\n");
|
|
+
|
|
+ set_bit(KEY_FLAG_TRUSTED_ONLY, &ima_keyring->flags);
|
|
|
|
return 0;
|
|
}
|
|
@@ -121,3 +147,59 @@ dodgy_cert:
|
|
return 0;
|
|
}
|
|
late_initcall(load_system_certificate_list);
|
|
+
|
|
+/*
|
|
+ * Load the compiled-in IMA certificate.
|
|
+ */
|
|
+static __init int load_ima_system_certificate(void)
|
|
+{
|
|
+ key_ref_t key;
|
|
+ const u8 *p, *end;
|
|
+ size_t plen;
|
|
+
|
|
+ pr_notice("Loading compiled-in X.509 IMA certificate\n");
|
|
+
|
|
+ p = ima_system_certificate;
|
|
+ end = p + ima_system_certificate_size;
|
|
+ while (p < end) {
|
|
+ /* Each cert begins with an ASN.1 SEQUENCE tag and must be more
|
|
+ * than 256 bytes in size.
|
|
+ */
|
|
+ if (end - p < 4)
|
|
+ goto dodgy_cert;
|
|
+ if (p[0] != 0x30 &&
|
|
+ p[1] != 0x82)
|
|
+ goto dodgy_cert;
|
|
+ plen = (p[2] << 8) | p[3];
|
|
+ plen += 4;
|
|
+ if (plen > end - p)
|
|
+ goto dodgy_cert;
|
|
+
|
|
+ key = key_create_or_update(make_key_ref(ima_keyring, 1),
|
|
+ "asymmetric",
|
|
+ NULL,
|
|
+ p,
|
|
+ plen,
|
|
+ ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
|
|
+ KEY_USR_VIEW | KEY_USR_READ),
|
|
+ KEY_ALLOC_NOT_IN_QUOTA |
|
|
+ KEY_ALLOC_TRUSTED);
|
|
+ if (IS_ERR(key)) {
|
|
+ pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
|
|
+ PTR_ERR(key));
|
|
+ } else {
|
|
+ set_bit(KEY_FLAG_BUILTIN, &key_ref_to_ptr(key)->flags);
|
|
+ pr_notice("Loaded X.509 cert '%s'\n",
|
|
+ key_ref_to_ptr(key)->description);
|
|
+ key_ref_put(key);
|
|
+ }
|
|
+ p += plen;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+
|
|
+dodgy_cert:
|
|
+ pr_err("Problem parsing in-kernel X.509 IMA certificate\n");
|
|
+ return 0;
|
|
+}
|
|
+late_initcall(load_ima_system_certificate);
|
|
--
|
|
1.8.3.1
|
|
|