[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