xref: /openbmc/linux/drivers/firmware/efi/libstub/tpm.c (revision 79832f0b)
1ccc829baSMatthew Garrett /*
2ccc829baSMatthew Garrett  * TPM handling.
3ccc829baSMatthew Garrett  *
4ccc829baSMatthew Garrett  * Copyright (C) 2016 CoreOS, Inc
5ccc829baSMatthew Garrett  * Copyright (C) 2017 Google, Inc.
6ccc829baSMatthew Garrett  *     Matthew Garrett <mjg59@google.com>
733b6d034SThiebaud Weksteen  *     Thiebaud Weksteen <tweek@google.com>
8ccc829baSMatthew Garrett  *
9ccc829baSMatthew Garrett  * This file is part of the Linux kernel, and is made available under the
10ccc829baSMatthew Garrett  * terms of the GNU General Public License version 2.
11ccc829baSMatthew Garrett  */
12ccc829baSMatthew Garrett #include <linux/efi.h>
1333b6d034SThiebaud Weksteen #include <linux/tpm_eventlog.h>
14ccc829baSMatthew Garrett #include <asm/efi.h>
15ccc829baSMatthew Garrett 
16ccc829baSMatthew Garrett #include "efistub.h"
17ccc829baSMatthew Garrett 
1833b6d034SThiebaud Weksteen #ifdef CONFIG_RESET_ATTACK_MITIGATION
19ccc829baSMatthew Garrett static const efi_char16_t efi_MemoryOverWriteRequest_name[] = {
20ccc829baSMatthew Garrett 	'M', 'e', 'm', 'o', 'r', 'y', 'O', 'v', 'e', 'r', 'w', 'r', 'i', 't',
21ccc829baSMatthew Garrett 	'e', 'R', 'e', 'q', 'u', 'e', 's', 't', 'C', 'o', 'n', 't', 'r', 'o',
22ccc829baSMatthew Garrett 	'l', 0
23ccc829baSMatthew Garrett };
24ccc829baSMatthew Garrett 
25ccc829baSMatthew Garrett #define MEMORY_ONLY_RESET_CONTROL_GUID \
26ccc829baSMatthew Garrett 	EFI_GUID(0xe20939be, 0x32d4, 0x41be, 0xa1, 0x50, 0x89, 0x7f, 0x85, 0xd4, 0x98, 0x29)
27ccc829baSMatthew Garrett 
28ccc829baSMatthew Garrett #define get_efi_var(name, vendor, ...) \
29ccc829baSMatthew Garrett 	efi_call_runtime(get_variable, \
30ccc829baSMatthew Garrett 			 (efi_char16_t *)(name), (efi_guid_t *)(vendor), \
31ccc829baSMatthew Garrett 			 __VA_ARGS__)
32ccc829baSMatthew Garrett 
33ccc829baSMatthew Garrett #define set_efi_var(name, vendor, ...) \
34ccc829baSMatthew Garrett 	efi_call_runtime(set_variable, \
35ccc829baSMatthew Garrett 			 (efi_char16_t *)(name), (efi_guid_t *)(vendor), \
36ccc829baSMatthew Garrett 			 __VA_ARGS__)
37ccc829baSMatthew Garrett 
38ccc829baSMatthew Garrett /*
39ccc829baSMatthew Garrett  * Enable reboot attack mitigation. This requests that the firmware clear the
40ccc829baSMatthew Garrett  * RAM on next reboot before proceeding with boot, ensuring that any secrets
41ccc829baSMatthew Garrett  * are cleared. If userland has ensured that all secrets have been removed
42ccc829baSMatthew Garrett  * from RAM before reboot it can simply reset this variable.
43ccc829baSMatthew Garrett  */
44ccc829baSMatthew Garrett void efi_enable_reset_attack_mitigation(efi_system_table_t *sys_table_arg)
45ccc829baSMatthew Garrett {
46ccc829baSMatthew Garrett 	u8 val = 1;
47ccc829baSMatthew Garrett 	efi_guid_t var_guid = MEMORY_ONLY_RESET_CONTROL_GUID;
48ccc829baSMatthew Garrett 	efi_status_t status;
49ccc829baSMatthew Garrett 	unsigned long datasize = 0;
50ccc829baSMatthew Garrett 
51ccc829baSMatthew Garrett 	status = get_efi_var(efi_MemoryOverWriteRequest_name, &var_guid,
52ccc829baSMatthew Garrett 			     NULL, &datasize, NULL);
53ccc829baSMatthew Garrett 
54ccc829baSMatthew Garrett 	if (status == EFI_NOT_FOUND)
55ccc829baSMatthew Garrett 		return;
56ccc829baSMatthew Garrett 
57ccc829baSMatthew Garrett 	set_efi_var(efi_MemoryOverWriteRequest_name, &var_guid,
58ccc829baSMatthew Garrett 		    EFI_VARIABLE_NON_VOLATILE |
59ccc829baSMatthew Garrett 		    EFI_VARIABLE_BOOTSERVICE_ACCESS |
60ccc829baSMatthew Garrett 		    EFI_VARIABLE_RUNTIME_ACCESS, sizeof(val), &val);
61ccc829baSMatthew Garrett }
6233b6d034SThiebaud Weksteen 
6333b6d034SThiebaud Weksteen #endif
6433b6d034SThiebaud Weksteen 
6533b6d034SThiebaud Weksteen void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg)
6633b6d034SThiebaud Weksteen {
6733b6d034SThiebaud Weksteen 	efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID;
6833b6d034SThiebaud Weksteen 	efi_guid_t linux_eventlog_guid = LINUX_EFI_TPM_EVENT_LOG_GUID;
6933b6d034SThiebaud Weksteen 	efi_status_t status;
7033b6d034SThiebaud Weksteen 	efi_physical_addr_t log_location, log_last_entry;
7179832f0bSArd Biesheuvel 	struct linux_efi_tpm_eventlog *log_tbl = NULL;
7233b6d034SThiebaud Weksteen 	unsigned long first_entry_addr, last_entry_addr;
7333b6d034SThiebaud Weksteen 	size_t log_size, last_entry_size;
7433b6d034SThiebaud Weksteen 	efi_bool_t truncated;
7579832f0bSArd Biesheuvel 	void *tcg2_protocol = NULL;
7633b6d034SThiebaud Weksteen 
7733b6d034SThiebaud Weksteen 	status = efi_call_early(locate_protocol, &tcg2_guid, NULL,
7833b6d034SThiebaud Weksteen 				&tcg2_protocol);
7933b6d034SThiebaud Weksteen 	if (status != EFI_SUCCESS)
8033b6d034SThiebaud Weksteen 		return;
8133b6d034SThiebaud Weksteen 
8233b6d034SThiebaud Weksteen 	status = efi_call_proto(efi_tcg2_protocol, get_event_log, tcg2_protocol,
8333b6d034SThiebaud Weksteen 				EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2,
8433b6d034SThiebaud Weksteen 				&log_location, &log_last_entry, &truncated);
8533b6d034SThiebaud Weksteen 	if (status != EFI_SUCCESS)
8633b6d034SThiebaud Weksteen 		return;
8733b6d034SThiebaud Weksteen 
8833b6d034SThiebaud Weksteen 	if (!log_location)
8933b6d034SThiebaud Weksteen 		return;
9033b6d034SThiebaud Weksteen 	first_entry_addr = (unsigned long) log_location;
9133b6d034SThiebaud Weksteen 
9233b6d034SThiebaud Weksteen 	/*
9333b6d034SThiebaud Weksteen 	 * We populate the EFI table even if the logs are empty.
9433b6d034SThiebaud Weksteen 	 */
9533b6d034SThiebaud Weksteen 	if (!log_last_entry) {
9633b6d034SThiebaud Weksteen 		log_size = 0;
9733b6d034SThiebaud Weksteen 	} else {
9833b6d034SThiebaud Weksteen 		last_entry_addr = (unsigned long) log_last_entry;
9933b6d034SThiebaud Weksteen 		/*
10033b6d034SThiebaud Weksteen 		 * get_event_log only returns the address of the last entry.
10133b6d034SThiebaud Weksteen 		 * We need to calculate its size to deduce the full size of
10233b6d034SThiebaud Weksteen 		 * the logs.
10333b6d034SThiebaud Weksteen 		 */
10433b6d034SThiebaud Weksteen 		last_entry_size = sizeof(struct tcpa_event) +
10533b6d034SThiebaud Weksteen 			((struct tcpa_event *) last_entry_addr)->event_size;
10633b6d034SThiebaud Weksteen 		log_size = log_last_entry - log_location + last_entry_size;
10733b6d034SThiebaud Weksteen 	}
10833b6d034SThiebaud Weksteen 
10933b6d034SThiebaud Weksteen 	/* Allocate space for the logs and copy them. */
11033b6d034SThiebaud Weksteen 	status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
11133b6d034SThiebaud Weksteen 				sizeof(*log_tbl) + log_size,
11233b6d034SThiebaud Weksteen 				(void **) &log_tbl);
11333b6d034SThiebaud Weksteen 
11433b6d034SThiebaud Weksteen 	if (status != EFI_SUCCESS) {
11533b6d034SThiebaud Weksteen 		efi_printk(sys_table_arg,
11633b6d034SThiebaud Weksteen 			   "Unable to allocate memory for event log\n");
11733b6d034SThiebaud Weksteen 		return;
11833b6d034SThiebaud Weksteen 	}
11933b6d034SThiebaud Weksteen 
12033b6d034SThiebaud Weksteen 	memset(log_tbl, 0, sizeof(*log_tbl) + log_size);
12133b6d034SThiebaud Weksteen 	log_tbl->size = log_size;
12233b6d034SThiebaud Weksteen 	log_tbl->version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2;
12333b6d034SThiebaud Weksteen 	memcpy(log_tbl->log, (void *) first_entry_addr, log_size);
12433b6d034SThiebaud Weksteen 
12533b6d034SThiebaud Weksteen 	status = efi_call_early(install_configuration_table,
12633b6d034SThiebaud Weksteen 				&linux_eventlog_guid, log_tbl);
12733b6d034SThiebaud Weksteen 	if (status != EFI_SUCCESS)
12833b6d034SThiebaud Weksteen 		goto err_free;
12933b6d034SThiebaud Weksteen 	return;
13033b6d034SThiebaud Weksteen 
13133b6d034SThiebaud Weksteen err_free:
13233b6d034SThiebaud Weksteen 	efi_call_early(free_pool, log_tbl);
13333b6d034SThiebaud Weksteen }
13433b6d034SThiebaud Weksteen 
13533b6d034SThiebaud Weksteen void efi_retrieve_tpm2_eventlog(efi_system_table_t *sys_table_arg)
13633b6d034SThiebaud Weksteen {
13733b6d034SThiebaud Weksteen 	/* Only try to retrieve the logs in 1.2 format. */
13833b6d034SThiebaud Weksteen 	efi_retrieve_tpm2_eventlog_1_2(sys_table_arg);
13933b6d034SThiebaud Weksteen }
140