From 8a4535bcfe24d317be675e53cdc8c61d22fdc7f3 Mon Sep 17 00:00:00 2001 From: Josh Boyer 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 --- 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 +#include +#include +#include +#include +#include +#include +#include +#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