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