Skip to content

Commit

Permalink
tpm: Don't duplicate events from the final event log in the TCG2 log
Browse files Browse the repository at this point in the history
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@google.com>
Reported-by: Joe Richey <joerichey@google.com>
Suggested-by: Joe Richey <joerichey@google.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
  • Loading branch information
Matthew Garrett authored and Jarkko Sakkinen committed Jun 24, 2019
1 parent 82d736a commit 166a280
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 1 deletion.
11 changes: 10 additions & 1 deletion drivers/char/tpm/eventlog/efi.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,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);
Expand All @@ -85,8 +87,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;

Expand Down
30 changes: 30 additions & 0 deletions drivers/firmware/efi/libstub/tpm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);

Expand Down
1 change: 1 addition & 0 deletions include/linux/efi.h
Original file line number Diff line number Diff line change
Expand Up @@ -1708,6 +1708,7 @@ struct linux_efi_random_seed {

struct linux_efi_tpm_eventlog {
u32 size;
u32 final_events_preboot_size;
u8 version;
u8 log[];
};
Expand Down

0 comments on commit 166a280

Please sign in to comment.