214 lines
6.6 KiB
Diff
214 lines
6.6 KiB
Diff
From 8a4535bcfe24d317be675e53cdc8c61d22fdc7f3 Mon Sep 17 00:00:00 2001
|
|
From: Josh Boyer <jwboyer@fedoraproject.org>
|
|
Date: Fri, 26 Oct 2012 12:42:16 -0400
|
|
Subject: [PATCH 18/20] 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 +
|
|
init/Kconfig | 9 ++++
|
|
kernel/Makefile | 3 ++
|
|
kernel/modsign_uefi.c | 99 +++++++++++++++++++++++++++++++++++++++++++
|
|
5 files changed, 125 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/init/Kconfig b/init/Kconfig
|
|
index 461ad575a608..93646fd7b1c8 100644
|
|
--- a/init/Kconfig
|
|
+++ b/init/Kconfig
|
|
@@ -2009,6 +2009,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 eb26e12c6c2a..e0c2268cb97e 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.9.3
|
|
|