760806a
From e5e7bc54fb53e48f1b33e537156fd152cfe3345d Mon Sep 17 00:00:00 2001
6a91557
From: Josh Boyer <jwboyer@fedoraproject.org>
6a91557
Date: Fri, 26 Oct 2012 12:42:16 -0400
6a91557
Subject: [PATCH] MODSIGN: Import certificates from UEFI Secure Boot
6a91557
6a91557
Secure Boot stores a list of allowed certificates in the 'db' variable.
6a91557
This imports those certificates into the system trusted keyring.  This
6a91557
allows for a third party signing certificate to be used in conjunction
6a91557
with signed modules.  By importing the public certificate into the 'db'
6a91557
variable, a user can allow a module signed with that certificate to
6a91557
load.  The shim UEFI bootloader has a similar certificate list stored
6a91557
in the 'MokListRT' variable.  We import those as well.
6a91557
6a91557
In the opposite case, Secure Boot maintains a list of disallowed
6a91557
certificates in the 'dbx' variable.  We load those certificates into
6a91557
the newly introduced system blacklist keyring and forbid any module
6a91557
signed with those from loading.
6a91557
6a91557
Signed-off-by: Josh Boyer <jwboyer@fedoraproject.org>
6a91557
---
6a91557
 include/linux/efi.h   |  6 ++++
6a91557
 init/Kconfig          |  9 +++++
6a91557
 kernel/Makefile       |  3 ++
6a91557
 kernel/modsign_uefi.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++
6a91557
 4 files changed, 110 insertions(+)
6a91557
 create mode 100644 kernel/modsign_uefi.c
6a91557
6a91557
diff --git a/include/linux/efi.h b/include/linux/efi.h
6a91557
index 41359e548bcb..db9e6118575e 100644
6a91557
--- a/include/linux/efi.h
6a91557
+++ b/include/linux/efi.h
6a91557
@@ -587,6 +587,12 @@ void efi_native_runtime_setup(void);
6a91557
 #define EFI_CERT_X509_GUID \
6a91557
     EFI_GUID(  0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72 )
6a91557
 
6a91557
+#define EFI_IMAGE_SECURITY_DATABASE_GUID \
6a91557
+    EFI_GUID(  0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f )
6a91557
+
6a91557
+#define EFI_SHIM_LOCK_GUID \
6a91557
+    EFI_GUID(  0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 )
6a91557
+
6a91557
 typedef struct {
6a91557
 	efi_guid_t guid;
6a91557
 	u64 table;
6a91557
diff --git a/init/Kconfig b/init/Kconfig
6a91557
index 223b1a32bbcb..3bad458f1c68 100644
6a91557
--- a/init/Kconfig
6a91557
+++ b/init/Kconfig
6a91557
@@ -1874,6 +1874,15 @@ config MODULE_SIG_ALL
6a91557
 comment "Do not forget to sign required modules with scripts/sign-file"
6a91557
 	depends on MODULE_SIG_FORCE && !MODULE_SIG_ALL
6a91557
 
6a91557
+config MODULE_SIG_UEFI
6a91557
+	bool "Allow modules signed with certs stored in UEFI"
6a91557
+	depends on MODULE_SIG && SYSTEM_BLACKLIST_KEYRING && EFI
6a91557
+	select EFI_SIGNATURE_LIST_PARSER
6a91557
+	help
6a91557
+	  This will import certificates stored in UEFI and allow modules
6a91557
+	  signed with those to be loaded.  It will also disallow loading
6a91557
+	  of modules stored in the UEFI dbx variable.
6a91557
+
6a91557
 choice
6a91557
 	prompt "Which hash algorithm should modules be signed with?"
6a91557
 	depends on MODULE_SIG
6a91557
diff --git a/kernel/Makefile b/kernel/Makefile
6a91557
index dc5c77544fd6..95bdf3398880 100644
6a91557
--- a/kernel/Makefile
6a91557
+++ b/kernel/Makefile
6a91557
@@ -45,6 +45,7 @@ obj-$(CONFIG_UID16) += uid16.o
6a91557
 obj-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += system_keyring.o system_certificates.o
6a91557
 obj-$(CONFIG_MODULES) += module.o
6a91557
 obj-$(CONFIG_MODULE_SIG) += module_signing.o
6a91557
+obj-$(CONFIG_MODULE_SIG_UEFI) += modsign_uefi.o
6a91557
 obj-$(CONFIG_KALLSYMS) += kallsyms.o
6a91557
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
6a91557
 obj-$(CONFIG_KEXEC) += kexec.o
6a91557
@@ -99,6 +100,8 @@ obj-$(CONFIG_TORTURE_TEST) += torture.o
6a91557
 
6a91557
 $(obj)/configs.o: $(obj)/config_data.h
6a91557
 
6a91557
+$(obj)/modsign_uefi.o: KBUILD_CFLAGS += -fshort-wchar
6a91557
+
6a91557
 # config_data.h contains the same information as ikconfig.h but gzipped.
6a91557
 # Info from config_data can be extracted from /proc/config*
6a91557
 targets += config_data.gz
6a91557
diff --git a/kernel/modsign_uefi.c b/kernel/modsign_uefi.c
6a91557
new file mode 100644
6a91557
index 000000000000..94b0eb38a284
6a91557
--- /dev/null
6a91557
+++ b/kernel/modsign_uefi.c
6a91557
@@ -0,0 +1,92 @@
6a91557
+#include <linux/kernel.h>
6a91557
+#include <linux/sched.h>
6a91557
+#include <linux/cred.h>
6a91557
+#include <linux/err.h>
6a91557
+#include <linux/efi.h>
6a91557
+#include <linux/slab.h>
6a91557
+#include <keys/asymmetric-type.h>
6a91557
+#include <keys/system_keyring.h>
6a91557
+#include "module-internal.h"
6a91557
+
6a91557
+static __init void *get_cert_list(efi_char16_t *name, efi_guid_t *guid, unsigned long *size)
6a91557
+{
6a91557
+	efi_status_t status;
6a91557
+	unsigned long lsize = 4;
6a91557
+	unsigned long tmpdb[4];
6a91557
+	void *db = NULL;
6a91557
+
6a91557
+	status = efi.get_variable(name, guid, NULL, &lsize, &tmpdb);
6a91557
+	if (status != EFI_BUFFER_TOO_SMALL) {
6a91557
+		pr_err("Couldn't get size: 0x%lx\n", status);
6a91557
+		return NULL;
6a91557
+	}
6a91557
+
6a91557
+	db = kmalloc(lsize, GFP_KERNEL);
6a91557
+	if (!db) {
6a91557
+		pr_err("Couldn't allocate memory for uefi cert list\n");
6a91557
+		goto out;
6a91557
+	}
6a91557
+
6a91557
+	status = efi.get_variable(name, guid, NULL, &lsize, db);
6a91557
+	if (status != EFI_SUCCESS) {
6a91557
+		kfree(db);
6a91557
+		db = NULL;
6a91557
+		pr_err("Error reading db var: 0x%lx\n", status);
6a91557
+	}
6a91557
+out:
6a91557
+	*size = lsize;
6a91557
+	return db;
6a91557
+}
6a91557
+
6a91557
+/*
6a91557
+ *  * Load the certs contained in the UEFI databases
6a91557
+ *   */
6a91557
+static int __init load_uefi_certs(void)
6a91557
+{
6a91557
+	efi_guid_t secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
6a91557
+	efi_guid_t mok_var = EFI_SHIM_LOCK_GUID;
6a91557
+	void *db = NULL, *dbx = NULL, *mok = NULL;
6a91557
+	unsigned long dbsize = 0, dbxsize = 0, moksize = 0;
6a91557
+	int rc = 0;
6a91557
+
6a91557
+	/* Check if SB is enabled and just return if not */
6a91557
+	if (!efi_enabled(EFI_SECURE_BOOT))
6a91557
+		return 0;
6a91557
+
6a91557
+	/* Get db, MokListRT, and dbx.  They might not exist, so it isn't
6a91557
+	 * an error if we can't get them.
6a91557
+	 */
6a91557
+	db = get_cert_list(L"db", &secure_var, &dbsize);
6a91557
+	if (!db) {
6a91557
+		pr_err("MODSIGN: Couldn't get UEFI db list\n");
6a91557
+	} else {
6a91557
+		rc = parse_efi_signature_list(db, dbsize, system_trusted_keyring);
6a91557
+		if (rc)
6a91557
+			pr_err("Couldn't parse db signatures: %d\n", rc);
6a91557
+		kfree(db);
6a91557
+	}
6a91557
+
6a91557
+	mok = get_cert_list(L"MokListRT", &mok_var, &moksize);
6a91557
+	if (!mok) {
6a91557
+		pr_info("MODSIGN: Couldn't get UEFI MokListRT\n");
6a91557
+	} else {
6a91557
+		rc = parse_efi_signature_list(mok, moksize, system_trusted_keyring);
6a91557
+		if (rc)
6a91557
+			pr_err("Couldn't parse MokListRT signatures: %d\n", rc);
6a91557
+		kfree(mok);
6a91557
+	}
6a91557
+
6a91557
+	dbx = get_cert_list(L"dbx", &secure_var, &dbxsize);
6a91557
+	if (!dbx) {
6a91557
+		pr_info("MODSIGN: Couldn't get UEFI dbx list\n");
6a91557
+	} else {
6a91557
+		rc = parse_efi_signature_list(dbx, dbxsize,
6a91557
+			system_blacklist_keyring);
6a91557
+		if (rc)
6a91557
+			pr_err("Couldn't parse dbx signatures: %d\n", rc);
6a91557
+		kfree(dbx);
6a91557
+	}
6a91557
+
6a91557
+	return rc;
6a91557
+}
6a91557
+late_initcall(load_uefi_certs);
6a91557
-- 
6a91557
1.9.3
6a91557