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 <[email protected]>
---
 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
[email protected]
https://admin.fedoraproject.org/mailman/listinfo/kernel

Reply via email to