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] --- kernel/module_signing.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/kernel/module_signing.c b/kernel/module_signing.c index d3d6f95..d30ac74 100644 --- a/kernel/module_signing.c +++ b/kernel/module_signing.c @@ -11,9 +11,12 @@ #include #include +#include #include #include #include +#include +#include #include "module-internal.h" enum pkey_id_type { @@ -42,19 +45,67 @@ __be32 sig_len; /* Length of signature data */ }; +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 = 0; + + tfm = crypto_alloc_shash("sha256", 0, 0); + if (IS_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; + desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; + 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, "bin"); + 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); if (modlen <= sizeof(ms)) return -EBADMSG; + wholelen = modlen + sizeof(MODULE_SIG_STRING) - 1; memcpy(&ms, mod + (modlen - sizeof(ms)), sizeof(ms)); modlen -= sizeof(ms); @@ -82,8 +133,15 @@ return -EBADMSG; } - 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; }