From effe39b1f6ba09d4e3ee91e6807730b8a76abf9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20=C5=BBygowski?= Date: Sun, 21 Nov 2021 13:07:17 +0100 Subject: security/intel/txt: Fix HEAP_ACM format depending on number of ACMs in CBFS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we may have either BIOS ACM or both BIOS and SINIT ACMs in CBFS, the size of txt_heap_acm_element will be different. We cannot always hardcode the size of ACM addresses array for two ACMs. If only the BIOS ACM was included, the BDR parsing failed in TBoot due to invalid size of HEAP_ACM element. Check if SINIT ACM is present in CBFS and push properly formatted BDR region onto the TXT heap. Use two separate txt_heap_acm_element structures with different lengths. TEST=Boot QubesOS 4.0 with TBoot 1.8.2 on Dell OptiPlex 9010 with and without SINIT ACM in CBFS and see that TBoot no longer complains on the wrong size of HEAP_ACM element Signed-off-by: Michał Żygowski Change-Id: Ib0c37a66d96e1ca3fb4d3f665e3ad35c6f1c5c1e Reviewed-on: https://review.coreboot.org/c/coreboot/+/59519 Tested-by: build bot (Jenkins) Reviewed-by: Angel Pons --- src/security/intel/txt/ramstage.c | 143 ++++++++++++++++++++++++---------- src/security/intel/txt/txt_register.h | 10 ++- 2 files changed, 109 insertions(+), 44 deletions(-) (limited to 'src') diff --git a/src/security/intel/txt/ramstage.c b/src/security/intel/txt/ramstage.c index 217d50c475..265f81e62d 100644 --- a/src/security/intel/txt/ramstage.c +++ b/src/security/intel/txt/ramstage.c @@ -200,82 +200,139 @@ static void push_sinit_heap(u8 **heap_ptr, void *data, size_t data_length) } } -static void txt_initialize_heap(void) +static void txt_heap_fill_common_bdr(struct txt_biosdataregion *bdr) +{ + /* TPM2.0 requires version 6 of BDT */ + bdr->version = CONFIG_INTEL_TXT_BDR_VERSION; + + bdr->no_logical_procs = dev_count_cpu(); + + /* The following have been removed from BIOS Data Table in version 6 */ + size_t policy_len; + void *policy_data = cbfs_map(CONFIG_INTEL_TXT_CBFS_BIOS_POLICY, &policy_len); + if (policy_data) { + /* Point to FIT Type 9 entry in flash */ + bdr->lcp_pd_base = (uintptr_t)policy_data; + bdr->lcp_pd_size = (uint64_t)policy_len; + cbfs_unmap(policy_data); + } else { + printk(BIOS_ERR, "TEE-TXT: Couldn't locate LCP PD Policy in CBFS.\n"); + } + + bdr->support_acpi_ppi = 0; + bdr->platform_type = 0; +} + +static void txt_heap_fill_bios_spec(struct txt_bios_spec_ver_element *spec) +{ + /* Fill in the version of the used TXT BIOS Specification */ + spec->header.type = HEAP_EXTDATA_TYPE_BIOS_SPEC_VER; + spec->header.size = sizeof(*spec); + spec->ver_major = 2; + spec->ver_minor = 1; + spec->ver_revision = 0; +} + +static void txt_heap_push_bdr_for_two_acms(u8 **heap_struct) { /* * BIOS Data Format * Chapter C.2 * Intel TXT Software Development Guide (Document: 315168-015) */ + /* Structure format for two present ACMs */ struct { struct txt_biosdataregion bdr; struct txt_bios_spec_ver_element spec; - struct txt_heap_acm_element heap_acm; + struct txt_heap_acm_element2 heap_acm; struct txt_extended_data_element_header end; } __packed data = {0}; - /* TPM2.0 requires version 6 of BDT */ - data.bdr.version = CONFIG_INTEL_TXT_BDR_VERSION; - - data.bdr.no_logical_procs = dev_count_cpu(); + txt_heap_fill_common_bdr(&data.bdr); + txt_heap_fill_bios_spec(&data.spec); void *sinit_base = (void *)(uintptr_t)read64((void *)TXT_SINIT_BASE); data.bdr.bios_sinit_size = cbfs_load(CONFIG_INTEL_TXT_CBFS_SINIT_ACM, sinit_base, read64((void *)TXT_SINIT_SIZE)); - if (data.bdr.bios_sinit_size) { - printk(BIOS_INFO, "TEE-TXT: Placing SINIT ACM in memory.\n"); - if (CONFIG(INTEL_TXT_LOGGING)) - txt_dump_acm_info(sinit_base); - } else { - printk(BIOS_ERR, "TEE-TXT: Couldn't locate SINIT ACM in CBFS.\n"); - /* Clear memory */ - memset(sinit_base, 0, read64((void *)TXT_SINIT_SIZE)); - } + /* Extended elements - ACM addresses */ + data.heap_acm.header.type = HEAP_EXTDATA_TYPE_ACM; + data.heap_acm.num_acms = 2; + data.heap_acm.acm_addrs[1] = (uintptr_t)sinit_base; - /* The following have been removed from BIOS Data Table in version 6 */ - size_t policy_len; - void *policy_data = cbfs_map(CONFIG_INTEL_TXT_CBFS_BIOS_POLICY, &policy_len); - if (policy_data) { - /* Point to FIT Type 9 entry in flash */ - data.bdr.lcp_pd_base = (uintptr_t)policy_data; - data.bdr.lcp_pd_size = (uint64_t)policy_len; - cbfs_unmap(policy_data); - } else { - printk(BIOS_ERR, "TEE-TXT: Couldn't locate LCP PD Policy in CBFS.\n"); - } + printk(BIOS_INFO, "TEE-TXT: Placing SINIT ACM in memory.\n"); + if (CONFIG(INTEL_TXT_LOGGING)) + txt_dump_acm_info(sinit_base); - data.bdr.support_acpi_ppi = 0; - data.bdr.platform_type = 0; + data.heap_acm.acm_addrs[0] = + (uintptr_t)cbfs_map(CONFIG_INTEL_TXT_CBFS_BIOS_ACM, NULL); - /* Fill in the version of the used TXT BIOS Specification */ - data.spec.header.type = HEAP_EXTDATA_TYPE_BIOS_SPEC_VER; - data.spec.header.size = sizeof(data.spec); - data.spec.ver_major = 2; - data.spec.ver_minor = 1; - data.spec.ver_revision = 0; + data.heap_acm.header.size = sizeof(data.heap_acm); + + /* Extended elements - End marker */ + data.end.type = HEAP_EXTDATA_TYPE_END; + data.end.size = sizeof(data.end); + + /* BiosData */ + push_sinit_heap(heap_struct, &data, sizeof(data)); +} + +static void txt_heap_push_bdr_for_one_acm(u8 **heap_struct) +{ + /* + * BIOS Data Format + * Chapter C.2 + * Intel TXT Software Development Guide (Document: 315168-015) + */ + /* Structure format for one present ACM */ + struct { + struct txt_biosdataregion bdr; + struct txt_bios_spec_ver_element spec; + struct txt_heap_acm_element1 heap_acm; + struct txt_extended_data_element_header end; + } __packed data = {0}; + + txt_heap_fill_common_bdr(&data.bdr); + txt_heap_fill_bios_spec(&data.spec); + + void *sinit_base = (void *)(uintptr_t)read64((void *)TXT_SINIT_BASE); + /* Clear SINIT ACM memory */ + memset(sinit_base, 0, read64((void *)TXT_SINIT_SIZE)); /* Extended elements - ACM addresses */ data.heap_acm.header.type = HEAP_EXTDATA_TYPE_ACM; - data.heap_acm.header.size = sizeof(data.heap_acm); - if (data.bdr.bios_sinit_size) { - data.heap_acm.num_acms = 2; - data.heap_acm.acm_addrs[1] = (uintptr_t)sinit_base; - } else { - data.heap_acm.num_acms = 1; - } data.heap_acm.acm_addrs[0] = (uintptr_t)cbfs_map(CONFIG_INTEL_TXT_CBFS_BIOS_ACM, NULL); + data.heap_acm.num_acms = 1; + + data.heap_acm.header.size = sizeof(data.heap_acm); + /* Extended elements - End marker */ data.end.type = HEAP_EXTDATA_TYPE_END; data.end.size = sizeof(data.end); + /* BiosData */ + push_sinit_heap(heap_struct, &data, sizeof(data)); +} + +static void txt_initialize_heap(void) +{ /* Fill TXT.HEAP.BASE with 4 subregions */ u8 *heap_struct = (void *)((uintptr_t)read64((void *)TXT_HEAP_BASE)); - /* BiosData */ - push_sinit_heap(&heap_struct, &data, sizeof(data)); + /* + * Since we may have either BIOS ACM or both BIOS and SINIT ACMs in + * CBFS, the size of txt_heap_acm_element will be different. We cannot + * always hardcode the number of ACM addresses for two ACMs. If we + * include BIOS ACM only, the BDR parsing will fail in TBoot due to + * invalid sizeof BDR. Check if SINIT ACM is present in CBFS and push + * properly formatted BDR region onto the TXT heap. + */ + if (cbfs_file_exists(CONFIG_INTEL_TXT_CBFS_SINIT_ACM)) + txt_heap_push_bdr_for_two_acms(&heap_struct); + else + txt_heap_push_bdr_for_one_acm(&heap_struct); /* OsMLEData */ /* FIXME: Does firmware need to write this? */ diff --git a/src/security/intel/txt/txt_register.h b/src/security/intel/txt/txt_register.h index 7971884294..2137715edb 100644 --- a/src/security/intel/txt/txt_register.h +++ b/src/security/intel/txt/txt_register.h @@ -252,7 +252,15 @@ struct __packed txt_bios_spec_ver_element { uint16_t ver_revision; }; -struct __packed txt_heap_acm_element { +/* Used when only the BIOS ACM is included in CBFS */ +struct __packed txt_heap_acm_element1 { + struct txt_extended_data_element_header header; + uint32_t num_acms; // must greater 0, smaller than 3 + uint64_t acm_addrs[1]; +}; + +/* Used when both BIOS and SINIT ACMs are included in CBFS */ +struct __packed txt_heap_acm_element2 { struct txt_extended_data_element_header header; uint32_t num_acms; // must greater 0, smaller than 3 uint64_t acm_addrs[2]; -- cgit v1.2.3