[PATCH 3/4] MODSIGN: checking the blacklisted hash before loading a kernel module
authorLee, Chun-Yi <joeyli.kernel@gmail.com>
Tue, 13 Mar 2018 10:38:02 +0000 (18:38 +0800)
committerSalvatore Bonaccorso <carnil@debian.org>
Thu, 22 May 2025 18:32:07 +0000 (20:32 +0200)
Origin: https://lore.kernel.org/patchwork/patch/933175/

This patch adds the logic for checking the kernel module's hash
base on blacklist. The hash must be generated by sha256 and enrolled
to dbx/mokx.

For example:
sha256sum sample.ko
mokutil --mokx --import-hash $HASH_RESULT

Whether the signature on ko file is stripped or not, the hash can be
compared by kernel.

Cc: David Howells <dhowells@redhat.com>
Cc: Josh Boyer <jwboyer@fedoraproject.org>
Cc: James Bottomley <James.Bottomley@HansenPartnership.com>
Signed-off-by: "Lee, Chun-Yi" <jlee@suse.com>
[Rebased by Luca Boccassi]
[bwh: Forward-ported to 5.19:
 - The type parameter to is_hash_blacklisted() is now an enumeration
   rather than a string
 - Adjust filename, context]

Gbp-Pq: Topic features/all/db-mok-keyring
Gbp-Pq: Name 0003-MODSIGN-checking-the-blacklisted-hash-before-loading-a-kernel-module.patch

kernel/module/signing.c

index a2ff4242e623d5d4e87d2f3d139d8620fb937579..494aa421916aec04dfb0ca967aa80a087fd55d74 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/verification.h>
 #include <linux/security.h>
 #include <crypto/public_key.h>
+#include <crypto/hash.h>
+#include <keys/system_keyring.h>
 #include <uapi/linux/module.h>
 #include "internal.h"
 
@@ -37,13 +39,60 @@ void set_module_sig_enforced(void)
        sig_enforce = true;
 }
 
+static int mod_is_hash_blacklisted(const void *mod, size_t verifylen)
+{
+       struct crypto_shash *tfm;
+       struct shash_desc *desc;
+       size_t digest_size, desc_size;
+       u8 *digest;
+       int ret;
+
+       tfm = crypto_alloc_shash("sha256", 0, 0);
+       if (IS_ERR(tfm)) {
+               ret = PTR_ERR(tfm);
+               goto error_return;
+       }
+
+       desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
+       digest_size = crypto_shash_digestsize(tfm);
+       digest = kzalloc(digest_size + desc_size, GFP_KERNEL);
+       if (!digest) {
+               pr_err("digest memory buffer allocate fail\n");
+               ret = -ENOMEM;
+               goto error_digest;
+       }
+       desc = (void *)digest + digest_size;
+       desc->tfm = tfm;
+       ret = crypto_shash_init(desc);
+       if (ret < 0)
+               goto error_shash;
+
+       ret = crypto_shash_finup(desc, mod, verifylen, digest);
+       if (ret < 0)
+               goto error_shash;
+
+       pr_debug("%ld digest: %*phN\n", verifylen, (int) digest_size, digest);
+
+       ret = is_hash_blacklisted(digest, digest_size, BLACKLIST_HASH_BINARY);
+       if (ret == -EKEYREJECTED)
+               pr_err("Module hash %*phN is blacklisted\n",
+                      (int) digest_size, digest);
+
+error_shash:
+       kfree(digest);
+error_digest:
+       crypto_free_shash(tfm);
+error_return:
+       return ret;
+}
+
 /*
  * Verify the signature on a module.
  */
 int mod_verify_sig(const void *mod, struct load_info *info)
 {
        struct module_signature ms;
-       size_t sig_len, modlen = info->len;
+       size_t sig_len, modlen = info->len, wholelen;
        int ret;
 
        pr_devel("==>%s(,%zu)\n", __func__, modlen);
@@ -51,6 +100,7 @@ int mod_verify_sig(const void *mod, struct load_info *info)
        if (modlen <= sizeof(ms))
                return -EBADMSG;
 
+       wholelen = modlen + sizeof(MODULE_SIG_STRING) - 1;
        memcpy(&ms, mod + (modlen - sizeof(ms)), sizeof(ms));
 
        ret = mod_check_sig(&ms, modlen, "module");
@@ -61,10 +111,17 @@ int mod_verify_sig(const void *mod, struct load_info *info)
        modlen -= sig_len + sizeof(ms);
        info->len = modlen;
 
-       return verify_pkcs7_signature(mod, modlen, mod + modlen, sig_len,
+       ret = verify_pkcs7_signature(mod, modlen, mod + modlen, sig_len,
                                      VERIFY_USE_SECONDARY_KEYRING,
                                      VERIFYING_MODULE_SIGNATURE,
                                      NULL, NULL);
+       pr_devel("verify_pkcs7_signature() = %d\n", ret);
+
+       /* checking hash of module is in blacklist */
+       if (!ret)
+               ret = mod_is_hash_blacklisted(mod, wholelen);
+
+       return ret;
 }
 
 int module_sig_check(struct load_info *info, int flags)