This patch add the support to load blacklisted hash or public key from MOKx that's maintained by bootloader. v2: + The hash type need the same with CONFIG_MODULE_SIG_HASH. + Handle the return value of func() + Move the logic of parsing EFI signature database to parse_efi_signature_db() for collecting certificates and hashes. + Still parsing hashes when signature parsing fail on MOKx. Signed-off-by: Lee, Chun-Yi <jlee@xxxxxxxx> --- include/linux/efi.h | 12 ++++ kernel/modsign_uefi.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 160 insertions(+), 2 deletions(-) Index: linux-3.12-SLE12/include/linux/efi.h =================================================================== --- linux-3.12-SLE12.orig/include/linux/efi.h +++ linux-3.12-SLE12/include/linux/efi.h @@ -392,6 +392,18 @@ typedef efi_status_t efi_query_variable_ #define EFI_CERT_SHA256_GUID \ EFI_GUID( 0xc1c41626, 0x504c, 0x4092, 0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28 ) +#define EFI_CERT_SHA1_GUID \ + EFI_GUID( 0x826ca512, 0xcf10, 0x4ac9, 0xb1, 0x87, 0xbe, 0x1, 0x49, 0x66, 0x31, 0xbd ) + +#define EFI_CERT_SHA512_GUID \ + EFI_GUID( 0x93e0fae, 0xa6c4, 0x4f50, 0x9f, 0x1b, 0xd4, 0x1e, 0x2b, 0x89, 0xc1, 0x9a ) + +#define EFI_CERT_SHA224_GUID \ + EFI_GUID( 0xb6e5233, 0xa65c, 0x44c9, 0x94, 0x7, 0xd9, 0xab, 0x83, 0xbf, 0xc8, 0xbd ) + +#define EFI_CERT_SHA384_GUID \ + EFI_GUID( 0xff3e5307, 0x9fd0, 0x48c9, 0x85, 0xf1, 0x8a, 0xd5, 0x6c, 0x70, 0x1e, 0x1 ) + #define EFI_CERT_X509_GUID \ EFI_GUID( 0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72 ) @@ -632,6 +644,10 @@ extern struct efi_memory_map memmap; struct key; extern int __init parse_efi_signature_list(const void *data, size_t size, struct key *keyring); +extern int __init parse_efi_signature_db(const void *data, size_t size, + struct key *keyring, efi_guid_t efi_cert_guid, + int (*func)(efi_guid_t, const efi_signature_data_t *, + size_t esize, struct key *keyring)); /** * efi_range_is_wc - check the WC bit on an address range Index: linux-3.12-SLE12/kernel/modsign_uefi.c =================================================================== --- linux-3.12-SLE12.orig/kernel/modsign_uefi.c +++ linux-3.12-SLE12/kernel/modsign_uefi.c @@ -4,10 +4,27 @@ #include <linux/err.h> #include <linux/efi.h> #include <linux/slab.h> +#include <crypto/public_key.h> #include <keys/asymmetric-type.h> #include <keys/system_keyring.h> #include "module-internal.h" +struct efi_hash_type { + u8 hash; /* Hash algorithm [enum pkey_hash_algo] */ + efi_guid_t efi_cert_guid; /* EFI_CERT_*_GUID */ + char *hash_name; /* nams string of hash */ + size_t size; /* size of hash */ +}; + +static const struct efi_hash_type efi_hash_types[] = { + {PKEY_HASH_SHA256, EFI_CERT_SHA256_GUID, "sha256", 32}, + {PKEY_HASH_SHA1, EFI_CERT_SHA1_GUID, "sha1", 20}, + {PKEY_HASH_SHA512, EFI_CERT_SHA512_GUID, "sha512", 64}, + {PKEY_HASH_SHA224, EFI_CERT_SHA224_GUID, "sha224", 28}, + {PKEY_HASH_SHA384, EFI_CERT_SHA384_GUID, "sha384", 48}, + {PKEY_HASH__LAST} +}; + static __init int check_ignore_db(void) { efi_status_t status; @@ -55,6 +72,68 @@ out: return db; } +static int __init signature_blacklist_func(efi_guid_t efi_cert_guid, + const efi_signature_data_t *elem, size_t esize, + struct key *keyring) +{ + struct module_hash *module_hash = NULL; + int i; + + for (i = 0; efi_hash_types[i].hash < PKEY_HASH__LAST; i++) { + struct efi_hash_type type = efi_hash_types[i]; + + if (efi_guidcmp(efi_cert_guid, type.efi_cert_guid) != 0) + continue; + + if (strcmp(type.hash_name, CONFIG_MODULE_SIG_HASH)) { + pr_err("Hash type is %s not %s: %*phN\n", + type.hash_name, CONFIG_MODULE_SIG_HASH, + (int)type.size, elem->signature_data); + return -ENOTSUPP; + } + + module_hash = kzalloc(sizeof(*module_hash) + type.size, GFP_KERNEL); + if (!module_hash) { + pr_err("module hash allocate fail\n"); + return -ENOMEM; + } + module_hash->hash = type.hash; + module_hash->hash_name = type.hash_name; + module_hash->size = type.size; + memcpy(module_hash->hash_data, elem->signature_data, type.size); + } + + if (!module_hash) { + pr_err("Problem loading hash of blacklisted module: %pUb\n", + &efi_cert_guid); + return -ENOTSUPP; + } else { + pr_notice("Loaded %s hash %*phN to blacklisted modules\n", + module_hash->hash_name, (int) module_hash->size, + module_hash->hash_data); + } + + list_add(&module_hash->list, &module_hash_blacklist); + + return 0; +} + +static int __init parse_efi_signature_list_hashs(const void *data, size_t size) +{ + int i, rc = 0; + + for (i = 0; !rc && efi_hash_types[i].hash < PKEY_HASH__LAST; i++) { + struct efi_hash_type type = efi_hash_types[i]; + rc = parse_efi_signature_db(data, size, NULL, + type.efi_cert_guid, signature_blacklist_func); + if (rc) + pr_err("Couldn't parse signatures of %s hash: %d\n", + type.hash_name, rc); + } + + return rc; +} + /* * * Load the certs contained in the UEFI databases * */ @@ -62,8 +141,8 @@ 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; + void *db = NULL, *dbx = NULL, *mok = NULL, *mokx = NULL; + unsigned long dbsize = 0, dbxsize = 0, moksize = 0, mokxsize = 0; int ignore_db, rc = 0; /* Check if SB is enabled and just return if not */ @@ -109,6 +188,20 @@ static int __init load_uefi_certs(void) kfree(dbx); } + mokx = get_cert_list(L"MokListXRT", &mok_var, &mokxsize); + if (!mokx) { + pr_info("MODSIGN: Couldn't get UEFI MokListXRT\n"); + } else { + rc = parse_efi_signature_list(mokx, mokxsize, + system_blacklist_keyring); + if (rc) + pr_err("Couldn't parse MokListXRT signatures: %d\n", rc); + rc = parse_efi_signature_list_hashs(mokx, mokxsize); + if (rc) + pr_err("Couldn't parse MokListXRT hashes: %d\n", rc); + kfree(mokx); + } + return rc; } late_initcall(load_uefi_certs); Index: linux-3.12-SLE12/crypto/asymmetric_keys/efi_parser.c =================================================================== --- linux-3.12-SLE12.orig/crypto/asymmetric_keys/efi_parser.c +++ linux-3.12-SLE12/crypto/asymmetric_keys/efi_parser.c @@ -18,13 +18,38 @@ static __initdata efi_guid_t efi_cert_x509_guid = EFI_CERT_X509_GUID; -/** - * parse_efi_signature_list - Parse an EFI signature list for certificates - * @data: The data blob to parse - * @size: The size of the data blob - * @keyring: The keyring to add extracted keys to - */ -int __init parse_efi_signature_list(const void *data, size_t size, struct key *keyring) +static int __init signature_certificates_func(efi_guid_t efi_cert_guid, + const efi_signature_data_t *elem, size_t esize, + struct key *keyring) +{ + key_ref_t key; + + key = key_create_or_update( + make_key_ref(keyring, 1), + "asymmetric", + NULL, + &elem->signature_data, + esize - sizeof(*elem), + (KEY_POS_ALL & ~KEY_POS_SETATTR) | + KEY_USR_VIEW, + KEY_ALLOC_NOT_IN_QUOTA | + KEY_ALLOC_TRUSTED); + + if (IS_ERR(key)) + pr_err("Problem loading in-kernel X.509 certificate (%ld)\n", + PTR_ERR(key)); + else + pr_notice("Loaded cert '%s' linked to '%s'\n", + key_ref_to_ptr(key)->description, + keyring->description); + + return 0; +} + +int parse_efi_signature_db(const void *data, size_t size, struct key *keyring, + efi_guid_t efi_cert_guid, + int (*func)(efi_guid_t, const efi_signature_data_t *, + size_t esize, struct key *keyring)) { unsigned offs = 0; size_t lsize, esize, hsize, elsize; @@ -34,7 +59,6 @@ int __init parse_efi_signature_list(cons while (size > 0) { efi_signature_list_t list; const efi_signature_data_t *elem; - key_ref_t key; if (size < sizeof(list)) return -EBADMSG; @@ -64,7 +88,7 @@ int __init parse_efi_signature_list(cons return -EBADMSG; } - if (efi_guidcmp(list.signature_type, efi_cert_x509_guid) != 0) { + if (efi_guidcmp(list.signature_type, efi_cert_guid) != 0) { data += lsize; size -= lsize; offs += lsize; @@ -76,28 +100,13 @@ int __init parse_efi_signature_list(cons offs += sizeof(list) + hsize; for (; elsize > 0; elsize -= esize) { + int ret = 0; elem = data; pr_devel("ELEM[%04x]\n", offs); - - key = key_create_or_update( - make_key_ref(keyring, 1), - "asymmetric", - NULL, - &elem->signature_data, - esize - sizeof(*elem), - (KEY_POS_ALL & ~KEY_POS_SETATTR) | - KEY_USR_VIEW, - KEY_ALLOC_NOT_IN_QUOTA | - KEY_ALLOC_TRUSTED); - - if (IS_ERR(key)) - pr_err("Problem loading in-kernel X.509 certificate (%ld)\n", - PTR_ERR(key)); - else - pr_notice("Loaded cert '%s' linked to '%s'\n", - key_ref_to_ptr(key)->description, - keyring->description); + ret = func(efi_cert_guid, elem, esize, keyring); + if (ret && ret != -ENOTSUPP) + return ret; data += esize; size -= esize; @@ -107,3 +116,18 @@ int __init parse_efi_signature_list(cons return 0; } + +/** + * parse_efi_signature_list - Parse an EFI signature list for certificates or hashs + * @data: The data blob to parse + * @size: The size of the data blob + * @keyring: The keyring to add extracted keys to + */ +int __init parse_efi_signature_list(const void *data, size_t size, + struct key *keyring) +{ + + parse_efi_signature_db(data, size, keyring, efi_cert_x509_guid, + signature_certificates_func); + return 0; +} _______________________________________________ kernel mailing list kernel@xxxxxxxxxxxxxxxxxxxxxxx https://admin.fedoraproject.org/mailman/listinfo/kernel