Merge ~xnox/ubuntu/+source/linux/+git/bionic:revocation-keys into ~ubuntu-kernel/ubuntu/+source/linux/+git/bionic:master-next

Proposed by Dimitri John Ledkov
Status: Needs review
Proposed branch: ~xnox/ubuntu/+source/linux/+git/bionic:revocation-keys
Merge into: ~ubuntu-kernel/ubuntu/+source/linux/+git/bionic:master-next
Diff against target: 1208 lines (+824/-65)
22 files modified
arch/x86/kernel/setup.c (+1/-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/load_uefi.c (+95/-14)
certs/revocation_certificates.S (+21/-0)
certs/system_keyring.c (+10/-47)
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 (+9/-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)
Reviewer Review Type Date Requested Status
Ubuntu Kernel Repositories Pending
Review via email: mp+412577@code.launchpad.net

Commit message

Support builtin revoked certificates and mokvar-table

Same story as before, backport support for builtin revoked
certificates, add support loading revoked certificates from
mokvar-table.

Some of the patches had to be adjusted during backport. For example,
instead of patching security/integrity/platform_certs/load_uefi.c
which does not exist in v4.15 kernel certs/load_uefi.c is. Some error
handling is done differently as well. For example, EFI status not
found is not handled when loading keys from variables.

This series doesn't have any reverts, as the lockdown patchset is
mostly older without any major reorgs that didn't make upstream. It is
slightly larger than focal's one as support for EFI_CERT_X509_GUID did
not land via linux-stable updates.

After this patch is applied, the RT boot testing & kernel built-in
final check will catch any kernels that do not have
CONFIG_SYSTEM_REVOCATION_KEYS set. In bionic, this may trip up raspi2,
snapdgaron, kvm flavours as they in theory can support UEFI, but are
not signed and may not enable all the lockdown and keyring
features. These flavours may need reverting 70de61082d ("UBUNTU:
[Packaging] Add system trusted and revocation keys final check") as
was done in Focal. Or enable all the keyrings and builtin revocation
keys.

To post a comment you must log in.

Unmerged commits

750558e... 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>

b0d255c... 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>

8d7c952... 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>

3b9b048... 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>

4dab349... 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>

1a3d39e... 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>

5db8878... 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>

52ad86c... 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>

849f596... by Lenny Szubowicz <email address hidden>

integrity: Load certs from the EFI MOK config table

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

Because of system-specific EFI firmware limitations, EFI volatile
variables may not be capable of holding the required contents of
the Machine Owner Key (MOK) certificate store when the certificate
list grows above some size. Therefore, an EFI boot loader may pass
the MOK certs via a EFI configuration table created specifically for
this purpose to avoid this firmware limitation.

An EFI configuration table is a much more primitive mechanism
compared to EFI variables and is well suited for one-way passage
of static information from a pre-OS environment to the kernel.

This patch adds the support to load certs from the MokListRT
entry in the MOK variable configuration table, if it's present.
The pre-existing support to load certs from the MokListRT EFI
variable remains and is used if the EFI MOK configuration table
isn't present or can't be successfully used.

Signed-off-by: Lenny Szubowicz <email address hidden>
Link: https://<email address hidden>
Signed-off-by: Ard Biesheuvel <email address hidden>
(cherry picked from commit 726bd8965a5f112d9601f7ce68effa1e46e02bf2)
Signed-off-by: Dimitri John Ledkov <email address hidden>

ba184a1... by Lenny Szubowicz <email address hidden>

integrity: Move import of MokListRT certs to a separate routine

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

Move the loading of certs from the UEFI MokListRT into a separate
routine to facilitate additional MokList functionality.

There is no visible functional change as a result of this patch.
Although the UEFI dbx certs are now loaded before the MokList certs,
they are loaded onto different key rings. So the order of the keys
on their respective key rings is the same.

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

Subscribers

People subscribed via source and target branches

to status/vote changes: