Blob Blame History Raw
From ba2b209daf984514229626803472e0b055832345 Mon Sep 17 00:00:00 2001
From: Josh Boyer <jwboyer@fedoraproject.org>
Date: Fri, 26 Oct 2012 12:42:16 -0400
Subject: [PATCH] MODSIGN: Import certificates from UEFI Secure Boot

Secure Boot stores a list of allowed certificates in the 'db' variable.
This imports those certificates into the system trusted keyring.  This
allows for a third party signing certificate to be used in conjunction
with signed modules.  By importing the public certificate into the 'db'
variable, a user can allow a module signed with that certificate to
load.  The shim UEFI bootloader has a similar certificate list stored
in the 'MokListRT' variable.  We import those as well.

In the opposite case, Secure Boot maintains a list of disallowed
certificates in the 'dbx' variable.  We load those certificates into
the newly introduced system blacklist keyring and forbid any module
signed with those from loading.

Signed-off-by: Josh Boyer <jwboyer@fedoraproject.org>
---
 certs/system_keyring.c        | 13 ++++++
 include/keys/system_keyring.h |  1 +
 include/linux/efi.h           |  6 +++
 init/Kconfig                  |  9 ++++
 kernel/Makefile               |  3 ++
 kernel/modsign_uefi.c         | 99 +++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 131 insertions(+)
 create mode 100644 kernel/modsign_uefi.c

diff --git a/certs/system_keyring.c b/certs/system_keyring.c
index 787eeead2f57..4d9123ed5c07 100644
--- a/certs/system_keyring.c
+++ b/certs/system_keyring.c
@@ -30,6 +30,19 @@ extern __initconst const u8 system_certificate_list[];
 extern __initconst const unsigned long system_certificate_list_size;
 
 /**
+ * get_system_keyring - Return a pointer to the system keyring
+ *
+ */
+struct key *get_system_keyring(void)
+{
+	struct key *system_keyring = NULL;
+
+	system_keyring = builtin_trusted_keys;
+	return system_keyring;
+}
+EXPORT_SYMBOL_GPL(get_system_keyring);
+
+/**
  * restrict_link_to_builtin_trusted - Restrict keyring addition by built in CA
  *
  * Restrict the addition of keys into a keyring based on the key-to-be-added
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
index 5bc291a3d261..56ff5715ab67 100644
--- a/include/keys/system_keyring.h
+++ b/include/keys/system_keyring.h
@@ -36,6 +36,7 @@ extern int restrict_link_by_builtin_and_secondary_trusted(
 #ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING
 extern struct key *system_blacklist_keyring;
 #endif
+extern struct key *get_system_keyring(void);
 
 #ifdef CONFIG_IMA_BLACKLIST_KEYRING
 extern struct key *ima_blacklist_keyring;
diff --git a/include/linux/efi.h b/include/linux/efi.h
index ff1877145aa4..2483de19c719 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -658,6 +658,12 @@ typedef struct {
 	u64 table;
 } efi_config_table_64_t;
 
+#define EFI_IMAGE_SECURITY_DATABASE_GUID \
+    EFI_GUID(  0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f )
+
+#define EFI_SHIM_LOCK_GUID \
+    EFI_GUID(  0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 )
+
 typedef struct {
 	efi_guid_t guid;
 	u32 table;
diff --git a/init/Kconfig b/init/Kconfig
index e5449d5aeff9..5408c96f6604 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1979,6 +1979,15 @@ config MODULE_SIG_ALL
 comment "Do not forget to sign required modules with scripts/sign-file"
 	depends on MODULE_SIG_FORCE && !MODULE_SIG_ALL
 
+config MODULE_SIG_UEFI
+	bool "Allow modules signed with certs stored in UEFI"
+	depends on MODULE_SIG && SYSTEM_BLACKLIST_KEYRING && EFI
+	select EFI_SIGNATURE_LIST_PARSER
+	help
+	  This will import certificates stored in UEFI and allow modules
+	  signed with those to be loaded.  It will also disallow loading
+	  of modules stored in the UEFI dbx variable.
+
 choice
 	prompt "Which hash algorithm should modules be signed with?"
 	depends on MODULE_SIG
diff --git a/kernel/Makefile b/kernel/Makefile
index e2ec54e2b952..8dab549985d8 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -57,6 +57,7 @@ endif
 obj-$(CONFIG_UID16) += uid16.o
 obj-$(CONFIG_MODULES) += module.o
 obj-$(CONFIG_MODULE_SIG) += module_signing.o
+obj-$(CONFIG_MODULE_SIG_UEFI) += modsign_uefi.o
 obj-$(CONFIG_KALLSYMS) += kallsyms.o
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
 obj-$(CONFIG_KEXEC_CORE) += kexec_core.o
@@ -113,6 +114,8 @@ obj-$(CONFIG_MEMBARRIER) += membarrier.o
 
 obj-$(CONFIG_HAS_IOMEM) += memremap.o
 
+$(obj)/modsign_uefi.o: KBUILD_CFLAGS += -fshort-wchar
+
 $(obj)/configs.o: $(obj)/config_data.h
 
 # config_data.h contains the same information as ikconfig.h but gzipped.
diff --git a/kernel/modsign_uefi.c b/kernel/modsign_uefi.c
new file mode 100644
index 000000000000..fe4a6f2bf10a
--- /dev/null
+++ b/kernel/modsign_uefi.c
@@ -0,0 +1,99 @@
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/cred.h>
+#include <linux/err.h>
+#include <linux/efi.h>
+#include <linux/slab.h>
+#include <keys/asymmetric-type.h>
+#include <keys/system_keyring.h>
+#include "module-internal.h"
+
+static __init void *get_cert_list(efi_char16_t *name, efi_guid_t *guid, unsigned long *size)
+{
+	efi_status_t status;
+	unsigned long lsize = 4;
+	unsigned long tmpdb[4];
+	void *db = NULL;
+
+	status = efi.get_variable(name, guid, NULL, &lsize, &tmpdb);
+	if (status != EFI_BUFFER_TOO_SMALL) {
+		pr_err("Couldn't get size: 0x%lx\n", status);
+		return NULL;
+	}
+
+	db = kmalloc(lsize, GFP_KERNEL);
+	if (!db) {
+		pr_err("Couldn't allocate memory for uefi cert list\n");
+		goto out;
+	}
+
+	status = efi.get_variable(name, guid, NULL, &lsize, db);
+	if (status != EFI_SUCCESS) {
+		kfree(db);
+		db = NULL;
+		pr_err("Error reading db var: 0x%lx\n", status);
+	}
+out:
+	*size = lsize;
+	return db;
+}
+
+/*
+ *  * Load the certs contained in the UEFI databases
+ *   */
+static int __init load_uefi_certs(void)
+{
+	efi_guid_t secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
+	efi_guid_t mok_var = EFI_SHIM_LOCK_GUID;
+	void *db = NULL, *dbx = NULL, *mok = NULL;
+	unsigned long dbsize = 0, dbxsize = 0, moksize = 0;
+	int rc = 0;
+	struct key *keyring = NULL;
+
+	/* Check if SB is enabled and just return if not */
+	if (!efi_enabled(EFI_SECURE_BOOT))
+		return 0;
+
+	keyring = get_system_keyring();
+	if (!keyring) {
+		pr_err("MODSIGN: Couldn't get system keyring\n");
+		return -EINVAL;
+	}
+
+	/* Get db, MokListRT, and dbx.  They might not exist, so it isn't
+	 * an error if we can't get them.
+	 */
+	db = get_cert_list(L"db", &secure_var, &dbsize);
+	if (!db) {
+		pr_err("MODSIGN: Couldn't get UEFI db list\n");
+	} else {
+		rc = parse_efi_signature_list(db, dbsize, keyring);
+		if (rc)
+			pr_err("Couldn't parse db signatures: %d\n", rc);
+		kfree(db);
+	}
+
+	mok = get_cert_list(L"MokListRT", &mok_var, &moksize);
+	if (!mok) {
+		pr_info("MODSIGN: Couldn't get UEFI MokListRT\n");
+	} else {
+		rc = parse_efi_signature_list(mok, moksize, keyring);
+		if (rc)
+			pr_err("Couldn't parse MokListRT signatures: %d\n", rc);
+		kfree(mok);
+	}
+
+	dbx = get_cert_list(L"dbx", &secure_var, &dbxsize);
+	if (!dbx) {
+		pr_info("MODSIGN: Couldn't get UEFI dbx list\n");
+	} else {
+		rc = parse_efi_signature_list(dbx, dbxsize,
+			system_blacklist_keyring);
+		if (rc)
+			pr_err("Couldn't parse dbx signatures: %d\n", rc);
+		kfree(dbx);
+	}
+
+	return rc;
+}
+late_initcall(load_uefi_certs);
-- 
2.5.5