Michał Żygowski has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/84926?usp=email )
Change subject: util/cbmem/cbmem.c: Avoid overflwos when parsing TCG TPM logs ......................................................................
util/cbmem/cbmem.c: Avoid overflwos when parsing TCG TPM logs
The utilit yassumed that TCG TPM log area is zeroed and then filled with events but it does not have to be true. If there is garbage after the last valid event entry, the utility will most likely access data outside of the cbmem area containing the logs. Relevant issue: https://github.com/linuxboot/heads/issues/1608
TEST=Dump TCG TPM1.2 event log on Dell OptiPlex 7010 and see "Invalid TPM1.2 log entry overflowing cbmem area" error is printed.
Change-Id: I7e057db3378b701d046d4e578272b10f294142a7 Signed-off-by: Michał Żygowski michal.zygowski@3mdeb.com --- M util/cbmem/cbmem.c 1 file changed, 17 insertions(+), 6 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/26/84926/1
diff --git a/util/cbmem/cbmem.c b/util/cbmem/cbmem.c index 15b6770..47444d3 100644 --- a/util/cbmem/cbmem.c +++ b/util/cbmem/cbmem.c @@ -862,7 +862,7 @@ printf("%s", tpm_event_types[event_type]); }
-static void parse_tpm12_log(const struct tcpa_spec_entry *spec_log) +static void parse_tpm12_log(const struct tcpa_spec_entry *spec_log, size_t size) { const uint8_t zero_block[sizeof(struct tcpa_spec_entry)] = {0};
@@ -883,6 +883,13 @@ uint32_t len; struct tcpa_log_entry *log_entry = (void *)current; uint32_t event_type = le32toh(log_entry->event_type); + current += sizeof(struct tcpa_log_entry); + len = le32toh(log_entry->event_data_size); + + if (current + len >= (uintptr_t)spec_log + size) { + fprintf(stderr, "Invalid TPM1.2 log entry overflowing cbmem area\n"); + break; + }
printf("TCPA log entry %u:\n", ++counter); printf("\tPCR: %d\n", le32toh(log_entry->pcr)); @@ -891,8 +898,6 @@ printf("\n"); printf("\tDigest: "); print_hex_line(log_entry->digest, SHA1_DIGEST_SIZE); - current += sizeof(struct tcpa_log_entry); - len = le32toh(log_entry->event_data_size); if (len != 0) { current += len; printf("\tEvent data: "); @@ -947,7 +952,7 @@ return current - (uintptr_t)&log_entry->digest_count; }
-static void parse_tpm2_log(const struct tcg_efi_spec_id_event *tpm2_log) +static void parse_tpm2_log(const struct tcg_efi_spec_id_event *tpm2_log, size_t size) { const uint8_t zero_block[12] = {0}; /* Only PCR index, event type and digest count */
@@ -990,6 +995,12 @@ /* Now event size and event are left to be parsed */ len = le32toh(*(uint32_t *)current); current += sizeof(uint32_t); + + if (current + len >= (uintptr_t)tpm2_log + size) { + fprintf(stderr, "Invalid TPM2.0 log entry overflowing cbmem area\n"); + break; + } + if (len != 0) { printf("\tEvent data: %.*s\n", len, (const char *)current); current += len; @@ -1017,7 +1028,7 @@ tspec_entry->spec_version_minor == 2 && tspec_entry->spec_errata >= 1 && le32toh(tspec_entry->entry.event_type) == EV_NO_ACTION) { - parse_tpm12_log(tspec_entry); + parse_tpm12_log(tspec_entry, size); } else { fprintf(stderr, "Unknown TPM1.2 log specification\n"); } @@ -1030,7 +1041,7 @@ if (tcg_spec_entry->spec_version_major == 2 && tcg_spec_entry->spec_version_minor == 0 && le32toh(tcg_spec_entry->event_type) == EV_NO_ACTION) { - parse_tpm2_log(tcg_spec_entry); + parse_tpm2_log(tcg_spec_entry, size); } else { fprintf(stderr, "Unknown TPM2 log specification.\n"); }