cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

load_uefi.c (6818B)


      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 */
     22static 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	{ }
     39};
     40
     41/*
     42 * Look to see if a UEFI variable called MokIgnoreDB exists and return true if
     43 * it does.
     44 *
     45 * This UEFI variable is set by the shim if a user tells the shim to not use
     46 * the certs/hashes in the UEFI db variable for verification purposes.  If it
     47 * is set, we should ignore the db variable also and the true return indicates
     48 * this.
     49 */
     50static __init bool uefi_check_ignore_db(void)
     51{
     52	efi_status_t status;
     53	unsigned int db = 0;
     54	unsigned long size = sizeof(db);
     55	efi_guid_t guid = EFI_SHIM_LOCK_GUID;
     56
     57	status = efi.get_variable(L"MokIgnoreDB", &guid, NULL, &size, &db);
     58	return status == EFI_SUCCESS;
     59}
     60
     61/*
     62 * Get a certificate list blob from the named EFI variable.
     63 */
     64static __init void *get_cert_list(efi_char16_t *name, efi_guid_t *guid,
     65				  unsigned long *size, efi_status_t *status)
     66{
     67	unsigned long lsize = 4;
     68	unsigned long tmpdb[4];
     69	void *db;
     70
     71	*status = efi.get_variable(name, guid, NULL, &lsize, &tmpdb);
     72	if (*status == EFI_NOT_FOUND)
     73		return NULL;
     74
     75	if (*status != EFI_BUFFER_TOO_SMALL) {
     76		pr_err("Couldn't get size: 0x%lx\n", *status);
     77		return NULL;
     78	}
     79
     80	db = kmalloc(lsize, GFP_KERNEL);
     81	if (!db)
     82		return NULL;
     83
     84	*status = efi.get_variable(name, guid, NULL, &lsize, db);
     85	if (*status != EFI_SUCCESS) {
     86		kfree(db);
     87		pr_err("Error reading db var: 0x%lx\n", *status);
     88		return NULL;
     89	}
     90
     91	*size = lsize;
     92	return db;
     93}
     94
     95/*
     96 * load_moklist_certs() - Load MokList certs
     97 *
     98 * Load the certs contained in the UEFI MokListRT database into the
     99 * platform trusted keyring.
    100 *
    101 * This routine checks the EFI MOK config table first. If and only if
    102 * that fails, this routine uses the MokListRT ordinary UEFI variable.
    103 *
    104 * Return:	Status
    105 */
    106static int __init load_moklist_certs(void)
    107{
    108	struct efi_mokvar_table_entry *mokvar_entry;
    109	efi_guid_t mok_var = EFI_SHIM_LOCK_GUID;
    110	void *mok;
    111	unsigned long moksize;
    112	efi_status_t status;
    113	int rc;
    114
    115	/* First try to load certs from the EFI MOKvar config table.
    116	 * It's not an error if the MOKvar config table doesn't exist
    117	 * or the MokListRT entry is not found in it.
    118	 */
    119	mokvar_entry = efi_mokvar_entry_find("MokListRT");
    120	if (mokvar_entry) {
    121		rc = parse_efi_signature_list("UEFI:MokListRT (MOKvar table)",
    122					      mokvar_entry->data,
    123					      mokvar_entry->data_size,
    124					      get_handler_for_mok);
    125		/* All done if that worked. */
    126		if (!rc)
    127			return rc;
    128
    129		pr_err("Couldn't parse MokListRT signatures from EFI MOKvar config table: %d\n",
    130		       rc);
    131	}
    132
    133	/* Get MokListRT. It might not exist, so it isn't an error
    134	 * if we can't get it.
    135	 */
    136	mok = get_cert_list(L"MokListRT", &mok_var, &moksize, &status);
    137	if (mok) {
    138		rc = parse_efi_signature_list("UEFI:MokListRT",
    139					      mok, moksize, get_handler_for_mok);
    140		kfree(mok);
    141		if (rc)
    142			pr_err("Couldn't parse MokListRT signatures: %d\n", rc);
    143		return rc;
    144	}
    145	if (status == EFI_NOT_FOUND)
    146		pr_debug("MokListRT variable wasn't found\n");
    147	else
    148		pr_info("Couldn't get UEFI MokListRT\n");
    149	return 0;
    150}
    151
    152/*
    153 * load_uefi_certs() - Load certs from UEFI sources
    154 *
    155 * Load the certs contained in the UEFI databases into the platform trusted
    156 * keyring and the UEFI blacklisted X.509 cert SHA256 hashes into the blacklist
    157 * keyring.
    158 */
    159static int __init load_uefi_certs(void)
    160{
    161	efi_guid_t secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
    162	efi_guid_t mok_var = EFI_SHIM_LOCK_GUID;
    163	void *db = NULL, *dbx = NULL, *mokx = NULL;
    164	unsigned long dbsize = 0, dbxsize = 0, mokxsize = 0;
    165	efi_status_t status;
    166	int rc = 0;
    167	const struct dmi_system_id *dmi_id;
    168
    169	dmi_id = dmi_first_match(uefi_skip_cert);
    170	if (dmi_id) {
    171		pr_err("Reading UEFI Secure Boot Certs is not supported on T2 Macs.\n");
    172		return false;
    173	}
    174
    175	if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
    176		return false;
    177
    178	/* Get db and dbx.  They might not exist, so it isn't an error
    179	 * if we can't get them.
    180	 */
    181	if (!uefi_check_ignore_db()) {
    182		db = get_cert_list(L"db", &secure_var, &dbsize, &status);
    183		if (!db) {
    184			if (status == EFI_NOT_FOUND)
    185				pr_debug("MODSIGN: db variable wasn't found\n");
    186			else
    187				pr_err("MODSIGN: Couldn't get UEFI db list\n");
    188		} else {
    189			rc = parse_efi_signature_list("UEFI:db",
    190					db, dbsize, get_handler_for_db);
    191			if (rc)
    192				pr_err("Couldn't parse db signatures: %d\n",
    193				       rc);
    194			kfree(db);
    195		}
    196	}
    197
    198	dbx = get_cert_list(L"dbx", &secure_var, &dbxsize, &status);
    199	if (!dbx) {
    200		if (status == EFI_NOT_FOUND)
    201			pr_debug("dbx variable wasn't found\n");
    202		else
    203			pr_info("Couldn't get UEFI dbx list\n");
    204	} else {
    205		rc = parse_efi_signature_list("UEFI:dbx",
    206					      dbx, dbxsize,
    207					      get_handler_for_dbx);
    208		if (rc)
    209			pr_err("Couldn't parse dbx signatures: %d\n", rc);
    210		kfree(dbx);
    211	}
    212
    213	/* the MOK/MOKx can not be trusted when secure boot is disabled */
    214	if (!arch_ima_get_secureboot())
    215		return 0;
    216
    217	mokx = get_cert_list(L"MokListXRT", &mok_var, &mokxsize, &status);
    218	if (!mokx) {
    219		if (status == EFI_NOT_FOUND)
    220			pr_debug("mokx variable wasn't found\n");
    221		else
    222			pr_info("Couldn't get mokx list\n");
    223	} else {
    224		rc = parse_efi_signature_list("UEFI:MokListXRT",
    225					      mokx, mokxsize,
    226					      get_handler_for_dbx);
    227		if (rc)
    228			pr_err("Couldn't parse mokx signatures %d\n", rc);
    229		kfree(mokx);
    230	}
    231
    232	/* Load the MokListRT certs */
    233	rc = load_moklist_certs();
    234
    235	return rc;
    236}
    237late_initcall(load_uefi_certs);