mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-26 14:14:01 +08:00
b4f1874c62
This fixes the boot issues since 5.3 on several Dell models when the TPM is enabled. Depending on the exact grub binary, booting the kernel would freeze early, or just report an error parsing the final events log. We get an event log in the SHA-1 format, which doesn't have a tcg_efi_specid_event_head in the first event, and there is a final events table which doesn't match the crypto agile format. __calc_tpm2_event_size reads bad "count" and "efispecid->num_algs", and either fails, or loops long enough for the machine to be appear frozen. So we now only parse the final events table, which is per the spec always supposed to be in the crypto agile format, when we got a event log in this format. Fixes:c46f340569
("tpm: Reserve the TPM final events table") Fixes:166a2809d6
("tpm: Don't duplicate events from the final event log in the TCG2 log") Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1779611 Signed-off-by: Loïc Yhuel <loic.yhuel@gmail.com> Link: https://lore.kernel.org/r/20200512040113.277768-1-loic.yhuel@gmail.com Reviewed-by: Javier Martinez Canillas <javierm@redhat.com> Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com> Reviewed-by: Matthew Garrett <mjg59@google.com> [ardb: warn when final events table is missing or in the wrong format] Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
109 lines
2.6 KiB
C
109 lines
2.6 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (C) 2017 Google, Inc.
|
|
* Thiebaud Weksteen <tweek@google.com>
|
|
*/
|
|
|
|
#define TPM_MEMREMAP(start, size) early_memremap(start, size)
|
|
#define TPM_MEMUNMAP(start, size) early_memunmap(start, size)
|
|
|
|
#include <asm/early_ioremap.h>
|
|
#include <linux/efi.h>
|
|
#include <linux/init.h>
|
|
#include <linux/memblock.h>
|
|
#include <linux/tpm_eventlog.h>
|
|
|
|
int efi_tpm_final_log_size;
|
|
EXPORT_SYMBOL(efi_tpm_final_log_size);
|
|
|
|
static int tpm2_calc_event_log_size(void *data, int count, void *size_info)
|
|
{
|
|
struct tcg_pcr_event2_head *header;
|
|
int event_size, size = 0;
|
|
|
|
while (count > 0) {
|
|
header = data + size;
|
|
event_size = __calc_tpm2_event_size(header, size_info, true);
|
|
if (event_size == 0)
|
|
return -1;
|
|
size += event_size;
|
|
count--;
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
/*
|
|
* Reserve the memory associated with the TPM Event Log configuration table.
|
|
*/
|
|
int __init efi_tpm_eventlog_init(void)
|
|
{
|
|
struct linux_efi_tpm_eventlog *log_tbl;
|
|
struct efi_tcg2_final_events_table *final_tbl;
|
|
int tbl_size;
|
|
int ret = 0;
|
|
|
|
if (efi.tpm_log == EFI_INVALID_TABLE_ADDR) {
|
|
/*
|
|
* We can't calculate the size of the final events without the
|
|
* first entry in the TPM log, so bail here.
|
|
*/
|
|
return 0;
|
|
}
|
|
|
|
log_tbl = early_memremap(efi.tpm_log, sizeof(*log_tbl));
|
|
if (!log_tbl) {
|
|
pr_err("Failed to map TPM Event Log table @ 0x%lx\n",
|
|
efi.tpm_log);
|
|
efi.tpm_log = EFI_INVALID_TABLE_ADDR;
|
|
return -ENOMEM;
|
|
}
|
|
|
|
tbl_size = sizeof(*log_tbl) + log_tbl->size;
|
|
memblock_reserve(efi.tpm_log, tbl_size);
|
|
|
|
if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR ||
|
|
log_tbl->version != EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) {
|
|
pr_warn(FW_BUG "TPM Final Events table missing or invalid\n");
|
|
goto out;
|
|
}
|
|
|
|
final_tbl = early_memremap(efi.tpm_final_log, sizeof(*final_tbl));
|
|
|
|
if (!final_tbl) {
|
|
pr_err("Failed to map TPM Final Event Log table @ 0x%lx\n",
|
|
efi.tpm_final_log);
|
|
efi.tpm_final_log = EFI_INVALID_TABLE_ADDR;
|
|
ret = -ENOMEM;
|
|
goto out;
|
|
}
|
|
|
|
tbl_size = 0;
|
|
if (final_tbl->nr_events != 0) {
|
|
void *events = (void *)efi.tpm_final_log
|
|
+ sizeof(final_tbl->version)
|
|
+ sizeof(final_tbl->nr_events);
|
|
|
|
tbl_size = tpm2_calc_event_log_size(events,
|
|
final_tbl->nr_events,
|
|
log_tbl->log);
|
|
}
|
|
|
|
if (tbl_size < 0) {
|
|
pr_err(FW_BUG "Failed to parse event in TPM Final Events Log\n");
|
|
ret = -EINVAL;
|
|
goto out_calc;
|
|
}
|
|
|
|
memblock_reserve((unsigned long)final_tbl,
|
|
tbl_size + sizeof(*final_tbl));
|
|
efi_tpm_final_log_size = tbl_size;
|
|
|
|
out_calc:
|
|
early_memunmap(final_tbl, sizeof(*final_tbl));
|
|
out:
|
|
early_memunmap(log_tbl, sizeof(*log_tbl));
|
|
return ret;
|
|
}
|
|
|