From: "Lee, Chun-Yi" Date: Tue, 13 Mar 2018 18:38:02 +0800 Subject: [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] --- kernel/module/signing.c | 59 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) --- 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 @@ 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 @@ 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 @@ 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)