MODSIGN: Provide module signing public keys to the kernel
authorDavid Howells <dhowells@redhat.com>
Wed, 26 Sep 2012 09:09:51 +0000 (10:09 +0100)
committerRusty Russell <rusty@rustcorp.com.au>
Wed, 10 Oct 2012 09:31:22 +0000 (20:01 +1030)
Include a PGP keyring containing the public keys required to perform module
verification in the kernel image during build and create a special keyring
during boot which is then populated with keys of crypto type holding the public
keys found in the PGP keyring.

These can be seen by root:

[root@andromeda ~]# cat /proc/keys
07ad4ee0 I-----     1 perm 3f010000     0     0 crypto    modsign.0: RSA 87b9b3bd []
15c7f8c3 I-----     1 perm 1f030000     0     0 keyring   .module_sign: 1/4
...

It is probably worth permitting root to invalidate these keys, resulting in
their removal and preventing further modules from being loaded with that key.

Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
kernel/Makefile
kernel/modsign_pubkey.c [new file with mode: 0644]
kernel/module-internal.h

index 58c6f111267e383c18cf3618fcb9902e6696a2ad..111a845460c9c307da619130f922199f8c3cbb76 100644 (file)
@@ -55,7 +55,7 @@ obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o
 obj-$(CONFIG_PROVE_LOCKING) += spinlock.o
 obj-$(CONFIG_UID16) += uid16.o
 obj-$(CONFIG_MODULES) += module.o
-obj-$(CONFIG_MODULE_SIG) += module_signing.o
+obj-$(CONFIG_MODULE_SIG) += module_signing.o modsign_pubkey.o
 obj-$(CONFIG_KALLSYMS) += kallsyms.o
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
 obj-$(CONFIG_KEXEC) += kexec.o
@@ -134,6 +134,13 @@ $(obj)/timeconst.h: $(src)/timeconst.pl FORCE
        $(call if_changed,timeconst)
 
 ifeq ($(CONFIG_MODULE_SIG),y)
+#
+# Pull the signing certificate and any extra certificates into the kernel
+#
+extra_certificates:
+       touch $@
+
+kernel/modsign_pubkey.o: signing_key.x509 extra_certificates
 
 ###############################################################################
 #
@@ -180,4 +187,4 @@ x509.genkey:
        @echo >>x509.genkey "subjectKeyIdentifier=hash"
        @echo >>x509.genkey "authorityKeyIdentifier=keyid"
 endif
-CLEAN_FILES += signing_key.priv signing_key.x509 x509.genkey
+CLEAN_FILES += signing_key.priv signing_key.x509 x509.genkey extra_certificates
diff --git a/kernel/modsign_pubkey.c b/kernel/modsign_pubkey.c
new file mode 100644 (file)
index 0000000..4646eb2
--- /dev/null
@@ -0,0 +1,113 @@
+/* Public keys for module signature verification
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/cred.h>
+#include <linux/err.h>
+#include <keys/asymmetric-type.h>
+#include "module-internal.h"
+
+struct key *modsign_keyring;
+
+extern __initdata const u8 modsign_certificate_list[];
+extern __initdata const u8 modsign_certificate_list_end[];
+asm(".section .init.data,\"aw\"\n"
+    "modsign_certificate_list:\n"
+    ".incbin \"signing_key.x509\"\n"
+    ".incbin \"extra_certificates\"\n"
+    "modsign_certificate_list_end:"
+    );
+
+/*
+ * We need to make sure ccache doesn't cache the .o file as it doesn't notice
+ * if modsign.pub changes.
+ */
+static __initdata const char annoy_ccache[] = __TIME__ "foo";
+
+/*
+ * Load the compiled-in keys
+ */
+static __init int module_verify_init(void)
+{
+       pr_notice("Initialise module verification\n");
+
+       modsign_keyring = key_alloc(&key_type_keyring, ".module_sign",
+                                   KUIDT_INIT(0), KGIDT_INIT(0),
+                                   current_cred(),
+                                   (KEY_POS_ALL & ~KEY_POS_SETATTR) |
+                                   KEY_USR_VIEW | KEY_USR_READ,
+                                   KEY_ALLOC_NOT_IN_QUOTA);
+       if (IS_ERR(modsign_keyring))
+               panic("Can't allocate module signing keyring\n");
+
+       if (key_instantiate_and_link(modsign_keyring, NULL, 0, NULL, NULL) < 0)
+               panic("Can't instantiate module signing keyring\n");
+
+       return 0;
+}
+
+/*
+ * Must be initialised before we try and load the keys into the keyring.
+ */
+device_initcall(module_verify_init);
+
+/*
+ * Load the compiled-in keys
+ */
+static __init int load_module_signing_keys(void)
+{
+       key_ref_t key;
+       const u8 *p, *end;
+       size_t plen;
+
+       pr_notice("Loading module verification certificates\n");
+
+       end = modsign_certificate_list_end;
+       p = modsign_certificate_list;
+       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(modsign_keyring, 1),
+                                          "asymmetric",
+                                          NULL,
+                                          p,
+                                          plen,
+                                          (KEY_POS_ALL & ~KEY_POS_SETATTR) |
+                                          KEY_USR_VIEW,
+                                          KEY_ALLOC_NOT_IN_QUOTA);
+               if (IS_ERR(key))
+                       pr_err("MODSIGN: Problem loading in-kernel X.509 certificate (%ld)\n",
+                              PTR_ERR(key));
+               else
+                       pr_notice("MODSIGN: Loaded cert '%s'\n",
+                                 key_ref_to_ptr(key)->description);
+               p += plen;
+       }
+
+       return 0;
+
+dodgy_cert:
+       pr_err("MODSIGN: Problem parsing in-kernel X.509 certificate list\n");
+       return 0;
+}
+late_initcall(load_module_signing_keys);
index 033c17fd70efa2949afc08d7c7881add501b6011..6114a13419bdc3e7424e82db981131c580f6349c 100644 (file)
@@ -9,5 +9,7 @@
  * 2 of the Licence, or (at your option) any later version.
  */
 
+extern struct key *modsign_keyring;
+
 extern int mod_verify_sig(const void *mod, unsigned long modlen,
                          const void *sig, unsigned long siglen);
This page took 0.029614 seconds and 5 git commands to generate.