1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <linux/kernel.h> 4 #include <linux/sched.h> 5 #include <linux/cred.h> 6 #include <linux/dmi.h> 7 #include <linux/err.h> 8 #include <linux/efi.h> 9 #include <linux/slab.h> 10 #include <linux/ima.h> 11 #include <keys/asymmetric-type.h> 12 #include <keys/system_keyring.h> 13 #include "../integrity.h" 14 #include "keyring_handler.h" 15 16 /* 17 * On T2 Macs reading the db and dbx efi variables to load UEFI Secure Boot 18 * certificates causes occurrence of a page fault in Apple's firmware and 19 * a crash disabling EFI runtime services. The following quirk skips reading 20 * these variables. 21 */ 22 static const struct dmi_system_id uefi_skip_cert[] = { 23 { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro15,1") }, 24 { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro15,2") }, 25 { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro15,3") }, 26 { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro15,4") }, 27 { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro16,1") }, 28 { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro16,2") }, 29 { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro16,3") }, 30 { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro16,4") }, 31 { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookAir8,1") }, 32 { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookAir8,2") }, 33 { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookAir9,1") }, 34 { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "Macmini8,1") }, 35 { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacPro7,1") }, 36 { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "iMac20,1") }, 37 { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "iMac20,2") }, 38 { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "iMacPro1,1") }, 39 { } 40 }; 41 42 /* 43 * Look to see if a UEFI variable called MokIgnoreDB exists and return true if 44 * it does. 45 * 46 * This UEFI variable is set by the shim if a user tells the shim to not use 47 * the certs/hashes in the UEFI db variable for verification purposes. If it 48 * is set, we should ignore the db variable also and the true return indicates 49 * this. 50 */ 51 static __init bool uefi_check_ignore_db(void) 52 { 53 efi_status_t status; 54 unsigned int db = 0; 55 unsigned long size = sizeof(db); 56 efi_guid_t guid = EFI_SHIM_LOCK_GUID; 57 58 status = efi.get_variable(L"MokIgnoreDB", &guid, NULL, &size, &db); 59 return status == EFI_SUCCESS; 60 } 61 62 /* 63 * Get a certificate list blob from the named EFI variable. 64 */ 65 static __init void *get_cert_list(efi_char16_t *name, efi_guid_t *guid, 66 unsigned long *size, efi_status_t *status) 67 { 68 unsigned long lsize = 4; 69 unsigned long tmpdb[4]; 70 void *db; 71 72 *status = efi.get_variable(name, guid, NULL, &lsize, &tmpdb); 73 if (*status == EFI_NOT_FOUND) 74 return NULL; 75 76 if (*status != EFI_BUFFER_TOO_SMALL) { 77 pr_err("Couldn't get size: 0x%lx\n", *status); 78 return NULL; 79 } 80 81 db = kmalloc(lsize, GFP_KERNEL); 82 if (!db) 83 return NULL; 84 85 *status = efi.get_variable(name, guid, NULL, &lsize, db); 86 if (*status != EFI_SUCCESS) { 87 kfree(db); 88 pr_err("Error reading db var: 0x%lx\n", *status); 89 return NULL; 90 } 91 92 *size = lsize; 93 return db; 94 } 95 96 /* 97 * load_moklist_certs() - Load MokList certs 98 * 99 * Load the certs contained in the UEFI MokListRT database into the 100 * platform trusted keyring. 101 * 102 * This routine checks the EFI MOK config table first. If and only if 103 * that fails, this routine uses the MokListRT ordinary UEFI variable. 104 * 105 * Return: Status 106 */ 107 static int __init load_moklist_certs(void) 108 { 109 struct efi_mokvar_table_entry *mokvar_entry; 110 efi_guid_t mok_var = EFI_SHIM_LOCK_GUID; 111 void *mok; 112 unsigned long moksize; 113 efi_status_t status; 114 int rc; 115 116 /* First try to load certs from the EFI MOKvar config table. 117 * It's not an error if the MOKvar config table doesn't exist 118 * or the MokListRT entry is not found in it. 119 */ 120 mokvar_entry = efi_mokvar_entry_find("MokListRT"); 121 if (mokvar_entry) { 122 rc = parse_efi_signature_list("UEFI:MokListRT (MOKvar table)", 123 mokvar_entry->data, 124 mokvar_entry->data_size, 125 get_handler_for_mok); 126 /* All done if that worked. */ 127 if (!rc) 128 return rc; 129 130 pr_err("Couldn't parse MokListRT signatures from EFI MOKvar config table: %d\n", 131 rc); 132 } 133 134 /* Get MokListRT. It might not exist, so it isn't an error 135 * if we can't get it. 136 */ 137 mok = get_cert_list(L"MokListRT", &mok_var, &moksize, &status); 138 if (mok) { 139 rc = parse_efi_signature_list("UEFI:MokListRT", 140 mok, moksize, get_handler_for_mok); 141 kfree(mok); 142 if (rc) 143 pr_err("Couldn't parse MokListRT signatures: %d\n", rc); 144 return rc; 145 } 146 if (status == EFI_NOT_FOUND) 147 pr_debug("MokListRT variable wasn't found\n"); 148 else 149 pr_info("Couldn't get UEFI MokListRT\n"); 150 return 0; 151 } 152 153 /* 154 * load_uefi_certs() - Load certs from UEFI sources 155 * 156 * Load the certs contained in the UEFI databases into the platform trusted 157 * keyring and the UEFI blacklisted X.509 cert SHA256 hashes into the blacklist 158 * keyring. 159 */ 160 static int __init load_uefi_certs(void) 161 { 162 efi_guid_t secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID; 163 efi_guid_t mok_var = EFI_SHIM_LOCK_GUID; 164 void *db = NULL, *dbx = NULL, *mokx = NULL; 165 unsigned long dbsize = 0, dbxsize = 0, mokxsize = 0; 166 efi_status_t status; 167 int rc = 0; 168 const struct dmi_system_id *dmi_id; 169 170 dmi_id = dmi_first_match(uefi_skip_cert); 171 if (dmi_id) { 172 pr_err("Reading UEFI Secure Boot Certs is not supported on T2 Macs.\n"); 173 return false; 174 } 175 176 if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE)) 177 return false; 178 179 /* Get db and dbx. They might not exist, so it isn't an error 180 * if we can't get them. 181 */ 182 if (!uefi_check_ignore_db()) { 183 db = get_cert_list(L"db", &secure_var, &dbsize, &status); 184 if (!db) { 185 if (status == EFI_NOT_FOUND) 186 pr_debug("MODSIGN: db variable wasn't found\n"); 187 else 188 pr_err("MODSIGN: Couldn't get UEFI db list\n"); 189 } else { 190 rc = parse_efi_signature_list("UEFI:db", 191 db, dbsize, get_handler_for_db); 192 if (rc) 193 pr_err("Couldn't parse db signatures: %d\n", 194 rc); 195 kfree(db); 196 } 197 } 198 199 dbx = get_cert_list(L"dbx", &secure_var, &dbxsize, &status); 200 if (!dbx) { 201 if (status == EFI_NOT_FOUND) 202 pr_debug("dbx variable wasn't found\n"); 203 else 204 pr_info("Couldn't get UEFI dbx list\n"); 205 } else { 206 rc = parse_efi_signature_list("UEFI:dbx", 207 dbx, dbxsize, 208 get_handler_for_dbx); 209 if (rc) 210 pr_err("Couldn't parse dbx signatures: %d\n", rc); 211 kfree(dbx); 212 } 213 214 /* the MOK/MOKx can not be trusted when secure boot is disabled */ 215 if (!arch_ima_get_secureboot()) 216 return 0; 217 218 mokx = get_cert_list(L"MokListXRT", &mok_var, &mokxsize, &status); 219 if (!mokx) { 220 if (status == EFI_NOT_FOUND) 221 pr_debug("mokx variable wasn't found\n"); 222 else 223 pr_info("Couldn't get mokx list\n"); 224 } else { 225 rc = parse_efi_signature_list("UEFI:MokListXRT", 226 mokx, mokxsize, 227 get_handler_for_dbx); 228 if (rc) 229 pr_err("Couldn't parse mokx signatures %d\n", rc); 230 kfree(mokx); 231 } 232 233 /* Load the MokListRT certs */ 234 rc = load_moklist_certs(); 235 236 return rc; 237 } 238 late_initcall(load_uefi_certs); 239
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.