[PATCH v2 1/1] efi_selftest: add selftest for EFI_TCG2_PROTOCOL and Measured Boot
Heinrich Schuchardt
xypron.glpk at gmx.de
Sun Nov 7 15:43:07 CET 2021
On 11/7/21 11:16, Heinrich Schuchardt wrote:
> On 11/4/21 11:45, Masahisa Kojima wrote:
>> This commit adds the missing EFI_TCG2_PROTOCOL selftest
>> and Measured Boot selftest in lib/efi_selftest.
>>
>> This selftest includes PE/COFF image measurement test,
>> some PCR values are different in each architecture.
>> With that, this commit also adds the pre-build efi application
>> for PE/COFF image measurement test for 32-bit arm, arm64,
>> ia32, x86_64, riscv32 and riscv64.
>
> Please, add some information about the includes here:
>
> * From which C code were they compiled?
> * State that the precompiled form is needed due the problem of
> reproducible builds.
>
>>
>> Signed-off-by: Masahisa Kojima <masahisa.kojima at linaro.org>
>> ---
>> lib/efi_selftest/efi_miniapp_tcg2_arm.h | 152 ++++
>> lib/efi_selftest/efi_miniapp_tcg2_arm64.h | 207 +++++
>> lib/efi_selftest/efi_miniapp_tcg2_ia32.h | 177 ++++
>> lib/efi_selftest/efi_miniapp_tcg2_riscv32.h | 173 ++++
>> lib/efi_selftest/efi_miniapp_tcg2_riscv64.h | 189 ++++
>> lib/efi_selftest/efi_miniapp_tcg2_x86_64.h | 178 ++++
>> lib/efi_selftest/efi_selftest_tcg2.c | 941 +++++++++++++++++++-
>> 7 files changed, 2016 insertions(+), 1 deletion(-)
>> create mode 100644 lib/efi_selftest/efi_miniapp_tcg2_arm.h
>> create mode 100644 lib/efi_selftest/efi_miniapp_tcg2_arm64.h
>> create mode 100644 lib/efi_selftest/efi_miniapp_tcg2_ia32.h
>> create mode 100644 lib/efi_selftest/efi_miniapp_tcg2_riscv32.h
>> create mode 100644 lib/efi_selftest/efi_miniapp_tcg2_riscv64.h
>> create mode 100644 lib/efi_selftest/efi_miniapp_tcg2_x86_64.h
>>
>> diff --git a/lib/efi_selftest/efi_miniapp_tcg2_arm.h
>> b/lib/efi_selftest/efi_miniapp_tcg2_arm.h
>> new file mode 100644
>> index 0000000000..37ce1a0ce5
>> --- /dev/null
>> +++ b/lib/efi_selftest/efi_miniapp_tcg2_arm.h
>> @@ -0,0 +1,152 @@
>> +/* SPDX-License-Identifier: GPL-2.0+ */
>> +/*
>> + * Non-zero 8 byte strings of a disk image
>> + *
>> + * Generated with tools/file2include
>
> Please, edit the headers of the includes and describe from which C code
> the EFI binaries were compiled.
>
> To me it looks like lib/efi_selftest/efi_miniapp_file_image_exit.c.
>
> How about:
>
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * This file contains a precompiled EFI binary built from
> + * lib/efi_selftest/efi_miniapp_file_image_exit.c and converted to an
> include
> + * using tools/file2include. It is used to testing the EFI_TCG2_PROTOCOL.
> + * The precompiled form is needed to avoid the problem of reproducible
> builds.
> + */
>
> Best regards
>
> Heinrich
>
>> + */
<snip/>
>> +
>> +struct boot_variable {
>> + u16 name[16];
>> + u8 *buf;
>> + efi_uintn_t size;
>> + u32 attr;
>> + const u8 *test_data;
>> + efi_uintn_t test_data_size;
>> +};
>> +
>> +static struct boot_variable boot_variable_test[] = {
>> + {u"BootOrder", NULL, 0, DEFAULT_ATTR, boot_order,
>> sizeof(boot_order)},
>> + {BOOT_NAME_1000, NULL, 0, DEFAULT_ATTR, boot_1000,
>> sizeof(boot_1000)},
>> + {BOOT_NAME_1001, NULL, 0, DEFAULT_ATTR, boot_1001,
>> sizeof(boot_1001)},
>> + {BOOT_NAME_1002, NULL, 0, DEFAULT_ATTR, boot_1002,
>> sizeof(boot_1002)},
>> +};
>> +
>> +/*
>> + * efi_status_t decompress() - Decompress the disk image.
>> + *
>> + * @image decompressed disk image
>> + * @return status code
>> + */
>> +static efi_status_t decompress(u8 **image)
>> +{
>> + u8 *buf;
>> + size_t i;
>> + size_t addr;
>> + size_t len;
>> + efi_status_t ret;
>> +
>> + ret = boottime->allocate_pool(EFI_LOADER_DATA, img.length,
>> + (void **)&buf);
>> + if (ret != EFI_SUCCESS) {
>> + efi_st_error("Out of memory\n");
>> + return ret;
>> + }
>> + boottime->set_mem(buf, img.length, 0);
>> +
>> + for (i = 0; ; ++i) {
>> + if (!img.lines[i].line)
>> + break;
>> + addr = img.lines[i].addr;
>> + len = COMPRESSED_DISK_IMAGE_BLOCK_SIZE;
>> + if (addr + len > img.length)
>> + len = img.length - addr;
>> + boottime->copy_mem(buf + addr, img.lines[i].line, len);
>> + }
>> + *image = buf;
>> + return ret;
>> +}
>> +
>> +/*
>> + * efi_status_t setup_boot_variable() - configure dummy boot variables
>> + *
>> + * Preexisting variable values are saved and will be restored by
>> + * calling restore_boot_variable().
>> + *
>> + * @return status code
>> + */
>> +static efi_status_t setup_boot_variable(void)
>> +{
>> + efi_status_t ret;
>> + u32 i;
>> + efi_uintn_t size;
>> +
>> + for (i = 0; i < ARRAY_SIZE(boot_variable_test); i++) {
>> + size = 0;
>> + ret = runtime->get_variable(boot_variable_test[i].name,
>> + &efi_global_variable_guid,
>> + &boot_variable_test[i].attr,
>> + &size,
>> + NULL);
>> + if (ret == EFI_BUFFER_TOO_SMALL) {
>> + /* Variable exists, save the current value */
>> + boot_variable_test[i].size = size;
>> + ret = boottime->allocate_pool(EFI_LOADER_DATA,
>> + boot_variable_test[i].size,
>> + (void **)&boot_variable_test[i].buf);
>> + if (ret != EFI_SUCCESS) {
>> + efi_st_error("Failed to allocate buffer for boot
>> variable\n");
>> + return ret;
>> + }
>> + ret = runtime->get_variable(boot_variable_test[i].name,
>> + &efi_global_variable_guid,
>> + &boot_variable_test[i].attr,
>> + &boot_variable_test[i].size,
>> + boot_variable_test[i].buf);
>> + if (ret != EFI_SUCCESS) {
>> + efi_st_error("Failed to get current boot variable\n");
>> + return ret;
>> + }
>> + }
>> +
>> + /* set boot variable for the measurement test */
>> + ret = runtime->set_variable(boot_variable_test[i].name,
>> + &efi_global_variable_guid,
>> + boot_variable_test[i].attr,
>> + boot_variable_test[i].test_data_size,
>> + boot_variable_test[i].test_data);
>> + if (ret != EFI_SUCCESS) {
>> + efi_st_error("Failed to set test boot variable(%d)n", i);
>> + return ret;
>> + }
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +/*
>> + * efi_status_t restore_boot_variable() - restore original values
>> + *
>> + * Restore the variable values saved in setup_boot_variable().
>> + *
>> + * @return status code
>> + */
>> +static efi_status_t restore_boot_variable(void)
>> +{
>> + int i;
>> + efi_status_t ret;
>> +
>> + for (i = 0; i < ARRAY_SIZE(boot_variable_test); i++) {
>> + if (boot_variable_test[i].buf) {
>> + ret = runtime->set_variable(boot_variable_test[i].name,
>> + &efi_global_variable_guid,
>> + boot_variable_test[i].attr,
>> + boot_variable_test[i].size,
>> + boot_variable_test[i].buf);
>> + if (ret != EFI_SUCCESS) {
>> + efi_st_error("Failed to restore boot variable\n");
>> + return ret;
>> + }
>> + ret = boottime->free_pool(boot_variable_test[i].buf);
>> + if (ret != EFI_SUCCESS) {
>> + efi_st_error("Failed to free boot variable\n");
>> + return ret;
>> + }
>> + } else {
>> + /* delete the variable used only for testing */
>> + ret = runtime->set_variable(boot_variable_test[i].name,
>> + &efi_global_variable_guid,
>> + 0, 0, NULL);
>> + if (ret != EFI_SUCCESS) {
>> + efi_st_error("Failed to delete boot variable\n");
>> + return ret;
>> + }
>> + }
>> + }
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + * void *find_smbios_table() - Find smbios table
>> + *
>> + * @systable system table
>> + * @return status code
>> + */
>> +static void *find_smbios_table(const struct efi_system_table *systable)
>> +{
>> + u32 i;
>> +
>> + for (i = 0; i < systable->nr_tables; i++) {
>> + if (!guidcmp(&smbios_guid, &systable->tables[i].guid))
>> + return systable->tables[i].table;
>> + }
>> +
>> + return NULL;
>> +}
>> +
>> +/**
>> + * efi_status_t setup_smbios_table() - Prepare the dummy SMBIOS table
>> + *
>> + * @systable system table
>> + * @return status code
>> + */
>> +static efi_status_t setup_smbios_table(const struct efi_system_table
>> *systable)
>> +{
>> + struct smbios_entry *se;
>> + efi_status_t ret;
>> + /* Map within the low 32 bits, to allow for 32bit SMBIOS tables */
>> + void *dmi;
>> + char *istart;
>> + int isize;
>> +
>> + if (sizeof(smbios_table_test) > EFI_PAGE_SIZE)
>> + return EFI_OUT_OF_RESOURCES;
>> +
>> + orig_smbios_table = find_smbios_table(systable);
>> +
>> + /* Reserve 4kiB page for SMBIOS */
>> + ret = boottime->allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
>> + EFI_RUNTIME_SERVICES_DATA, 1, &dmi_addr);
>> +
>> + if (ret != EFI_SUCCESS) {
>> + /* Could not find space in lowmem, use highmem instead */
>> + ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
>> + EFI_RUNTIME_SERVICES_DATA, 1,
>> + &dmi_addr);
>> +
>> + if (ret != EFI_SUCCESS)
>> + return ret;
>> + }
>> +
>> + dmi = (void *)(uintptr_t)dmi_addr;
>> + se = dmi;
>> + boottime->copy_mem(se, smbios_table_test,
>> sizeof(smbios_table_test));
>> +
>> + /* update smbios table start address */
>> + se->struct_table_address = (uintptr_t)((u8 *)dmi +
>> SMBIOS_ENTRY_HEADER_SIZE);
>> +
>> + /* calculate checksums */
>> + istart = (char *)se + SMBIOS_INTERMEDIATE_OFFSET;
>> + isize = sizeof(struct smbios_entry) - SMBIOS_INTERMEDIATE_OFFSET;
>> + se->intermediate_checksum = table_compute_checksum(istart, isize);
>> + se->checksum = table_compute_checksum(se, sizeof(struct
>> smbios_entry));
>> +
>> + /* Install SMBIOS information as configuration table */
>> + ret = boottime->install_configuration_table(&smbios_guid, dmi);
>> + if (ret != EFI_SUCCESS) {
>> + efi_st_error("Cannot install SMBIOS table\n");
>> + boottime->free_pages(dmi_addr, 1);
>> + }
>> +
>> + return ret;
>> +}
>> +
>> /**
>> * efi_st_tcg2_setup() - setup test
>> *
>> @@ -23,7 +617,193 @@ static const efi_guid_t guid_tcg2 =
>> EFI_TCG2_PROTOCOL_GUID;
>> static int efi_st_tcg2_setup(const efi_handle_t img_handle,
>> const struct efi_system_table *systable)
>> {
>> + efi_status_t ret;
>> + struct uefi_image_load_event image_load_event;
>> +
>> + image_handle = img_handle;
>> boottime = systable->boottime;
>> + runtime = systable->runtime;
>> +
>> + /* Load the application image into memory */
>> + decompress(&image);
>> +
>> + ret = boottime->allocate_pool(EFI_LOADER_DATA,
>> + sizeof(struct efi_tcg2_event) +
>> + sizeof(struct uefi_image_load_event),
>> + (void **)&efi_tcg2_event);
>> + if (!efi_tcg2_event)
>> + return EFI_ST_FAILURE;
>> +
>> + efi_tcg2_event->size = sizeof(struct efi_tcg2_event) +
>> + sizeof(struct uefi_image_load_event);
>> + efi_tcg2_event->header.header_size = sizeof(struct
>> efi_tcg2_event_header);
>> + efi_tcg2_event->header.header_version = 1;
>> + efi_tcg2_event->header.pcr_index = 6;
>> + efi_tcg2_event->header.event_type = EV_EFI_RUNTIME_SERVICES_DRIVER;
>> + image_load_event.image_location_in_memory = 0x12345678;
>> + image_load_event.image_length_in_memory = 0x300000;
>> + image_load_event.image_link_time_address = 0x87654321;
>> + image_load_event.length_of_device_path = 0;
>> + boottime->copy_mem(efi_tcg2_event->event, &image_load_event,
>> + sizeof(struct uefi_image_load_event));
>> +
>> + ret = setup_boot_variable();
>> + if (ret != EFI_SUCCESS)
>> + return EFI_ST_FAILURE;
>> +
>> + ret = setup_smbios_table(systable);
>> + if (ret != EFI_SUCCESS)
>> + return EFI_ST_FAILURE;
>> +
>> + ret = boottime->allocate_pool(EFI_LOADER_DATA,
>> + (EFI_TCG2_MAX_PCR_INDEX + 1) *
>> + TPM2_SHA256_DIGEST_SIZE,
>> + (void **)&pcrs);
>> + if (!pcrs)
>> + return EFI_ST_FAILURE;
>> +
>> + boottime->set_mem(pcrs, (EFI_TCG2_MAX_PCR_INDEX + 1) *
>> TPM2_SHA256_DIGEST_SIZE, 0);
>> +
>> + /* setup expected PCRs per architecture */
>> + boottime->copy_mem(&expected_pcrs[4], &expected_pcrs_per_arch[0],
>> TPM2_SHA256_DIGEST_SIZE);
>> + boottime->copy_mem(&expected_pcrs[6], &expected_pcrs_per_arch[1],
>> TPM2_SHA256_DIGEST_SIZE);
>> +
>> + return EFI_ST_SUCCESS;
>> +}
>> +
>> +/**
>> + * efi_status_t get_manufacturer_id() - Get manufacturer_id through
>> submit_command API
>> + *
>> + * @tcg2 tcg2 protocol
>> + * @manufacturer_id pointer to the manufacturer_id
>> + * @return status code
>> + */
>> +static efi_status_t get_manufacturer_id(struct efi_tcg2_protocol
>> *tcg2, u32 *manufacturer_id)
>> +{
>> + efi_status_t ret;
>> + u8 cmd[TPM2_CMD_BUF_SIZE] = {
>> + tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
>> + tpm_u32(22), /* Length */
>> + tpm_u32(TPM2_CC_GET_CAPABILITY), /* Command code */
>> +
>> + tpm_u32(TPM2_CAP_TPM_PROPERTIES), /* Capability */
>> + tpm_u32(TPM2_PT_MANUFACTURER), /* Property */
>> + tpm_u32(1), /* Property count */
>> + };
>> + u8 resp[TPM2_CMD_BUF_SIZE];
>> + unsigned int value_off;
>> +
>> + ret = tcg2->submit_command(tcg2, 22, cmd,
>> + TPM2_CMD_BUF_SIZE, resp);
>> + if (ret != EFI_SUCCESS)
>> + return ret;
>> +
>> + /*
>> + * In the response buffer, the properties are located after the:
>> + * tag (u16), response size (u32), response code (u32),
>> + * YES/NO flag (u8), TPM_CAP (u32).
>> + * The value is located after count (u32), property (u32).
>> + */
>> + value_off = sizeof(u16) + sizeof(u32) + sizeof(u32) +
>> + sizeof(u8) + sizeof(u32) + sizeof(u32) + sizeof(u32);
>> + *manufacturer_id = get_unaligned_be32(&resp[value_off]);
>> +
>> + return ret;
>> +}
>> +
>> +/**
>> + * efi_status_t get_manufacturer_id_buffer_small() - call
>> submit_command with small resp buffer
>> + *
>> + * @tcg2 tcg2 protocol
>> + * @manufacturer_id pointer to the manufacturer_id
>> + * @return status code
>> + */
>> +static efi_status_t get_manufacturer_id_buffer_small(struct
>> efi_tcg2_protocol *tcg2)
>> +{
>> + efi_status_t ret;
>> + u8 cmd[TPM2_CMD_BUF_SIZE] = {
>> + tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
>> + tpm_u32(22), /* Length */
>> + tpm_u32(TPM2_CC_GET_CAPABILITY), /* Command code */
>> +
>> + tpm_u32(TPM2_CAP_TPM_PROPERTIES), /* Capability */
>> + tpm_u32(TPM2_PT_MANUFACTURER), /* Property */
>> + tpm_u32(1), /* Property count */
>> + };
>> + u8 resp[1]; /* set smaller buffer than expected */
>> +
>> + ret = tcg2->submit_command(tcg2, 22, cmd, 1, resp);
>> +
>> + return ret;
>> +}
>> +
>> +/**
>> + * efi_status_t read_pcr() - Read the PCR from the TPM device
>> + *
>> + * @tcg2 tcg2 protocol
>> + * @idx pcr index to read
>> + * @return status code
>> + */
>> +static efi_status_t read_pcr(struct efi_tcg2_protocol *tcg2, u32 idx)
>> +{
>> + efi_status_t ret;
>> + u32 cmd_len = 17 + IDX_ARRAY_SZ;
>> + u8 cmd[TPM2_CMD_BUF_SIZE] = {
>> + tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
>> + tpm_u32(cmd_len), /* Length */
>> + tpm_u32(TPM2_CC_PCR_READ), /* Command code */
>> + /* TPML_PCR_SELECTION */
>> + tpm_u32(1), /* Number of selections */
>> + tpm_u16(TPM2_ALG_SHA256), /* Algorithm of the hash */
>> + IDX_ARRAY_SZ, /* Array size for selection */
>> + /* bitmap(idx), Selected PCR bitmap */
>> + };
>> + u8 resp[TPM2_CMD_BUF_SIZE];
>> + u32 pcr_sel_idx = idx / 8;
>> + u8 pcr_sel_bit = BIT(idx % 8);
>> +
>> + cmd[17 + pcr_sel_idx] = pcr_sel_bit;
>> + ret = tcg2->submit_command(tcg2, cmd_len, cmd,
>> + TPM2_CMD_BUF_SIZE, resp);
>> + if (ret != EFI_SUCCESS) {
>> + efi_st_error("tcg2->submit_command fail to read PCR\n");
>> + return ret;
>> + }
>> +
>> + boottime->copy_mem(pcrs[idx], &resp[TPM2_PCR_READ_HEADER_SIZE],
>> + TPM2_SHA256_DIGEST_SIZE);
>> +
>> + return ret;
>> +}
>> +
>> +/**
>> + * int validate_pcrs() - Compare the expected and actual pcrs
>> + *
>> + * @return status code
>> + */
>> +static int validate_pcrs(void)
>> +{
>> + u32 i;
>> +
>> + /*
>> + * - Skip PCR[0] validation. PCR[0] contains U-Boot version
>> measurement
>> + * it contains the commit hash, so the measurement varies
>> every build
>> + * with different commit hash.
>> + * - Skip PCR[7] validation. PCR[7] contains UEFI Secure Boot
>> variables
>> + * measurement. These variables can not be updated through
>> efi_selftest and
>> + * vary depending on the platform.
>> + * - Skip PCR[17..22] validation, they are not used in TCG PC
>> Client
>> + * Platform Firmware Profile Specification
>> + */
>> + for (i = 1; i < (EFI_TCG2_MAX_PCR_INDEX + 1); i++) {
>> + if (i == 7 || (i > 16 && i < 23))
>> + continue; /* skip validation */
>> +
>> + if (memcmp(pcrs[i], expected_pcrs[i],
>> TPM2_SHA256_DIGEST_SIZE)) {
>> + efi_st_error("PCR[%d] is not the expected value\n", i);
>> + return EFI_ST_FAILURE;
>> + }
>> + }
>>
>> return EFI_ST_SUCCESS;
>> }
>> @@ -31,7 +811,8 @@ static int efi_st_tcg2_setup(const efi_handle_t
>> img_handle,
>> /**
>> * efi_st_tcg2_execute() - execute test
>> *
>> - * Call the GetCapability service of the EFI_TCG2_PROTOCOL.
>> + * Call EFI_TCG2_PROTOCOL services and check the
>> + * Measured Boot behavior.
>> *
>> * Return: status code
>> */
>> @@ -40,12 +821,22 @@ static int efi_st_tcg2_execute(void)
>> struct efi_tcg2_protocol *tcg2;
>> struct efi_tcg2_boot_service_capability capability;
>> efi_status_t ret;
>> + u32 active_pcr_banks;
>> + u64 eventlog, eventlog_last_entry;
>> + bool eventlog_truncated;
>> + efi_handle_t handle;
>> + efi_uintn_t exit_data_size = 0;
>> + u16 *exit_data = NULL;
>> + u32 i;
>> + u32 manufacturer_id;
>>
>> ret = boottime->locate_protocol(&guid_tcg2, NULL, (void **)&tcg2);
>> if (ret != EFI_SUCCESS) {
>> efi_st_error("TCG2 protocol is not available.\n");
>> return EFI_ST_FAILURE;
Is this really a failure? It could simply be that no TPM chip or
emulation is available. We could imply write a warning and exit with
EFI_SUCCESS. But as described below we have to make the test "onrequest"
let's leave this now as iss
>> }
>> +
>> + /* EFI_TCG2_PROTOCOL.GetCapability test */
>> capability.size = sizeof(struct
>> efi_tcg2_boot_service_capability) - 1;
>> ret = tcg2->get_capability(tcg2, &capability);
>> if (ret != EFI_BUFFER_TOO_SMALL) {
>> @@ -64,12 +855,160 @@ static int efi_st_tcg2_execute(void)
>> }
>> efi_st_printf("TPM supports 0x%.8x event logs\n",
>> capability.supported_event_logs);
>> +
>> + /* EFI_TCG2_PROTOCOL.GetActivePcrBanks test */
>> + ret = tcg2->get_active_pcr_banks(tcg2, &active_pcr_banks);
>> + if (ret != EFI_SUCCESS) {
>> + efi_st_error("tcg2->get_active_pcr_banks failed\n");
>> + return EFI_ST_FAILURE;
>> + }
>> + if (active_pcr_banks != capability.active_pcr_banks) {
>> + efi_st_error("tcg2->get_active_pcr_banks return wrong value\n");
>> + return EFI_ST_FAILURE;
>> + }
>> +
>> + /* EFI_TCG2_PROTOCOL.HashLogExtendEvent test */
>> + ret = tcg2->hash_log_extend_event(tcg2, EFI_TCG2_EXTEND_ONLY,
>> + (uintptr_t)image,
>> + img.length, efi_tcg2_event);
>> + if (ret != EFI_SUCCESS) {
>> + efi_st_error("tcg2->hash_log_extend_event(EXTEND_ONLY)
>> failed\n");
>> + return EFI_ST_FAILURE;
>> + }
>> +
>> + ret = tcg2->hash_log_extend_event(tcg2, PE_COFF_IMAGE,
>> (uintptr_t)image,
>> + img.length, efi_tcg2_event);
>> + if (ret != EFI_SUCCESS) {
>> + efi_st_error("tcg2->hash_log_extend_event(PE_COFF_IMAGE)
>> failed\n");
>> + return EFI_ST_FAILURE;
>> + }
>> +
>> + /* EFI_TCG2_PROTOCOL.SubmitCommand test */
>> + ret = get_manufacturer_id_buffer_small(tcg2);
>> + if (ret != EFI_OUT_OF_RESOURCES) {
>> + efi_st_error("get_manufacturer_id buffer too small failed\n");
>> + return EFI_ST_FAILURE;
>> + }
>> +
>> + ret = get_manufacturer_id(tcg2, &manufacturer_id);
>> + if (ret != EFI_SUCCESS) {
>> + efi_st_error("get_manufacturer_id failed\n");
>> + return EFI_ST_FAILURE;
>> + }
>> + if (capability.manufacturer_id != manufacturer_id) {
>> + efi_st_error("tcg2->submit_command test failed\n");
>> + return EFI_ST_FAILURE;
>> + }
>> +
>> + /* tcg2_measure_pe_image test */
>> + ret = boottime->load_image(false, image_handle, NULL, image,
>> + img.length, &handle);
>> + if (ret != EFI_SUCCESS) {
>> + efi_st_error("Failed to load image\n");
>> + return EFI_ST_FAILURE;
>> + }
>> +
>> + /* measure ready_to_boot event(boot variables, smbios table,
>> etc.) */
>> + /* TODO: add GPT measurement test */
>> + ret = boottime->start_image(handle, &exit_data_size, &exit_data);
>> + if (ret != EFI_UNSUPPORTED) {
>> + efi_st_error("Wrong return value from application\n");
>> + return EFI_ST_FAILURE;
>> + }
>> + ret = boottime->free_pool(exit_data);
>> + if (ret != EFI_SUCCESS) {
>> + efi_st_error("Failed to free exit data\n");
>> + return EFI_ST_FAILURE;
>> + }
>> +
>> + /* validate PCR read from the TPM device */
>> + for (i = 0; i < (EFI_TCG2_MAX_PCR_INDEX + 1); i++) {
>> + ret = read_pcr(tcg2, i);
>> + if (ret != EFI_SUCCESS) {
>> + efi_st_error("read pcr error\n");
>> + return EFI_ST_FAILURE;
>> + }
>> + }
>> + if (validate_pcrs()) {
>> + efi_st_error("PCR validation failed\n");
>> + return EFI_ST_FAILURE;
>> + }
>> +
>> + /* EFI_TCG2_PROTOCOL.GetEventLog test */
>> + ret = tcg2->get_eventlog(tcg2, TCG2_EVENT_LOG_FORMAT_TCG_2,
>> &eventlog,
>> + &eventlog_last_entry, &eventlog_truncated);
>> + if (ret != EFI_SUCCESS) {
>> + efi_st_error("tcg2->get_eventlog failed\n");
>> + return EFI_ST_FAILURE;
>> + }
>> + /* TODO: eventlog format check */
>> +
>> return EFI_ST_SUCCESS;
>> }
>>
>> +/*
>> + * efi_st_tcg2_teardown() - Tear down unit test
>> + *
>> + * @return: EFI_ST_SUCCESS for success
>> + */
>> +static int efi_st_tcg2_teardown(void)
>> +{
>> + efi_status_t r = EFI_ST_SUCCESS;
>> +
>> + if (image) {
>> + r = boottime->free_pool(image);
>> + if (r != EFI_SUCCESS) {
>> + efi_st_error("Failed to free image\n");
>> + return EFI_ST_FAILURE;
>> + }
>> + }
>> + if (efi_tcg2_event) {
>> + r = boottime->free_pool(efi_tcg2_event);
>> + if (r != EFI_SUCCESS) {
>> + efi_st_error("Failed to free efi_tcg2_event\n");
>> + return EFI_ST_FAILURE;
>> + }
>> + }
>> + if (pcrs) {
>> + r = boottime->free_pool(pcrs);
>> + if (r != EFI_SUCCESS) {
>> + efi_st_error("Failed to free pcr\n");
>> + return EFI_ST_FAILURE;
>> + }
>> + }
>> +
>> + r = restore_boot_variable();
>> + if (r != EFI_SUCCESS) {
>> + efi_st_error("Failed to restore boot variables\n");
>> + return EFI_ST_FAILURE;
>> + }
>> +
>> + /*
>> + * Restore SMBIOS table
>> + * If orig_smbios_table is NULL, calling
>> install_configuration_table()
>> + * removes dummy SMBIOS table form systab.
>> + */
>> + r = boottime->install_configuration_table(&smbios_guid,
>> orig_smbios_table);
>> + if (r != EFI_SUCCESS) {
>> + efi_st_error("Failed to restore SMBOIS table\n");
>> + return EFI_ST_FAILURE;
>> + }
>> +
>> + if (dmi_addr) {
>> + r = boottime->free_pages(dmi_addr, 1);
>> + if (r != EFI_SUCCESS) {
>> + efi_st_error("Failed to free dummy smbios table\n");
>> + return EFI_ST_FAILURE;
>> + }
>> + }
>> +
>> + return r;
>> +}
>> +
>> EFI_UNIT_TEST(tcg2) = {
>> .name = "tcg2",
>> .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
>> .execute = efi_st_tcg2_execute,
>> .setup = efi_st_tcg2_setup,
>> + .teardown = efi_st_tcg2_teardown,
Please add:
.on_request = true,
because we have to execute tpm2 startup TPM2_SU_CLEAR before it can succeed.
Best regards
Heinrich
>> };
>>
More information about the U-Boot
mailing list