diff --git a/debian/changelog b/debian/changelog index e8546daae..b17f71d9b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1103,6 +1103,9 @@ linux (4.19.37-1) UNRELEASED; urgency=medium [ Luca Boccassi ] * libbpf-dev: generate pkg-config file for libbpf by backporting libbpf-generate-pkg-config.patch from bpf-next. + * Import patches to enable loading keys from UEFI db and MOK from + http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git to + allow kernel modules built by users (eg: by dkms) to be verified. [ Bastian Blank ] * Don't longer recommend irqbalance. (closes: #926967) diff --git a/debian/config/config b/debian/config/config index ec09b3640..26c7a6189 100644 --- a/debian/config/config +++ b/debian/config/config @@ -78,6 +78,11 @@ CONFIG_MODULE_SIG_KEY="" #. Whenever the filename changes, this also needs to be updated in #. debian/featureset-*/config CONFIG_SYSTEM_TRUSTED_KEYS="debian/certs/debian-uefi-certs.pem" +#. Add secondary keyring with keys from UEFI db and MOK. +CONFIG_SECONDARY_TRUSTED_KEYRING=y +CONFIG_SYSTEM_BLACKLIST_KEYRING=y +CONFIG_EFI_SIGNATURE_LIST_PARSER=y +CONFIG_LOAD_UEFI_KEYS=y ## ## file: crypto/Kconfig diff --git a/debian/patches/features/all/db-mok-keyring/0001-KEYS-Allow-unrestricted-boot-time-addition-of-keys-t.patch b/debian/patches/features/all/db-mok-keyring/0001-KEYS-Allow-unrestricted-boot-time-addition-of-keys-t.patch new file mode 100644 index 000000000..69ffb5c04 --- /dev/null +++ b/debian/patches/features/all/db-mok-keyring/0001-KEYS-Allow-unrestricted-boot-time-addition-of-keys-t.patch @@ -0,0 +1,98 @@ +Origin: git://git.kernel.org/pub/scm/linux/kernel/git/jforbes/linux.git +From fd416971ea1b441df3e1922c441d1ed66a4ca1d2 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Fri, 5 May 2017 08:21:56 +0100 +Subject: [PATCH 1/7] KEYS: Allow unrestricted boot-time addition of keys to + secondary keyring + +Allow keys to be added to the system secondary certificates keyring during +kernel initialisation in an unrestricted fashion. Such keys are implicitly +trusted and don't have their trust chains checked on link. + +This allows keys in the UEFI database to be added in secure boot mode for +the purposes of module signing. + +Signed-off-by: David Howells +(cherry picked from commit 40db8fc497d010ae6cee6297c3882d3dc3d76d48 + git://git.kernel.org/pub/scm/linux/kernel/git/jforbes/linux.git) +--- + certs/internal.h | 18 ++++++++++++++++++ + certs/system_keyring.c | 33 +++++++++++++++++++++++++++++++++ + 2 files changed, 51 insertions(+) + create mode 100644 certs/internal.h + +diff --git a/certs/internal.h b/certs/internal.h +new file mode 100644 +index 000000000000..5dcbefb0c23a +--- /dev/null ++++ b/certs/internal.h +@@ -0,0 +1,18 @@ ++/* Internal definitions ++ * ++ * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++/* ++ * system_keyring.c ++ */ ++#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING ++extern void __init add_trusted_secondary_key(const char *source, ++ const void *data, size_t len); ++#endif +diff --git a/certs/system_keyring.c b/certs/system_keyring.c +index 81728717523d..62cd664ea031 100644 +--- a/certs/system_keyring.c ++++ b/certs/system_keyring.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include "internal.h" + + static struct key *builtin_trusted_keys; + #ifdef CONFIG_SECONDARY_TRUSTED_KEYRING +@@ -266,3 +267,35 @@ int verify_pkcs7_signature(const void *data, size_t len, + EXPORT_SYMBOL_GPL(verify_pkcs7_signature); + + #endif /* CONFIG_SYSTEM_DATA_VERIFICATION */ ++ ++#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING ++/** ++ * add_trusted_secondary_key - Add to secondary keyring with no validation ++ * @source: Source of key ++ * @data: The blob holding the key ++ * @len: The length of the data blob ++ * ++ * Add a key to the secondary keyring without checking its trust chain. This ++ * is available only during kernel initialisation. ++ */ ++void __init add_trusted_secondary_key(const char *source, ++ const void *data, size_t len) ++{ ++ key_ref_t key; ++ ++ key = key_create_or_update(make_key_ref(secondary_trusted_keys, 1), ++ "asymmetric", ++ NULL, data, len, ++ (KEY_POS_ALL & ~KEY_POS_SETATTR) | ++ KEY_USR_VIEW, ++ KEY_ALLOC_NOT_IN_QUOTA | ++ KEY_ALLOC_BYPASS_RESTRICTION); ++ ++ if (IS_ERR(key)) ++ pr_err("Problem loading %s X.509 certificate (%ld)\n", ++ source, PTR_ERR(key)); ++ else ++ pr_notice("Loaded %s cert '%s' linked to secondary sys keyring\n", ++ source, key_ref_to_ptr(key)->description); ++} ++#endif /* CONFIG_SECONDARY_TRUSTED_KEYRING */ +-- +2.20.1 + diff --git a/debian/patches/features/all/db-mok-keyring/0002-efi-Add-EFI-signature-data-types.patch b/debian/patches/features/all/db-mok-keyring/0002-efi-Add-EFI-signature-data-types.patch new file mode 100644 index 000000000..9138398fe --- /dev/null +++ b/debian/patches/features/all/db-mok-keyring/0002-efi-Add-EFI-signature-data-types.patch @@ -0,0 +1,63 @@ +Origin: git://git.kernel.org/pub/scm/linux/kernel/git/jforbes/linux.git +From 31c5efef25006ae5fc1542e4705e863a98b624b6 Mon Sep 17 00:00:00 2001 +From: Dave Howells +Date: Fri, 5 May 2017 08:21:58 +0100 +Subject: [PATCH 2/7] efi: Add EFI signature data types + +Add the data types that are used for containing hashes, keys and +certificates for cryptographic verification along with their corresponding +type GUIDs. + +Signed-off-by: David Howells +(cherry picked from commit 446e0e29d7d53fe7786d33603df5a6682dd00c12 + git://git.kernel.org/pub/scm/linux/kernel/git/jforbes/linux.git) +--- + include/linux/efi.h | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/include/linux/efi.h b/include/linux/efi.h +index 401e4b254e30..99cba6fe1234 100644 +--- a/include/linux/efi.h ++++ b/include/linux/efi.h +@@ -663,6 +663,10 @@ void efi_native_runtime_setup(void); + #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) + ++#define EFI_CERT_SHA256_GUID EFI_GUID(0xc1c41626, 0x504c, 0x4092, 0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28) ++#define EFI_CERT_X509_GUID EFI_GUID(0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72) ++#define EFI_CERT_X509_SHA256_GUID EFI_GUID(0x3bd2a492, 0x96c0, 0x4079, 0xb4, 0x20, 0xfc, 0xf9, 0x8e, 0xf1, 0x03, 0xed) ++ + /* + * This GUID is used to pass to the kernel proper the struct screen_info + * structure that was populated by the stub based on the GOP protocol instance +@@ -933,6 +937,27 @@ typedef struct { + efi_memory_desc_t entry[0]; + } efi_memory_attributes_table_t; + ++typedef struct { ++ efi_guid_t signature_owner; ++ u8 signature_data[]; ++} efi_signature_data_t; ++ ++typedef struct { ++ efi_guid_t signature_type; ++ u32 signature_list_size; ++ u32 signature_header_size; ++ u32 signature_size; ++ u8 signature_header[]; ++ /* efi_signature_data_t signatures[][] */ ++} efi_signature_list_t; ++ ++typedef u8 efi_sha256_hash_t[32]; ++ ++typedef struct { ++ efi_sha256_hash_t to_be_signed_hash; ++ efi_time_t time_of_revocation; ++} efi_cert_x509_sha256_t; ++ + /* + * All runtime access to EFI goes through this structure: + */ +-- +2.20.1 + diff --git a/debian/patches/features/all/db-mok-keyring/0003-efi-Add-an-EFI-signature-blob-parser.patch b/debian/patches/features/all/db-mok-keyring/0003-efi-Add-an-EFI-signature-blob-parser.patch new file mode 100644 index 000000000..152c907c7 --- /dev/null +++ b/debian/patches/features/all/db-mok-keyring/0003-efi-Add-an-EFI-signature-blob-parser.patch @@ -0,0 +1,200 @@ +Origin: git://git.kernel.org/pub/scm/linux/kernel/git/jforbes/linux.git +From b0cea6fe6d97f4fa3ac2dbddd54b79d74045c670 Mon Sep 17 00:00:00 2001 +From: Dave Howells +Date: Fri, 5 May 2017 08:21:58 +0100 +Subject: [PATCH 3/7] efi: Add an EFI signature blob parser + +Add a function to parse an EFI signature blob looking for elements of +interest. A list is made up of a series of sublists, where all the +elements in a sublist are of the same type, but sublists can be of +different types. + +For each sublist encountered, the function pointed to by the +get_handler_for_guid argument is called with the type specifier GUID and +returns either a pointer to a function to handle elements of that type or +NULL if the type is not of interest. + +If the sublist is of interest, each element is passed to the handler +function in turn. + +Signed-off-by: David Howells +(cherry picked from commit 41a595bb0dc097c19ad377a0c32c993234aa2525 + git://git.kernel.org/pub/scm/linux/kernel/git/jforbes/linux.git) +--- + certs/Kconfig | 8 ++++ + certs/Makefile | 1 + + certs/efi_parser.c | 112 ++++++++++++++++++++++++++++++++++++++++++++ + include/linux/efi.h | 9 ++++ + 4 files changed, 130 insertions(+) + create mode 100644 certs/efi_parser.c + +diff --git a/certs/Kconfig b/certs/Kconfig +index c94e93d8bccf..650ffcb8db79 100644 +--- a/certs/Kconfig ++++ b/certs/Kconfig +@@ -83,4 +83,12 @@ config SYSTEM_BLACKLIST_HASH_LIST + wrapper to incorporate the list into the kernel. Each should + be a string of hex digits. + ++config EFI_SIGNATURE_LIST_PARSER ++ bool "EFI signature list parser" ++ depends on EFI ++ select X509_CERTIFICATE_PARSER ++ help ++ This option provides support for parsing EFI signature lists for ++ X.509 certificates and turning them into keys. ++ + endmenu +diff --git a/certs/Makefile b/certs/Makefile +index 5d0999b9e21b..7e5e179ac685 100644 +--- a/certs/Makefile ++++ b/certs/Makefile +@@ -10,6 +10,7 @@ obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist_hashes.o + else + obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist_nohashes.o + endif ++obj-$(CONFIG_EFI_SIGNATURE_LIST_PARSER) += efi_parser.o + + ifeq ($(CONFIG_SYSTEM_TRUSTED_KEYRING),y) + +diff --git a/certs/efi_parser.c b/certs/efi_parser.c +new file mode 100644 +index 000000000000..4e396f98f5c7 +--- /dev/null ++++ b/certs/efi_parser.c +@@ -0,0 +1,112 @@ ++/* EFI signature/key/certificate list parser ++ * ++ * Copyright (C) 2012, 2016 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#define pr_fmt(fmt) "EFI: "fmt ++#include ++#include ++#include ++#include ++ ++/** ++ * parse_efi_signature_list - Parse an EFI signature list for certificates ++ * @source: The source of the key ++ * @data: The data blob to parse ++ * @size: The size of the data blob ++ * @get_handler_for_guid: Get the handler func for the sig type (or NULL) ++ * ++ * Parse an EFI signature list looking for elements of interest. A list is ++ * made up of a series of sublists, where all the elements in a sublist are of ++ * the same type, but sublists can be of different types. ++ * ++ * For each sublist encountered, the @get_handler_for_guid function is called ++ * with the type specifier GUID and returns either a pointer to a function to ++ * handle elements of that type or NULL if the type is not of interest. ++ * ++ * If the sublist is of interest, each element is passed to the handler ++ * function in turn. ++ * ++ * Error EBADMSG is returned if the list doesn't parse correctly and 0 is ++ * returned if the list was parsed correctly. No error can be returned from ++ * the @get_handler_for_guid function or the element handler function it ++ * returns. ++ */ ++int __init parse_efi_signature_list( ++ const char *source, ++ const void *data, size_t size, ++ efi_element_handler_t (*get_handler_for_guid)(const efi_guid_t *)) ++{ ++ efi_element_handler_t handler; ++ unsigned offs = 0; ++ ++ pr_devel("-->%s(,%zu)\n", __func__, size); ++ ++ while (size > 0) { ++ const efi_signature_data_t *elem; ++ efi_signature_list_t list; ++ size_t lsize, esize, hsize, elsize; ++ ++ if (size < sizeof(list)) ++ return -EBADMSG; ++ ++ memcpy(&list, data, sizeof(list)); ++ pr_devel("LIST[%04x] guid=%pUl ls=%x hs=%x ss=%x\n", ++ offs, ++ list.signature_type.b, list.signature_list_size, ++ list.signature_header_size, list.signature_size); ++ ++ lsize = list.signature_list_size; ++ hsize = list.signature_header_size; ++ esize = list.signature_size; ++ elsize = lsize - sizeof(list) - hsize; ++ ++ if (lsize > size) { ++ pr_devel("<--%s() = -EBADMSG [overrun @%x]\n", ++ __func__, offs); ++ return -EBADMSG; ++ } ++ ++ if (lsize < sizeof(list) || ++ lsize - sizeof(list) < hsize || ++ esize < sizeof(*elem) || ++ elsize < esize || ++ elsize % esize != 0) { ++ pr_devel("- bad size combo @%x\n", offs); ++ return -EBADMSG; ++ } ++ ++ handler = get_handler_for_guid(&list.signature_type); ++ if (!handler) { ++ data += lsize; ++ size -= lsize; ++ offs += lsize; ++ continue; ++ } ++ ++ data += sizeof(list) + hsize; ++ size -= sizeof(list) + hsize; ++ offs += sizeof(list) + hsize; ++ ++ for (; elsize > 0; elsize -= esize) { ++ elem = data; ++ ++ pr_devel("ELEM[%04x]\n", offs); ++ handler(source, ++ &elem->signature_data, ++ esize - sizeof(*elem)); ++ ++ data += esize; ++ size -= esize; ++ offs += esize; ++ } ++ } ++ ++ return 0; ++} +diff --git a/include/linux/efi.h b/include/linux/efi.h +index 99cba6fe1234..2016145e2d6d 100644 +--- a/include/linux/efi.h ++++ b/include/linux/efi.h +@@ -1138,6 +1138,15 @@ extern int efi_memattr_apply_permissions(struct mm_struct *mm, + char * __init efi_md_typeattr_format(char *buf, size_t size, + const efi_memory_desc_t *md); + ++ ++typedef void (*efi_element_handler_t)(const char *source, ++ const void *element_data, ++ size_t element_size); ++extern int __init parse_efi_signature_list( ++ const char *source, ++ const void *data, size_t size, ++ efi_element_handler_t (*get_handler_for_guid)(const efi_guid_t *)); ++ + /** + * efi_range_is_wc - check the WC bit on an address range + * @start: starting kvirt address +-- +2.20.1 + diff --git a/debian/patches/features/all/db-mok-keyring/0004-MODSIGN-Import-certificates-from-UEFI-Secure-Boot.patch b/debian/patches/features/all/db-mok-keyring/0004-MODSIGN-Import-certificates-from-UEFI-Secure-Boot.patch new file mode 100644 index 000000000..c6628a592 --- /dev/null +++ b/debian/patches/features/all/db-mok-keyring/0004-MODSIGN-Import-certificates-from-UEFI-Secure-Boot.patch @@ -0,0 +1,249 @@ +Origin: git://git.kernel.org/pub/scm/linux/kernel/git/jforbes/linux.git +From 3f74625c50a48b870c7312459d30701b6758b9a3 Mon Sep 17 00:00:00 2001 +From: Josh Boyer +Date: Fri, 5 May 2017 08:21:59 +0100 +Subject: [PATCH 4/7] 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. + +Secure Boot also 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 and +forbid the use within the kernel of any key with a matching hash. + +This facility is enabled by setting CONFIG_LOAD_UEFI_KEYS. + +Signed-off-by: Josh Boyer +Signed-off-by: David Howells +(cherry picked from commit 7b7aae2efea13b5a7b80305856c28f235ea8b2fa + git://git.kernel.org/pub/scm/linux/kernel/git/jforbes/linux.git) +--- + certs/Kconfig | 16 +++++ + certs/Makefile | 4 ++ + certs/load_uefi.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 188 insertions(+) + create mode 100644 certs/load_uefi.c + +diff --git a/certs/Kconfig b/certs/Kconfig +index 650ffcb8db79..548859925c1f 100644 +--- a/certs/Kconfig ++++ b/certs/Kconfig +@@ -91,4 +91,20 @@ config EFI_SIGNATURE_LIST_PARSER + This option provides support for parsing EFI signature lists for + X.509 certificates and turning them into keys. + ++config LOAD_UEFI_KEYS ++ bool "Load certs and blacklist from UEFI db for module checking" ++ depends on SYSTEM_BLACKLIST_KEYRING ++ depends on SECONDARY_TRUSTED_KEYRING ++ depends on EFI ++ depends on EFI_SIGNATURE_LIST_PARSER ++ help ++ If the kernel is booted in secure boot mode, this option will cause ++ the kernel to load the certificates from the UEFI db and MokListRT ++ into the secondary trusted keyring. It will also load any X.509 ++ SHA256 hashes in the dbx list into the blacklist. ++ ++ The effect of this is that, if the kernel is booted in secure boot ++ mode, modules signed with UEFI-stored keys will be permitted to be ++ loaded and keys that match the blacklist will be rejected. ++ + endmenu +diff --git a/certs/Makefile b/certs/Makefile +index 7e5e179ac685..3f127ac80740 100644 +--- a/certs/Makefile ++++ b/certs/Makefile +@@ -12,6 +12,10 @@ obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist_nohashes.o + endif + obj-$(CONFIG_EFI_SIGNATURE_LIST_PARSER) += efi_parser.o + ++obj-$(CONFIG_LOAD_UEFI_KEYS) += load_uefi.o ++$(obj)/load_uefi.o: KBUILD_CFLAGS += -fshort-wchar ++ ++ + ifeq ($(CONFIG_SYSTEM_TRUSTED_KEYRING),y) + + $(eval $(call config_filename,SYSTEM_TRUSTED_KEYS)) +diff --git a/certs/load_uefi.c b/certs/load_uefi.c +new file mode 100644 +index 000000000000..b44e464c3ff4 +--- /dev/null ++++ b/certs/load_uefi.c +@@ -0,0 +1,168 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "internal.h" ++ ++static __initdata efi_guid_t efi_cert_x509_guid = EFI_CERT_X509_GUID; ++static __initdata efi_guid_t efi_cert_x509_sha256_guid = EFI_CERT_X509_SHA256_GUID; ++static __initdata efi_guid_t efi_cert_sha256_guid = EFI_CERT_SHA256_GUID; ++ ++/* ++ * Get a certificate list blob from the named EFI variable. ++ */ ++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; ++ ++ 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"); ++ return NULL; ++ } ++ ++ status = efi.get_variable(name, guid, NULL, &lsize, db); ++ if (status != EFI_SUCCESS) { ++ kfree(db); ++ pr_err("Error reading db var: 0x%lx\n", status); ++ return NULL; ++ } ++ ++ *size = lsize; ++ return db; ++} ++ ++/* ++ * Blacklist an X509 TBS hash. ++ */ ++static __init void uefi_blacklist_x509_tbs(const char *source, ++ const void *data, size_t len) ++{ ++ char *hash, *p; ++ ++ hash = kmalloc(4 + len * 2 + 1, GFP_KERNEL); ++ if (!hash) ++ return; ++ p = memcpy(hash, "tbs:", 4); ++ p += 4; ++ bin2hex(p, data, len); ++ p += len * 2; ++ *p = 0; ++ ++ mark_hash_blacklisted(hash); ++ kfree(hash); ++} ++ ++/* ++ * Blacklist the hash of an executable. ++ */ ++static __init void uefi_blacklist_binary(const char *source, ++ const void *data, size_t len) ++{ ++ char *hash, *p; ++ ++ hash = kmalloc(4 + len * 2 + 1, GFP_KERNEL); ++ if (!hash) ++ return; ++ p = memcpy(hash, "bin:", 4); ++ p += 4; ++ bin2hex(p, data, len); ++ p += len * 2; ++ *p = 0; ++ ++ mark_hash_blacklisted(hash); ++ kfree(hash); ++} ++ ++/* ++ * Return the appropriate handler for particular signature list types found in ++ * the UEFI db and MokListRT tables. ++ */ ++static __init efi_element_handler_t get_handler_for_db(const efi_guid_t *sig_type) ++{ ++ if (efi_guidcmp(*sig_type, efi_cert_x509_guid) == 0) ++ return add_trusted_secondary_key; ++ return 0; ++} ++ ++/* ++ * Return the appropriate handler for particular signature list types found in ++ * the UEFI dbx and MokListXRT tables. ++ */ ++static __init efi_element_handler_t get_handler_for_dbx(const efi_guid_t *sig_type) ++{ ++ if (efi_guidcmp(*sig_type, efi_cert_x509_sha256_guid) == 0) ++ return uefi_blacklist_x509_tbs; ++ if (efi_guidcmp(*sig_type, efi_cert_sha256_guid) == 0) ++ return uefi_blacklist_binary; ++ return 0; ++} ++ ++/* ++ * 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; ++ ++ if (!efi.get_variable) ++ return false; ++ ++ /* 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("UEFI:db", ++ db, dbsize, get_handler_for_db); ++ 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("UEFI:MokListRT", ++ mok, moksize, get_handler_for_db); ++ 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("UEFI:dbx", ++ dbx, dbxsize, ++ get_handler_for_dbx); ++ if (rc) ++ pr_err("Couldn't parse dbx signatures: %d\n", rc); ++ kfree(dbx); ++ } ++ ++ return rc; ++} ++late_initcall(load_uefi_certs); +-- +2.20.1 + diff --git a/debian/patches/features/all/db-mok-keyring/0005-MODSIGN-Allow-the-db-UEFI-variable-to-be-suppressed.patch b/debian/patches/features/all/db-mok-keyring/0005-MODSIGN-Allow-the-db-UEFI-variable-to-be-suppressed.patch new file mode 100644 index 000000000..5224bbc77 --- /dev/null +++ b/debian/patches/features/all/db-mok-keyring/0005-MODSIGN-Allow-the-db-UEFI-variable-to-be-suppressed.patch @@ -0,0 +1,91 @@ +Origin: git://git.kernel.org/pub/scm/linux/kernel/git/jforbes/linux.git +From 7defba7cee1c8a882fef24cc9037faab9e546e01 Mon Sep 17 00:00:00 2001 +From: Josh Boyer +Date: Fri, 5 May 2017 08:21:59 +0100 +Subject: [PATCH 5/7] MODSIGN: Allow the "db" UEFI variable to be suppressed + +If a user tells shim to not use the certs/hashes in the UEFI db variable +for verification purposes, shim will set a UEFI variable called +MokIgnoreDB. Have the uefi import code look for this and ignore the db +variable if it is found. + +Signed-off-by: Josh Boyer +Signed-off-by: David Howells +(cherry picked from commit b51ca4e4d6c0c8000789de31a1184a41ac611d33 + git://git.kernel.org/pub/scm/linux/kernel/git/jforbes/linux.git) +--- + certs/load_uefi.c | 44 ++++++++++++++++++++++++++++++++++---------- + 1 file changed, 34 insertions(+), 10 deletions(-) + +diff --git a/certs/load_uefi.c b/certs/load_uefi.c +index b44e464c3ff4..3d8845986019 100644 +--- a/certs/load_uefi.c ++++ b/certs/load_uefi.c +@@ -12,6 +12,26 @@ static __initdata efi_guid_t efi_cert_x509_guid = EFI_CERT_X509_GUID; + static __initdata efi_guid_t efi_cert_x509_sha256_guid = EFI_CERT_X509_SHA256_GUID; + static __initdata efi_guid_t efi_cert_sha256_guid = EFI_CERT_SHA256_GUID; + ++/* ++ * Look to see if a UEFI variable called MokIgnoreDB exists and return true if ++ * it does. ++ * ++ * This UEFI variable is set by the shim if a user tells the shim to not use ++ * the certs/hashes in the UEFI db variable for verification purposes. If it ++ * is set, we should ignore the db variable also and the true return indicates ++ * this. ++ */ ++static __init bool uefi_check_ignore_db(void) ++{ ++ efi_status_t status; ++ unsigned int db = 0; ++ unsigned long size = sizeof(db); ++ efi_guid_t guid = EFI_SHIM_LOCK_GUID; ++ ++ status = efi.get_variable(L"MokIgnoreDB", &guid, NULL, &size, &db); ++ return status == EFI_SUCCESS; ++} ++ + /* + * Get a certificate list blob from the named EFI variable. + */ +@@ -113,7 +133,9 @@ static __init efi_element_handler_t get_handler_for_dbx(const efi_guid_t *sig_ty + } + + /* +- * Load the certs contained in the UEFI databases ++ * Load the certs contained in the UEFI databases into the secondary trusted ++ * keyring and the UEFI blacklisted X.509 cert SHA256 hashes into the blacklist ++ * keyring. + */ + static int __init load_uefi_certs(void) + { +@@ -129,15 +151,17 @@ static int __init load_uefi_certs(void) + /* 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("UEFI:db", +- db, dbsize, get_handler_for_db); +- if (rc) +- pr_err("Couldn't parse db signatures: %d\n", rc); +- kfree(db); ++ if (!uefi_check_ignore_db()) { ++ 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("UEFI:db", ++ db, dbsize, get_handler_for_db); ++ if (rc) ++ pr_err("Couldn't parse db signatures: %d\n", rc); ++ kfree(db); ++ } + } + + mok = get_cert_list(L"MokListRT", &mok_var, &moksize); +-- +2.20.1 + diff --git a/debian/patches/features/all/db-mok-keyring/0006-Make-get_cert_list-not-complain-about-cert-lists-tha.patch b/debian/patches/features/all/db-mok-keyring/0006-Make-get_cert_list-not-complain-about-cert-lists-tha.patch new file mode 100644 index 000000000..420e1304e --- /dev/null +++ b/debian/patches/features/all/db-mok-keyring/0006-Make-get_cert_list-not-complain-about-cert-lists-tha.patch @@ -0,0 +1,112 @@ +Origin: git://git.kernel.org/pub/scm/linux/kernel/git/jforbes/linux.git +From 71be2cb73f4def7903c7fe49babe15c908220ac5 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 2 Oct 2017 18:25:29 -0400 +Subject: [PATCH 6/7] Make get_cert_list() not complain about cert lists that + aren't present. + +Signed-off-by: Peter Jones +(cherry picked from commit 0f4d5c7b49b45e7cf038bb769e33451b78a6445d + git://git.kernel.org/pub/scm/linux/kernel/git/jforbes/linux.git) +--- + certs/load_uefi.c | 37 ++++++++++++++++++++++--------------- + 1 file changed, 22 insertions(+), 15 deletions(-) + +diff --git a/certs/load_uefi.c b/certs/load_uefi.c +index 3d8845986019..9ef34c44fd1b 100644 +--- a/certs/load_uefi.c ++++ b/certs/load_uefi.c +@@ -35,8 +35,8 @@ static __init bool uefi_check_ignore_db(void) + /* + * Get a certificate list blob from the named EFI variable. + */ +-static __init void *get_cert_list(efi_char16_t *name, efi_guid_t *guid, +- unsigned long *size) ++static __init int get_cert_list(efi_char16_t *name, efi_guid_t *guid, ++ unsigned long *size, void **cert_list) + { + efi_status_t status; + unsigned long lsize = 4; +@@ -44,26 +44,33 @@ static __init void *get_cert_list(efi_char16_t *name, efi_guid_t *guid, + void *db; + + status = efi.get_variable(name, guid, NULL, &lsize, &tmpdb); ++ if (status == EFI_NOT_FOUND) { ++ *size = 0; ++ *cert_list = NULL; ++ return 0; ++ } ++ + if (status != EFI_BUFFER_TOO_SMALL) { + pr_err("Couldn't get size: 0x%lx\n", status); +- return NULL; ++ return efi_status_to_err(status); + } + + db = kmalloc(lsize, GFP_KERNEL); + if (!db) { + pr_err("Couldn't allocate memory for uefi cert list\n"); +- return NULL; ++ return -ENOMEM; + } + + status = efi.get_variable(name, guid, NULL, &lsize, db); + if (status != EFI_SUCCESS) { + kfree(db); + pr_err("Error reading db var: 0x%lx\n", status); +- return NULL; ++ return efi_status_to_err(status); + } + + *size = lsize; +- return db; ++ *cert_list = db; ++ return 0; + } + + /* +@@ -152,10 +159,10 @@ static int __init load_uefi_certs(void) + * an error if we can't get them. + */ + if (!uefi_check_ignore_db()) { +- db = get_cert_list(L"db", &secure_var, &dbsize); +- if (!db) { ++ rc = get_cert_list(L"db", &secure_var, &dbsize, &db); ++ if (rc < 0) { + pr_err("MODSIGN: Couldn't get UEFI db list\n"); +- } else { ++ } else if (dbsize != 0) { + rc = parse_efi_signature_list("UEFI:db", + db, dbsize, get_handler_for_db); + if (rc) +@@ -164,10 +171,10 @@ static int __init load_uefi_certs(void) + } + } + +- mok = get_cert_list(L"MokListRT", &mok_var, &moksize); +- if (!mok) { ++ rc = get_cert_list(L"MokListRT", &mok_var, &moksize, &mok); ++ if (rc < 0) { + pr_info("MODSIGN: Couldn't get UEFI MokListRT\n"); +- } else { ++ } else if (moksize != 0) { + rc = parse_efi_signature_list("UEFI:MokListRT", + mok, moksize, get_handler_for_db); + if (rc) +@@ -175,10 +182,10 @@ static int __init load_uefi_certs(void) + kfree(mok); + } + +- dbx = get_cert_list(L"dbx", &secure_var, &dbxsize); +- if (!dbx) { ++ rc = get_cert_list(L"dbx", &secure_var, &dbxsize, &dbx); ++ if (rc < 0) { + pr_info("MODSIGN: Couldn't get UEFI dbx list\n"); +- } else { ++ } else if (dbxsize != 0) { + rc = parse_efi_signature_list("UEFI:dbx", + dbx, dbxsize, + get_handler_for_dbx); +-- +2.20.1 + diff --git a/debian/patches/features/all/db-mok-keyring/0007-modsign-Use-secondary-trust-keyring-for-module-signi.patch b/debian/patches/features/all/db-mok-keyring/0007-modsign-Use-secondary-trust-keyring-for-module-signi.patch new file mode 100644 index 000000000..998fbf84a --- /dev/null +++ b/debian/patches/features/all/db-mok-keyring/0007-modsign-Use-secondary-trust-keyring-for-module-signi.patch @@ -0,0 +1,30 @@ +Origin: git://git.kernel.org/pub/scm/linux/kernel/git/jforbes/linux.git +From 013d7c3f79a2f4df248f69daca9cbf2175788814 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Thu, 3 Aug 2017 16:56:22 +0100 +Subject: [PATCH 7/7] modsign: Use secondary trust keyring for module signing + +Use secondary trust keyring for module signing as that's where the UEFI +keys get stashed. + +Signed-off-by: David Howells +--- + kernel/module_signing.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/kernel/module_signing.c b/kernel/module_signing.c +index f2075ce8e4b3..6b9a926fd86b 100644 +--- a/kernel/module_signing.c ++++ b/kernel/module_signing.c +@@ -83,6 +83,7 @@ int mod_verify_sig(const void *mod, struct load_info *info) + } + + return verify_pkcs7_signature(mod, modlen, mod + modlen, sig_len, +- NULL, VERIFYING_MODULE_SIGNATURE, ++ VERIFY_USE_SECONDARY_KEYRING, ++ VERIFYING_MODULE_SIGNATURE, + NULL, NULL); + } +-- +2.20.1 + diff --git a/debian/patches/series b/debian/patches/series index 603250676..32ced0d13 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -143,6 +143,15 @@ features/all/lockdown/arm64-add-kernel-config-option-to-lock-down-when.patch # until the "kernel_lockdown.7" manual page exists features/all/lockdown/lockdown-refer-to-debian-wiki-until-manual-page-exists.patch +# load db and MOK keys into secondary keyring for kernel modules verification +features/all/db-mok-keyring/0001-KEYS-Allow-unrestricted-boot-time-addition-of-keys-t.patch +features/all/db-mok-keyring/0002-efi-Add-EFI-signature-data-types.patch +features/all/db-mok-keyring/0003-efi-Add-an-EFI-signature-blob-parser.patch +features/all/db-mok-keyring/0004-MODSIGN-Import-certificates-from-UEFI-Secure-Boot.patch +features/all/db-mok-keyring/0005-MODSIGN-Allow-the-db-UEFI-variable-to-be-suppressed.patch +features/all/db-mok-keyring/0006-Make-get_cert_list-not-complain-about-cert-lists-tha.patch +features/all/db-mok-keyring/0007-modsign-Use-secondary-trust-keyring-for-module-signi.patch + # Security fixes debian/i386-686-pae-pci-set-pci-nobios-by-default.patch bugfix/all/xen-pciback-Don-t-disable-PCI_COMMAND-on-PCI-device-.patch