68d0d67
Bugzilla: N/A
68d0d67
Upstream-status: Fedora mustard for now
68d0d67
05892a5
From 2b668e069365b608e855cf1f5edcf8caed0aaa4d Mon Sep 17 00:00:00 2001
c9d9c5a
From: Dave Howells <dhowells@redhat.com>
c9d9c5a
Date: Tue, 23 Oct 2012 09:30:54 -0400
9d22d52
Subject: [PATCH 1/5] Add EFI signature data types
c9d9c5a
c9d9c5a
Add the data types that are used for containing hashes, keys and certificates
c9d9c5a
for cryptographic verification.
c9d9c5a
c9d9c5a
Signed-off-by: David Howells <dhowells@redhat.com>
c9d9c5a
---
c9d9c5a
 include/linux/efi.h | 20 ++++++++++++++++++++
c9d9c5a
 1 file changed, 20 insertions(+)
c9d9c5a
c9d9c5a
diff --git a/include/linux/efi.h b/include/linux/efi.h
05892a5
index 0c1d367..de1faea 100644
c9d9c5a
--- a/include/linux/efi.h
c9d9c5a
+++ b/include/linux/efi.h
05892a5
@@ -394,6 +394,12 @@ typedef efi_status_t efi_query_variable_store_t(u32 attributes, unsigned long si
c9d9c5a
 #define EFI_FILE_SYSTEM_GUID \
c9d9c5a
     EFI_GUID(  0x964e5b22, 0x6459, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b )
c9d9c5a
 
c9d9c5a
+#define EFI_CERT_SHA256_GUID \
c9d9c5a
+    EFI_GUID(  0xc1c41626, 0x504c, 0x4092, 0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28 )
c9d9c5a
+
c9d9c5a
+#define EFI_CERT_X509_GUID \
c9d9c5a
+    EFI_GUID(  0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72 )
c9d9c5a
+
c9d9c5a
 typedef struct {
c9d9c5a
 	efi_guid_t guid;
c9d9c5a
 	u64 table;
05892a5
@@ -541,6 +547,20 @@ typedef struct _efi_file_io_interface {
c9d9c5a
 
c9d9c5a
 #define EFI_INVALID_TABLE_ADDR		(~0UL)
c9d9c5a
 
c9d9c5a
+typedef struct  {
c9d9c5a
+	efi_guid_t signature_owner;
c9d9c5a
+	u8 signature_data[];
c9d9c5a
+} efi_signature_data_t;
c9d9c5a
+
c9d9c5a
+typedef struct {
c9d9c5a
+	efi_guid_t signature_type;
c9d9c5a
+	u32 signature_list_size;
c9d9c5a
+	u32 signature_header_size;
c9d9c5a
+	u32 signature_size;
c9d9c5a
+	u8 signature_header[];
c9d9c5a
+	/* efi_signature_data_t signatures[][] */
c9d9c5a
+} efi_signature_list_t;
c9d9c5a
+
c9d9c5a
 /*
c9d9c5a
  * All runtime access to EFI goes through this structure:
c9d9c5a
  */
c9d9c5a
-- 
05892a5
1.8.4.2
c9d9c5a
c9d9c5a
05892a5
From 42d75e3e3fe134cc274f765525031b764540a587 Mon Sep 17 00:00:00 2001
c9d9c5a
From: Dave Howells <dhowells@redhat.com>
c9d9c5a
Date: Tue, 23 Oct 2012 09:36:28 -0400
9d22d52
Subject: [PATCH 2/5] Add an EFI signature blob parser and key loader.
c9d9c5a
c9d9c5a
X.509 certificates are loaded into the specified keyring as asymmetric type
c9d9c5a
keys.
c9d9c5a
c9d9c5a
Signed-off-by: David Howells <dhowells@redhat.com>
c9d9c5a
---
c9d9c5a
 crypto/asymmetric_keys/Kconfig      |   8 +++
c9d9c5a
 crypto/asymmetric_keys/Makefile     |   1 +
d7ee6f3
 crypto/asymmetric_keys/efi_parser.c | 109 ++++++++++++++++++++++++++++++++++++
c9d9c5a
 include/linux/efi.h                 |   4 ++
d7ee6f3
 4 files changed, 122 insertions(+)
c9d9c5a
 create mode 100644 crypto/asymmetric_keys/efi_parser.c
c9d9c5a
c9d9c5a
diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig
05892a5
index 03a6eb9..6306ffc 100644
c9d9c5a
--- a/crypto/asymmetric_keys/Kconfig
c9d9c5a
+++ b/crypto/asymmetric_keys/Kconfig
05892a5
@@ -37,4 +37,12 @@ config X509_CERTIFICATE_PARSER
c9d9c5a
 	  data and provides the ability to instantiate a crypto key from a
c9d9c5a
 	  public key packet found inside the certificate.
c9d9c5a
 
c9d9c5a
+config EFI_SIGNATURE_LIST_PARSER
c9d9c5a
+	bool "EFI signature list parser"
c9d9c5a
+	depends on EFI
c9d9c5a
+	select X509_CERTIFICATE_PARSER
c9d9c5a
+	help
c9d9c5a
+	  This option provides support for parsing EFI signature lists for
c9d9c5a
+	  X.509 certificates and turning them into keys.
c9d9c5a
+
c9d9c5a
 endif # ASYMMETRIC_KEY_TYPE
c9d9c5a
diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
c9d9c5a
index 0727204..cd8388e 100644
c9d9c5a
--- a/crypto/asymmetric_keys/Makefile
c9d9c5a
+++ b/crypto/asymmetric_keys/Makefile
c9d9c5a
@@ -8,6 +8,7 @@ asymmetric_keys-y := asymmetric_type.o signature.o
c9d9c5a
 
c9d9c5a
 obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o
c9d9c5a
 obj-$(CONFIG_PUBLIC_KEY_ALGO_RSA) += rsa.o
c9d9c5a
+obj-$(CONFIG_EFI_SIGNATURE_LIST_PARSER) += efi_parser.o
c9d9c5a
 
c9d9c5a
 #
c9d9c5a
 # X.509 Certificate handling
c9d9c5a
diff --git a/crypto/asymmetric_keys/efi_parser.c b/crypto/asymmetric_keys/efi_parser.c
c9d9c5a
new file mode 100644
d7ee6f3
index 0000000..424896a
c9d9c5a
--- /dev/null
c9d9c5a
+++ b/crypto/asymmetric_keys/efi_parser.c
d7ee6f3
@@ -0,0 +1,109 @@
c9d9c5a
+/* EFI signature/key/certificate list parser
c9d9c5a
+ *
c9d9c5a
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
c9d9c5a
+ * Written by David Howells (dhowells@redhat.com)
c9d9c5a
+ *
c9d9c5a
+ * This program is free software; you can redistribute it and/or
c9d9c5a
+ * modify it under the terms of the GNU General Public Licence
c9d9c5a
+ * as published by the Free Software Foundation; either version
c9d9c5a
+ * 2 of the Licence, or (at your option) any later version.
c9d9c5a
+ */
c9d9c5a
+
c9d9c5a
+#define pr_fmt(fmt) "EFI: "fmt
c9d9c5a
+#include <linux/module.h>
c9d9c5a
+#include <linux/printk.h>
c9d9c5a
+#include <linux/err.h>
c9d9c5a
+#include <linux/efi.h>
c9d9c5a
+#include <keys/asymmetric-type.h>
c9d9c5a
+
c9d9c5a
+static __initdata efi_guid_t efi_cert_x509_guid = EFI_CERT_X509_GUID;
c9d9c5a
+
c9d9c5a
+/**
c9d9c5a
+ * parse_efi_signature_list - Parse an EFI signature list for certificates
c9d9c5a
+ * @data: The data blob to parse
c9d9c5a
+ * @size: The size of the data blob
c9d9c5a
+ * @keyring: The keyring to add extracted keys to
c9d9c5a
+ */
c9d9c5a
+int __init parse_efi_signature_list(const void *data, size_t size, struct key *keyring)
c9d9c5a
+{
c9d9c5a
+	unsigned offs = 0;
c9d9c5a
+	size_t lsize, esize, hsize, elsize;
c9d9c5a
+
c9d9c5a
+	pr_devel("-->%s(,%zu)\n", __func__, size);
c9d9c5a
+
c9d9c5a
+	while (size > 0) {
c9d9c5a
+		efi_signature_list_t list;
c9d9c5a
+		const efi_signature_data_t *elem;
c9d9c5a
+		key_ref_t key;
c9d9c5a
+
c9d9c5a
+		if (size < sizeof(list))
c9d9c5a
+			return -EBADMSG;
c9d9c5a
+
c9d9c5a
+		memcpy(&list, data, sizeof(list));
c9d9c5a
+		pr_devel("LIST[%04x] guid=%pUl ls=%x hs=%x ss=%x\n",
c9d9c5a
+			 offs,
c9d9c5a
+			 list.signature_type.b, list.signature_list_size,
c9d9c5a
+			 list.signature_header_size, list.signature_size);
c9d9c5a
+
c9d9c5a
+		lsize = list.signature_list_size;
c9d9c5a
+		hsize = list.signature_header_size;
c9d9c5a
+		esize = list.signature_size;
c9d9c5a
+		elsize = lsize - sizeof(list) - hsize;
c9d9c5a
+
c9d9c5a
+		if (lsize > size) {
c9d9c5a
+			pr_devel("<--%s() = -EBADMSG [overrun @%x]\n",
c9d9c5a
+				 __func__, offs);
c9d9c5a
+			return -EBADMSG;
c9d9c5a
+		}
c9d9c5a
+		if (lsize < sizeof(list) ||
c9d9c5a
+		    lsize - sizeof(list) < hsize ||
c9d9c5a
+		    esize < sizeof(*elem) ||
c9d9c5a
+		    elsize < esize ||
c9d9c5a
+		    elsize % esize != 0) {
c9d9c5a
+			pr_devel("- bad size combo @%x\n", offs);
c9d9c5a
+			return -EBADMSG;
c9d9c5a
+		}
c9d9c5a
+
c9d9c5a
+		if (efi_guidcmp(list.signature_type, efi_cert_x509_guid) != 0) {
c9d9c5a
+			data += lsize;
c9d9c5a
+			size -= lsize;
c9d9c5a
+			offs += lsize;
c9d9c5a
+			continue;
c9d9c5a
+		}
c9d9c5a
+
c9d9c5a
+		data += sizeof(list) + hsize;
c9d9c5a
+		size -= sizeof(list) + hsize;
c9d9c5a
+		offs += sizeof(list) + hsize;
c9d9c5a
+
c9d9c5a
+		for (; elsize > 0; elsize -= esize) {
c9d9c5a
+			elem = data;
c9d9c5a
+
c9d9c5a
+			pr_devel("ELEM[%04x]\n", offs);
c9d9c5a
+
c9d9c5a
+			key = key_create_or_update(
c9d9c5a
+				make_key_ref(keyring, 1),
c9d9c5a
+				"asymmetric",
c9d9c5a
+				NULL,
c9d9c5a
+				&elem->signature_data,
c9d9c5a
+				esize - sizeof(*elem),
c9d9c5a
+				(KEY_POS_ALL & ~KEY_POS_SETATTR) |
c9d9c5a
+				KEY_USR_VIEW,
d7ee6f3
+				KEY_ALLOC_NOT_IN_QUOTA |
d7ee6f3
+				KEY_ALLOC_TRUSTED);
c9d9c5a
+
c9d9c5a
+			if (IS_ERR(key))
c9d9c5a
+				pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
c9d9c5a
+				       PTR_ERR(key));
c9d9c5a
+			else
c9d9c5a
+				pr_notice("Loaded cert '%s' linked to '%s'\n",
c9d9c5a
+					  key_ref_to_ptr(key)->description,
c9d9c5a
+					  keyring->description);
c9d9c5a
+
c9d9c5a
+			data += esize;
c9d9c5a
+			size -= esize;
c9d9c5a
+			offs += esize;
c9d9c5a
+		}
c9d9c5a
+	}
c9d9c5a
+
c9d9c5a
+	return 0;
c9d9c5a
+}
c9d9c5a
diff --git a/include/linux/efi.h b/include/linux/efi.h
05892a5
index de1faea..13e1425 100644
c9d9c5a
--- a/include/linux/efi.h
c9d9c5a
+++ b/include/linux/efi.h
05892a5
@@ -641,6 +641,10 @@ extern int efi_set_rtc_mmss(const struct timespec *now);
c9d9c5a
 extern void efi_reserve_boot_services(void);
c9d9c5a
 extern struct efi_memory_map memmap;
c9d9c5a
 
c9d9c5a
+struct key;
c9d9c5a
+extern int __init parse_efi_signature_list(const void *data, size_t size,
c9d9c5a
+					   struct key *keyring);
c9d9c5a
+
c9d9c5a
 /**
c9d9c5a
  * efi_range_is_wc - check the WC bit on an address range
c9d9c5a
  * @start: starting kvirt address
c9d9c5a
-- 
05892a5
1.8.4.2
c9d9c5a
c9d9c5a
05892a5
From d750dbcdcb3a712a2ea4ec57b9c9729c6a26b41d Mon Sep 17 00:00:00 2001
c9d9c5a
From: Josh Boyer <jwboyer@fedoraproject.org>
c9d9c5a
Date: Fri, 26 Oct 2012 12:36:24 -0400
9d22d52
Subject: [PATCH 3/5] KEYS: Add a system blacklist keyring
c9d9c5a
c9d9c5a
This adds an additional keyring that is used to store certificates that
c9d9c5a
are blacklisted.  This keyring is searched first when loading signed modules
c9d9c5a
and if the module's certificate is found, it will refuse to load.  This is
c9d9c5a
useful in cases where third party certificates are used for module signing.
c9d9c5a
c9d9c5a
Signed-off-by: Josh Boyer <jwboyer@fedoraproject.org>
c9d9c5a
---
d7ee6f3
 include/keys/system_keyring.h |  4 ++++
d7ee6f3
 init/Kconfig                  |  9 +++++++++
d7ee6f3
 kernel/module_signing.c       | 12 ++++++++++++
d7ee6f3
 kernel/system_keyring.c       | 17 +++++++++++++++++
d7ee6f3
 4 files changed, 42 insertions(+)
c9d9c5a
d7ee6f3
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
d7ee6f3
index 8dabc39..e466de1 100644
d7ee6f3
--- a/include/keys/system_keyring.h
d7ee6f3
+++ b/include/keys/system_keyring.h
d7ee6f3
@@ -18,6 +18,10 @@
c9d9c5a
 
d7ee6f3
 extern struct key *system_trusted_keyring;
c9d9c5a
 
d7ee6f3
+#ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING
d7ee6f3
+extern struct key *system_blacklist_keyring;
c9d9c5a
+#endif
c9d9c5a
+
d7ee6f3
 #endif
c9d9c5a
 
d7ee6f3
 #endif /* _KEYS_SYSTEM_KEYRING_H */
d7ee6f3
diff --git a/init/Kconfig b/init/Kconfig
05892a5
index 5236dc5..f59e6fe 100644
d7ee6f3
--- a/init/Kconfig
d7ee6f3
+++ b/init/Kconfig
05892a5
@@ -1673,6 +1673,15 @@ config SYSTEM_TRUSTED_KEYRING
c9d9c5a
 
d7ee6f3
 	  Keys in this keyring are used by module signature checking.
c9d9c5a
 
d7ee6f3
+config SYSTEM_BLACKLIST_KEYRING
d7ee6f3
+	bool "Provide system-wide ring of blacklisted keys"
d7ee6f3
+	depends on KEYS
d7ee6f3
+	help
d7ee6f3
+	  Provide a system keyring to which blacklisted keys can be added.  Keys
d7ee6f3
+	  in the keyring are considered entirely untrusted.  Keys in this keyring
d7ee6f3
+	  are used by the module signature checking to reject loading of modules
d7ee6f3
+	  signed with a blacklisted key.
d7ee6f3
+
d7ee6f3
 menuconfig MODULES
d7ee6f3
 	bool "Enable loadable module support"
9d22d52
 	option modules
c9d9c5a
diff --git a/kernel/module_signing.c b/kernel/module_signing.c
05892a5
index be5b8fa..fed815f 100644
c9d9c5a
--- a/kernel/module_signing.c
c9d9c5a
+++ b/kernel/module_signing.c
d7ee6f3
@@ -158,6 +158,18 @@ static struct key *request_asymmetric_key(const char *signer, size_t signer_len,
c9d9c5a
 
c9d9c5a
 	pr_debug("Look up: \"%s\"\n", id);
c9d9c5a
 
d7ee6f3
+#ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING
d7ee6f3
+	key = keyring_search(make_key_ref(system_blacklist_keyring, 1),
c9d9c5a
+				   &key_type_asymmetric, id);
c9d9c5a
+	if (!IS_ERR(key)) {
c9d9c5a
+		/* module is signed with a cert in the blacklist.  reject */
c9d9c5a
+		pr_err("Module key '%s' is in blacklist\n", id);
c9d9c5a
+		key_ref_put(key);
c9d9c5a
+		kfree(id);
c9d9c5a
+		return ERR_PTR(-EKEYREJECTED);
c9d9c5a
+	}
c9d9c5a
+#endif
c9d9c5a
+
d7ee6f3
 	key = keyring_search(make_key_ref(system_trusted_keyring, 1),
c9d9c5a
 			     &key_type_asymmetric, id);
c9d9c5a
 	if (IS_ERR(key))
d7ee6f3
diff --git a/kernel/system_keyring.c b/kernel/system_keyring.c
05892a5
index 52ebc70..478c4f8 100644
d7ee6f3
--- a/kernel/system_keyring.c
d7ee6f3
+++ b/kernel/system_keyring.c
d7ee6f3
@@ -20,6 +20,9 @@
d7ee6f3
 
d7ee6f3
 struct key *system_trusted_keyring;
d7ee6f3
 EXPORT_SYMBOL_GPL(system_trusted_keyring);
d7ee6f3
+#ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING
d7ee6f3
+struct key *system_blacklist_keyring;
d7ee6f3
+#endif
d7ee6f3
 
356f0ca
 extern __initconst const u8 system_certificate_list[];
05892a5
 extern __initconst const unsigned long system_certificate_list_size;
d7ee6f3
@@ -41,6 +44,20 @@ static __init int system_trusted_keyring_init(void)
d7ee6f3
 		panic("Can't allocate system trusted keyring\n");
d7ee6f3
 
d7ee6f3
 	set_bit(KEY_FLAG_TRUSTED_ONLY, &system_trusted_keyring->flags);
d7ee6f3
+
d7ee6f3
+#ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING
d7ee6f3
+	system_blacklist_keyring = keyring_alloc(".system_blacklist_keyring",
d7ee6f3
+				    KUIDT_INIT(0), KGIDT_INIT(0),
d7ee6f3
+				    current_cred(),
d7ee6f3
+				    (KEY_POS_ALL & ~KEY_POS_SETATTR) |
d7ee6f3
+				    KEY_USR_VIEW | KEY_USR_READ,
d7ee6f3
+				    KEY_ALLOC_NOT_IN_QUOTA, NULL);
d7ee6f3
+	if (IS_ERR(system_blacklist_keyring))
d7ee6f3
+		panic("Can't allocate system blacklist keyring\n");
d7ee6f3
+
d7ee6f3
+	set_bit(KEY_FLAG_TRUSTED_ONLY, &system_blacklist_keyring->flags);
d7ee6f3
+#endif
d7ee6f3
+
d7ee6f3
 	return 0;
d7ee6f3
 }
d7ee6f3
 
c9d9c5a
-- 
05892a5
1.8.4.2
c9d9c5a
c9d9c5a
05892a5
From c32beadd0d75fddcd75b700e4a75884d7a82e9bb Mon Sep 17 00:00:00 2001
c9d9c5a
From: Josh Boyer <jwboyer@fedoraproject.org>
c9d9c5a
Date: Fri, 26 Oct 2012 12:42:16 -0400
9d22d52
Subject: [PATCH 4/5] MODSIGN: Import certificates from UEFI Secure Boot
c9d9c5a
c9d9c5a
Secure Boot stores a list of allowed certificates in the 'db' variable.
d7ee6f3
This imports those certificates into the system trusted keyring.  This
c9d9c5a
allows for a third party signing certificate to be used in conjunction
c9d9c5a
with signed modules.  By importing the public certificate into the 'db'
c9d9c5a
variable, a user can allow a module signed with that certificate to
c9d9c5a
load.  The shim UEFI bootloader has a similar certificate list stored
c9d9c5a
in the 'MokListRT' variable.  We import those as well.
c9d9c5a
c9d9c5a
In the opposite case, Secure Boot maintains a list of disallowed
c9d9c5a
certificates in the 'dbx' variable.  We load those certificates into
d7ee6f3
the newly introduced system blacklist keyring and forbid any module
c9d9c5a
signed with those from loading.
c9d9c5a
c9d9c5a
Signed-off-by: Josh Boyer <jwboyer@fedoraproject.org>
c9d9c5a
---
c9d9c5a
 include/linux/efi.h   |  6 ++++
c9d9c5a
 init/Kconfig          |  9 +++++
c9d9c5a
 kernel/Makefile       |  3 ++
d7ee6f3
 kernel/modsign_uefi.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++
d7ee6f3
 4 files changed, 110 insertions(+)
c9d9c5a
 create mode 100644 kernel/modsign_uefi.c
c9d9c5a
c9d9c5a
diff --git a/include/linux/efi.h b/include/linux/efi.h
05892a5
index 13e1425..a7175eb 100644
c9d9c5a
--- a/include/linux/efi.h
c9d9c5a
+++ b/include/linux/efi.h
05892a5
@@ -400,6 +400,12 @@ typedef efi_status_t efi_query_variable_store_t(u32 attributes, unsigned long si
c9d9c5a
 #define EFI_CERT_X509_GUID \
c9d9c5a
     EFI_GUID(  0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72 )
c9d9c5a
 
c9d9c5a
+#define EFI_IMAGE_SECURITY_DATABASE_GUID \
c9d9c5a
+    EFI_GUID(  0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f )
c9d9c5a
+
c9d9c5a
+#define EFI_SHIM_LOCK_GUID \
c9d9c5a
+    EFI_GUID(  0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 )
c9d9c5a
+
c9d9c5a
 typedef struct {
c9d9c5a
 	efi_guid_t guid;
c9d9c5a
 	u64 table;
c9d9c5a
diff --git a/init/Kconfig b/init/Kconfig
05892a5
index f59e6fe..90fa75f 100644
c9d9c5a
--- a/init/Kconfig
c9d9c5a
+++ b/init/Kconfig
05892a5
@@ -1792,6 +1792,15 @@ config MODULE_SIG_ALL
d7ee6f3
 comment "Do not forget to sign required modules with scripts/sign-file"
d7ee6f3
 	depends on MODULE_SIG_FORCE && !MODULE_SIG_ALL
c9d9c5a
 
c9d9c5a
+config MODULE_SIG_UEFI
c9d9c5a
+	bool "Allow modules signed with certs stored in UEFI"
d7ee6f3
+	depends on MODULE_SIG && SYSTEM_BLACKLIST_KEYRING && EFI
c9d9c5a
+	select EFI_SIGNATURE_LIST_PARSER
c9d9c5a
+	help
c9d9c5a
+	  This will import certificates stored in UEFI and allow modules
c9d9c5a
+	  signed with those to be loaded.  It will also disallow loading
c9d9c5a
+	  of modules stored in the UEFI dbx variable.
c9d9c5a
+
c9d9c5a
 choice
c9d9c5a
 	prompt "Which hash algorithm should modules be signed with?"
c9d9c5a
 	depends on MODULE_SIG
c9d9c5a
diff --git a/kernel/Makefile b/kernel/Makefile
05892a5
index bc010ee..bee938f 100644
c9d9c5a
--- a/kernel/Makefile
c9d9c5a
+++ b/kernel/Makefile
05892a5
@@ -44,6 +44,7 @@ obj-$(CONFIG_UID16) += uid16.o
d7ee6f3
 obj-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += system_keyring.o system_certificates.o
c9d9c5a
 obj-$(CONFIG_MODULES) += module.o
d7ee6f3
 obj-$(CONFIG_MODULE_SIG) += module_signing.o
c9d9c5a
+obj-$(CONFIG_MODULE_SIG_UEFI) += modsign_uefi.o
c9d9c5a
 obj-$(CONFIG_KALLSYMS) += kallsyms.o
c9d9c5a
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
c9d9c5a
 obj-$(CONFIG_KEXEC) += kexec.o
05892a5
@@ -96,6 +97,8 @@ obj-$(CONFIG_CONTEXT_TRACKING) += context_tracking.o
c9d9c5a
 
c9d9c5a
 $(obj)/configs.o: $(obj)/config_data.h
c9d9c5a
 
c9d9c5a
+$(obj)/modsign_uefi.o: KBUILD_CFLAGS += -fshort-wchar
c9d9c5a
+
c9d9c5a
 # config_data.h contains the same information as ikconfig.h but gzipped.
c9d9c5a
 # Info from config_data can be extracted from /proc/config*
c9d9c5a
 targets += config_data.gz
c9d9c5a
diff --git a/kernel/modsign_uefi.c b/kernel/modsign_uefi.c
c9d9c5a
new file mode 100644
d7ee6f3
index 0000000..94b0eb3
c9d9c5a
--- /dev/null
c9d9c5a
+++ b/kernel/modsign_uefi.c
d7ee6f3
@@ -0,0 +1,92 @@
c9d9c5a
+#include <linux/kernel.h>
c9d9c5a
+#include <linux/sched.h>
c9d9c5a
+#include <linux/cred.h>
c9d9c5a
+#include <linux/err.h>
c9d9c5a
+#include <linux/efi.h>
c9d9c5a
+#include <linux/slab.h>
c9d9c5a
+#include <keys/asymmetric-type.h>
d7ee6f3
+#include <keys/system_keyring.h>
c9d9c5a
+#include "module-internal.h"
c9d9c5a
+
c9d9c5a
+static __init void *get_cert_list(efi_char16_t *name, efi_guid_t *guid, unsigned long *size)
c9d9c5a
+{
c9d9c5a
+	efi_status_t status;
c9d9c5a
+	unsigned long lsize = 4;
c9d9c5a
+	unsigned long tmpdb[4];
c9d9c5a
+	void *db = NULL;
c9d9c5a
+
c9d9c5a
+	status = efi.get_variable(name, guid, NULL, &lsize, &tmpdb);
c9d9c5a
+	if (status != EFI_BUFFER_TOO_SMALL) {
c9d9c5a
+		pr_err("Couldn't get size: 0x%lx\n", status);
c9d9c5a
+		return NULL;
c9d9c5a
+	}
c9d9c5a
+
c9d9c5a
+	db = kmalloc(lsize, GFP_KERNEL);
c9d9c5a
+	if (!db) {
c9d9c5a
+		pr_err("Couldn't allocate memory for uefi cert list\n");
c9d9c5a
+		goto out;
c9d9c5a
+	}
c9d9c5a
+
c9d9c5a
+	status = efi.get_variable(name, guid, NULL, &lsize, db);
c9d9c5a
+	if (status != EFI_SUCCESS) {
c9d9c5a
+		kfree(db);
c9d9c5a
+		db = NULL;
c9d9c5a
+		pr_err("Error reading db var: 0x%lx\n", status);
c9d9c5a
+	}
c9d9c5a
+out:
c9d9c5a
+	*size = lsize;
c9d9c5a
+	return db;
c9d9c5a
+}
c9d9c5a
+
c9d9c5a
+/*
c9d9c5a
+ *  * Load the certs contained in the UEFI databases
c9d9c5a
+ *   */
c9d9c5a
+static int __init load_uefi_certs(void)
c9d9c5a
+{
c9d9c5a
+	efi_guid_t secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
c9d9c5a
+	efi_guid_t mok_var = EFI_SHIM_LOCK_GUID;
c9d9c5a
+	void *db = NULL, *dbx = NULL, *mok = NULL;
c9d9c5a
+	unsigned long dbsize = 0, dbxsize = 0, moksize = 0;
c9d9c5a
+	int rc = 0;
c9d9c5a
+
c9d9c5a
+	/* Check if SB is enabled and just return if not */
c9d9c5a
+	if (!efi_enabled(EFI_SECURE_BOOT))
c9d9c5a
+		return 0;
c9d9c5a
+
c9d9c5a
+	/* Get db, MokListRT, and dbx.  They might not exist, so it isn't
c9d9c5a
+	 * an error if we can't get them.
c9d9c5a
+	 */
c9d9c5a
+	db = get_cert_list(L"db", &secure_var, &dbsize);
c9d9c5a
+	if (!db) {
c9d9c5a
+		pr_err("MODSIGN: Couldn't get UEFI db list\n");
c9d9c5a
+	} else {
d7ee6f3
+		rc = parse_efi_signature_list(db, dbsize, system_trusted_keyring);
c9d9c5a
+		if (rc)
c9d9c5a
+			pr_err("Couldn't parse db signatures: %d\n", rc);
c9d9c5a
+		kfree(db);
c9d9c5a
+	}
c9d9c5a
+
c9d9c5a
+	mok = get_cert_list(L"MokListRT", &mok_var, &moksize);
c9d9c5a
+	if (!mok) {
c9d9c5a
+		pr_info("MODSIGN: Couldn't get UEFI MokListRT\n");
c9d9c5a
+	} else {
d7ee6f3
+		rc = parse_efi_signature_list(mok, moksize, system_trusted_keyring);
c9d9c5a
+		if (rc)
c9d9c5a
+			pr_err("Couldn't parse MokListRT signatures: %d\n", rc);
c9d9c5a
+		kfree(mok);
c9d9c5a
+	}
c9d9c5a
+
c9d9c5a
+	dbx = get_cert_list(L"dbx", &secure_var, &dbxsize);
c9d9c5a
+	if (!dbx) {
c9d9c5a
+		pr_info("MODSIGN: Couldn't get UEFI dbx list\n");
c9d9c5a
+	} else {
c9d9c5a
+		rc = parse_efi_signature_list(dbx, dbxsize,
d7ee6f3
+			system_blacklist_keyring);
c9d9c5a
+		if (rc)
c9d9c5a
+			pr_err("Couldn't parse dbx signatures: %d\n", rc);
c9d9c5a
+		kfree(dbx);
c9d9c5a
+	}
c9d9c5a
+
c9d9c5a
+	return rc;
c9d9c5a
+}
c9d9c5a
+late_initcall(load_uefi_certs);
c9d9c5a
-- 
05892a5
1.8.4.2
c9d9c5a
9d22d52
05892a5
From 5c86fc6c7e4d51286d75ee6d8ceedf983ae434fb Mon Sep 17 00:00:00 2001
9d22d52
From: Josh Boyer <jwboyer@fedoraproject.org>
9d22d52
Date: Thu, 3 Oct 2013 10:14:23 -0400
9d22d52
Subject: [PATCH 5/5] MODSIGN: Support not importing certs from db
9d22d52
9d22d52
If a user tells shim to not use the certs/hashes in the UEFI db variable
9d22d52
for verification purposes, shim will set a UEFI variable called MokIgnoreDB.
9d22d52
Have the uefi import code look for this and not import things from the db
9d22d52
variable.
9d22d52
9d22d52
Signed-off-by: Josh Boyer <jwboyer@fedoraproject.org>
9d22d52
---
9d22d52
 kernel/modsign_uefi.c | 40 +++++++++++++++++++++++++++++++---------
9d22d52
 1 file changed, 31 insertions(+), 9 deletions(-)
9d22d52
9d22d52
diff --git a/kernel/modsign_uefi.c b/kernel/modsign_uefi.c
9d22d52
index 94b0eb3..ae28b97 100644
9d22d52
--- a/kernel/modsign_uefi.c
9d22d52
+++ b/kernel/modsign_uefi.c
9d22d52
@@ -8,6 +8,23 @@
9d22d52
 #include <keys/system_keyring.h>
9d22d52
 #include "module-internal.h"
9d22d52
 
9d22d52
+static __init int check_ignore_db(void)
9d22d52
+{
9d22d52
+	efi_status_t status;
9d22d52
+	unsigned int db = 0;
9d22d52
+	unsigned long size = sizeof(db);
9d22d52
+	efi_guid_t guid = EFI_SHIM_LOCK_GUID;
9d22d52
+
9d22d52
+	/* Check and see if the MokIgnoreDB variable exists.  If that fails
9d22d52
+	 * then we don't ignore DB.  If it succeeds, we do.
9d22d52
+	 */
9d22d52
+	status = efi.get_variable(L"MokIgnoreDB", &guid, NULL, &size, &db);
9d22d52
+	if (status != EFI_SUCCESS)
9d22d52
+		return 0;
9d22d52
+
9d22d52
+	return 1;
9d22d52
+}
9d22d52
+
9d22d52
 static __init void *get_cert_list(efi_char16_t *name, efi_guid_t *guid, unsigned long *size)
9d22d52
 {
9d22d52
 	efi_status_t status;
9d22d52
@@ -47,23 +64,28 @@ static int __init load_uefi_certs(void)
9d22d52
 	efi_guid_t mok_var = EFI_SHIM_LOCK_GUID;
9d22d52
 	void *db = NULL, *dbx = NULL, *mok = NULL;
9d22d52
 	unsigned long dbsize = 0, dbxsize = 0, moksize = 0;
9d22d52
-	int rc = 0;
9d22d52
+	int ignore_db, rc = 0;
9d22d52
 
9d22d52
 	/* Check if SB is enabled and just return if not */
9d22d52
 	if (!efi_enabled(EFI_SECURE_BOOT))
9d22d52
 		return 0;
9d22d52
 
9d22d52
+	/* See if the user has setup Ignore DB mode */
9d22d52
+	ignore_db = check_ignore_db();
9d22d52
+
9d22d52
 	/* Get db, MokListRT, and dbx.  They might not exist, so it isn't
9d22d52
 	 * an error if we can't get them.
9d22d52
 	 */
9d22d52
-	db = get_cert_list(L"db", &secure_var, &dbsize);
9d22d52
-	if (!db) {
9d22d52
-		pr_err("MODSIGN: Couldn't get UEFI db list\n");
9d22d52
-	} else {
9d22d52
-		rc = parse_efi_signature_list(db, dbsize, system_trusted_keyring);
9d22d52
-		if (rc)
9d22d52
-			pr_err("Couldn't parse db signatures: %d\n", rc);
9d22d52
-		kfree(db);
9d22d52
+	if (!ignore_db) {
9d22d52
+		db = get_cert_list(L"db", &secure_var, &dbsize);
9d22d52
+		if (!db) {
9d22d52
+			pr_err("MODSIGN: Couldn't get UEFI db list\n");
9d22d52
+		} else {
9d22d52
+			rc = parse_efi_signature_list(db, dbsize, system_trusted_keyring);
9d22d52
+			if (rc)
9d22d52
+				pr_err("Couldn't parse db signatures: %d\n", rc);
9d22d52
+			kfree(db);
9d22d52
+		}
9d22d52
 	}
9d22d52
 
9d22d52
 	mok = get_cert_list(L"MokListRT", &mok_var, &moksize);
9d22d52
-- 
05892a5
1.8.4.2
9d22d52