On Fri, 7 Jun 2019 at 22:52, Matthew Garrett <matthewgarrett@xxxxxxxxxx> wrote: > > After the first call to GetEventLog() on UEFI systems using the TCG2 > crypto agile log format, any further log events (other than those > triggered by ExitBootServices()) will be logged in both the main log and > also in the Final Events Log. While the kernel only calls GetEventLog() > immediately before ExitBootServices(), we can't control whether earlier > parts of the boot process have done so. This will result in log entries > that exist in both logs, and so the current approach of simply appending > the Final Event Log to the main log will result in events being > duplicated. > > We can avoid this problem by looking at the size of the Final Event Log > just before we call ExitBootServices() and exporting this to the main > kernel. The kernel can then skip over all events that occured before > ExitBootServices() and only append events that were not also logged to > the main log. > > Signed-off-by: Matthew Garrett <mjg59@xxxxxxxxxx> > Reported-by: Joe Richey <joerichey@xxxxxxxxxx> > Suggested-by: Joe Richey <joerichey@xxxxxxxxxx> > --- > drivers/char/tpm/eventlog/efi.c | 11 ++++++++++- > drivers/firmware/efi/libstub/tpm.c | 30 ++++++++++++++++++++++++++++++ > drivers/firmware/efi/tpm.c | 2 +- > include/linux/efi.h | 1 + > 4 files changed, 42 insertions(+), 2 deletions(-) > > diff --git a/drivers/char/tpm/eventlog/efi.c b/drivers/char/tpm/eventlog/efi.c > index 9179cf6bdee9..be6540f2cb3d 100644 > --- a/drivers/char/tpm/eventlog/efi.c > +++ b/drivers/char/tpm/eventlog/efi.c > @@ -80,6 +80,8 @@ int tpm_read_log_efi(struct tpm_chip *chip) > goto out; > } > > + efi_tpm_final_log_size -= log_tbl->final_events_preboot_size; > + > tmp = krealloc(log->bios_event_log, > log_size + efi_tpm_final_log_size, > GFP_KERNEL); > @@ -90,8 +92,15 @@ int tpm_read_log_efi(struct tpm_chip *chip) > } > > log->bios_event_log = tmp; > + > + /* > + * Copy any of the final events log that didn't also end up in the > + * main log. Events can be logged in both if events are generated > + * between GetEventLog() and ExitBootServices(). > + */ > memcpy((void *)log->bios_event_log + log_size, > - final_tbl->events, efi_tpm_final_log_size); > + final_tbl->events + log_tbl->final_events_preboot_size, > + efi_tpm_final_log_size); > log->bios_event_log_end = log->bios_event_log + > log_size + efi_tpm_final_log_size; > > diff --git a/drivers/firmware/efi/libstub/tpm.c b/drivers/firmware/efi/libstub/tpm.c > index 6b3b507a54eb..eb9af83e4d59 100644 > --- a/drivers/firmware/efi/libstub/tpm.c > +++ b/drivers/firmware/efi/libstub/tpm.c > @@ -64,11 +64,13 @@ void efi_retrieve_tpm2_eventlog(efi_system_table_t *sys_table_arg) > efi_status_t status; > efi_physical_addr_t log_location = 0, log_last_entry = 0; > struct linux_efi_tpm_eventlog *log_tbl = NULL; > + struct efi_tcg2_final_events_table *final_events_table; > unsigned long first_entry_addr, last_entry_addr; > size_t log_size, last_entry_size; > efi_bool_t truncated; > int version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_2; > void *tcg2_protocol = NULL; > + int final_events_size = 0; > > status = efi_call_early(locate_protocol, &tcg2_guid, NULL, > &tcg2_protocol); > @@ -134,8 +136,36 @@ void efi_retrieve_tpm2_eventlog(efi_system_table_t *sys_table_arg) > return; > } > > + /* > + * Figure out whether any events have already been logged to the > + * final events structure, and if so how much space they take up > + */ > + final_events_table = get_efi_config_table(sys_table_arg, > + LINUX_EFI_TPM_FINAL_LOG_GUID); > + if (final_events_table && final_events_table->nr_events) { > + struct tcg_pcr_event2_head *header; > + int offset; > + void *data; > + int event_size; > + int i = final_events_table->nr_events; > + > + data = (void *)final_events_table; > + offset = sizeof(final_events_table->version) + > + sizeof(final_events_table->nr_events); > + > + while (i > 0) { > + header = data + offset + final_events_size; > + event_size = __calc_tpm2_event_size(header, > + (void *)(long)log_location, > + false); > + final_events_size += event_size; > + i--; > + } > + } > + > memset(log_tbl, 0, sizeof(*log_tbl) + log_size); > log_tbl->size = log_size; > + log_tbl->final_events_preboot_size = final_events_size; > log_tbl->version = version; > memcpy(log_tbl->log, (void *) first_entry_addr, log_size); > > diff --git a/drivers/firmware/efi/tpm.c b/drivers/firmware/efi/tpm.c > index 2c912ea08166..0bdceb5913aa 100644 > --- a/drivers/firmware/efi/tpm.c > +++ b/drivers/firmware/efi/tpm.c > @@ -76,7 +76,7 @@ int __init efi_tpm_eventlog_init(void) > goto out; > } > > - tbl_size = tpm2_calc_event_log_size(efi.tpm_final_log > + tbl_size = tpm2_calc_event_log_size((void *)efi.tpm_final_log > + sizeof(final_tbl->version) > + sizeof(final_tbl->nr_events), > final_tbl->nr_events, > diff --git a/include/linux/efi.h b/include/linux/efi.h > index e33c70a52a9d..2a26004a9bdb 100644 > --- a/include/linux/efi.h > +++ b/include/linux/efi.h > @@ -1703,6 +1703,7 @@ struct linux_efi_random_seed { > > struct linux_efi_tpm_eventlog { > u32 size; > + u32 final_events_preboot_size; > u8 version; > u8 log[]; > }; Acked-by: Ard Biesheuvel <ard.biesheuvel@xxxxxxxxxx>