ea38f2f
From 8a4535bcfe24d317be675e53cdc8c61d22fdc7f3 Mon Sep 17 00:00:00 2001
6a91557
From: Josh Boyer <jwboyer@fedoraproject.org>
6a91557
Date: Fri, 26 Oct 2012 12:42:16 -0400
ea38f2f
Subject: [PATCH 18/20] 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
---
42d2805
 certs/system_keyring.c        | 13 ++++++
42d2805
 include/keys/system_keyring.h |  1 +
42d2805
 init/Kconfig                  |  9 ++++
42d2805
 kernel/Makefile               |  3 ++
42d2805
 kernel/modsign_uefi.c         | 99 +++++++++++++++++++++++++++++++++++++++++++
ea38f2f
 5 files changed, 125 insertions(+)
6a91557
 create mode 100644 kernel/modsign_uefi.c
6a91557
42d2805
diff --git a/certs/system_keyring.c b/certs/system_keyring.c
42d2805
index 787eeead2f57..4d9123ed5c07 100644
42d2805
--- a/certs/system_keyring.c
42d2805
+++ b/certs/system_keyring.c
42d2805
@@ -30,6 +30,19 @@ extern __initconst const u8 system_certificate_list[];
42d2805
 extern __initconst const unsigned long system_certificate_list_size;
42d2805
 
42d2805
 /**
42d2805
+ * get_system_keyring - Return a pointer to the system keyring
42d2805
+ *
42d2805
+ */
42d2805
+struct key *get_system_keyring(void)
42d2805
+{
42d2805
+	struct key *system_keyring = NULL;
42d2805
+
42d2805
+	system_keyring = builtin_trusted_keys;
42d2805
+	return system_keyring;
42d2805
+}
42d2805
+EXPORT_SYMBOL_GPL(get_system_keyring);
42d2805
+
42d2805
+/**
42d2805
  * restrict_link_to_builtin_trusted - Restrict keyring addition by built in CA
42d2805
  *
42d2805
  * Restrict the addition of keys into a keyring based on the key-to-be-added
42d2805
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
42d2805
index 5bc291a3d261..56ff5715ab67 100644
42d2805
--- a/include/keys/system_keyring.h
42d2805
+++ b/include/keys/system_keyring.h
42d2805
@@ -36,6 +36,7 @@ extern int restrict_link_by_builtin_and_secondary_trusted(
42d2805
 #ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING
42d2805
 extern struct key *system_blacklist_keyring;
42d2805
 #endif
42d2805
+extern struct key *get_system_keyring(void);
42d2805
 
42d2805
 #ifdef CONFIG_IMA_BLACKLIST_KEYRING
42d2805
 extern struct key *ima_blacklist_keyring;
6a91557
diff --git a/init/Kconfig b/init/Kconfig
ea38f2f
index 461ad575a608..93646fd7b1c8 100644
6a91557
--- a/init/Kconfig
6a91557
+++ b/init/Kconfig
ea38f2f
@@ -2009,6 +2009,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
ea38f2f
index eb26e12c6c2a..e0c2268cb97e 100644
6a91557
--- a/kernel/Makefile
6a91557
+++ b/kernel/Makefile
42d2805
@@ -57,6 +57,7 @@ endif
18c8249
 obj-$(CONFIG_UID16) += uid16.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
d6943bf
 obj-$(CONFIG_KEXEC_CORE) += kexec_core.o
42d2805
@@ -113,6 +114,8 @@ obj-$(CONFIG_MEMBARRIER) += membarrier.o
6a91557
 
18c8249
 obj-$(CONFIG_HAS_IOMEM) += memremap.o
6a91557
 
6a91557
+$(obj)/modsign_uefi.o: KBUILD_CFLAGS += -fshort-wchar
6a91557
+
18c8249
 $(obj)/configs.o: $(obj)/config_data.h
18c8249
 
6a91557
 # config_data.h contains the same information as ikconfig.h but gzipped.
6a91557
diff --git a/kernel/modsign_uefi.c b/kernel/modsign_uefi.c
6a91557
new file mode 100644
42d2805
index 000000000000..fe4a6f2bf10a
6a91557
--- /dev/null
6a91557
+++ b/kernel/modsign_uefi.c
42d2805
@@ -0,0 +1,99 @@
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;
42d2805
+	struct key *keyring = NULL;
6a91557
+
6a91557
+	/* Check if SB is enabled and just return if not */
6a91557
+	if (!efi_enabled(EFI_SECURE_BOOT))
6a91557
+		return 0;
6a91557
+
42d2805
+	keyring = get_system_keyring();
42d2805
+	if (!keyring) {
42d2805
+		pr_err("MODSIGN: Couldn't get system keyring\n");
42d2805
+		return -EINVAL;
42d2805
+	}
42d2805
+
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 {
42d2805
+		rc = parse_efi_signature_list(db, dbsize, 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 {
42d2805
+		rc = parse_efi_signature_list(mok, moksize, 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);
18c8249
-- 
ea38f2f
2.9.3
18c8249