summaryrefslogtreecommitdiffstats
path: root/debian/patches/features/all/db-mok-keyring/0003-MODSIGN-checking-the-blacklisted-hash-before-loading-a-kernel-module.patch
blob: a7ec5ccb56522a3a678f7eb9edd4aa8ac07d35e5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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 | 59 +++++++++++++++++++++++++++++++++++++++--
 1 file changed, 57 insertions(+), 2 deletions(-)

--- a/kernel/module_signing.c
+++ b/kernel/module_signing.c
@@ -12,15 +12,62 @@
 #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"
 
+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;
+	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);
@@ -28,6 +75,7 @@ int mod_verify_sig(const void *mod, stru
 	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");
@@ -38,8 +86,15 @@ int mod_verify_sig(const void *mod, stru
 	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;
 }