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