130 lines
3.5 KiB
Diff
130 lines
3.5 KiB
Diff
From: "Lee, Chun-Yi" <joeyli.kernel@gmail.com>
|
|
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 <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]
|
|
---
|
|
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 @@h
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/errno.h>
|
|
+#include <linux/module.h>
|
|
#include <linux/string.h>
|
|
#include <linux/verification.h>
|
|
#include <crypto/public_key.h>
|
|
+#include <crypto/hash.h>
|
|
+#include <keys/system_keyring.h>
|
|
#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;
|
|
}
|