14febfb8dSArd Biesheuvel // SPDX-License-Identifier: GPL-2.0 2ccc829baSMatthew Garrett /* 3ccc829baSMatthew Garrett * TPM handling. 4ccc829baSMatthew Garrett * 5ccc829baSMatthew Garrett * Copyright (C) 2016 CoreOS, Inc 6ccc829baSMatthew Garrett * Copyright (C) 2017 Google, Inc. 7ccc829baSMatthew Garrett * Matthew Garrett <mjg59@google.com> 833b6d034SThiebaud Weksteen * Thiebaud Weksteen <tweek@google.com> 9ccc829baSMatthew Garrett */ 10ccc829baSMatthew Garrett #include <linux/efi.h> 1133b6d034SThiebaud Weksteen #include <linux/tpm_eventlog.h> 12ccc829baSMatthew Garrett #include <asm/efi.h> 13ccc829baSMatthew Garrett 14ccc829baSMatthew Garrett #include "efistub.h" 15ccc829baSMatthew Garrett 1633b6d034SThiebaud Weksteen #ifdef CONFIG_RESET_ATTACK_MITIGATION 1736b64976SArd Biesheuvel static const efi_char16_t efi_MemoryOverWriteRequest_name[] = 1836b64976SArd Biesheuvel L"MemoryOverwriteRequestControl"; 19ccc829baSMatthew Garrett 20ccc829baSMatthew Garrett #define MEMORY_ONLY_RESET_CONTROL_GUID \ 21ccc829baSMatthew Garrett EFI_GUID(0xe20939be, 0x32d4, 0x41be, 0xa1, 0x50, 0x89, 0x7f, 0x85, 0xd4, 0x98, 0x29) 22ccc829baSMatthew Garrett 23ccc829baSMatthew Garrett #define get_efi_var(name, vendor, ...) \ 24ccc829baSMatthew Garrett efi_call_runtime(get_variable, \ 25ccc829baSMatthew Garrett (efi_char16_t *)(name), (efi_guid_t *)(vendor), \ 26ccc829baSMatthew Garrett __VA_ARGS__) 27ccc829baSMatthew Garrett 28ccc829baSMatthew Garrett #define set_efi_var(name, vendor, ...) \ 29ccc829baSMatthew Garrett efi_call_runtime(set_variable, \ 30ccc829baSMatthew Garrett (efi_char16_t *)(name), (efi_guid_t *)(vendor), \ 31ccc829baSMatthew Garrett __VA_ARGS__) 32ccc829baSMatthew Garrett 33ccc829baSMatthew Garrett /* 34ccc829baSMatthew Garrett * Enable reboot attack mitigation. This requests that the firmware clear the 35ccc829baSMatthew Garrett * RAM on next reboot before proceeding with boot, ensuring that any secrets 36ccc829baSMatthew Garrett * are cleared. If userland has ensured that all secrets have been removed 37ccc829baSMatthew Garrett * from RAM before reboot it can simply reset this variable. 38ccc829baSMatthew Garrett */ 39cd33a5c1SArd Biesheuvel void efi_enable_reset_attack_mitigation(void) 40ccc829baSMatthew Garrett { 41ccc829baSMatthew Garrett u8 val = 1; 42ccc829baSMatthew Garrett efi_guid_t var_guid = MEMORY_ONLY_RESET_CONTROL_GUID; 43ccc829baSMatthew Garrett efi_status_t status; 44ccc829baSMatthew Garrett unsigned long datasize = 0; 45ccc829baSMatthew Garrett 46ccc829baSMatthew Garrett status = get_efi_var(efi_MemoryOverWriteRequest_name, &var_guid, 47ccc829baSMatthew Garrett NULL, &datasize, NULL); 48ccc829baSMatthew Garrett 49ccc829baSMatthew Garrett if (status == EFI_NOT_FOUND) 50ccc829baSMatthew Garrett return; 51ccc829baSMatthew Garrett 52ccc829baSMatthew Garrett set_efi_var(efi_MemoryOverWriteRequest_name, &var_guid, 53ccc829baSMatthew Garrett EFI_VARIABLE_NON_VOLATILE | 54ccc829baSMatthew Garrett EFI_VARIABLE_BOOTSERVICE_ACCESS | 55ccc829baSMatthew Garrett EFI_VARIABLE_RUNTIME_ACCESS, sizeof(val), &val); 56ccc829baSMatthew Garrett } 5733b6d034SThiebaud Weksteen 5833b6d034SThiebaud Weksteen #endif 5933b6d034SThiebaud Weksteen 60cd33a5c1SArd Biesheuvel void efi_retrieve_tpm2_eventlog(void) 6133b6d034SThiebaud Weksteen { 6233b6d034SThiebaud Weksteen efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID; 6333b6d034SThiebaud Weksteen efi_guid_t linux_eventlog_guid = LINUX_EFI_TPM_EVENT_LOG_GUID; 6433b6d034SThiebaud Weksteen efi_status_t status; 6552e1cf2dSHans de Goede efi_physical_addr_t log_location = 0, log_last_entry = 0; 6679832f0bSArd Biesheuvel struct linux_efi_tpm_eventlog *log_tbl = NULL; 67166a2809SMatthew Garrett struct efi_tcg2_final_events_table *final_events_table; 6833b6d034SThiebaud Weksteen unsigned long first_entry_addr, last_entry_addr; 6933b6d034SThiebaud Weksteen size_t log_size, last_entry_size; 7033b6d034SThiebaud Weksteen efi_bool_t truncated; 716b032619SMatthew Garrett int version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_2; 72960a8d01SArd Biesheuvel efi_tcg2_protocol_t *tcg2_protocol = NULL; 73166a2809SMatthew Garrett int final_events_size = 0; 7433b6d034SThiebaud Weksteen 7533b6d034SThiebaud Weksteen status = efi_call_early(locate_protocol, &tcg2_guid, NULL, 76960a8d01SArd Biesheuvel (void **)&tcg2_protocol); 7733b6d034SThiebaud Weksteen if (status != EFI_SUCCESS) 7833b6d034SThiebaud Weksteen return; 7933b6d034SThiebaud Weksteen 806b032619SMatthew Garrett status = efi_call_proto(efi_tcg2_protocol, get_event_log, 816b032619SMatthew Garrett tcg2_protocol, version, &log_location, 826b032619SMatthew Garrett &log_last_entry, &truncated); 836b032619SMatthew Garrett 846b032619SMatthew Garrett if (status != EFI_SUCCESS || !log_location) { 856b032619SMatthew Garrett version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2; 866b032619SMatthew Garrett status = efi_call_proto(efi_tcg2_protocol, get_event_log, 876b032619SMatthew Garrett tcg2_protocol, version, &log_location, 886b032619SMatthew Garrett &log_last_entry, &truncated); 896b032619SMatthew Garrett if (status != EFI_SUCCESS || !log_location) 9033b6d034SThiebaud Weksteen return; 9133b6d034SThiebaud Weksteen 926b032619SMatthew Garrett } 936b032619SMatthew Garrett 9433b6d034SThiebaud Weksteen first_entry_addr = (unsigned long) log_location; 9533b6d034SThiebaud Weksteen 9633b6d034SThiebaud Weksteen /* 9733b6d034SThiebaud Weksteen * We populate the EFI table even if the logs are empty. 9833b6d034SThiebaud Weksteen */ 9933b6d034SThiebaud Weksteen if (!log_last_entry) { 10033b6d034SThiebaud Weksteen log_size = 0; 10133b6d034SThiebaud Weksteen } else { 10233b6d034SThiebaud Weksteen last_entry_addr = (unsigned long) log_last_entry; 10333b6d034SThiebaud Weksteen /* 10433b6d034SThiebaud Weksteen * get_event_log only returns the address of the last entry. 10533b6d034SThiebaud Weksteen * We need to calculate its size to deduce the full size of 10633b6d034SThiebaud Weksteen * the logs. 10733b6d034SThiebaud Weksteen */ 1086b032619SMatthew Garrett if (version == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) { 1096b032619SMatthew Garrett /* 1106b032619SMatthew Garrett * The TCG2 log format has variable length entries, 1116b032619SMatthew Garrett * and the information to decode the hash algorithms 1126b032619SMatthew Garrett * back into a size is contained in the first entry - 1136b032619SMatthew Garrett * pass a pointer to the final entry (to calculate its 1146b032619SMatthew Garrett * size) and the first entry (so we know how long each 1156b032619SMatthew Garrett * digest is) 1166b032619SMatthew Garrett */ 1176b032619SMatthew Garrett last_entry_size = 1186b032619SMatthew Garrett __calc_tpm2_event_size((void *)last_entry_addr, 1196b032619SMatthew Garrett (void *)(long)log_location, 1206b032619SMatthew Garrett false); 1216b032619SMatthew Garrett } else { 12233b6d034SThiebaud Weksteen last_entry_size = sizeof(struct tcpa_event) + 12333b6d034SThiebaud Weksteen ((struct tcpa_event *) last_entry_addr)->event_size; 1246b032619SMatthew Garrett } 12533b6d034SThiebaud Weksteen log_size = log_last_entry - log_location + last_entry_size; 12633b6d034SThiebaud Weksteen } 12733b6d034SThiebaud Weksteen 12833b6d034SThiebaud Weksteen /* Allocate space for the logs and copy them. */ 12933b6d034SThiebaud Weksteen status = efi_call_early(allocate_pool, EFI_LOADER_DATA, 13033b6d034SThiebaud Weksteen sizeof(*log_tbl) + log_size, 13133b6d034SThiebaud Weksteen (void **) &log_tbl); 13233b6d034SThiebaud Weksteen 13333b6d034SThiebaud Weksteen if (status != EFI_SUCCESS) { 1348173ec79SArd Biesheuvel efi_printk("Unable to allocate memory for event log\n"); 13533b6d034SThiebaud Weksteen return; 13633b6d034SThiebaud Weksteen } 13733b6d034SThiebaud Weksteen 138166a2809SMatthew Garrett /* 139166a2809SMatthew Garrett * Figure out whether any events have already been logged to the 140166a2809SMatthew Garrett * final events structure, and if so how much space they take up 141166a2809SMatthew Garrett */ 142cd33a5c1SArd Biesheuvel final_events_table = get_efi_config_table(LINUX_EFI_TPM_FINAL_LOG_GUID); 143166a2809SMatthew Garrett if (final_events_table && final_events_table->nr_events) { 144166a2809SMatthew Garrett struct tcg_pcr_event2_head *header; 145166a2809SMatthew Garrett int offset; 146166a2809SMatthew Garrett void *data; 147166a2809SMatthew Garrett int event_size; 148166a2809SMatthew Garrett int i = final_events_table->nr_events; 149166a2809SMatthew Garrett 150166a2809SMatthew Garrett data = (void *)final_events_table; 151166a2809SMatthew Garrett offset = sizeof(final_events_table->version) + 152166a2809SMatthew Garrett sizeof(final_events_table->nr_events); 153166a2809SMatthew Garrett 154166a2809SMatthew Garrett while (i > 0) { 155166a2809SMatthew Garrett header = data + offset + final_events_size; 156166a2809SMatthew Garrett event_size = __calc_tpm2_event_size(header, 157166a2809SMatthew Garrett (void *)(long)log_location, 158166a2809SMatthew Garrett false); 159166a2809SMatthew Garrett final_events_size += event_size; 160166a2809SMatthew Garrett i--; 161166a2809SMatthew Garrett } 162166a2809SMatthew Garrett } 163166a2809SMatthew Garrett 16433b6d034SThiebaud Weksteen memset(log_tbl, 0, sizeof(*log_tbl) + log_size); 16533b6d034SThiebaud Weksteen log_tbl->size = log_size; 166166a2809SMatthew Garrett log_tbl->final_events_preboot_size = final_events_size; 1676b032619SMatthew Garrett log_tbl->version = version; 16833b6d034SThiebaud Weksteen memcpy(log_tbl->log, (void *) first_entry_addr, log_size); 16933b6d034SThiebaud Weksteen 17033b6d034SThiebaud Weksteen status = efi_call_early(install_configuration_table, 17133b6d034SThiebaud Weksteen &linux_eventlog_guid, log_tbl); 17233b6d034SThiebaud Weksteen if (status != EFI_SUCCESS) 17333b6d034SThiebaud Weksteen goto err_free; 17433b6d034SThiebaud Weksteen return; 17533b6d034SThiebaud Weksteen 17633b6d034SThiebaud Weksteen err_free: 17733b6d034SThiebaud Weksteen efi_call_early(free_pool, log_tbl); 17833b6d034SThiebaud Weksteen } 179