From: Lee, Chun-Yi Date: Tue, 13 Mar 2018 10:38:02 +0000 (+0800) Subject: [PATCH 3/4] MODSIGN: checking the blacklisted hash before loading a kernel module X-Git-Tag: archive/raspbian/6.1.140-1+rpi1^2~61 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=d970cdd7da0de1cb9c0f7f41e301327e722cbb6c;p=linux.git [PATCH 3/4] MODSIGN: checking the blacklisted hash before loading a kernel module 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 Cc: Josh Boyer Cc: James Bottomley Signed-off-by: "Lee, Chun-Yi" [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 --- diff --git a/kernel/module/signing.c b/kernel/module/signing.c index a2ff4242e62..494aa421916 100644 --- a/kernel/module/signing.c +++ b/kernel/module/signing.c @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include #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)