Merge ~xnox/ubuntu/+source/linux/+git/focal:hwe-5.8-revocation-certs into ~ubuntu-kernel/ubuntu/+source/linux/+git/focal:hwe-5.8

Proposed by Dimitri John Ledkov
Status: Needs review
Proposed branch: ~xnox/ubuntu/+source/linux/+git/focal:hwe-5.8-revocation-certs
Merge into: ~ubuntu-kernel/ubuntu/+source/linux/+git/focal:hwe-5.8
Diff against target: 1245 lines (+830/-70)
25 files modified
arch/x86/kernel/setup.c (+1/-0)
arch/x86/platform/efi/efi.c (+3/-0)
certs/.gitignore (+1/-0)
certs/Kconfig (+17/-0)
certs/Makefile (+18/-3)
certs/blacklist.c (+67/-0)
certs/blacklist.h (+2/-0)
certs/common.c (+58/-0)
certs/common.h (+9/-0)
certs/revocation_certificates.S (+21/-0)
certs/system_keyring.c (+9/-47)
debian.hwe-5.8/config/config.common.ubuntu (+2/-0)
debian.master/config/annotations (+1/-0)
debian.master/config/config.common.ubuntu (+2/-0)
debian/revoked-certs/canonical-uefi-2012-all.pem (+86/-0)
debian/rules (+13/-1)
drivers/firmware/efi/Makefile (+1/-0)
drivers/firmware/efi/arm-init.c (+1/-0)
drivers/firmware/efi/efi.c (+6/-0)
drivers/firmware/efi/mokvar-table.c (+362/-0)
include/keys/system_keyring.h (+15/-0)
include/linux/efi.h (+34/-0)
scripts/Makefile (+1/-0)
security/integrity/platform_certs/keyring_handler.c (+12/-0)
security/integrity/platform_certs/load_uefi.c (+88/-19)
Reviewer Review Type Date Requested Status
Canonical Kernel Team Pending
Ubuntu Kernel Repositories Pending
Review via email: mp+409282@code.launchpad.net
To post a comment you must log in.

Unmerged commits

41e8fbe... by Dimitri John Ledkov

UBUNTU: [Config] Configure CONFIG_SYSTEM_REVOCATION_KEYS with revoked keys

BugLink: https://bugs.launchpad.net/bugs/1932029
Signed-off-by: Dimitri John Ledkov <email address hidden>
Signed-off-by: Andrea Righi <email address hidden>
(cherry picked from commit 741f622c4dbc162b82f8c9045f9c6c6446f57eb5)
(xnox: cherry-pick is from impish:linux)
Signed-off-by: Dimitri John Ledkov <email address hidden>

8139ffa... by Dimitri John Ledkov

UBUNTU: [Packaging] Revoke 2012 UEFI signing certificate as built-in

BugLink: https://bugs.launchpad.net/bugs/1932029
Signed-off-by: Dimitri John Ledkov <email address hidden>
Signed-off-by: Andrea Righi <email address hidden>
(cherry picked from commit 3f72ce72f0b51b6da2638cdded93bb32b9dad2ec)
(xnox: cherry-pick is from impish:linux)
Signed-off-by: Dimitri John Ledkov <email address hidden>

644278e... by Dimitri John Ledkov

UBUNTU: [Packaging] build canonical-revoked-certs.pem from branch/arch certs

BugLink: https://bugs.launchpad.net/bugs/1932029
Signed-off-by: Dimitri John Ledkov <email address hidden>
Signed-off-by: Andrea Righi <email address hidden>
(cherry picked from commit 3e44f229eef829ee3044651975512569824c4e5f)
(xnox: cherry-pick is from impish:linux)
Signed-off-by: Dimitri John Ledkov <email address hidden>

49ad197... by Tim Gardner

UBUNTU: SAUCE: Dump stack when X.509 certificates cannot be loaded

BugLink: https://bugs.launchpad.net/bugs/1932029

Signed-off-by: Tim Gardner <email address hidden>
(cherry picked from commit b5b4085dc5547a01593cd79dbf51bd9108f84e9f)
(xnox: cherry-pick is from impish:linux SAUCE)
Signed-off-by: Dimitri John Ledkov <email address hidden>

552ecb7... by Dimitri John Ledkov

UBUNTU: SAUCE: integrity: add informational messages when revoking certs

integrity_load_cert() prints messages of the source and cert details
when adding certs as trusted. Mirror those messages in
uefi_revocation_list_x509() when adding certs as revoked.

Sample dmesg with this change:

    integrity: Platform Keyring initialized
    integrity: Loading X.509 certificate: UEFI:db
    integrity: Loaded X.509 cert 'Microsoft Corporation UEFI CA 2011: 13adbf4309bd82709c8cd54f316ed522988a1bd4'
    integrity: Revoking X.509 certificate: UEFI:MokListXRT (MOKvar table)
    blacklist: Revoked X.509 cert 'Canonical Ltd. Secure Boot Signing: 61482aa2830d0ab2ad5af10b7250da9033ddcef0'
    integrity: Loading X.509 certificate: UEFI:MokListRT (MOKvar table)
    integrity: Loaded X.509 cert 'Canonical Ltd. Master Certificate Authority: ad91990bc22ab1f517048c23b6655a268e345a63'

BugLink: https://bugs.launchpad.net/bugs/1928679
Signed-off-by: Dimitri John Ledkov <email address hidden>
Acked-by: Krzysztof Kozlowski <email address hidden>
Signed-off-by: Seth Forshee <email address hidden>
(cherry picked from commit ba9fb788f89cb81c5ed836db2355a7a3b0f8c248)
(xnox: cherry-pick is from impish:linux SAUCE)
Signed-off-by: Dimitri John Ledkov <email address hidden>

428ff20... by Dimitri John Ledkov

UBUNTU: SAUCE: integrity: Load mokx certs from the EFI MOK config table

Refactor load_moklist_certs() to load either MokListRT into db, or
MokListXRT into dbx. Call load_moklist_certs() twice - first to load
mokx certs into dbx, then mok certs into db.

This thus now attempts to load mokx certs via the EFI MOKvar config
table first, and if that fails, via the EFI variable. Previously mokx
certs were only loaded via the EFI variable. Which fails when
MokListXRT is large. Instead of large MokListXRT variable, only
MokListXRT{1,2,3} are available which are not loaded. This is the case
with Ubuntu's 15.4 based shim. This patch is required to address
CVE-2020-26541 when certificates are revoked via MokListXRT.

Fixes: ebd9c2ae369a ("integrity: Load mokx variables into the blacklist keyring")
BugLink: https://bugs.launchpad.net/bugs/1928679
Signed-off-by: Dimitri John Ledkov <email address hidden>
Acked-by: Krzysztof Kozlowski <email address hidden>
Signed-off-by: Seth Forshee <email address hidden>
(cherry picked from commit a9e3aae16235d6af12509a64f1337da4485ccbae)
(xnox: cherry-pick is from impish:linux SAUCE)
Signed-off-by: Dimitri John Ledkov <email address hidden>

0983bac... by Linus Torvalds <email address hidden>

certs: add 'x509_revocation_list' to gitignore

BugLink: https://bugs.launchpad.net/bugs/1932029

Commit d1f044103dad ("certs: Add ability to preload revocation certs")
created a new generated file for revocation certs, but didn't tell git
to ignore it. Thus causing unnecessary "git status" noise after a
kernel build with CONFIG_SYSTEM_REVOCATION_LIST enabled.

Add the proper gitignore magic.

Signed-off-by: Linus Torvalds <email address hidden>
(cherry picked from commit 81f202315856edb75a371f3376aa3a47543c16f0)
Signed-off-by: Dimitri John Ledkov <email address hidden>

7f447b9... by Eric Snowberg <email address hidden>

integrity: Load mokx variables into the blacklist keyring

BugLink: https://bugs.launchpad.net/bugs/1932029

During boot the Secure Boot Forbidden Signature Database, dbx,
is loaded into the blacklist keyring. Systems booted with shim
have an equivalent Forbidden Signature Database called mokx.
Currently mokx is only used by shim and grub, the contents are
ignored by the kernel.

Add the ability to load mokx into the blacklist keyring during boot.

Signed-off-by: Eric Snowberg <email address hidden>
Suggested-by: James Bottomley <email address hidden>
Signed-off-by: David Howells <email address hidden>
Reviewed-by: Jarkko Sakkinen <email address hidden>
cc: <email address hidden>
Link: https://<email address hidden>/
Link: https://<email address hidden>/ # v5
Link: https://<email address hidden>/
Link: https://<email address hidden>/ # v2
Link: https://<email address hidden>/ # v3
(cherry picked from commit ebd9c2ae369a45bdd9f8615484db09be58fc242b)
Signed-off-by: Dimitri John Ledkov <email address hidden>

e53bef9... by Eric Snowberg <email address hidden>

certs: Add ability to preload revocation certs

BugLink: https://bugs.launchpad.net/bugs/1932029

Add a new Kconfig option called SYSTEM_REVOCATION_KEYS. If set,
this option should be the filename of a PEM-formated file containing
X.509 certificates to be included in the default blacklist keyring.

DH Changes:
 - Make the new Kconfig option depend on SYSTEM_REVOCATION_LIST.
 - Fix SYSTEM_REVOCATION_KEYS=n, but CONFIG_SYSTEM_REVOCATION_LIST=y[1][2].
 - Use CONFIG_SYSTEM_REVOCATION_LIST for extract-cert[3].
 - Use CONFIG_SYSTEM_REVOCATION_LIST for revocation_certificates.o[3].

Signed-off-by: Eric Snowberg <email address hidden>
Acked-by: Jarkko Sakkinen <email address hidden>
Signed-off-by: David Howells <email address hidden>
cc: Randy Dunlap <email address hidden>
cc: <email address hidden>
Link: https://<email address hidden>/ [1]
Link: https://<email address hidden>/ [2]
Link: https://<email address hidden>/ [3]
Link: https://<email address hidden>/
Link: https://<email address hidden>/ # v5
Link: https://<email address hidden>/
Link: https://<email address hidden>/ # v2
Link: https://<email address hidden>/ # v3
(cherry picked from commit d1f044103dad70c1cec0a8f3abdf00834fec8b98)
Signed-off-by: Dimitri John Ledkov <email address hidden>

06f11ec... by Eric Snowberg <email address hidden>

certs: Move load_system_certificate_list to a common function

BugLink: https://bugs.launchpad.net/bugs/1932029

Move functionality within load_system_certificate_list to a common
function, so it can be reused in the future.

DH Changes:
 - Added inclusion of common.h to common.c (Eric [1]).

Signed-off-by: Eric Snowberg <email address hidden>
Acked-by: Jarkko Sakkinen <email address hidden>
Signed-off-by: David Howells <email address hidden>
cc: <email address hidden>
Link: https://<email address hidden>/ [1]
Link: https://<email address hidden>/
Link: https://<email address hidden>/ # v5
Link: https://<email address hidden>/
Link: https://<email address hidden>/ # v2
Link: https://<email address hidden>/ # v3
(cherry picked from commit 2565ca7f5ec1a98d51eea8860c4ab923f1ca2c85)
Signed-off-by: Dimitri John Ledkov <email address hidden>

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
2index c619e19..1bdd6a4 100644
3--- a/arch/x86/kernel/setup.c
4+++ b/arch/x86/kernel/setup.c
5@@ -1086,6 +1086,7 @@ void __init setup_arch(char **cmdline_p)
6 efi_fake_memmap();
7 efi_find_mirror();
8 efi_esrt_init();
9+ efi_mokvar_table_init();
10
11 /*
12 * The EFI specification says that boot service code won't be
13diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
14index e966115..8a9b86f 100644
15--- a/arch/x86/platform/efi/efi.c
16+++ b/arch/x86/platform/efi/efi.c
17@@ -91,6 +91,9 @@ static const unsigned long * const efi_tables[] = {
18 &efi.tpm_log,
19 &efi.tpm_final_log,
20 &efi_rng_seed,
21+#ifdef CONFIG_LOAD_UEFI_KEYS
22+ &efi.mokvar_table,
23+#endif
24 };
25
26 u64 efi_setup; /* efi setup_data physical address */
27diff --git a/certs/.gitignore b/certs/.gitignore
28index 2a24839..6cbd1f1 100644
29--- a/certs/.gitignore
30+++ b/certs/.gitignore
31@@ -1,2 +1,3 @@
32 # SPDX-License-Identifier: GPL-2.0-only
33 x509_certificate_list
34+x509_revocation_list
35diff --git a/certs/Kconfig b/certs/Kconfig
36index c94e93d..ab88d2a 100644
37--- a/certs/Kconfig
38+++ b/certs/Kconfig
39@@ -83,4 +83,21 @@ config SYSTEM_BLACKLIST_HASH_LIST
40 wrapper to incorporate the list into the kernel. Each <hash> should
41 be a string of hex digits.
42
43+config SYSTEM_REVOCATION_LIST
44+ bool "Provide system-wide ring of revocation certificates"
45+ depends on SYSTEM_BLACKLIST_KEYRING
46+ depends on PKCS7_MESSAGE_PARSER=y
47+ help
48+ If set, this allows revocation certificates to be stored in the
49+ blacklist keyring and implements a hook whereby a PKCS#7 message can
50+ be checked to see if it matches such a certificate.
51+
52+config SYSTEM_REVOCATION_KEYS
53+ string "X.509 certificates to be preloaded into the system blacklist keyring"
54+ depends on SYSTEM_REVOCATION_LIST
55+ help
56+ If set, this option should be the filename of a PEM-formatted file
57+ containing X.509 certificates to be included in the default blacklist
58+ keyring.
59+
60 endmenu
61diff --git a/certs/Makefile b/certs/Makefile
62index f4c25b6..b6db52e 100644
63--- a/certs/Makefile
64+++ b/certs/Makefile
65@@ -3,8 +3,9 @@
66 # Makefile for the linux kernel signature checking certificates.
67 #
68
69-obj-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += system_keyring.o system_certificates.o
70-obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist.o
71+obj-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += system_keyring.o system_certificates.o common.o
72+obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist.o common.o
73+obj-$(CONFIG_SYSTEM_REVOCATION_LIST) += revocation_certificates.o
74 ifneq ($(CONFIG_SYSTEM_BLACKLIST_HASH_LIST),"")
75 obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist_hashes.o
76 else
77@@ -29,7 +30,7 @@ $(obj)/x509_certificate_list: scripts/extract-cert $(SYSTEM_TRUSTED_KEYS_SRCPREF
78 $(call if_changed,extract_certs,$(SYSTEM_TRUSTED_KEYS_SRCPREFIX)$(CONFIG_SYSTEM_TRUSTED_KEYS))
79 endif # CONFIG_SYSTEM_TRUSTED_KEYRING
80
81-clean-files := x509_certificate_list .x509.list
82+clean-files := x509_certificate_list .x509.list x509_revocation_list
83
84 ifeq ($(CONFIG_MODULE_SIG),y)
85 ###############################################################################
86@@ -104,3 +105,17 @@ targets += signing_key.x509
87 $(obj)/signing_key.x509: scripts/extract-cert $(X509_DEP) FORCE
88 $(call if_changed,extract_certs,$(MODULE_SIG_KEY_SRCPREFIX)$(CONFIG_MODULE_SIG_KEY))
89 endif # CONFIG_MODULE_SIG
90+
91+ifeq ($(CONFIG_SYSTEM_REVOCATION_LIST),y)
92+
93+$(eval $(call config_filename,SYSTEM_REVOCATION_KEYS))
94+
95+$(obj)/revocation_certificates.o: $(obj)/x509_revocation_list
96+
97+quiet_cmd_extract_certs = EXTRACT_CERTS $(patsubst "%",%,$(2))
98+ cmd_extract_certs = scripts/extract-cert $(2) $@
99+
100+targets += x509_revocation_list
101+$(obj)/x509_revocation_list: scripts/extract-cert $(SYSTEM_REVOCATION_KEYS_SRCPREFIX)$(SYSTEM_REVOCATION_KEYS_FILENAME) FORCE
102+ $(call if_changed,extract_certs,$(SYSTEM_REVOCATION_KEYS_SRCPREFIX)$(CONFIG_SYSTEM_REVOCATION_KEYS))
103+endif
104diff --git a/certs/blacklist.c b/certs/blacklist.c
105index f1c434b..7638dfa 100644
106--- a/certs/blacklist.c
107+++ b/certs/blacklist.c
108@@ -16,9 +16,15 @@
109 #include <linux/seq_file.h>
110 #include <keys/system_keyring.h>
111 #include "blacklist.h"
112+#include "common.h"
113
114 static struct key *blacklist_keyring;
115
116+#ifdef CONFIG_SYSTEM_REVOCATION_LIST
117+extern __initconst const u8 revocation_certificate_list[];
118+extern __initconst const unsigned long revocation_certificate_list_size;
119+#endif
120+
121 /*
122 * The description must be a type prefix, a colon and then an even number of
123 * hex digits. The hash is kept in the description.
124@@ -144,6 +150,52 @@ int is_binary_blacklisted(const u8 *hash, size_t hash_len)
125 }
126 EXPORT_SYMBOL_GPL(is_binary_blacklisted);
127
128+#ifdef CONFIG_SYSTEM_REVOCATION_LIST
129+/**
130+ * add_key_to_revocation_list - Add a revocation certificate to the blacklist
131+ * @data: The data blob containing the certificate
132+ * @size: The size of data blob
133+ */
134+int add_key_to_revocation_list(const char *data, size_t size)
135+{
136+ key_ref_t key;
137+
138+ key = key_create_or_update(make_key_ref(blacklist_keyring, true),
139+ "asymmetric",
140+ NULL,
141+ data,
142+ size,
143+ ((KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW),
144+ KEY_ALLOC_NOT_IN_QUOTA | KEY_ALLOC_BUILT_IN);
145+
146+ if (IS_ERR(key)) {
147+ pr_err("Problem with revocation key (%ld)\n", PTR_ERR(key));
148+ return PTR_ERR(key);
149+ } else {
150+ pr_notice("Revoked X.509 cert '%s'\n",
151+ key_ref_to_ptr(key)->description);
152+ }
153+
154+ return 0;
155+}
156+
157+/**
158+ * is_key_on_revocation_list - Determine if the key for a PKCS#7 message is revoked
159+ * @pkcs7: The PKCS#7 message to check
160+ */
161+int is_key_on_revocation_list(struct pkcs7_message *pkcs7)
162+{
163+ int ret;
164+
165+ ret = pkcs7_validate_trust(pkcs7, blacklist_keyring);
166+
167+ if (ret == 0)
168+ return -EKEYREJECTED;
169+
170+ return -ENOKEY;
171+}
172+#endif
173+
174 /*
175 * Initialise the blacklist
176 */
177@@ -177,3 +229,18 @@ static int __init blacklist_init(void)
178 * Must be initialised before we try and load the keys into the keyring.
179 */
180 device_initcall(blacklist_init);
181+
182+#ifdef CONFIG_SYSTEM_REVOCATION_LIST
183+/*
184+ * Load the compiled-in list of revocation X.509 certificates.
185+ */
186+static __init int load_revocation_certificate_list(void)
187+{
188+ if (revocation_certificate_list_size)
189+ pr_notice("Loading compiled-in revocation X.509 certificates\n");
190+
191+ return load_certificate_list(revocation_certificate_list, revocation_certificate_list_size,
192+ blacklist_keyring);
193+}
194+late_initcall(load_revocation_certificate_list);
195+#endif
196diff --git a/certs/blacklist.h b/certs/blacklist.h
197index 1efd6fa..51b320c 100644
198--- a/certs/blacklist.h
199+++ b/certs/blacklist.h
200@@ -1,3 +1,5 @@
201 #include <linux/kernel.h>
202+#include <linux/errno.h>
203+#include <crypto/pkcs7.h>
204
205 extern const char __initconst *const blacklist_hashes[];
206diff --git a/certs/common.c b/certs/common.c
207new file mode 100644
208index 0000000..23af4fc
209--- /dev/null
210+++ b/certs/common.c
211@@ -0,0 +1,58 @@
212+// SPDX-License-Identifier: GPL-2.0-or-later
213+
214+#include <linux/kernel.h>
215+#include <linux/key.h>
216+#include "common.h"
217+
218+int load_certificate_list(const u8 cert_list[],
219+ const unsigned long list_size,
220+ const struct key *keyring)
221+{
222+ key_ref_t key;
223+ const u8 *p, *end;
224+ size_t plen;
225+
226+ p = cert_list;
227+ end = p + list_size;
228+ while (p < end) {
229+ /* Each cert begins with an ASN.1 SEQUENCE tag and must be more
230+ * than 256 bytes in size.
231+ */
232+ if (end - p < 4)
233+ goto dodgy_cert;
234+ if (p[0] != 0x30 &&
235+ p[1] != 0x82)
236+ goto dodgy_cert;
237+ plen = (p[2] << 8) | p[3];
238+ plen += 4;
239+ if (plen > end - p)
240+ goto dodgy_cert;
241+
242+ key = key_create_or_update(make_key_ref(keyring, 1),
243+ "asymmetric",
244+ NULL,
245+ p,
246+ plen,
247+ ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
248+ KEY_USR_VIEW | KEY_USR_READ),
249+ KEY_ALLOC_NOT_IN_QUOTA |
250+ KEY_ALLOC_BUILT_IN |
251+ KEY_ALLOC_BYPASS_RESTRICTION);
252+ if (IS_ERR(key)) {
253+ pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
254+ PTR_ERR(key));
255+ WARN_ON_ONCE(1);
256+ } else {
257+ pr_notice("Loaded X.509 cert '%s'\n",
258+ key_ref_to_ptr(key)->description);
259+ key_ref_put(key);
260+ }
261+ p += plen;
262+ }
263+
264+ return 0;
265+
266+dodgy_cert:
267+ pr_err("Problem parsing in-kernel X.509 certificate list\n");
268+ return 0;
269+}
270diff --git a/certs/common.h b/certs/common.h
271new file mode 100644
272index 0000000..abdb579
273--- /dev/null
274+++ b/certs/common.h
275@@ -0,0 +1,9 @@
276+/* SPDX-License-Identifier: GPL-2.0-or-later */
277+
278+#ifndef _CERT_COMMON_H
279+#define _CERT_COMMON_H
280+
281+int load_certificate_list(const u8 cert_list[], const unsigned long list_size,
282+ const struct key *keyring);
283+
284+#endif
285diff --git a/certs/revocation_certificates.S b/certs/revocation_certificates.S
286new file mode 100644
287index 0000000..f21aae8
288--- /dev/null
289+++ b/certs/revocation_certificates.S
290@@ -0,0 +1,21 @@
291+/* SPDX-License-Identifier: GPL-2.0 */
292+#include <linux/export.h>
293+#include <linux/init.h>
294+
295+ __INITRODATA
296+
297+ .align 8
298+ .globl revocation_certificate_list
299+revocation_certificate_list:
300+__revocation_list_start:
301+ .incbin "certs/x509_revocation_list"
302+__revocation_list_end:
303+
304+ .align 8
305+ .globl revocation_certificate_list_size
306+revocation_certificate_list_size:
307+#ifdef CONFIG_64BIT
308+ .quad __revocation_list_end - __revocation_list_start
309+#else
310+ .long __revocation_list_end - __revocation_list_start
311+#endif
312diff --git a/certs/system_keyring.c b/certs/system_keyring.c
313index 7d4c816..a44a891 100644
314--- a/certs/system_keyring.c
315+++ b/certs/system_keyring.c
316@@ -15,6 +15,7 @@
317 #include <keys/asymmetric-type.h>
318 #include <keys/system_keyring.h>
319 #include <crypto/pkcs7.h>
320+#include "common.h"
321
322 static struct key *builtin_trusted_keys;
323 #ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
324@@ -136,55 +137,10 @@ device_initcall(system_trusted_keyring_init);
325 */
326 static __init int load_system_certificate_list(void)
327 {
328- key_ref_t key;
329- const u8 *p, *end;
330- size_t plen;
331-
332 pr_notice("Loading compiled-in X.509 certificates\n");
333
334- p = system_certificate_list;
335- end = p + system_certificate_list_size;
336- while (p < end) {
337- /* Each cert begins with an ASN.1 SEQUENCE tag and must be more
338- * than 256 bytes in size.
339- */
340- if (end - p < 4)
341- goto dodgy_cert;
342- if (p[0] != 0x30 &&
343- p[1] != 0x82)
344- goto dodgy_cert;
345- plen = (p[2] << 8) | p[3];
346- plen += 4;
347- if (plen > end - p)
348- goto dodgy_cert;
349-
350- key = key_create_or_update(make_key_ref(builtin_trusted_keys, 1),
351- "asymmetric",
352- NULL,
353- p,
354- plen,
355- ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
356- KEY_USR_VIEW | KEY_USR_READ),
357- KEY_ALLOC_NOT_IN_QUOTA |
358- KEY_ALLOC_BUILT_IN |
359- KEY_ALLOC_BYPASS_RESTRICTION);
360- if (IS_ERR(key)) {
361- pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
362- PTR_ERR(key));
363- WARN_ON_ONCE(1);
364- } else {
365- pr_notice("Loaded X.509 cert '%s'\n",
366- key_ref_to_ptr(key)->description);
367- key_ref_put(key);
368- }
369- p += plen;
370- }
371-
372- return 0;
373-
374-dodgy_cert:
375- pr_err("Problem parsing in-kernel X.509 certificate list\n");
376- return 0;
377+ return load_certificate_list(system_certificate_list, system_certificate_list_size,
378+ builtin_trusted_keys);
379 }
380 late_initcall(load_system_certificate_list);
381
382@@ -242,6 +198,12 @@ int verify_pkcs7_message_sig(const void *data, size_t len,
383 pr_devel("PKCS#7 platform keyring is not available\n");
384 goto error;
385 }
386+
387+ ret = is_key_on_revocation_list(pkcs7);
388+ if (ret != -ENOKEY) {
389+ pr_devel("PKCS#7 platform key is on revocation list\n");
390+ goto error;
391+ }
392 }
393 ret = pkcs7_validate_trust(pkcs7, trusted_keys);
394 if (ret < 0) {
395diff --git a/debian.hwe-5.8/config/config.common.ubuntu b/debian.hwe-5.8/config/config.common.ubuntu
396index c3597d4..2a0d711 100644
397--- a/debian.hwe-5.8/config/config.common.ubuntu
398+++ b/debian.hwe-5.8/config/config.common.ubuntu
399@@ -10197,6 +10197,8 @@ CONFIG_SYSTEM_BLACKLIST_KEYRING=y
400 CONFIG_SYSTEM_DATA_VERIFICATION=y
401 CONFIG_SYSTEM_EXTRA_CERTIFICATE=y
402 CONFIG_SYSTEM_EXTRA_CERTIFICATE_SIZE=4096
403+CONFIG_SYSTEM_REVOCATION_KEYS="debian/canonical-revoked-certs.pem"
404+CONFIG_SYSTEM_REVOCATION_LIST=y
405 CONFIG_SYSTEM_TRUSTED_KEYRING=y
406 CONFIG_SYSTEM_TRUSTED_KEYS="debian/canonical-certs.pem"
407 CONFIG_SYSVIPC=y
408diff --git a/debian.master/config/annotations b/debian.master/config/annotations
409index 47c71de..ef064b0 100644
410--- a/debian.master/config/annotations
411+++ b/debian.master/config/annotations
412@@ -369,6 +369,7 @@ CONFIG_SYSTEM_TRUSTED_KEYRING policy<{'amd64': 'y', 'arm64': '
413 CONFIG_SYSTEM_TRUSTED_KEYS policy<{'amd64': '"debian/canonical-certs.pem"', 'arm64': '"debian/canonical-certs.pem"', 'armhf': '"debian/canonical-certs.pem"', 'ppc64el': '"debian/canonical-certs.pem"', 's390x': '"debian/canonical-certs.pem"'}>
414 CONFIG_SYSTEM_EXTRA_CERTIFICATE policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y', 's390x': 'y'}>
415 CONFIG_SYSTEM_EXTRA_CERTIFICATE_SIZE policy<{'amd64': '4096', 'arm64': '4096', 'armhf': '4096', 'ppc64el': '4096', 's390x': '4096'}>
416+CONFIG_SYSTEM_REVOCATION_KEYS policy<{'amd64': '"debian/canonical-revoked-certs.pem"', 'arm64': '"debian/canonical-revoked-certs.pem"', 'armhf': '"debian/canonical-revoked-certs.pem"', 'ppc64el': '"debian/canonical-revoked-certs.pem"', 's390x': '"debian/canonical-revoked-certs.pem"'}>
417 CONFIG_SECONDARY_TRUSTED_KEYRING policy<{'amd64': 'y', 'arm64': 'y', 'armhf': 'y', 'ppc64el': 'y', 's390x': 'y'}>
418
419 # Menu: Cryptographic API >> Hardware crypto devices
420diff --git a/debian.master/config/config.common.ubuntu b/debian.master/config/config.common.ubuntu
421index f9392ab..fd4f39a 100644
422--- a/debian.master/config/config.common.ubuntu
423+++ b/debian.master/config/config.common.ubuntu
424@@ -10198,6 +10198,8 @@ CONFIG_SYSTEM_BLACKLIST_KEYRING=y
425 CONFIG_SYSTEM_DATA_VERIFICATION=y
426 CONFIG_SYSTEM_EXTRA_CERTIFICATE=y
427 CONFIG_SYSTEM_EXTRA_CERTIFICATE_SIZE=4096
428+CONFIG_SYSTEM_REVOCATION_KEYS="debian/canonical-revoked-certs.pem"
429+CONFIG_SYSTEM_REVOCATION_LIST=y
430 CONFIG_SYSTEM_TRUSTED_KEYRING=y
431 CONFIG_SYSTEM_TRUSTED_KEYS="debian/canonical-certs.pem"
432 CONFIG_SYSVIPC=y
433diff --git a/debian/revoked-certs/canonical-uefi-2012-all.pem b/debian/revoked-certs/canonical-uefi-2012-all.pem
434new file mode 100644
435index 0000000..06c116e
436--- /dev/null
437+++ b/debian/revoked-certs/canonical-uefi-2012-all.pem
438@@ -0,0 +1,86 @@
439+Certificate:
440+ Data:
441+ Version: 3 (0x2)
442+ Serial Number: 1 (0x1)
443+ Signature Algorithm: sha256WithRSAEncryption
444+ Issuer: C = GB, ST = Isle of Man, L = Douglas, O = Canonical Ltd., CN = Canonical Ltd. Master Certificate Authority
445+ Validity
446+ Not Before: Apr 12 11:39:08 2012 GMT
447+ Not After : Apr 11 11:39:08 2042 GMT
448+ Subject: C = GB, ST = Isle of Man, O = Canonical Ltd., OU = Secure Boot, CN = Canonical Ltd. Secure Boot Signing
449+ Subject Public Key Info:
450+ Public Key Algorithm: rsaEncryption
451+ RSA Public-Key: (2048 bit)
452+ Modulus:
453+ 00:c9:5f:9b:62:8f:0b:b0:64:82:ac:be:c9:e2:62:
454+ e3:4b:d2:9f:1e:8a:d5:61:1a:2b:5d:38:f4:b7:ce:
455+ b9:9a:b8:43:b8:43:97:77:ab:4f:7f:0c:70:46:0b:
456+ fc:7f:6d:c6:6d:ea:80:5e:01:d2:b7:66:1e:87:de:
457+ 0d:6d:d0:41:97:a8:a5:af:0c:63:4f:f7:7c:c2:52:
458+ cc:a0:31:a9:bb:89:5d:99:1e:46:6f:55:73:b9:76:
459+ 69:ec:d7:c1:fc:21:d6:c6:07:e7:4f:bd:22:de:e4:
460+ a8:5b:2d:db:95:34:19:97:d6:28:4b:21:4c:ca:bb:
461+ 1d:79:a6:17:7f:5a:f9:67:e6:5c:78:45:3d:10:6d:
462+ b0:17:59:26:11:c5:57:e3:7f:4e:82:ba:f6:2c:4e:
463+ c8:37:4d:ff:85:15:84:47:e0:ed:3b:7c:7f:bc:af:
464+ e9:01:05:a7:0c:6f:c3:e9:8d:a3:ce:be:a6:e3:cd:
465+ 3c:b5:58:2c:9e:c2:03:1c:60:22:37:39:ff:41:02:
466+ c1:29:a4:65:51:ff:33:34:aa:42:15:f9:95:78:fc:
467+ 2d:f5:da:8a:85:7c:82:9d:fb:37:2c:6b:a5:a8:df:
468+ 7c:55:0b:80:2e:3c:b0:63:e1:cd:38:48:89:e8:14:
469+ 06:0b:82:bc:fd:d4:07:68:1b:0f:3e:d9:15:dd:94:
470+ 11:1b
471+ Exponent: 65537 (0x10001)
472+ X509v3 extensions:
473+ X509v3 Basic Constraints: critical
474+ CA:FALSE
475+ X509v3 Extended Key Usage:
476+ Code Signing, 1.3.6.1.4.1.311.10.3.6
477+ Netscape Comment:
478+ OpenSSL Generated Certificate
479+ X509v3 Subject Key Identifier:
480+ 61:48:2A:A2:83:0D:0A:B2:AD:5A:F1:0B:72:50:DA:90:33:DD:CE:F0
481+ X509v3 Authority Key Identifier:
482+ keyid:AD:91:99:0B:C2:2A:B1:F5:17:04:8C:23:B6:65:5A:26:8E:34:5A:63
483+
484+ Signature Algorithm: sha256WithRSAEncryption
485+ 8f:8a:a1:06:1f:29:b7:0a:4a:d5:c5:fd:81:ab:25:ea:c0:7d:
486+ e2:fc:6a:96:a0:79:93:67:ee:05:0e:25:12:25:e4:5a:f6:aa:
487+ 1a:f1:12:f3:05:8d:87:5e:f1:5a:5c:cb:8d:23:73:65:1d:15:
488+ b9:de:22:6b:d6:49:67:c9:a3:c6:d7:62:4e:5c:b5:f9:03:83:
489+ 40:81:dc:87:9c:3c:3f:1c:0d:51:9f:94:65:0a:84:48:67:e4:
490+ a2:f8:a6:4a:f0:e7:cd:cd:bd:94:e3:09:d2:5d:2d:16:1b:05:
491+ 15:0b:cb:44:b4:3e:61:42:22:c4:2a:5c:4e:c5:1d:a3:e2:e0:
492+ 52:b2:eb:f4:8b:2b:dc:38:39:5d:fb:88:a1:56:65:5f:2b:4f:
493+ 26:ff:06:78:10:12:eb:8c:5d:32:e3:c6:45:af:25:9b:a0:ff:
494+ 8e:ef:47:09:a3:e9:8b:37:92:92:69:76:7e:34:3b:92:05:67:
495+ 4e:b0:25:ed:bc:5e:5f:8f:b4:d6:ca:40:ff:e4:e2:31:23:0c:
496+ 85:25:ae:0c:55:01:ec:e5:47:5e:df:5b:bc:14:33:e3:c6:f5:
497+ 18:b6:d9:f7:dd:b3:b4:a1:31:d3:5a:5c:5d:7d:3e:bf:0a:e4:
498+ e4:e8:b4:59:7d:3b:b4:8c:a3:1b:b5:20:a3:b9:3e:84:6f:8c:
499+ 21:00:c3:39
500+-----BEGIN CERTIFICATE-----
501+MIIEIDCCAwigAwIBAgIBATANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMCR0Ix
502+FDASBgNVBAgMC0lzbGUgb2YgTWFuMRAwDgYDVQQHDAdEb3VnbGFzMRcwFQYDVQQK
503+DA5DYW5vbmljYWwgTHRkLjE0MDIGA1UEAwwrQ2Fub25pY2FsIEx0ZC4gTWFzdGVy
504+IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xMjA0MTIxMTM5MDhaFw00MjA0MTEx
505+MTM5MDhaMH8xCzAJBgNVBAYTAkdCMRQwEgYDVQQIDAtJc2xlIG9mIE1hbjEXMBUG
506+A1UECgwOQ2Fub25pY2FsIEx0ZC4xFDASBgNVBAsMC1NlY3VyZSBCb290MSswKQYD
507+VQQDDCJDYW5vbmljYWwgTHRkLiBTZWN1cmUgQm9vdCBTaWduaW5nMIIBIjANBgkq
508+hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyV+bYo8LsGSCrL7J4mLjS9KfHorVYRor
509+XTj0t865mrhDuEOXd6tPfwxwRgv8f23GbeqAXgHSt2Yeh94NbdBBl6ilrwxjT/d8
510+wlLMoDGpu4ldmR5Gb1VzuXZp7NfB/CHWxgfnT70i3uSoWy3blTQZl9YoSyFMyrsd
511+eaYXf1r5Z+ZceEU9EG2wF1kmEcVX439Ogrr2LE7IN03/hRWER+DtO3x/vK/pAQWn
512+DG/D6Y2jzr6m4808tVgsnsIDHGAiNzn/QQLBKaRlUf8zNKpCFfmVePwt9dqKhXyC
513+nfs3LGulqN98VQuALjywY+HNOEiJ6BQGC4K8/dQHaBsPPtkV3ZQRGwIDAQABo4Gg
514+MIGdMAwGA1UdEwEB/wQCMAAwHwYDVR0lBBgwFgYIKwYBBQUHAwMGCisGAQQBgjcK
515+AwYwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRl
516+MB0GA1UdDgQWBBRhSCqigw0Ksq1a8QtyUNqQM93O8DAfBgNVHSMEGDAWgBStkZkL
517+wiqx9RcEjCO2ZVomjjRaYzANBgkqhkiG9w0BAQsFAAOCAQEAj4qhBh8ptwpK1cX9
518+gasl6sB94vxqlqB5k2fuBQ4lEiXkWvaqGvES8wWNh17xWlzLjSNzZR0Vud4ia9ZJ
519+Z8mjxtdiTly1+QODQIHch5w8PxwNUZ+UZQqESGfkovimSvDnzc29lOMJ0l0tFhsF
520+FQvLRLQ+YUIixCpcTsUdo+LgUrLr9Isr3Dg5XfuIoVZlXytPJv8GeBAS64xdMuPG
521+Ra8lm6D/ju9HCaPpizeSkml2fjQ7kgVnTrAl7bxeX4+01spA/+TiMSMMhSWuDFUB
522+7OVHXt9bvBQz48b1GLbZ992ztKEx01pcXX0+vwrk5Oi0WX07tIyjG7Ugo7k+hG+M
523+IQDDOQ==
524+-----END CERTIFICATE-----
525diff --git a/debian/rules b/debian/rules
526index 3355879..557c9b1 100755
527--- a/debian/rules
528+++ b/debian/rules
529@@ -127,7 +127,7 @@ binary: binary-indep binary-arch
530
531 build: build-arch build-indep
532
533-clean: debian/control debian/canonical-certs.pem
534+clean: debian/control debian/canonical-certs.pem debian/canonical-revoked-certs.pem
535 dh_testdir
536 dh_testroot
537 dh_clean
538@@ -237,3 +237,15 @@ debian/canonical-certs.pem: $(wildcard $(DROOT)/certs/*-all.pem) $(wildcard $(DR
539 fi; \
540 done; \
541 done >"$@"
542+
543+debian/canonical-revoked-certs.pem: $(wildcard $(DROOT)/revoked-certs/*-all.pem) $(wildcard $(DROOT)/revoked-certs/*-$(arch).pem) $(wildcard $(DEBIAN)/revoked-certs/*-all.pem) $(wildcard $(DEBIAN)/revoked-certs/*-$(arch).pem)
544+ for cert in $(sort $(notdir $^)); \
545+ do \
546+ for dir in $(DEBIAN) $(DROOT); \
547+ do \
548+ if [ -f "$$dir/revoked-certs/$$cert" ]; then \
549+ cat "$$dir/revoked-certs/$$cert"; \
550+ break; \
551+ fi; \
552+ done; \
553+ done >"$@"
554diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile
555index f0ef02d..be5ee0b 100644
556--- a/drivers/firmware/efi/Makefile
557+++ b/drivers/firmware/efi/Makefile
558@@ -29,6 +29,7 @@ obj-$(CONFIG_EFI) += secureboot.o
559 obj-$(CONFIG_APPLE_PROPERTIES) += apple-properties.o
560 obj-$(CONFIG_EFI_RCI2_TABLE) += rci2-table.o
561 obj-$(CONFIG_EFI_EMBEDDED_FIRMWARE) += embedded-firmware.o
562+obj-$(CONFIG_LOAD_UEFI_KEYS) += mokvar-table.o
563
564 fake_map-y += fake_mem.o
565 fake_map-$(CONFIG_X86) += x86_fake_mem.o
566diff --git a/drivers/firmware/efi/arm-init.c b/drivers/firmware/efi/arm-init.c
567index 788f227..c8e4481 100644
568--- a/drivers/firmware/efi/arm-init.c
569+++ b/drivers/firmware/efi/arm-init.c
570@@ -244,6 +244,7 @@ void __init efi_init(void)
571
572 reserve_regions();
573 efi_esrt_init();
574+ efi_mokvar_table_init();
575
576 memblock_reserve(data.phys_map & PAGE_MASK,
577 PAGE_ALIGN(data.size + (data.phys_map & ~PAGE_MASK)));
578diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
579index d1f6f77..a5faafd 100644
580--- a/drivers/firmware/efi/efi.c
581+++ b/drivers/firmware/efi/efi.c
582@@ -44,6 +44,9 @@ struct efi __read_mostly efi = {
583 .esrt = EFI_INVALID_TABLE_ADDR,
584 .tpm_log = EFI_INVALID_TABLE_ADDR,
585 .tpm_final_log = EFI_INVALID_TABLE_ADDR,
586+#ifdef CONFIG_LOAD_UEFI_KEYS
587+ .mokvar_table = EFI_INVALID_TABLE_ADDR,
588+#endif
589 };
590 EXPORT_SYMBOL(efi);
591
592@@ -520,6 +523,9 @@ static const efi_config_table_type_t common_tables[] __initconst = {
593 #ifdef CONFIG_EFI_RCI2_TABLE
594 {DELLEMC_EFI_RCI2_TABLE_GUID, &rci2_table_phys },
595 #endif
596+#ifdef CONFIG_LOAD_UEFI_KEYS
597+ {LINUX_EFI_MOK_VARIABLE_TABLE_GUID, &efi.mokvar_table, "MOKvar" },
598+#endif
599 {},
600 };
601
602diff --git a/drivers/firmware/efi/mokvar-table.c b/drivers/firmware/efi/mokvar-table.c
603new file mode 100644
604index 0000000..38722d2
605--- /dev/null
606+++ b/drivers/firmware/efi/mokvar-table.c
607@@ -0,0 +1,362 @@
608+// SPDX-License-Identifier: GPL-2.0
609+/*
610+ * mokvar-table.c
611+ *
612+ * Copyright (c) 2020 Red Hat
613+ * Author: Lenny Szubowicz <lszubowi@redhat.com>
614+ *
615+ * This module contains the kernel support for the Linux EFI Machine
616+ * Owner Key (MOK) variable configuration table, which is identified by
617+ * the LINUX_EFI_MOK_VARIABLE_TABLE_GUID.
618+ *
619+ * This EFI configuration table provides a more robust alternative to
620+ * EFI volatile variables by which an EFI boot loader can pass the
621+ * contents of the Machine Owner Key (MOK) certificate stores to the
622+ * kernel during boot. If both the EFI MOK config table and corresponding
623+ * EFI MOK variables are present, the table should be considered as
624+ * more authoritative.
625+ *
626+ * This module includes code that validates and maps the EFI MOK table,
627+ * if it's presence was detected very early in boot.
628+ *
629+ * Kernel interface routines are provided to walk through all the
630+ * entries in the MOK config table or to search for a specific named
631+ * entry.
632+ *
633+ * The contents of the individual named MOK config table entries are
634+ * made available to user space via read-only sysfs binary files under:
635+ *
636+ * /sys/firmware/efi/mok-variables/
637+ *
638+ */
639+#define pr_fmt(fmt) "mokvar: " fmt
640+
641+#include <linux/capability.h>
642+#include <linux/efi.h>
643+#include <linux/init.h>
644+#include <linux/io.h>
645+#include <linux/kernel.h>
646+#include <linux/kobject.h>
647+#include <linux/list.h>
648+#include <linux/slab.h>
649+
650+#include <asm/early_ioremap.h>
651+
652+/*
653+ * The LINUX_EFI_MOK_VARIABLE_TABLE_GUID config table is a packed
654+ * sequence of struct efi_mokvar_table_entry, one for each named
655+ * MOK variable. The sequence is terminated by an entry with a
656+ * completely NULL name and 0 data size.
657+ *
658+ * efi_mokvar_table_size is set to the computed size of the
659+ * MOK config table by efi_mokvar_table_init(). This will be
660+ * non-zero if and only if the table if present and has been
661+ * validated by efi_mokvar_table_init().
662+ */
663+static size_t efi_mokvar_table_size;
664+
665+/*
666+ * efi_mokvar_table_va is the kernel virtual address at which the
667+ * EFI MOK config table has been mapped by efi_mokvar_sysfs_init().
668+ */
669+static struct efi_mokvar_table_entry *efi_mokvar_table_va;
670+
671+/*
672+ * Each /sys/firmware/efi/mok-variables/ sysfs file is represented by
673+ * an instance of struct efi_mokvar_sysfs_attr on efi_mokvar_sysfs_list.
674+ * bin_attr.private points to the associated EFI MOK config table entry.
675+ *
676+ * This list is created during boot and then remains unchanged.
677+ * So no synchronization is currently required to walk the list.
678+ */
679+struct efi_mokvar_sysfs_attr {
680+ struct bin_attribute bin_attr;
681+ struct list_head node;
682+};
683+
684+static LIST_HEAD(efi_mokvar_sysfs_list);
685+static struct kobject *mokvar_kobj;
686+
687+/*
688+ * efi_mokvar_table_init() - Early boot validation of EFI MOK config table
689+ *
690+ * If present, validate and compute the size of the EFI MOK variable
691+ * configuration table. This table may be provided by an EFI boot loader
692+ * as an alternative to ordinary EFI variables, due to platform-dependent
693+ * limitations. The memory occupied by this table is marked as reserved.
694+ *
695+ * This routine must be called before efi_free_boot_services() in order
696+ * to guarantee that it can mark the table as reserved.
697+ *
698+ * Implicit inputs:
699+ * efi.mokvar_table: Physical address of EFI MOK variable config table
700+ * or special value that indicates no such table.
701+ *
702+ * Implicit outputs:
703+ * efi_mokvar_table_size: Computed size of EFI MOK variable config table.
704+ * The table is considered present and valid if this
705+ * is non-zero.
706+ */
707+void __init efi_mokvar_table_init(void)
708+{
709+ efi_memory_desc_t md;
710+ void *va = NULL;
711+ unsigned long cur_offset = 0;
712+ unsigned long offset_limit;
713+ unsigned long map_size = 0;
714+ unsigned long map_size_needed = 0;
715+ unsigned long size;
716+ struct efi_mokvar_table_entry *mokvar_entry;
717+ int err;
718+
719+ if (!efi_enabled(EFI_MEMMAP))
720+ return;
721+
722+ if (efi.mokvar_table == EFI_INVALID_TABLE_ADDR)
723+ return;
724+ /*
725+ * The EFI MOK config table must fit within a single EFI memory
726+ * descriptor range.
727+ */
728+ err = efi_mem_desc_lookup(efi.mokvar_table, &md);
729+ if (err) {
730+ pr_warn("EFI MOKvar config table is not within the EFI memory map\n");
731+ return;
732+ }
733+
734+ offset_limit = efi_mem_desc_end(&md) - efi.mokvar_table;
735+
736+ /*
737+ * Validate the MOK config table. Since there is no table header
738+ * from which we could get the total size of the MOK config table,
739+ * we compute the total size as we validate each variably sized
740+ * entry, remapping as necessary.
741+ */
742+ err = -EINVAL;
743+ while (cur_offset + sizeof(*mokvar_entry) <= offset_limit) {
744+ mokvar_entry = va + cur_offset;
745+ map_size_needed = cur_offset + sizeof(*mokvar_entry);
746+ if (map_size_needed > map_size) {
747+ if (va)
748+ early_memunmap(va, map_size);
749+ /*
750+ * Map a little more than the fixed size entry
751+ * header, anticipating some data. It's safe to
752+ * do so as long as we stay within current memory
753+ * descriptor.
754+ */
755+ map_size = min(map_size_needed + 2*EFI_PAGE_SIZE,
756+ offset_limit);
757+ va = early_memremap(efi.mokvar_table, map_size);
758+ if (!va) {
759+ pr_err("Failed to map EFI MOKvar config table pa=0x%lx, size=%lu.\n",
760+ efi.mokvar_table, map_size);
761+ return;
762+ }
763+ mokvar_entry = va + cur_offset;
764+ }
765+
766+ /* Check for last sentinel entry */
767+ if (mokvar_entry->name[0] == '\0') {
768+ if (mokvar_entry->data_size != 0)
769+ break;
770+ err = 0;
771+ break;
772+ }
773+
774+ /* Sanity check that the name is null terminated */
775+ size = strnlen(mokvar_entry->name,
776+ sizeof(mokvar_entry->name));
777+ if (size >= sizeof(mokvar_entry->name))
778+ break;
779+
780+ /* Advance to the next entry */
781+ cur_offset = map_size_needed + mokvar_entry->data_size;
782+ }
783+
784+ if (va)
785+ early_memunmap(va, map_size);
786+ if (err) {
787+ pr_err("EFI MOKvar config table is not valid\n");
788+ return;
789+ }
790+
791+ if (md.type == EFI_BOOT_SERVICES_DATA)
792+ efi_mem_reserve(efi.mokvar_table, map_size_needed);
793+
794+ efi_mokvar_table_size = map_size_needed;
795+}
796+
797+/*
798+ * efi_mokvar_entry_next() - Get next entry in the EFI MOK config table
799+ *
800+ * mokvar_entry: Pointer to current EFI MOK config table entry
801+ * or null. Null indicates get first entry.
802+ * Passed by reference. This is updated to the
803+ * same value as the return value.
804+ *
805+ * Returns: Pointer to next EFI MOK config table entry
806+ * or null, if there are no more entries.
807+ * Same value is returned in the mokvar_entry
808+ * parameter.
809+ *
810+ * This routine depends on the EFI MOK config table being entirely
811+ * mapped with it's starting virtual address in efi_mokvar_table_va.
812+ */
813+struct efi_mokvar_table_entry *efi_mokvar_entry_next(
814+ struct efi_mokvar_table_entry **mokvar_entry)
815+{
816+ struct efi_mokvar_table_entry *mokvar_cur;
817+ struct efi_mokvar_table_entry *mokvar_next;
818+ size_t size_cur;
819+
820+ mokvar_cur = *mokvar_entry;
821+ *mokvar_entry = NULL;
822+
823+ if (efi_mokvar_table_va == NULL)
824+ return NULL;
825+
826+ if (mokvar_cur == NULL) {
827+ mokvar_next = efi_mokvar_table_va;
828+ } else {
829+ if (mokvar_cur->name[0] == '\0')
830+ return NULL;
831+ size_cur = sizeof(*mokvar_cur) + mokvar_cur->data_size;
832+ mokvar_next = (void *)mokvar_cur + size_cur;
833+ }
834+
835+ if (mokvar_next->name[0] == '\0')
836+ return NULL;
837+
838+ *mokvar_entry = mokvar_next;
839+ return mokvar_next;
840+}
841+
842+/*
843+ * efi_mokvar_entry_find() - Find EFI MOK config entry by name
844+ *
845+ * name: Name of the entry to look for.
846+ *
847+ * Returns: Pointer to EFI MOK config table entry if found;
848+ * null otherwise.
849+ *
850+ * This routine depends on the EFI MOK config table being entirely
851+ * mapped with it's starting virtual address in efi_mokvar_table_va.
852+ */
853+struct efi_mokvar_table_entry *efi_mokvar_entry_find(const char *name)
854+{
855+ struct efi_mokvar_table_entry *mokvar_entry = NULL;
856+
857+ while (efi_mokvar_entry_next(&mokvar_entry)) {
858+ if (!strncmp(name, mokvar_entry->name,
859+ sizeof(mokvar_entry->name)))
860+ return mokvar_entry;
861+ }
862+ return NULL;
863+}
864+
865+/*
866+ * efi_mokvar_sysfs_read() - sysfs binary file read routine
867+ *
868+ * Returns: Count of bytes read.
869+ *
870+ * Copy EFI MOK config table entry data for this mokvar sysfs binary file
871+ * to the supplied buffer, starting at the specified offset into mokvar table
872+ * entry data, for the specified count bytes. The copy is limited by the
873+ * amount of data in this mokvar config table entry.
874+ */
875+static ssize_t efi_mokvar_sysfs_read(struct file *file, struct kobject *kobj,
876+ struct bin_attribute *bin_attr, char *buf,
877+ loff_t off, size_t count)
878+{
879+ struct efi_mokvar_table_entry *mokvar_entry = bin_attr->private;
880+
881+ if (!capable(CAP_SYS_ADMIN))
882+ return 0;
883+
884+ if (off >= mokvar_entry->data_size)
885+ return 0;
886+ if (count > mokvar_entry->data_size - off)
887+ count = mokvar_entry->data_size - off;
888+
889+ memcpy(buf, mokvar_entry->data + off, count);
890+ return count;
891+}
892+
893+/*
894+ * efi_mokvar_sysfs_init() - Map EFI MOK config table and create sysfs
895+ *
896+ * Map the EFI MOK variable config table for run-time use by the kernel
897+ * and create the sysfs entries in /sys/firmware/efi/mok-variables/
898+ *
899+ * This routine just returns if a valid EFI MOK variable config table
900+ * was not found earlier during boot.
901+ *
902+ * This routine must be called during a "middle" initcall phase, i.e.
903+ * after efi_mokvar_table_init() but before UEFI certs are loaded
904+ * during late init.
905+ *
906+ * Implicit inputs:
907+ * efi.mokvar_table: Physical address of EFI MOK variable config table
908+ * or special value that indicates no such table.
909+ *
910+ * efi_mokvar_table_size: Computed size of EFI MOK variable config table.
911+ * The table is considered present and valid if this
912+ * is non-zero.
913+ *
914+ * Implicit outputs:
915+ * efi_mokvar_table_va: Start virtual address of the EFI MOK config table.
916+ */
917+static int __init efi_mokvar_sysfs_init(void)
918+{
919+ void *config_va;
920+ struct efi_mokvar_table_entry *mokvar_entry = NULL;
921+ struct efi_mokvar_sysfs_attr *mokvar_sysfs = NULL;
922+ int err = 0;
923+
924+ if (efi_mokvar_table_size == 0)
925+ return -ENOENT;
926+
927+ config_va = memremap(efi.mokvar_table, efi_mokvar_table_size,
928+ MEMREMAP_WB);
929+ if (!config_va) {
930+ pr_err("Failed to map EFI MOKvar config table\n");
931+ return -ENOMEM;
932+ }
933+ efi_mokvar_table_va = config_va;
934+
935+ mokvar_kobj = kobject_create_and_add("mok-variables", efi_kobj);
936+ if (!mokvar_kobj) {
937+ pr_err("Failed to create EFI mok-variables sysfs entry\n");
938+ return -ENOMEM;
939+ }
940+
941+ while (efi_mokvar_entry_next(&mokvar_entry)) {
942+ mokvar_sysfs = kzalloc(sizeof(*mokvar_sysfs), GFP_KERNEL);
943+ if (!mokvar_sysfs) {
944+ err = -ENOMEM;
945+ break;
946+ }
947+
948+ sysfs_bin_attr_init(&mokvar_sysfs->bin_attr);
949+ mokvar_sysfs->bin_attr.private = mokvar_entry;
950+ mokvar_sysfs->bin_attr.attr.name = mokvar_entry->name;
951+ mokvar_sysfs->bin_attr.attr.mode = 0400;
952+ mokvar_sysfs->bin_attr.size = mokvar_entry->data_size;
953+ mokvar_sysfs->bin_attr.read = efi_mokvar_sysfs_read;
954+
955+ err = sysfs_create_bin_file(mokvar_kobj,
956+ &mokvar_sysfs->bin_attr);
957+ if (err)
958+ break;
959+
960+ list_add_tail(&mokvar_sysfs->node, &efi_mokvar_sysfs_list);
961+ }
962+
963+ if (err) {
964+ pr_err("Failed to create some EFI mok-variables sysfs entries\n");
965+ kfree(mokvar_sysfs);
966+ }
967+ return err;
968+}
969+device_initcall(efi_mokvar_sysfs_init);
970diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
971index fb8b07d..875e002 100644
972--- a/include/keys/system_keyring.h
973+++ b/include/keys/system_keyring.h
974@@ -31,6 +31,7 @@ extern int restrict_link_by_builtin_and_secondary_trusted(
975 #define restrict_link_by_builtin_and_secondary_trusted restrict_link_by_builtin_trusted
976 #endif
977
978+extern struct pkcs7_message *pkcs7;
979 #ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING
980 extern int mark_hash_blacklisted(const char *hash);
981 extern int is_hash_blacklisted(const u8 *hash, size_t hash_len,
982@@ -49,6 +50,20 @@ static inline int is_binary_blacklisted(const u8 *hash, size_t hash_len)
983 }
984 #endif
985
986+#ifdef CONFIG_SYSTEM_REVOCATION_LIST
987+extern int add_key_to_revocation_list(const char *data, size_t size);
988+extern int is_key_on_revocation_list(struct pkcs7_message *pkcs7);
989+#else
990+static inline int add_key_to_revocation_list(const char *data, size_t size)
991+{
992+ return 0;
993+}
994+static inline int is_key_on_revocation_list(struct pkcs7_message *pkcs7)
995+{
996+ return -ENOKEY;
997+}
998+#endif
999+
1000 #ifdef CONFIG_IMA_BLACKLIST_KEYRING
1001 extern struct key *ima_blacklist_keyring;
1002
1003diff --git a/include/linux/efi.h b/include/linux/efi.h
1004index 2793a2d..09c0939 100644
1005--- a/include/linux/efi.h
1006+++ b/include/linux/efi.h
1007@@ -361,6 +361,7 @@ void efi_native_runtime_setup(void);
1008 #define LINUX_EFI_TPM_FINAL_LOG_GUID EFI_GUID(0x1e2ed096, 0x30e2, 0x4254, 0xbd, 0x89, 0x86, 0x3b, 0xbe, 0xf8, 0x23, 0x25)
1009 #define LINUX_EFI_MEMRESERVE_TABLE_GUID EFI_GUID(0x888eb0c6, 0x8ede, 0x4ff5, 0xa8, 0xf0, 0x9a, 0xee, 0x5c, 0xb9, 0x77, 0xc2)
1010 #define LINUX_EFI_INITRD_MEDIA_GUID EFI_GUID(0x5568e427, 0x68fc, 0x4f3d, 0xac, 0x74, 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68)
1011+#define LINUX_EFI_MOK_VARIABLE_TABLE_GUID EFI_GUID(0xc451ed2b, 0x9694, 0x45d3, 0xba, 0xba, 0xed, 0x9f, 0x89, 0x88, 0xa3, 0x89)
1012
1013 /* OEM GUIDs */
1014 #define DELLEMC_EFI_RCI2_TABLE_GUID EFI_GUID(0x2d9f28a2, 0xa886, 0x456a, 0x97, 0xa8, 0xf1, 0x1e, 0xf2, 0x4f, 0xf4, 0x55)
1015@@ -550,6 +551,7 @@ extern struct efi {
1016 unsigned long esrt; /* ESRT table */
1017 unsigned long tpm_log; /* TPM2 Event Log table */
1018 unsigned long tpm_final_log; /* TPM2 Final Events Log table */
1019+ unsigned long mokvar_table; /* MOK variable config table */
1020
1021 efi_get_time_t *get_time;
1022 efi_set_time_t *set_time;
1023@@ -1271,4 +1273,36 @@ void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size);
1024
1025 char *efi_systab_show_arch(char *str);
1026
1027+/*
1028+ * The LINUX_EFI_MOK_VARIABLE_TABLE_GUID config table can be provided
1029+ * to the kernel by an EFI boot loader. The table contains a packed
1030+ * sequence of these entries, one for each named MOK variable.
1031+ * The sequence is terminated by an entry with a completely NULL
1032+ * name and 0 data size.
1033+ */
1034+struct efi_mokvar_table_entry {
1035+ char name[256];
1036+ u64 data_size;
1037+ u8 data[];
1038+} __attribute((packed));
1039+
1040+#ifdef CONFIG_LOAD_UEFI_KEYS
1041+extern void __init efi_mokvar_table_init(void);
1042+extern struct efi_mokvar_table_entry *efi_mokvar_entry_next(
1043+ struct efi_mokvar_table_entry **mokvar_entry);
1044+extern struct efi_mokvar_table_entry *efi_mokvar_entry_find(const char *name);
1045+#else
1046+static inline void efi_mokvar_table_init(void) { }
1047+static inline struct efi_mokvar_table_entry *efi_mokvar_entry_next(
1048+ struct efi_mokvar_table_entry **mokvar_entry)
1049+{
1050+ return NULL;
1051+}
1052+static inline struct efi_mokvar_table_entry *efi_mokvar_entry_find(
1053+ const char *name)
1054+{
1055+ return NULL;
1056+}
1057+#endif
1058+
1059 #endif /* _LINUX_EFI_H */
1060diff --git a/scripts/Makefile b/scripts/Makefile
1061index b3f6415..99ff04d 100644
1062--- a/scripts/Makefile
1063+++ b/scripts/Makefile
1064@@ -14,6 +14,7 @@ always-$(CONFIG_ASN1) += asn1_compiler
1065 always-$(CONFIG_MODULE_SIG_FORMAT) += sign-file
1066 always-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += extract-cert
1067 always-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE) += insert-sys-cert
1068+hostprogs-always-$(CONFIG_SYSTEM_REVOCATION_LIST) += extract-cert
1069
1070 HOSTCFLAGS_sorttable.o = -I$(srctree)/tools/include
1071 HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include
1072diff --git a/security/integrity/platform_certs/keyring_handler.c b/security/integrity/platform_certs/keyring_handler.c
1073index c5ba695..9f85626 100644
1074--- a/security/integrity/platform_certs/keyring_handler.c
1075+++ b/security/integrity/platform_certs/keyring_handler.c
1076@@ -56,6 +56,16 @@ static __init void uefi_blacklist_binary(const char *source,
1077 }
1078
1079 /*
1080+ * Add an X509 cert to the revocation list.
1081+ */
1082+static __init void uefi_revocation_list_x509(const char *source,
1083+ const void *data, size_t len)
1084+{
1085+ pr_info("Revoking X.509 certificate: %s\n", source);
1086+ add_key_to_revocation_list(data, len);
1087+}
1088+
1089+/*
1090 * Return the appropriate handler for particular signature list types found in
1091 * the UEFI db and MokListRT tables.
1092 */
1093@@ -76,5 +86,7 @@ __init efi_element_handler_t get_handler_for_dbx(const efi_guid_t *sig_type)
1094 return uefi_blacklist_x509_tbs;
1095 if (efi_guidcmp(*sig_type, efi_cert_sha256_guid) == 0)
1096 return uefi_blacklist_binary;
1097+ if (efi_guidcmp(*sig_type, efi_cert_x509_guid) == 0)
1098+ return uefi_revocation_list_x509;
1099 return 0;
1100 }
1101diff --git a/security/integrity/platform_certs/load_uefi.c b/security/integrity/platform_certs/load_uefi.c
1102index 8c95b68..b010b4a 100644
1103--- a/security/integrity/platform_certs/load_uefi.c
1104+++ b/security/integrity/platform_certs/load_uefi.c
1105@@ -68,6 +68,80 @@ static __init void *get_cert_list(efi_char16_t *name, efi_guid_t *guid,
1106 }
1107
1108 /*
1109+ * load_moklist_certs() - Load Mok(X)List certs
1110+ * @load_db: Load MokListRT into db when true; MokListXRT into dbx when false
1111+ *
1112+ * Load the certs contained in the UEFI MokList(X)RT database into the
1113+ * platform trusted/denied keyring.
1114+ *
1115+ * This routine checks the EFI MOK config table first. If and only if
1116+ * that fails, this routine uses the MokList(X)RT ordinary UEFI variable.
1117+ *
1118+ * Return: Status
1119+ */
1120+static int __init load_moklist_certs(const bool load_db)
1121+{
1122+ struct efi_mokvar_table_entry *mokvar_entry;
1123+ efi_guid_t mok_var = EFI_SHIM_LOCK_GUID;
1124+ void *mok;
1125+ unsigned long moksize;
1126+ efi_status_t status;
1127+ int rc;
1128+ const char *mokvar_name = "MokListRT";
1129+ /* Should be const, but get_cert_list() doesn't have it as const yet */
1130+ efi_char16_t *efivar_name = L"MokListRT";
1131+ const char *parse_mokvar_name = "UEFI:MokListRT (MOKvar table)";
1132+ const char *parse_efivar_name = "UEFI:MokListRT";
1133+ efi_element_handler_t (*get_handler_for_guid)(const efi_guid_t *) = get_handler_for_db;
1134+
1135+ if (!load_db) {
1136+ mokvar_name = "MokListXRT";
1137+ efivar_name = L"MokListXRT";
1138+ parse_mokvar_name = "UEFI:MokListXRT (MOKvar table)";
1139+ parse_efivar_name = "UEFI:MokListXRT";
1140+ get_handler_for_guid = get_handler_for_dbx;
1141+ }
1142+
1143+ /* First try to load certs from the EFI MOKvar config table.
1144+ * It's not an error if the MOKvar config table doesn't exist
1145+ * or the MokListRT entry is not found in it.
1146+ */
1147+ mokvar_entry = efi_mokvar_entry_find(mokvar_name);
1148+ if (mokvar_entry) {
1149+ rc = parse_efi_signature_list(parse_mokvar_name,
1150+ mokvar_entry->data,
1151+ mokvar_entry->data_size,
1152+ get_handler_for_guid);
1153+ /* All done if that worked. */
1154+ if (!rc)
1155+ return rc;
1156+
1157+ pr_err("Couldn't parse %s signatures from EFI MOKvar config table: %d\n",
1158+ mokvar_name, rc);
1159+ }
1160+
1161+ /* Get MokListRT. It might not exist, so it isn't an error
1162+ * if we can't get it.
1163+ */
1164+ mok = get_cert_list(efivar_name, &mok_var, &moksize, &status);
1165+ if (mok) {
1166+ rc = parse_efi_signature_list(parse_efivar_name,
1167+ mok, moksize, get_handler_for_guid);
1168+ kfree(mok);
1169+ if (rc)
1170+ pr_err("Couldn't parse %s signatures: %d\n", mokvar_name, rc);
1171+ return rc;
1172+ }
1173+ if (status == EFI_NOT_FOUND)
1174+ pr_debug("%s variable wasn't found\n", mokvar_name);
1175+ else
1176+ pr_info("Couldn't get UEFI %s\n", mokvar_name);
1177+ return 0;
1178+}
1179+
1180+/*
1181+ * load_uefi_certs() - Load certs from UEFI sources
1182+ *
1183 * Load the certs contained in the UEFI databases into the platform trusted
1184 * keyring and the UEFI blacklisted X.509 cert SHA256 hashes into the blacklist
1185 * keyring.
1186@@ -75,17 +149,16 @@ static __init void *get_cert_list(efi_char16_t *name, efi_guid_t *guid,
1187 static int __init load_uefi_certs(void)
1188 {
1189 efi_guid_t secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
1190- efi_guid_t mok_var = EFI_SHIM_LOCK_GUID;
1191- void *db = NULL, *dbx = NULL, *mok = NULL;
1192- unsigned long dbsize = 0, dbxsize = 0, moksize = 0;
1193+ void *db = NULL, *dbx = NULL;
1194+ unsigned long dbsize = 0, dbxsize = 0;
1195 efi_status_t status;
1196 int rc = 0;
1197
1198 if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
1199 return false;
1200
1201- /* Get db, MokListRT, and dbx. They might not exist, so it isn't
1202- * an error if we can't get them.
1203+ /* Get db and dbx. They might not exist, so it isn't an error
1204+ * if we can't get them.
1205 */
1206 if (!uefi_check_ignore_db()) {
1207 db = get_cert_list(L"db", &secure_var, &dbsize, &status);
1208@@ -104,20 +177,6 @@ static int __init load_uefi_certs(void)
1209 }
1210 }
1211
1212- mok = get_cert_list(L"MokListRT", &mok_var, &moksize, &status);
1213- if (!mok) {
1214- if (status == EFI_NOT_FOUND)
1215- pr_debug("MokListRT variable wasn't found\n");
1216- else
1217- pr_info("Couldn't get UEFI MokListRT\n");
1218- } else {
1219- rc = parse_efi_signature_list("UEFI:MokListRT",
1220- mok, moksize, get_handler_for_db);
1221- if (rc)
1222- pr_err("Couldn't parse MokListRT signatures: %d\n", rc);
1223- kfree(mok);
1224- }
1225-
1226 dbx = get_cert_list(L"dbx", &secure_var, &dbxsize, &status);
1227 if (!dbx) {
1228 if (status == EFI_NOT_FOUND)
1229@@ -133,6 +192,16 @@ static int __init load_uefi_certs(void)
1230 kfree(dbx);
1231 }
1232
1233+ /* Load the MokListXRT certs */
1234+ rc = load_moklist_certs(false);
1235+ if (rc)
1236+ pr_err("Couldn't parse mokx signatures: %d\n", rc);
1237+
1238+ /* Load the MokListRT certs */
1239+ rc = load_moklist_certs(true);
1240+ if (rc)
1241+ pr_err("Couldn't parse mok signatures: %d\n", rc);
1242+
1243 return rc;
1244 }
1245 late_initcall(load_uefi_certs);

Subscribers

People subscribed via source and target branches