[PATCH v2 1/2] MODSIGN: check hash of kernel module in blacklist

Lee, Chun-Yi joeyli.kernel at gmail.com
Tue Feb 4 16:41:06 UTC 2014


This patch introduces a blacklist list of kernel module's hash. It check
the blacklist before checking kernel module signature.
It didn't limit what hash algorithm used but the module of hash algorithm
need build-in or put in initrd for verify kernel module in initrd.

v2:
 + Use the digest generated by mod_make_digest() to avoid computing the hash twice.
 + Also check the hash of whole module file is not in the module hash blacklist.
 + Change the statements of information log.

Signed-off-by: Lee, Chun-Yi <jlee at suse.com>
---
 kernel/module-internal.h |   14 ++++++++
 kernel/module.c          |    9 +++++-
 kernel/module_signing.c  |   79 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 101 insertions(+), 1 deletions(-)

Index: linux-3.12-SLE12/kernel/module-internal.h
===================================================================
--- linux-3.12-SLE12.orig/kernel/module-internal.h
+++ linux-3.12-SLE12/kernel/module-internal.h
@@ -9,4 +9,17 @@
  * 2 of the Licence, or (at your option) any later version.
  */
 
+/*
+ * Module hash.
+ */
+struct module_hash {
+	struct list_head list;  /* list of all hashs */
+	u8 hash;                /* Hash algorithm [enum pkey_hash_algo] */
+	char *hash_name;        /* nams string of hash */
+	size_t size;            /* size of hash */
+	u8 hash_data[];         /* Hash data */
+};
+
+extern struct list_head module_hash_blacklist;
+
 extern int mod_verify_sig(const void *mod, unsigned long *_modlen);
Index: linux-3.12-SLE12/kernel/module_signing.c
===================================================================
--- linux-3.12-SLE12.orig/kernel/module_signing.c
+++ linux-3.12-SLE12/kernel/module_signing.c
@@ -11,12 +11,15 @@
 
 #include <linux/kernel.h>
 #include <linux/err.h>
+#include <linux/module.h>
 #include <crypto/public_key.h>
 #include <crypto/hash.h>
 #include <keys/asymmetric-type.h>
 #include <keys/system_keyring.h>
 #include "module-internal.h"
 
+LIST_HEAD(module_hash_blacklist);
+
 /*
  * Module signature information block.
  *
@@ -193,6 +196,82 @@ static struct key *request_asymmetric_ke
 	return key_ref_to_ptr(key);
 }
 
+static int check_blacklist(const char *hash_algo_name, const void *hash)
+{
+	struct module_hash *module_hash;
+	int ret = 0;
+
+	list_for_each_entry(module_hash, &module_hash_blacklist, list) {
+		if (strcmp(hash_algo_name, module_hash->hash_name))
+			continue;
+
+		if (!memcmp(hash, module_hash->hash_data, module_hash->size)) {
+			ret = -EKEYREJECTED;
+			pr_info("Module hash is in the module hash blacklist: "
+				"%*phN\n", (int)module_hash->size,
+				module_hash->hash_data);
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int mod_verify_hash(const void *mod, unsigned long modlen,
+		struct public_key_signature *pks)
+{
+	const char *pks_hash_algo = pkey_hash_algo_name[pks->pkey_hash_algo];
+	struct crypto_shash *tfm;
+	struct shash_desc *desc;
+	size_t digest_size, desc_size;
+	u8 *digest;
+	int ret = 0;
+
+	if (list_empty(&module_hash_blacklist))
+		return 0;
+
+	/* check digest of module is not in hash blacklist */
+	ret = check_blacklist(pks_hash_algo, pks->digest);
+	if (ret)
+		goto error_return;
+
+	/* check hash of whole module file */
+	tfm = crypto_alloc_shash(pks_hash_algo, 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, modlen, digest);
+	if (ret < 0)
+		goto error_shash;
+
+	pr_debug("%ld digest: %*phN\n", modlen, (int) digest_size, digest);
+
+	/* check the hash of whole module file including signature */
+	ret = check_blacklist(pks_hash_algo, digest);
+
+error_shash:
+	kfree(digest);
+error_digest:
+	crypto_free_shash(tfm);
+error_return:
+	return ret;
+}
+
 /*
  * Verify the signature on a module.
  */
@@ -202,7 +281,7 @@ int mod_verify_sig(const void *mod, unsi
 	struct module_signature ms;
 	struct key *key;
 	const void *sig;
-	size_t modlen = *_modlen, sig_len;
+	size_t modlen = *_modlen, sig_len, wholelen;
 	int ret;
 
 	pr_devel("==>%s(,%zu)\n", __func__, modlen);
@@ -210,6 +289,7 @@ int mod_verify_sig(const void *mod, unsi
 	if (modlen <= sizeof(ms))
 		return -EBADMSG;
 
+	wholelen = modlen + sizeof(MODULE_SIG_STRING) - 1;
 	memcpy(&ms, mod + (modlen - sizeof(ms)), sizeof(ms));
 	modlen -= sizeof(ms);
 
@@ -252,6 +332,10 @@ int mod_verify_sig(const void *mod, unsi
 	ret = verify_signature(key, pks);
 	pr_devel("verify_signature() = %d\n", ret);
 
+	/* check hash of module not in blacklist */
+	if (!ret)
+		ret = mod_verify_hash(mod, wholelen, pks);
+
 error_free_pks:
 	mpi_free(pks->rsa.s);
 	kfree(pks);


More information about the kernel mailing list