| From e658c82be5561412c5e83b5e74e9da4830593f3e Mon Sep 17 00:00:00 2001 |
| From: Jerry Snitselaar <jsnitsel@redhat.com> |
| Date: Wed, 2 Oct 2019 18:59:02 +0200 |
| Subject: efi/tpm: Only set 'efi_tpm_final_log_size' after successful event log parsing |
| |
| From: Jerry Snitselaar <jsnitsel@redhat.com> |
| |
| commit e658c82be5561412c5e83b5e74e9da4830593f3e upstream. |
| |
| If __calc_tpm2_event_size() fails to parse an event it will return 0, |
| resulting tpm2_calc_event_log_size() returning -1. Currently there is |
| no check of this return value, and 'efi_tpm_final_log_size' can end up |
| being set to this negative value resulting in a crash like this one: |
| |
| BUG: unable to handle page fault for address: ffffbc8fc00866ad |
| #PF: supervisor read access in kernel mode |
| #PF: error_code(0x0000) - not-present page |
| |
| RIP: 0010:memcpy_erms+0x6/0x10 |
| Call Trace: |
| tpm_read_log_efi() |
| tpm_bios_log_setup() |
| tpm_chip_register() |
| tpm_tis_core_init.cold.9+0x28c/0x466 |
| tpm_tis_plat_probe() |
| platform_drv_probe() |
| ... |
| |
| Also __calc_tpm2_event_size() returns a size of 0 when it fails |
| to parse an event, so update function documentation to reflect this. |
| |
| The root cause of the issue that caused the failure of event parsing |
| in this case is resolved by Peter Jone's patchset dealing with large |
| event logs where crossing over a page boundary causes the page with |
| the event count to be unmapped. |
| |
| Signed-off-by: Jerry Snitselaar <jsnitsel@redhat.com> |
| Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> |
| Cc: Ben Dooks <ben.dooks@codethink.co.uk> |
| Cc: Dave Young <dyoung@redhat.com> |
| Cc: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> |
| Cc: Linus Torvalds <torvalds@linux-foundation.org> |
| Cc: Lukas Wunner <lukas@wunner.de> |
| Cc: Lyude Paul <lyude@redhat.com> |
| Cc: Matthew Garrett <mjg59@google.com> |
| Cc: Octavian Purdila <octavian.purdila@intel.com> |
| Cc: Peter Jones <pjones@redhat.com> |
| Cc: Peter Zijlstra <peterz@infradead.org> |
| Cc: Scott Talbert <swt@techie.net> |
| Cc: Thomas Gleixner <tglx@linutronix.de> |
| Cc: linux-efi@vger.kernel.org |
| Cc: linux-integrity@vger.kernel.org |
| Cc: stable@vger.kernel.org |
| Fixes: c46f3405692de ("tpm: Reserve the TPM final events table") |
| Link: https://lkml.kernel.org/r/20191002165904.8819-6-ard.biesheuvel@linaro.org |
| Signed-off-by: Ingo Molnar <mingo@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/firmware/efi/tpm.c | 9 ++++++++- |
| include/linux/tpm_eventlog.h | 2 +- |
| 2 files changed, 9 insertions(+), 2 deletions(-) |
| |
| --- a/drivers/firmware/efi/tpm.c |
| +++ b/drivers/firmware/efi/tpm.c |
| @@ -85,11 +85,18 @@ int __init efi_tpm_eventlog_init(void) |
| 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"); |
| + goto out_calc; |
| + } |
| + |
| memblock_reserve((unsigned long)final_tbl, |
| tbl_size + sizeof(*final_tbl)); |
| - early_memunmap(final_tbl, 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; |
| --- a/include/linux/tpm_eventlog.h |
| +++ b/include/linux/tpm_eventlog.h |
| @@ -152,7 +152,7 @@ struct tcg_algorithm_info { |
| * total. Once we've done this we know the offset of the data length field, |
| * and can calculate the total size of the event. |
| * |
| - * Return: size of the event on success, <0 on failure |
| + * Return: size of the event on success, 0 on failure |
| */ |
| |
| static inline int __calc_tpm2_event_size(struct tcg_pcr_event2_head *event, |