115ea0e1eSJosh Boyer // SPDX-License-Identifier: GPL-2.0
215ea0e1eSJosh Boyer
315ea0e1eSJosh Boyer #include <linux/kernel.h>
415ea0e1eSJosh Boyer #include <linux/sched.h>
515ea0e1eSJosh Boyer #include <linux/cred.h>
6155ca952SAditya Garg #include <linux/dmi.h>
715ea0e1eSJosh Boyer #include <linux/err.h>
815ea0e1eSJosh Boyer #include <linux/efi.h>
915ea0e1eSJosh Boyer #include <linux/slab.h>
1092ad1955SLee, Chun-Yi #include <linux/ima.h>
1115ea0e1eSJosh Boyer #include <keys/asymmetric-type.h>
1215ea0e1eSJosh Boyer #include <keys/system_keyring.h>
1315ea0e1eSJosh Boyer #include "../integrity.h"
14ad723674SNayna Jain #include "keyring_handler.h"
1515ea0e1eSJosh Boyer
1615ea0e1eSJosh Boyer /*
17155ca952SAditya Garg * On T2 Macs reading the db and dbx efi variables to load UEFI Secure Boot
18155ca952SAditya Garg * certificates causes occurrence of a page fault in Apple's firmware and
19155ca952SAditya Garg * a crash disabling EFI runtime services. The following quirk skips reading
20155ca952SAditya Garg * these variables.
21155ca952SAditya Garg */
22155ca952SAditya Garg static const struct dmi_system_id uefi_skip_cert[] = {
23155ca952SAditya Garg { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro15,1") },
24155ca952SAditya Garg { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro15,2") },
25155ca952SAditya Garg { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro15,3") },
26155ca952SAditya Garg { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro15,4") },
27155ca952SAditya Garg { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro16,1") },
28155ca952SAditya Garg { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro16,2") },
29155ca952SAditya Garg { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro16,3") },
30155ca952SAditya Garg { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro16,4") },
31155ca952SAditya Garg { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookAir8,1") },
32155ca952SAditya Garg { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookAir8,2") },
33155ca952SAditya Garg { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookAir9,1") },
34bab715bdSOrlando Chamberlain { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "Macmini8,1") },
35155ca952SAditya Garg { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacPro7,1") },
36155ca952SAditya Garg { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "iMac20,1") },
37155ca952SAditya Garg { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "iMac20,2") },
38*0be56a11SAditya Garg { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "iMacPro1,1") },
39155ca952SAditya Garg { }
40155ca952SAditya Garg };
41155ca952SAditya Garg
42155ca952SAditya Garg /*
43386b49f5SJosh Boyer * Look to see if a UEFI variable called MokIgnoreDB exists and return true if
44386b49f5SJosh Boyer * it does.
45386b49f5SJosh Boyer *
46386b49f5SJosh Boyer * This UEFI variable is set by the shim if a user tells the shim to not use
47386b49f5SJosh Boyer * the certs/hashes in the UEFI db variable for verification purposes. If it
48386b49f5SJosh Boyer * is set, we should ignore the db variable also and the true return indicates
49386b49f5SJosh Boyer * this.
50386b49f5SJosh Boyer */
uefi_check_ignore_db(void)51386b49f5SJosh Boyer static __init bool uefi_check_ignore_db(void)
52386b49f5SJosh Boyer {
53386b49f5SJosh Boyer efi_status_t status;
54386b49f5SJosh Boyer unsigned int db = 0;
55386b49f5SJosh Boyer unsigned long size = sizeof(db);
56386b49f5SJosh Boyer efi_guid_t guid = EFI_SHIM_LOCK_GUID;
57386b49f5SJosh Boyer
58386b49f5SJosh Boyer status = efi.get_variable(L"MokIgnoreDB", &guid, NULL, &size, &db);
59386b49f5SJosh Boyer return status == EFI_SUCCESS;
60386b49f5SJosh Boyer }
61386b49f5SJosh Boyer
62386b49f5SJosh Boyer /*
6315ea0e1eSJosh Boyer * Get a certificate list blob from the named EFI variable.
6415ea0e1eSJosh Boyer */
get_cert_list(efi_char16_t * name,efi_guid_t * guid,unsigned long * size,efi_status_t * status)6515ea0e1eSJosh Boyer static __init void *get_cert_list(efi_char16_t *name, efi_guid_t *guid,
663be54d55SJavier Martinez Canillas unsigned long *size, efi_status_t *status)
6715ea0e1eSJosh Boyer {
6815ea0e1eSJosh Boyer unsigned long lsize = 4;
6915ea0e1eSJosh Boyer unsigned long tmpdb[4];
7015ea0e1eSJosh Boyer void *db;
7115ea0e1eSJosh Boyer
723be54d55SJavier Martinez Canillas *status = efi.get_variable(name, guid, NULL, &lsize, &tmpdb);
733be54d55SJavier Martinez Canillas if (*status == EFI_NOT_FOUND)
743be54d55SJavier Martinez Canillas return NULL;
753be54d55SJavier Martinez Canillas
763be54d55SJavier Martinez Canillas if (*status != EFI_BUFFER_TOO_SMALL) {
773be54d55SJavier Martinez Canillas pr_err("Couldn't get size: 0x%lx\n", *status);
7815ea0e1eSJosh Boyer return NULL;
7915ea0e1eSJosh Boyer }
8015ea0e1eSJosh Boyer
8115ea0e1eSJosh Boyer db = kmalloc(lsize, GFP_KERNEL);
8215ea0e1eSJosh Boyer if (!db)
8315ea0e1eSJosh Boyer return NULL;
8415ea0e1eSJosh Boyer
853be54d55SJavier Martinez Canillas *status = efi.get_variable(name, guid, NULL, &lsize, db);
863be54d55SJavier Martinez Canillas if (*status != EFI_SUCCESS) {
8715ea0e1eSJosh Boyer kfree(db);
883be54d55SJavier Martinez Canillas pr_err("Error reading db var: 0x%lx\n", *status);
8915ea0e1eSJosh Boyer return NULL;
9015ea0e1eSJosh Boyer }
9115ea0e1eSJosh Boyer
9215ea0e1eSJosh Boyer *size = lsize;
9315ea0e1eSJosh Boyer return db;
9415ea0e1eSJosh Boyer }
9515ea0e1eSJosh Boyer
9615ea0e1eSJosh Boyer /*
9738a1f03aSLenny Szubowicz * load_moklist_certs() - Load MokList certs
9838a1f03aSLenny Szubowicz *
9938a1f03aSLenny Szubowicz * Load the certs contained in the UEFI MokListRT database into the
10038a1f03aSLenny Szubowicz * platform trusted keyring.
10138a1f03aSLenny Szubowicz *
102726bd896SLenny Szubowicz * This routine checks the EFI MOK config table first. If and only if
103726bd896SLenny Szubowicz * that fails, this routine uses the MokListRT ordinary UEFI variable.
104726bd896SLenny Szubowicz *
10538a1f03aSLenny Szubowicz * Return: Status
10638a1f03aSLenny Szubowicz */
load_moklist_certs(void)10738a1f03aSLenny Szubowicz static int __init load_moklist_certs(void)
10838a1f03aSLenny Szubowicz {
109726bd896SLenny Szubowicz struct efi_mokvar_table_entry *mokvar_entry;
11038a1f03aSLenny Szubowicz efi_guid_t mok_var = EFI_SHIM_LOCK_GUID;
11138a1f03aSLenny Szubowicz void *mok;
11238a1f03aSLenny Szubowicz unsigned long moksize;
11338a1f03aSLenny Szubowicz efi_status_t status;
11438a1f03aSLenny Szubowicz int rc;
11538a1f03aSLenny Szubowicz
116726bd896SLenny Szubowicz /* First try to load certs from the EFI MOKvar config table.
117726bd896SLenny Szubowicz * It's not an error if the MOKvar config table doesn't exist
118726bd896SLenny Szubowicz * or the MokListRT entry is not found in it.
119726bd896SLenny Szubowicz */
120726bd896SLenny Szubowicz mokvar_entry = efi_mokvar_entry_find("MokListRT");
121726bd896SLenny Szubowicz if (mokvar_entry) {
122726bd896SLenny Szubowicz rc = parse_efi_signature_list("UEFI:MokListRT (MOKvar table)",
123726bd896SLenny Szubowicz mokvar_entry->data,
124726bd896SLenny Szubowicz mokvar_entry->data_size,
12545fcd5e5SEric Snowberg get_handler_for_mok);
126726bd896SLenny Szubowicz /* All done if that worked. */
127726bd896SLenny Szubowicz if (!rc)
128726bd896SLenny Szubowicz return rc;
129726bd896SLenny Szubowicz
130726bd896SLenny Szubowicz pr_err("Couldn't parse MokListRT signatures from EFI MOKvar config table: %d\n",
131726bd896SLenny Szubowicz rc);
132726bd896SLenny Szubowicz }
133726bd896SLenny Szubowicz
13438a1f03aSLenny Szubowicz /* Get MokListRT. It might not exist, so it isn't an error
13538a1f03aSLenny Szubowicz * if we can't get it.
13638a1f03aSLenny Szubowicz */
13738a1f03aSLenny Szubowicz mok = get_cert_list(L"MokListRT", &mok_var, &moksize, &status);
13838a1f03aSLenny Szubowicz if (mok) {
13938a1f03aSLenny Szubowicz rc = parse_efi_signature_list("UEFI:MokListRT",
14045fcd5e5SEric Snowberg mok, moksize, get_handler_for_mok);
14138a1f03aSLenny Szubowicz kfree(mok);
14238a1f03aSLenny Szubowicz if (rc)
14338a1f03aSLenny Szubowicz pr_err("Couldn't parse MokListRT signatures: %d\n", rc);
14438a1f03aSLenny Szubowicz return rc;
14538a1f03aSLenny Szubowicz }
14638a1f03aSLenny Szubowicz if (status == EFI_NOT_FOUND)
14738a1f03aSLenny Szubowicz pr_debug("MokListRT variable wasn't found\n");
14838a1f03aSLenny Szubowicz else
14938a1f03aSLenny Szubowicz pr_info("Couldn't get UEFI MokListRT\n");
15038a1f03aSLenny Szubowicz return 0;
15138a1f03aSLenny Szubowicz }
15238a1f03aSLenny Szubowicz
15338a1f03aSLenny Szubowicz /*
15438a1f03aSLenny Szubowicz * load_uefi_certs() - Load certs from UEFI sources
15538a1f03aSLenny Szubowicz *
156386b49f5SJosh Boyer * Load the certs contained in the UEFI databases into the platform trusted
157386b49f5SJosh Boyer * keyring and the UEFI blacklisted X.509 cert SHA256 hashes into the blacklist
158386b49f5SJosh Boyer * keyring.
15915ea0e1eSJosh Boyer */
load_uefi_certs(void)16015ea0e1eSJosh Boyer static int __init load_uefi_certs(void)
16115ea0e1eSJosh Boyer {
16215ea0e1eSJosh Boyer efi_guid_t secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
163ebd9c2aeSEric Snowberg efi_guid_t mok_var = EFI_SHIM_LOCK_GUID;
164ebd9c2aeSEric Snowberg void *db = NULL, *dbx = NULL, *mokx = NULL;
165ebd9c2aeSEric Snowberg unsigned long dbsize = 0, dbxsize = 0, mokxsize = 0;
1663be54d55SJavier Martinez Canillas efi_status_t status;
16715ea0e1eSJosh Boyer int rc = 0;
168155ca952SAditya Garg const struct dmi_system_id *dmi_id;
169155ca952SAditya Garg
170155ca952SAditya Garg dmi_id = dmi_first_match(uefi_skip_cert);
171155ca952SAditya Garg if (dmi_id) {
172155ca952SAditya Garg pr_err("Reading UEFI Secure Boot Certs is not supported on T2 Macs.\n");
173155ca952SAditya Garg return false;
174155ca952SAditya Garg }
17515ea0e1eSJosh Boyer
1766b75d54dSArd Biesheuvel if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
17715ea0e1eSJosh Boyer return false;
17815ea0e1eSJosh Boyer
17938a1f03aSLenny Szubowicz /* Get db and dbx. They might not exist, so it isn't an error
18038a1f03aSLenny Szubowicz * if we can't get them.
18115ea0e1eSJosh Boyer */
182386b49f5SJosh Boyer if (!uefi_check_ignore_db()) {
1833be54d55SJavier Martinez Canillas db = get_cert_list(L"db", &secure_var, &dbsize, &status);
18415ea0e1eSJosh Boyer if (!db) {
1853be54d55SJavier Martinez Canillas if (status == EFI_NOT_FOUND)
1863be54d55SJavier Martinez Canillas pr_debug("MODSIGN: db variable wasn't found\n");
1873be54d55SJavier Martinez Canillas else
188386b49f5SJosh Boyer pr_err("MODSIGN: Couldn't get UEFI db list\n");
18915ea0e1eSJosh Boyer } else {
19015ea0e1eSJosh Boyer rc = parse_efi_signature_list("UEFI:db",
19115ea0e1eSJosh Boyer db, dbsize, get_handler_for_db);
19215ea0e1eSJosh Boyer if (rc)
193386b49f5SJosh Boyer pr_err("Couldn't parse db signatures: %d\n",
194386b49f5SJosh Boyer rc);
19515ea0e1eSJosh Boyer kfree(db);
19615ea0e1eSJosh Boyer }
197386b49f5SJosh Boyer }
19815ea0e1eSJosh Boyer
1993be54d55SJavier Martinez Canillas dbx = get_cert_list(L"dbx", &secure_var, &dbxsize, &status);
20015ea0e1eSJosh Boyer if (!dbx) {
2013be54d55SJavier Martinez Canillas if (status == EFI_NOT_FOUND)
2023be54d55SJavier Martinez Canillas pr_debug("dbx variable wasn't found\n");
2033be54d55SJavier Martinez Canillas else
20415ea0e1eSJosh Boyer pr_info("Couldn't get UEFI dbx list\n");
20515ea0e1eSJosh Boyer } else {
20615ea0e1eSJosh Boyer rc = parse_efi_signature_list("UEFI:dbx",
20715ea0e1eSJosh Boyer dbx, dbxsize,
20815ea0e1eSJosh Boyer get_handler_for_dbx);
20915ea0e1eSJosh Boyer if (rc)
21015ea0e1eSJosh Boyer pr_err("Couldn't parse dbx signatures: %d\n", rc);
21115ea0e1eSJosh Boyer kfree(dbx);
21215ea0e1eSJosh Boyer }
21315ea0e1eSJosh Boyer
21492ad1955SLee, Chun-Yi /* the MOK/MOKx can not be trusted when secure boot is disabled */
21592ad1955SLee, Chun-Yi if (!arch_ima_get_secureboot())
21692ad1955SLee, Chun-Yi return 0;
21792ad1955SLee, Chun-Yi
218ebd9c2aeSEric Snowberg mokx = get_cert_list(L"MokListXRT", &mok_var, &mokxsize, &status);
219ebd9c2aeSEric Snowberg if (!mokx) {
220ebd9c2aeSEric Snowberg if (status == EFI_NOT_FOUND)
221ebd9c2aeSEric Snowberg pr_debug("mokx variable wasn't found\n");
222ebd9c2aeSEric Snowberg else
223ebd9c2aeSEric Snowberg pr_info("Couldn't get mokx list\n");
224ebd9c2aeSEric Snowberg } else {
225ebd9c2aeSEric Snowberg rc = parse_efi_signature_list("UEFI:MokListXRT",
226ebd9c2aeSEric Snowberg mokx, mokxsize,
227ebd9c2aeSEric Snowberg get_handler_for_dbx);
228ebd9c2aeSEric Snowberg if (rc)
229ebd9c2aeSEric Snowberg pr_err("Couldn't parse mokx signatures %d\n", rc);
230ebd9c2aeSEric Snowberg kfree(mokx);
231ebd9c2aeSEric Snowberg }
232ebd9c2aeSEric Snowberg
23338a1f03aSLenny Szubowicz /* Load the MokListRT certs */
23438a1f03aSLenny Szubowicz rc = load_moklist_certs();
23538a1f03aSLenny Szubowicz
23615ea0e1eSJosh Boyer return rc;
23715ea0e1eSJosh Boyer }
23815ea0e1eSJosh Boyer late_initcall(load_uefi_certs);
239