[PATCH 0/2] add selftest for EFI_TCG2_PROTOCOL and Measured Boot

This patch series adds the selftest for the EFI_TCG2_PROTOCOL and Measured Boot flow. This selftest is verified on qemu with swtpm.
This covers most of the functionalities, but there are some limitations and TODO items.
[Limitation] - tcg2 selftest must run at the beginning of the efi_selftest because some measurement occurs in efi_tcg2_register() and boottime->image_load(). Need to configure the efi_selftest with "setenv efi_selftest tcg2; bootefi selftest" - Skip ExitBootService measurement test - EFI application can not read PCR after calling ExitBootService - Skip EventLog Validation - Measured Boot measures U-Boot version, so EventLog varies every build having different commit hash. - Skip PCR[0] validation - PCR[0] include U-Boot version measurement, this value varies every build having different commit hash. - Skip PCR[7] validation - Secure Boot Variables can not be updated through efi_selftest. - The initial PCR value of PCR[17 - 22] is all 0xff, I'm not sure it is expected or not.
[TODO] - GPT measurement test - Secure Boot Variable test - Eventlog validation
Masahisa Kojima (2): efi_loader: add missing const qualifier efi_selftest: add selftest for EFI_TCG2_PROTOCOL and Measured Boot
include/efi_api.h | 2 +- lib/efi_loader/efi_boottime.c | 5 +- lib/efi_selftest/Makefile | 10 + .../efi_selftest_miniapp_measuredboot.c | 93 ++ lib/efi_selftest/efi_selftest_tcg2.c | 804 +++++++++++++++++- 5 files changed, 910 insertions(+), 4 deletions(-) create mode 100644 lib/efi_selftest/efi_selftest_miniapp_measuredboot.c

This commit fixes the following compilation warning of boottime->install_configuration_table() function.
--- lib/efi_selftest/efi_selftest_tcg2.c:475:46: warning: passing argument 1 of ‘boottime->install_configuration_table’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers] ret = boottime->install_configuration_table(&smbios_guid, dmi); ---
Signed-off-by: Masahisa Kojima masahisa.kojima@linaro.org --- include/efi_api.h | 2 +- lib/efi_loader/efi_boottime.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/include/efi_api.h b/include/efi_api.h index c8f959bb72..0accad08c8 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -120,7 +120,7 @@ struct efi_boot_services { struct efi_device_path **device_path, efi_handle_t *device); efi_status_t (EFIAPI *install_configuration_table)( - efi_guid_t *guid, void *table); + const efi_guid_t *guid, void *table);
efi_status_t (EFIAPI *load_image)(bool boot_policiy, efi_handle_t parent_image, diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index bf5661e1ee..1823990d9b 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1692,8 +1692,9 @@ out: * * Return: status code */ -static efi_status_t EFIAPI efi_install_configuration_table_ext(efi_guid_t *guid, - void *table) +static efi_status_t +EFIAPI efi_install_configuration_table_ext(const efi_guid_t *guid, + void *table) { EFI_ENTRY("%pUl, %p", guid, table); return EFI_EXIT(efi_install_configuration_table(guid, table));

On 10/22/21 13:24, Masahisa Kojima wrote:
This commit fixes the following compilation warning of boottime->install_configuration_table() function.
lib/efi_selftest/efi_selftest_tcg2.c:475:46: warning: passing argument 1 of ‘boottime->install_configuration_table’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers] ret = boottime->install_configuration_table(&smbios_guid, dmi);
Signed-off-by: Masahisa Kojima masahisa.kojima@linaro.org
The first --- separates the commit message from the rest of the patch:
$ scripts/checkpatch.pl 0001-efi_loader-add-missing-const-qualifier.patch ERROR: Missing Signed-off-by: line by nominal patch author 'Masahisa Kojima masahisa.kojima@linaro.org'
I will reformat the commit message when merging.
Reviewed-by: Heinrich Schuchardt xypron.glpk@gmx.de
include/efi_api.h | 2 +- lib/efi_loader/efi_boottime.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/include/efi_api.h b/include/efi_api.h index c8f959bb72..0accad08c8 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -120,7 +120,7 @@ struct efi_boot_services { struct efi_device_path **device_path, efi_handle_t *device); efi_status_t (EFIAPI *install_configuration_table)(
efi_guid_t *guid, void *table);
const efi_guid_t *guid, void *table);
efi_status_t (EFIAPI *load_image)(bool boot_policiy, efi_handle_t parent_image,
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index bf5661e1ee..1823990d9b 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1692,8 +1692,9 @@ out:
- Return: status code
*/ -static efi_status_t EFIAPI efi_install_configuration_table_ext(efi_guid_t *guid,
void *table)
+static efi_status_t +EFIAPI efi_install_configuration_table_ext(const efi_guid_t *guid,
{ EFI_ENTRY("%pUl, %p", guid, table); return EFI_EXIT(efi_install_configuration_table(guid, table));void *table)

On Sat, 23 Oct 2021 at 11:40, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 10/22/21 13:24, Masahisa Kojima wrote:
This commit fixes the following compilation warning of boottime->install_configuration_table() function.
lib/efi_selftest/efi_selftest_tcg2.c:475:46: warning: passing argument 1 of ‘boottime->install_configuration_table’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers] ret = boottime->install_configuration_table(&smbios_guid, dmi);
Signed-off-by: Masahisa Kojima masahisa.kojima@linaro.org
The first --- separates the commit message from the rest of the patch:
$ scripts/checkpatch.pl 0001-efi_loader-add-missing-const-qualifier.patch ERROR: Missing Signed-off-by: line by nominal patch author 'Masahisa Kojima masahisa.kojima@linaro.org'
I will reformat the commit message when merging.
Reviewed-by: Heinrich Schuchardt xypron.glpk@gmx.de
Reviewed-by: Ilias Apalodimas ilias.apalodimas@linaro.org

This commit adds the missing EFI_TCG2_PROTOCOL selftest and Measured Boot selftest in lib/efi_selftest.
Signed-off-by: Masahisa Kojima masahisa.kojima@linaro.org --- lib/efi_selftest/Makefile | 10 + .../efi_selftest_miniapp_measuredboot.c | 93 ++ lib/efi_selftest/efi_selftest_tcg2.c | 804 +++++++++++++++++- 3 files changed, 906 insertions(+), 1 deletion(-) create mode 100644 lib/efi_selftest/efi_selftest_miniapp_measuredboot.c
diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 9ff6e1760c..09950ee028 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -14,6 +14,8 @@ CFLAGS_efi_selftest_miniapp_exception.o := $(CFLAGS_EFI) -Os -ffreestanding CFLAGS_REMOVE_efi_selftest_miniapp_exception.o := $(CFLAGS_NON_EFI) CFLAGS_efi_selftest_miniapp_exit.o := $(CFLAGS_EFI) -Os -ffreestanding CFLAGS_REMOVE_efi_selftest_miniapp_exit.o := $(CFLAGS_NON_EFI) +CFLAGS_efi_selftest_miniapp_measuredboot.o := $(CFLAGS_EFI) -Os -ffreestanding +CFLAGS_REMOVE_efi_selftest_miniapp_measuredboot.o := $(CFLAGS_NON_EFI) CFLAGS_efi_selftest_miniapp_return.o := $(CFLAGS_EFI) -Os -ffreestanding CFLAGS_REMOVE_efi_selftest_miniapp_return.o := $(CFLAGS_NON_EFI) CFLAGS_initrddump_exit.o := $(CFLAGS_EFI) -Os -ffreestanding @@ -78,9 +80,11 @@ obj-$(CONFIG_EFI_ESRT) += efi_selftest_esrt.o targets += \ efi_miniapp_file_image_exception.h \ efi_miniapp_file_image_exit.h \ +efi_miniapp_file_image_measuredboot.h \ efi_miniapp_file_image_return.h \ efi_selftest_miniapp_exception.efi \ efi_selftest_miniapp_exit.efi \ +efi_selftest_miniapp_measuredboot.efi \ efi_selftest_miniapp_return.efi
ifeq ($(CONFIG_GENERATE_ACPI_TABLE),) @@ -99,6 +103,10 @@ $(obj)/efi_miniapp_file_image_exit.h: $(obj)/efi_selftest_miniapp_exit.efi $(obj)/../../tools/file2include $(obj)/efi_selftest_miniapp_exit.efi > \ $(obj)/efi_miniapp_file_image_exit.h
+$(obj)/efi_miniapp_file_image_measuredboot.h: $(obj)/efi_selftest_miniapp_measuredboot.efi + $(obj)/../../tools/file2include $(obj)/efi_selftest_miniapp_measuredboot.efi > \ + $(obj)/efi_miniapp_file_image_measuredboot.h + $(obj)/efi_miniapp_file_image_return.h: $(obj)/efi_selftest_miniapp_return.efi $(obj)/../../tools/file2include $(obj)/efi_selftest_miniapp_return.efi > \ $(obj)/efi_miniapp_file_image_return.h @@ -112,3 +120,5 @@ $(obj)/efi_selftest_loadimage.o: $(obj)/efi_miniapp_file_image_exit.h $(obj)/efi_selftest_startimage_exit.o: $(obj)/efi_miniapp_file_image_exit.h
$(obj)/efi_selftest_startimage_return.o: $(obj)/efi_miniapp_file_image_return.h + +$(obj)/efi_selftest_tcg2.o: $(obj)/efi_miniapp_file_image_measuredboot.h diff --git a/lib/efi_selftest/efi_selftest_miniapp_measuredboot.c b/lib/efi_selftest/efi_selftest_miniapp_measuredboot.c new file mode 100644 index 0000000000..926713c1c2 --- /dev/null +++ b/lib/efi_selftest/efi_selftest_miniapp_measuredboot.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_miniapp_measuredboot + * + * Copyright (c) 2018 Heinrich Schuchardt + * Copyright (c) 2021 Masahisa Kojima + * + * This EFI application is run by the StartImage selftest. + * It uses the Exit boot service to return and used for + * Measured Boot selftest. + */ + +#include <common.h> +#include <efi_selftest.h> + +static efi_guid_t loaded_image_protocol_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID; + +/** + * check_loaded_image_protocol() - check image_base/image_size + * + * Try to open the loaded image protocol. Check that this function is located + * between image_base and image_base + image_size. + * + * @image_handle: handle of the loaded image + * @systable: system table + * @return: status code + */ +static efi_status_t EFIAPI check_loaded_image_protocol + (efi_handle_t image_handle, struct efi_system_table *systable) +{ + struct efi_simple_text_output_protocol *cout = systable->con_out; + struct efi_boot_services *boottime = systable->boottime; + struct efi_loaded_image *loaded_image_protocol; + efi_status_t ret; + + /* + * Open the loaded image protocol. + */ + ret = boottime->open_protocol + (image_handle, &loaded_image_protocol_guid, + (void **)&loaded_image_protocol, NULL, + NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + cout->output_string(cout, + L"Could not open loaded image protocol"); + return ret; + } + if ((void *)check_loaded_image_protocol < + loaded_image_protocol->image_base || + (void *)check_loaded_image_protocol >= + loaded_image_protocol->image_base + + loaded_image_protocol->image_size) { + cout->output_string(cout, + L"Incorrect image_base or image_size\n"); + return EFI_NOT_FOUND; + } + return EFI_SUCCESS; +} + +/** + * Entry point of the EFI application. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: status code + */ +efi_status_t EFIAPI efi_main(efi_handle_t handle, + struct efi_system_table *systable) +{ + struct efi_simple_text_output_protocol *con_out = systable->con_out; + efi_status_t ret; + u16 text[] = EFI_ST_SUCCESS_STR; + + con_out->output_string(con_out, L"EFI application calling Exit\n"); + + if (check_loaded_image_protocol(handle, systable) != EFI_SUCCESS) { + con_out->output_string(con_out, + L"Loaded image protocol missing\n"); + ret = EFI_NOT_FOUND; + goto out; + } + + /* This return value is expected by the calling test */ + ret = EFI_UNSUPPORTED; +out: + systable->boottime->exit(handle, ret, sizeof(text), text); + + /* + * This statement should not be reached. + * To enable testing use a different return value. + */ + return EFI_SUCCESS; +} diff --git a/lib/efi_selftest/efi_selftest_tcg2.c b/lib/efi_selftest/efi_selftest_tcg2.c index 1399309cec..50de735f5e 100644 --- a/lib/efi_selftest/efi_selftest_tcg2.c +++ b/lib/efi_selftest/efi_selftest_tcg2.c @@ -9,10 +9,495 @@
#include <efi_selftest.h> #include <efi_tcg2.h> +/* Include containing the miniapp.efi application */ +#include "efi_miniapp_file_image_measuredboot.h" + +#include <linux/unaligned/access_ok.h> +#include <mapmem.h> +#include <smbios.h> +#include <tables_csum.h>
static struct efi_boot_services *boottime; static const efi_guid_t guid_tcg2 = EFI_TCG2_PROTOCOL_GUID;
+/* Block size of compressed disk image */ +#define COMPRESSED_DISK_IMAGE_BLOCK_SIZE 8 + +static efi_handle_t image_handle; +/* Decompressed file image */ +static u8 *image; + +/* One 8 byte block of the compressed disk image */ +struct line { + size_t addr; + char *line; +}; + +/* Compressed file image */ +struct compressed_file_image { + size_t length; + struct line lines[]; +}; + +static struct compressed_file_image img = EFI_ST_DISK_IMG; + +static struct efi_tcg2_event *efi_tcg2_event; + +static struct efi_runtime_services *runtime; +#define BOOT_NAME_1000 u"Boot1000" +#define BOOT_NAME_1001 u"Boot1001" +#define BOOT_NAME_1002 u"Boot1002" + +#define DEFAULT_ATTR (EFI_VARIABLE_NON_VOLATILE | \ + EFI_VARIABLE_BOOTSERVICE_ACCESS | \ + EFI_VARIABLE_RUNTIME_ACCESS) + +/* "efidebug boot add -b 1000 test1000 virtio 0:1 /EFI/debian/grubaa64.efi" */ +static const u8 boot_1000[] = { +0x01, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, +0x74, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x04, 0x14, 0x00, 0xb9, 0x73, +0x1d, 0xe6, 0x84, 0xa3, 0xcc, 0x4a, 0xae, 0xab, 0x82, 0xe8, 0x28, 0xf3, +0x62, 0x8b, 0x01, 0x04, 0x15, 0x00, 0x92, 0x37, 0x29, 0x63, 0xf5, 0xad, +0x25, 0x93, 0xb9, 0x9f, 0x4e, 0x0e, 0x45, 0x5c, 0x1b, 0x1e, 0x00, 0x04, +0x01, 0x2a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, +0x5a, 0x47, 0xc2, 0x35, 0x27, 0x44, 0x47, 0x9f, 0x01, 0x67, 0xfe, 0xfa, +0x1d, 0x06, 0xae, 0x02, 0x02, 0x04, 0x04, 0x36, 0x00, 0x5c, 0x00, 0x45, +0x00, 0x46, 0x00, 0x49, 0x00, 0x5c, 0x00, 0x64, 0x00, 0x65, 0x00, 0x62, +0x00, 0x69, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x5c, 0x00, 0x67, 0x00, 0x72, +0x00, 0x75, 0x00, 0x62, 0x00, 0x61, 0x00, 0x61, 0x00, 0x36, 0x00, 0x34, +0x00, 0x2e, 0x00, 0x65, 0x00, 0x66, 0x00, 0x69, 0x00, 0x00, 0x00, 0x7f, +0xff, 0x04, 0x00 }; + +/* "efidebug boot add -b 1001 test1001 virtio 0:1 /EFI/debian/grubaa64.efi" */ +static const u8 boot_1001[] = { +0x01, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, +0x74, 0x00, 0x31, 0x00, 0x00, 0x00, 0x01, 0x04, 0x14, 0x00, 0xb9, 0x73, +0x1d, 0xe6, 0x84, 0xa3, 0xcc, 0x4a, 0xae, 0xab, 0x82, 0xe8, 0x28, 0xf3, +0x62, 0x8b, 0x01, 0x04, 0x15, 0x00, 0x92, 0x37, 0x29, 0x63, 0xf5, 0xad, +0x25, 0x93, 0xb9, 0x9f, 0x4e, 0x0e, 0x45, 0x5c, 0x1b, 0x1e, 0x00, 0x04, +0x01, 0x2a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, +0x5a, 0x47, 0xc2, 0x35, 0x27, 0x44, 0x47, 0x9f, 0x01, 0x67, 0xfe, 0xfa, +0x1d, 0x06, 0xae, 0x02, 0x02, 0x04, 0x04, 0x36, 0x00, 0x5c, 0x00, 0x45, +0x00, 0x46, 0x00, 0x49, 0x00, 0x5c, 0x00, 0x64, 0x00, 0x65, 0x00, 0x62, +0x00, 0x69, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x5c, 0x00, 0x67, 0x00, 0x72, +0x00, 0x75, 0x00, 0x62, 0x00, 0x61, 0x00, 0x61, 0x00, 0x36, 0x00, 0x34, +0x00, 0x2e, 0x00, 0x65, 0x00, 0x66, 0x00, 0x69, 0x00, 0x00, 0x00, 0x7f, +0xff, 0x04, 0x00 }; + +/* "efidebug boot add -b 1002 test1002 virtio 0:1 /EFI/debian/grubaa64.efi" */ +static const u8 boot_1002[] = { +0x01, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, +0x74, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x04, 0x14, 0x00, 0xb9, 0x73, +0x1d, 0xe6, 0x84, 0xa3, 0xcc, 0x4a, 0xae, 0xab, 0x82, 0xe8, 0x28, 0xf3, +0x62, 0x8b, 0x01, 0x04, 0x15, 0x00, 0x92, 0x37, 0x29, 0x63, 0xf5, 0xad, +0x25, 0x93, 0xb9, 0x9f, 0x4e, 0x0e, 0x45, 0x5c, 0x1b, 0x1e, 0x00, 0x04, +0x01, 0x2a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, +0x5a, 0x47, 0xc2, 0x35, 0x27, 0x44, 0x47, 0x9f, 0x01, 0x67, 0xfe, 0xfa, +0x1d, 0x06, 0xae, 0x02, 0x02, 0x04, 0x04, 0x36, 0x00, 0x5c, 0x00, 0x45, +0x00, 0x46, 0x00, 0x49, 0x00, 0x5c, 0x00, 0x64, 0x00, 0x65, 0x00, 0x62, +0x00, 0x69, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x5c, 0x00, 0x67, 0x00, 0x72, +0x00, 0x75, 0x00, 0x62, 0x00, 0x61, 0x00, 0x61, 0x00, 0x36, 0x00, 0x34, +0x00, 0x2e, 0x00, 0x65, 0x00, 0x66, 0x00, 0x69, 0x00, 0x00, 0x00, 0x7f, +0xff, 0x04, 0x00}; + +/* "efidebug boot order 1002 1000 1001" */ +static u8 boot_order[] = {0x02, 0x10, 0x00, 0x10, 0x01, 0x10}; + +static void *orig_smbios_table; +static u64 dmi_addr = U32_MAX; +#define SMBIOS_ENTRY_HEADER_SIZE 0x20 +/* smbios table for the measurement test */ +static u8 smbios_table_test[] = { +0x5f, 0x53, 0x4d, 0x5f, 0x2c, 0x1f, 0x03, 0x00, 0x54, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x5f, 0x44, 0x4d, 0x49, 0x5f, 0xe4, 0x5c, 0x01, +0x20, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, +0x01, 0x02, 0x00, 0x00, 0x03, 0x00, 0x80, 0x08, 0x01, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x0c, 0x15, 0x0a, 0xff, 0xff, 0x55, 0x2d, 0x42, 0x6f, +0x6f, 0x74, 0x00, 0x32, 0x30, 0x32, 0x31, 0x2e, 0x31, 0x30, 0x2d, 0x72, +0x63, 0x34, 0x2d, 0x30, 0x30, 0x30, 0x30, 0x35, 0x2d, 0x67, 0x37, 0x32, +0x37, 0x63, 0x33, 0x66, 0x33, 0x32, 0x35, 0x39, 0x2d, 0x64, 0x69, 0x72, +0x74, 0x79, 0x00, 0x31, 0x30, 0x2f, 0x30, 0x31, 0x2f, 0x32, 0x30, 0x32, +0x31, 0x00, 0x00, 0x01, 0x1b, 0x01, 0x00, 0x01, 0x02, 0x00, 0x03, 0x31, +0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, +0x6e, 0x00, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x20, 0x50, 0x72, +0x6f, 0x64, 0x75, 0x63, 0x74, 0x00, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, +0x37, 0x38, 0x00, 0x00, 0x02, 0x0e, 0x02, 0x00, 0x01, 0x02, 0x00, 0x04, +0x03, 0x01, 0x01, 0x01, 0x00, 0x0a, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, +0x6e, 0x00, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x20, 0x50, 0x72, +0x6f, 0x64, 0x75, 0x63, 0x74, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, +0x33, 0x33, 0x00, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x00, +0x00, 0x03, 0x15, 0x03, 0x00, 0x01, 0x03, 0x00, 0x02, 0x03, 0x03, 0x03, +0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x6e, +0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x00, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, +0x37, 0x38, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, +0x00, 0x04, 0x30, 0x04, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x01, 0x06, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x03, 0x04, +0x04, 0x04, 0x08, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x08, 0x00, 0x01, +0x00, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x00, 0x31, 0x32, 0x33, +0x34, 0x35, 0x36, 0x37, 0x38, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, +0x33, 0x33, 0x00, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x00, +0x00, 0x20, 0x0b, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7f, 0x04, 0x06, 0x00, 0x00, 0x00 +}; + +#define TPM2_CMD_BUF_SIZE 64 +/* TPM command is big endian */ +#define __MSB(x) ((x) >> 8) +#define __LSB(x) ((x) & 0xFF) +#define tpm_u16(x) __MSB(x), __LSB(x) +#define tpm_u32(x) tpm_u16((x) >> 16), tpm_u16((x) & 0xFFFF) +#define TPM2_PCR_READ_HEADER_SIZE 30 + +static u8 *pcrs; +static u8 expected_pcrs[EFI_TCG2_MAX_PCR_INDEX + 1][TPM2_SHA256_DIGEST_SIZE] = { + {0x91, 0x21, 0x37, 0xc7, 0x1a, 0x49, 0x19, 0xc8, + 0xf1, 0xfb, 0xa9, 0x84, 0x5c, 0x65, 0xa9, 0xdd, + 0x7b, 0xb9, 0xfe, 0xa1, 0xcd, 0x64, 0x49, 0xdd, + 0xed, 0xe2, 0x65, 0x82, 0xc5, 0x3e, 0xf4, 0xc4}, + + {0xf5, 0x79, 0xf3, 0x20, 0x62, 0x6e, 0x8b, 0x58, + 0x62, 0xa3, 0x4e, 0x2f, 0xb7, 0x10, 0xac, 0x34, + 0x4e, 0x68, 0x94, 0x37, 0x87, 0x29, 0xc4, 0xbe, + 0xa3, 0xc4, 0xd9, 0x14, 0x2b, 0x66, 0x79, 0x9b}, + + {0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, + 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, + 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, + 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, + + {0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, + 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, + 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, + 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, + + {0xbe, 0xea, 0xdc, 0xe0, 0x44, 0x5b, 0x5f, 0x14, + 0xef, 0x24, 0x5d, 0x13, 0x15, 0xfe, 0x41, 0x86, + 0xc2, 0xd5, 0xdc, 0x0d, 0x04, 0x2f, 0xd4, 0x04, + 0x0d, 0x02, 0x62, 0xc0, 0x34, 0x80, 0xee, 0xd5}, + + {0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, + 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, + 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, + 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, + + {0x8d, 0x28, 0xde, 0x72, 0x22, 0x3e, 0x88, 0x1a, + 0x37, 0xfa, 0x47, 0x12, 0x68, 0x45, 0xdf, 0x71, + 0x50, 0x8f, 0xab, 0x59, 0x50, 0x7b, 0x52, 0x32, + 0xa6, 0xaa, 0x03, 0x3d, 0x4e, 0x22, 0x89, 0xd7}, + + {0x96, 0x74, 0xae, 0xcd, 0x3f, 0x40, 0xb4, 0xa9, + 0x36, 0xae, 0x19, 0xc8, 0x84, 0x8a, 0xb9, 0x5a, + 0x87, 0x99, 0xd8, 0x89, 0x7f, 0xfc, 0x40, 0x48, + 0x05, 0x99, 0x65, 0x2e, 0x55, 0xd4, 0x93, 0x32}, + + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, +}; + +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)}, +}; + +/* + * 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; +} + +/* + * Configure dummy boot variables. + * + * @return status code + */ +static efi_status_t setup_boot_variable(void) +{ + efi_status_t ret; + u32 i; + efi_uintn_t size; + u8 dummy; + + for (i = 0; i < ARRAY_SIZE(boot_variable_test); i++) { + size = 1; + ret = runtime->get_variable(boot_variable_test[i].name, + &efi_global_variable_guid, + &boot_variable_test[i].attr, + &size, + &dummy); + if (ret == EFI_BUFFER_TOO_SMALL) { + /* Variable exists, save the current vaiable */ + 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("fail 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("fail 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("### fail to set test boot variable(%d)n", i); + return ret; + } + } + + return 0; +} + +/* + * Restore original boot variables. + * + * @return status code + */ +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("### fail 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("### fail to delete boot variable\n"); + return ret; + } + } + } + + return EFI_SUCCESS; +} + +/** + * 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; +} + +/** + * Prepare the dummy SMBIOS table + * + * @systable system table + * @return status code + */ +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 +508,171 @@ 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); + + return EFI_ST_SUCCESS; +} + +/** + * 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; +} + +/** + * 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; + u8 idx_array_sz = 3; /* support 24 PCRs */ + 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); + u8 *dst; + + 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; + } + + dst = pcrs + (idx * TPM2_SHA256_DIGEST_SIZE); + boottime->copy_mem(dst, &resp[TPM2_PCR_READ_HEADER_SIZE], + TPM2_SHA256_DIGEST_SIZE); + + return ret; +} + +/** + * Compare the expected and actual pcrs + * + * @return status code + */ +static int validate_pcrs(void) +{ + u32 i; + u8 *expected = (u8 *)expected_pcrs; + u8 *result = pcrs; + + /* + * - 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 + * it varies depending on the platform. + */ + for (i = 0; i < (EFI_TCG2_MAX_PCR_INDEX + 1); i++) { + result = pcrs + (TPM2_SHA256_DIGEST_SIZE * i); + if (i == 0 || i == 7) { + expected += TPM2_SHA256_DIGEST_SIZE; + result += TPM2_SHA256_DIGEST_SIZE; + continue; /* skip validation */ + } + if (memcmp(expected, result, TPM2_SHA256_DIGEST_SIZE)) { + efi_st_printf("PCR[%d] is not the expected value\n", i); + return EFI_ST_FAILURE; + } + expected += TPM2_SHA256_DIGEST_SIZE; + result += TPM2_SHA256_DIGEST_SIZE; + }
return EFI_ST_SUCCESS; } @@ -31,7 +680,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 +690,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; } + + /* 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 +724,154 @@ 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(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; }
+/* + * 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, };

On 10/22/21 13:24, Masahisa Kojima wrote:
This commit adds the missing EFI_TCG2_PROTOCOL selftest and Measured Boot selftest in lib/efi_selftest.
Signed-off-by: Masahisa Kojima masahisa.kojima@linaro.org
lib/efi_selftest/Makefile | 10 + .../efi_selftest_miniapp_measuredboot.c | 93 ++ lib/efi_selftest/efi_selftest_tcg2.c | 804 +++++++++++++++++- 3 files changed, 906 insertions(+), 1 deletion(-) create mode 100644 lib/efi_selftest/efi_selftest_miniapp_measuredboot.c
diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 9ff6e1760c..09950ee028 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -14,6 +14,8 @@ CFLAGS_efi_selftest_miniapp_exception.o := $(CFLAGS_EFI) -Os -ffreestanding CFLAGS_REMOVE_efi_selftest_miniapp_exception.o := $(CFLAGS_NON_EFI) CFLAGS_efi_selftest_miniapp_exit.o := $(CFLAGS_EFI) -Os -ffreestanding CFLAGS_REMOVE_efi_selftest_miniapp_exit.o := $(CFLAGS_NON_EFI) +CFLAGS_efi_selftest_miniapp_measuredboot.o := $(CFLAGS_EFI) -Os -ffreestanding +CFLAGS_REMOVE_efi_selftest_miniapp_measuredboot.o := $(CFLAGS_NON_EFI) CFLAGS_efi_selftest_miniapp_return.o := $(CFLAGS_EFI) -Os -ffreestanding CFLAGS_REMOVE_efi_selftest_miniapp_return.o := $(CFLAGS_NON_EFI) CFLAGS_initrddump_exit.o := $(CFLAGS_EFI) -Os -ffreestanding @@ -78,9 +80,11 @@ obj-$(CONFIG_EFI_ESRT) += efi_selftest_esrt.o targets += \ efi_miniapp_file_image_exception.h \ efi_miniapp_file_image_exit.h \ +efi_miniapp_file_image_measuredboot.h \ efi_miniapp_file_image_return.h \ efi_selftest_miniapp_exception.efi \ efi_selftest_miniapp_exit.efi \ +efi_selftest_miniapp_measuredboot.efi \ efi_selftest_miniapp_return.efi
ifeq ($(CONFIG_GENERATE_ACPI_TABLE),) @@ -99,6 +103,10 @@ $(obj)/efi_miniapp_file_image_exit.h: $(obj)/efi_selftest_miniapp_exit.efi $(obj)/../../tools/file2include $(obj)/efi_selftest_miniapp_exit.efi > \ $(obj)/efi_miniapp_file_image_exit.h
+$(obj)/efi_miniapp_file_image_measuredboot.h: $(obj)/efi_selftest_miniapp_measuredboot.efi
- $(obj)/../../tools/file2include $(obj)/efi_selftest_miniapp_measuredboot.efi > \
- $(obj)/efi_miniapp_file_image_measuredboot.h
- $(obj)/efi_miniapp_file_image_return.h: $(obj)/efi_selftest_miniapp_return.efi $(obj)/../../tools/file2include $(obj)/efi_selftest_miniapp_return.efi > \ $(obj)/efi_miniapp_file_image_return.h
@@ -112,3 +120,5 @@ $(obj)/efi_selftest_loadimage.o: $(obj)/efi_miniapp_file_image_exit.h $(obj)/efi_selftest_startimage_exit.o: $(obj)/efi_miniapp_file_image_exit.h
$(obj)/efi_selftest_startimage_return.o: $(obj)/efi_miniapp_file_image_return.h
+$(obj)/efi_selftest_tcg2.o: $(obj)/efi_miniapp_file_image_measuredboot.h diff --git a/lib/efi_selftest/efi_selftest_miniapp_measuredboot.c b/lib/efi_selftest/efi_selftest_miniapp_measuredboot.c
Thank you for going the extra mile and adding the test.
Which image is actually loaded seems to be irrelevant for the test. Can we reuse an existing one, e.g. efi_miniapp_file_image_return.h?
I guess the PCR related to the loaded image is not checked as it will depend on the build tools and date.
new file mode 100644 index 0000000000..926713c1c2 --- /dev/null +++ b/lib/efi_selftest/efi_selftest_miniapp_measuredboot.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- efi_selftest_miniapp_measuredboot
- Copyright (c) 2018 Heinrich Schuchardt
- Copyright (c) 2021 Masahisa Kojima
- This EFI application is run by the StartImage selftest.
This is incorrect due to copy and paste.
- It uses the Exit boot service to return and used for
- Measured Boot selftest.
- */
+#include <common.h> +#include <efi_selftest.h>
+static efi_guid_t loaded_image_protocol_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
+/**
- check_loaded_image_protocol() - check image_base/image_size
- Try to open the loaded image protocol. Check that this function is located
- between image_base and image_base + image_size.
- @image_handle: handle of the loaded image
- @systable: system table
- @return: status code
- */
+static efi_status_t EFIAPI check_loaded_image_protocol
(efi_handle_t image_handle, struct efi_system_table *systable)
+{
- struct efi_simple_text_output_protocol *cout = systable->con_out;
- struct efi_boot_services *boottime = systable->boottime;
- struct efi_loaded_image *loaded_image_protocol;
- efi_status_t ret;
- /*
* Open the loaded image protocol.
*/
- ret = boottime->open_protocol
(image_handle, &loaded_image_protocol_guid,
(void **)&loaded_image_protocol, NULL,
NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
- if (ret != EFI_SUCCESS) {
cout->output_string(cout,
L"Could not open loaded image protocol");
return ret;
- }
- if ((void *)check_loaded_image_protocol <
loaded_image_protocol->image_base ||
(void *)check_loaded_image_protocol >=
loaded_image_protocol->image_base +
loaded_image_protocol->image_size) {
cout->output_string(cout,
L"Incorrect image_base or image_size\n");
return EFI_NOT_FOUND;
- }
- return EFI_SUCCESS;
+}
+/**
- Entry point of the EFI application.
- @handle: handle of the loaded image
- @systable: system table
- @return: status code
- */
+efi_status_t EFIAPI efi_main(efi_handle_t handle,
struct efi_system_table *systable)
+{
- struct efi_simple_text_output_protocol *con_out = systable->con_out;
- efi_status_t ret;
- u16 text[] = EFI_ST_SUCCESS_STR;
- con_out->output_string(con_out, L"EFI application calling Exit\n");
- if (check_loaded_image_protocol(handle, systable) != EFI_SUCCESS) {
con_out->output_string(con_out,
L"Loaded image protocol missing\n");
ret = EFI_NOT_FOUND;
goto out;
- }
- /* This return value is expected by the calling test */
- ret = EFI_UNSUPPORTED;
+out:
- systable->boottime->exit(handle, ret, sizeof(text), text);
- /*
* This statement should not be reached.
* To enable testing use a different return value.
*/
- return EFI_SUCCESS;
+} diff --git a/lib/efi_selftest/efi_selftest_tcg2.c b/lib/efi_selftest/efi_selftest_tcg2.c index 1399309cec..50de735f5e 100644 --- a/lib/efi_selftest/efi_selftest_tcg2.c +++ b/lib/efi_selftest/efi_selftest_tcg2.c @@ -9,10 +9,495 @@
#include <efi_selftest.h> #include <efi_tcg2.h> +/* Include containing the miniapp.efi application */ +#include "efi_miniapp_file_image_measuredboot.h"
efi_miniapp_file_image_return.h
+#include <linux/unaligned/access_ok.h> +#include <mapmem.h> +#include <smbios.h> +#include <tables_csum.h>
static struct efi_boot_services *boottime; static const efi_guid_t guid_tcg2 = EFI_TCG2_PROTOCOL_GUID;
+/* Block size of compressed disk image */ +#define COMPRESSED_DISK_IMAGE_BLOCK_SIZE 8
+static efi_handle_t image_handle; +/* Decompressed file image */ +static u8 *image;
+/* One 8 byte block of the compressed disk image */ +struct line {
- size_t addr;
- char *line;
+};
+/* Compressed file image */ +struct compressed_file_image {
- size_t length;
- struct line lines[];
+};
+static struct compressed_file_image img = EFI_ST_DISK_IMG;
+static struct efi_tcg2_event *efi_tcg2_event;
+static struct efi_runtime_services *runtime; +#define BOOT_NAME_1000 u"Boot1000" +#define BOOT_NAME_1001 u"Boot1001" +#define BOOT_NAME_1002 u"Boot1002"
+#define DEFAULT_ATTR (EFI_VARIABLE_NON_VOLATILE | \
EFI_VARIABLE_BOOTSERVICE_ACCESS | \
EFI_VARIABLE_RUNTIME_ACCESS)
+/* "efidebug boot add -b 1000 test1000 virtio 0:1 /EFI/debian/grubaa64.efi" */ +static const u8 boot_1000[] = { +0x01, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, +0x74, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x04, 0x14, 0x00, 0xb9, 0x73, +0x1d, 0xe6, 0x84, 0xa3, 0xcc, 0x4a, 0xae, 0xab, 0x82, 0xe8, 0x28, 0xf3, +0x62, 0x8b, 0x01, 0x04, 0x15, 0x00, 0x92, 0x37, 0x29, 0x63, 0xf5, 0xad, +0x25, 0x93, 0xb9, 0x9f, 0x4e, 0x0e, 0x45, 0x5c, 0x1b, 0x1e, 0x00, 0x04, +0x01, 0x2a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, +0x5a, 0x47, 0xc2, 0x35, 0x27, 0x44, 0x47, 0x9f, 0x01, 0x67, 0xfe, 0xfa, +0x1d, 0x06, 0xae, 0x02, 0x02, 0x04, 0x04, 0x36, 0x00, 0x5c, 0x00, 0x45, +0x00, 0x46, 0x00, 0x49, 0x00, 0x5c, 0x00, 0x64, 0x00, 0x65, 0x00, 0x62, +0x00, 0x69, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x5c, 0x00, 0x67, 0x00, 0x72, +0x00, 0x75, 0x00, 0x62, 0x00, 0x61, 0x00, 0x61, 0x00, 0x36, 0x00, 0x34, +0x00, 0x2e, 0x00, 0x65, 0x00, 0x66, 0x00, 0x69, 0x00, 0x00, 0x00, 0x7f, +0xff, 0x04, 0x00 };
+/* "efidebug boot add -b 1001 test1001 virtio 0:1 /EFI/debian/grubaa64.efi" */ +static const u8 boot_1001[] = { +0x01, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, +0x74, 0x00, 0x31, 0x00, 0x00, 0x00, 0x01, 0x04, 0x14, 0x00, 0xb9, 0x73, +0x1d, 0xe6, 0x84, 0xa3, 0xcc, 0x4a, 0xae, 0xab, 0x82, 0xe8, 0x28, 0xf3, +0x62, 0x8b, 0x01, 0x04, 0x15, 0x00, 0x92, 0x37, 0x29, 0x63, 0xf5, 0xad, +0x25, 0x93, 0xb9, 0x9f, 0x4e, 0x0e, 0x45, 0x5c, 0x1b, 0x1e, 0x00, 0x04, +0x01, 0x2a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, +0x5a, 0x47, 0xc2, 0x35, 0x27, 0x44, 0x47, 0x9f, 0x01, 0x67, 0xfe, 0xfa, +0x1d, 0x06, 0xae, 0x02, 0x02, 0x04, 0x04, 0x36, 0x00, 0x5c, 0x00, 0x45, +0x00, 0x46, 0x00, 0x49, 0x00, 0x5c, 0x00, 0x64, 0x00, 0x65, 0x00, 0x62, +0x00, 0x69, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x5c, 0x00, 0x67, 0x00, 0x72, +0x00, 0x75, 0x00, 0x62, 0x00, 0x61, 0x00, 0x61, 0x00, 0x36, 0x00, 0x34, +0x00, 0x2e, 0x00, 0x65, 0x00, 0x66, 0x00, 0x69, 0x00, 0x00, 0x00, 0x7f, +0xff, 0x04, 0x00 };
+/* "efidebug boot add -b 1002 test1002 virtio 0:1 /EFI/debian/grubaa64.efi" */ +static const u8 boot_1002[] = { +0x01, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, +0x74, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x04, 0x14, 0x00, 0xb9, 0x73, +0x1d, 0xe6, 0x84, 0xa3, 0xcc, 0x4a, 0xae, 0xab, 0x82, 0xe8, 0x28, 0xf3, +0x62, 0x8b, 0x01, 0x04, 0x15, 0x00, 0x92, 0x37, 0x29, 0x63, 0xf5, 0xad, +0x25, 0x93, 0xb9, 0x9f, 0x4e, 0x0e, 0x45, 0x5c, 0x1b, 0x1e, 0x00, 0x04, +0x01, 0x2a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, +0x5a, 0x47, 0xc2, 0x35, 0x27, 0x44, 0x47, 0x9f, 0x01, 0x67, 0xfe, 0xfa, +0x1d, 0x06, 0xae, 0x02, 0x02, 0x04, 0x04, 0x36, 0x00, 0x5c, 0x00, 0x45, +0x00, 0x46, 0x00, 0x49, 0x00, 0x5c, 0x00, 0x64, 0x00, 0x65, 0x00, 0x62, +0x00, 0x69, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x5c, 0x00, 0x67, 0x00, 0x72, +0x00, 0x75, 0x00, 0x62, 0x00, 0x61, 0x00, 0x61, 0x00, 0x36, 0x00, 0x34, +0x00, 0x2e, 0x00, 0x65, 0x00, 0x66, 0x00, 0x69, 0x00, 0x00, 0x00, 0x7f, +0xff, 0x04, 0x00};
+/* "efidebug boot order 1002 1000 1001" */ +static u8 boot_order[] = {0x02, 0x10, 0x00, 0x10, 0x01, 0x10};
+static void *orig_smbios_table; +static u64 dmi_addr = U32_MAX; +#define SMBIOS_ENTRY_HEADER_SIZE 0x20 +/* smbios table for the measurement test */ +static u8 smbios_table_test[] = { +0x5f, 0x53, 0x4d, 0x5f, 0x2c, 0x1f, 0x03, 0x00, 0x54, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x5f, 0x44, 0x4d, 0x49, 0x5f, 0xe4, 0x5c, 0x01, +0x20, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, +0x01, 0x02, 0x00, 0x00, 0x03, 0x00, 0x80, 0x08, 0x01, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x0c, 0x15, 0x0a, 0xff, 0xff, 0x55, 0x2d, 0x42, 0x6f, +0x6f, 0x74, 0x00, 0x32, 0x30, 0x32, 0x31, 0x2e, 0x31, 0x30, 0x2d, 0x72, +0x63, 0x34, 0x2d, 0x30, 0x30, 0x30, 0x30, 0x35, 0x2d, 0x67, 0x37, 0x32, +0x37, 0x63, 0x33, 0x66, 0x33, 0x32, 0x35, 0x39, 0x2d, 0x64, 0x69, 0x72, +0x74, 0x79, 0x00, 0x31, 0x30, 0x2f, 0x30, 0x31, 0x2f, 0x32, 0x30, 0x32, +0x31, 0x00, 0x00, 0x01, 0x1b, 0x01, 0x00, 0x01, 0x02, 0x00, 0x03, 0x31, +0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, +0x6e, 0x00, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x20, 0x50, 0x72, +0x6f, 0x64, 0x75, 0x63, 0x74, 0x00, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, +0x37, 0x38, 0x00, 0x00, 0x02, 0x0e, 0x02, 0x00, 0x01, 0x02, 0x00, 0x04, +0x03, 0x01, 0x01, 0x01, 0x00, 0x0a, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, +0x6e, 0x00, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x20, 0x50, 0x72, +0x6f, 0x64, 0x75, 0x63, 0x74, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, +0x33, 0x33, 0x00, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x00, +0x00, 0x03, 0x15, 0x03, 0x00, 0x01, 0x03, 0x00, 0x02, 0x03, 0x03, 0x03, +0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x6e, +0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x00, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, +0x37, 0x38, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, +0x00, 0x04, 0x30, 0x04, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x01, 0x06, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x03, 0x04, +0x04, 0x04, 0x08, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x08, 0x00, 0x01, +0x00, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x00, 0x31, 0x32, 0x33, +0x34, 0x35, 0x36, 0x37, 0x38, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, +0x33, 0x33, 0x00, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x00, +0x00, 0x20, 0x0b, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7f, 0x04, 0x06, 0x00, 0x00, 0x00 +};
+#define TPM2_CMD_BUF_SIZE 64 +/* TPM command is big endian */ +#define __MSB(x) ((x) >> 8) +#define __LSB(x) ((x) & 0xFF) +#define tpm_u16(x) __MSB(x), __LSB(x) +#define tpm_u32(x) tpm_u16((x) >> 16), tpm_u16((x) & 0xFFFF) +#define TPM2_PCR_READ_HEADER_SIZE 30
+static u8 *pcrs; +static u8 expected_pcrs[EFI_TCG2_MAX_PCR_INDEX + 1][TPM2_SHA256_DIGEST_SIZE] = {
- {0x91, 0x21, 0x37, 0xc7, 0x1a, 0x49, 0x19, 0xc8,
0xf1, 0xfb, 0xa9, 0x84, 0x5c, 0x65, 0xa9, 0xdd,
0x7b, 0xb9, 0xfe, 0xa1, 0xcd, 0x64, 0x49, 0xdd,
0xed, 0xe2, 0x65, 0x82, 0xc5, 0x3e, 0xf4, 0xc4},
- {0xf5, 0x79, 0xf3, 0x20, 0x62, 0x6e, 0x8b, 0x58,
0x62, 0xa3, 0x4e, 0x2f, 0xb7, 0x10, 0xac, 0x34,
0x4e, 0x68, 0x94, 0x37, 0x87, 0x29, 0xc4, 0xbe,
0xa3, 0xc4, 0xd9, 0x14, 0x2b, 0x66, 0x79, 0x9b},
- {0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea,
0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d,
0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a,
0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69},
- {0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea,
0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d,
0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a,
0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69},
- {0xbe, 0xea, 0xdc, 0xe0, 0x44, 0x5b, 0x5f, 0x14,
0xef, 0x24, 0x5d, 0x13, 0x15, 0xfe, 0x41, 0x86,
0xc2, 0xd5, 0xdc, 0x0d, 0x04, 0x2f, 0xd4, 0x04,
0x0d, 0x02, 0x62, 0xc0, 0x34, 0x80, 0xee, 0xd5},
- {0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea,
0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d,
0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a,
0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69},
- {0x8d, 0x28, 0xde, 0x72, 0x22, 0x3e, 0x88, 0x1a,
0x37, 0xfa, 0x47, 0x12, 0x68, 0x45, 0xdf, 0x71,
0x50, 0x8f, 0xab, 0x59, 0x50, 0x7b, 0x52, 0x32,
0xa6, 0xaa, 0x03, 0x3d, 0x4e, 0x22, 0x89, 0xd7},
- {0x96, 0x74, 0xae, 0xcd, 0x3f, 0x40, 0xb4, 0xa9,
0x36, 0xae, 0x19, 0xc8, 0x84, 0x8a, 0xb9, 0x5a,
0x87, 0x99, 0xd8, 0x89, 0x7f, 0xfc, 0x40, 0x48,
0x05, 0x99, 0x65, 0x2e, 0x55, 0xd4, 0x93, 0x32},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+};
+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)},
+};
+/*
- 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;
+}
+/*
- Configure dummy boot variables.
/** * 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;
- u8 dummy;
This variable is superfluous.
- for (i = 0; i < ARRAY_SIZE(boot_variable_test); i++) {
size = 1;
Please, set size to 0.
ret = runtime->get_variable(boot_variable_test[i].name,
&efi_global_variable_guid,
&boot_variable_test[i].attr,
&size,
&dummy);
Instead of dummy you can use NULL if size = 0.
if (ret == EFI_BUFFER_TOO_SMALL) {
/* Variable exists, save the current vaiable */
%s/vaiable/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("fail to allocate buffer for boot variable\n");
In all other tests we use 'Failed to'
%s/fail/Failed/
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("fail to get current boot variable\n");
%s/fail/Failed/
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("### fail to set test boot variable(%d)n", i);
%s/### fail/Failed/
return ret;
}
- }
- return 0;
+}
+/*
/** * efi_status_t restore_boot_variable() - restore original values * * Restore the variable values saved in setup_boot_variable(). *
- Restore original boot variables.
- @return status code
- */
+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("### fail 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("### fail to delete boot variable\n");
%s/### fail/Failed/
return ret;
}
}
- }
- return EFI_SUCCESS;
+}
+/**
- 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;
+}
+/**
- Prepare the dummy SMBIOS table
- @systable system table
- @return status code
- */
+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 +508,171 @@ 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);
- return EFI_ST_SUCCESS;
+}
+/**
- 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;
+}
+/**
- 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;
- u8 idx_array_sz = 3; /* support 24 PCRs */
This is a constant.
#define IDX_ARRAY_SZ 3
You can move it close to the TPM2_CMD_BUF_SIZE definition.
- 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);
- u8 *dst;
- 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;
- }
- dst = pcrs + (idx * TPM2_SHA256_DIGEST_SIZE);
- boottime->copy_mem(dst, &resp[TPM2_PCR_READ_HEADER_SIZE],
TPM2_SHA256_DIGEST_SIZE);
- return ret;
+}
+/**
- Compare the expected and actual pcrs
- @return status code
- */
+static int validate_pcrs(void) +{
- u32 i;
- u8 *expected = (u8 *)expected_pcrs;
- u8 *result = pcrs;
Making expected_pcrs and pcrs arrays with elements of size TPM2_SHA256_DIGEST_SIZE can replace these pointers.
- /*
* - 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
* it varies depending on the platform.
%s/it varies/vary/
*/
- for (i = 0; i < (EFI_TCG2_MAX_PCR_INDEX + 1); i++) {
for (i = 1; i < (EFI_TCG2_MAX_PCR_INDEX + 1); ++i) { if (i != 7) continue; if (memcmp(pcr[i], expected_pcr[i], PM2_SHA256_DIGEST_SIZE)) { if (memcmp(expected, result, TPM2_SHA256_DIGEST_SIZE)) { efi_st_printf("PCR[%d] is not the expected value\n", i); return EFI_ST_FAILURE; } } }
result = pcrs + (TPM2_SHA256_DIGEST_SIZE * i);
if (i == 0 || i == 7) {
expected += TPM2_SHA256_DIGEST_SIZE;
result += TPM2_SHA256_DIGEST_SIZE;
continue; /* skip validation */
}
if (memcmp(expected, result, TPM2_SHA256_DIGEST_SIZE)) {
efi_st_printf("PCR[%d] is not the expected value\n", i);
return EFI_ST_FAILURE;
}
expected += TPM2_SHA256_DIGEST_SIZE;
result += TPM2_SHA256_DIGEST_SIZE;
}
return EFI_ST_SUCCESS; }
@@ -31,7 +680,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 +690,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; }
/* 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 +724,154 @@ 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(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 */
lib/efi_selftest/efi_selftest_block_device.c shows how to setup a memory based block device.
- 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; }
+/*
- Tear down unit test.
/** * efi_st_tcg2_teardown() - tear down unit test *
Overall the design looks good to me.
Best regards
Heinrich
- @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, };

On Sat, 23 Oct 2021 at 18:42, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 10/22/21 13:24, Masahisa Kojima wrote:
This commit adds the missing EFI_TCG2_PROTOCOL selftest and Measured Boot selftest in lib/efi_selftest.
Signed-off-by: Masahisa Kojima masahisa.kojima@linaro.org
lib/efi_selftest/Makefile | 10 + .../efi_selftest_miniapp_measuredboot.c | 93 ++ lib/efi_selftest/efi_selftest_tcg2.c | 804 +++++++++++++++++- 3 files changed, 906 insertions(+), 1 deletion(-) create mode 100644 lib/efi_selftest/efi_selftest_miniapp_measuredboot.c
diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 9ff6e1760c..09950ee028 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -14,6 +14,8 @@ CFLAGS_efi_selftest_miniapp_exception.o := $(CFLAGS_EFI) -Os -ffreestanding CFLAGS_REMOVE_efi_selftest_miniapp_exception.o := $(CFLAGS_NON_EFI) CFLAGS_efi_selftest_miniapp_exit.o := $(CFLAGS_EFI) -Os -ffreestanding CFLAGS_REMOVE_efi_selftest_miniapp_exit.o := $(CFLAGS_NON_EFI) +CFLAGS_efi_selftest_miniapp_measuredboot.o := $(CFLAGS_EFI) -Os -ffreestanding +CFLAGS_REMOVE_efi_selftest_miniapp_measuredboot.o := $(CFLAGS_NON_EFI) CFLAGS_efi_selftest_miniapp_return.o := $(CFLAGS_EFI) -Os -ffreestanding CFLAGS_REMOVE_efi_selftest_miniapp_return.o := $(CFLAGS_NON_EFI) CFLAGS_initrddump_exit.o := $(CFLAGS_EFI) -Os -ffreestanding @@ -78,9 +80,11 @@ obj-$(CONFIG_EFI_ESRT) += efi_selftest_esrt.o targets += \ efi_miniapp_file_image_exception.h \ efi_miniapp_file_image_exit.h \ +efi_miniapp_file_image_measuredboot.h \ efi_miniapp_file_image_return.h \ efi_selftest_miniapp_exception.efi \ efi_selftest_miniapp_exit.efi \ +efi_selftest_miniapp_measuredboot.efi \ efi_selftest_miniapp_return.efi
ifeq ($(CONFIG_GENERATE_ACPI_TABLE),) @@ -99,6 +103,10 @@ $(obj)/efi_miniapp_file_image_exit.h: $(obj)/efi_selftest_miniapp_exit.efi $(obj)/../../tools/file2include $(obj)/efi_selftest_miniapp_exit.efi > \ $(obj)/efi_miniapp_file_image_exit.h
+$(obj)/efi_miniapp_file_image_measuredboot.h: $(obj)/efi_selftest_miniapp_measuredboot.efi
$(obj)/../../tools/file2include $(obj)/efi_selftest_miniapp_measuredboot.efi > \
$(obj)/efi_miniapp_file_image_measuredboot.h
- $(obj)/efi_miniapp_file_image_return.h: $(obj)/efi_selftest_miniapp_return.efi $(obj)/../../tools/file2include $(obj)/efi_selftest_miniapp_return.efi > \ $(obj)/efi_miniapp_file_image_return.h
@@ -112,3 +120,5 @@ $(obj)/efi_selftest_loadimage.o: $(obj)/efi_miniapp_file_image_exit.h $(obj)/efi_selftest_startimage_exit.o: $(obj)/efi_miniapp_file_image_exit.h
$(obj)/efi_selftest_startimage_return.o: $(obj)/efi_miniapp_file_image_return.h
+$(obj)/efi_selftest_tcg2.o: $(obj)/efi_miniapp_file_image_measuredboot.h diff --git a/lib/efi_selftest/efi_selftest_miniapp_measuredboot.c b/lib/efi_selftest/efi_selftest_miniapp_measuredboot.c
Thank you for going the extra mile and adding the test.
Which image is actually loaded seems to be irrelevant for the test. Can we reuse an existing one, e.g. efi_miniapp_file_image_return.h?
I guess the PCR related to the loaded image is not checked as it will depend on the build tools and date.
Sorry, I'm doing wrong. Actually this selftest verifies the PE/COFF image measurement, so measuremt will be different depending on the build tools and date. # In my build environment, timestamp is set to all zero.
To test the PE/COFF image measurement, I must prepare the static PE/COFF image. I plan to add efi_miniapp_file_image_measuredboot.h as a pre-compiled small static PE/COFF image for the measurement test, instead of adding efi_selftest_miniapp_measuredboot.c or reusing existing one.
new file mode 100644 index 0000000000..926713c1c2 --- /dev/null +++ b/lib/efi_selftest/efi_selftest_miniapp_measuredboot.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- efi_selftest_miniapp_measuredboot
- Copyright (c) 2018 Heinrich Schuchardt
- Copyright (c) 2021 Masahisa Kojima
- This EFI application is run by the StartImage selftest.
This is incorrect due to copy and paste.
- It uses the Exit boot service to return and used for
- Measured Boot selftest.
- */
+#include <common.h> +#include <efi_selftest.h>
+static efi_guid_t loaded_image_protocol_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
+/**
- check_loaded_image_protocol() - check image_base/image_size
- Try to open the loaded image protocol. Check that this function is located
- between image_base and image_base + image_size.
- @image_handle: handle of the loaded image
- @systable: system table
- @return: status code
- */
+static efi_status_t EFIAPI check_loaded_image_protocol
(efi_handle_t image_handle, struct efi_system_table *systable)
+{
struct efi_simple_text_output_protocol *cout = systable->con_out;
struct efi_boot_services *boottime = systable->boottime;
struct efi_loaded_image *loaded_image_protocol;
efi_status_t ret;
/*
* Open the loaded image protocol.
*/
ret = boottime->open_protocol
(image_handle, &loaded_image_protocol_guid,
(void **)&loaded_image_protocol, NULL,
NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (ret != EFI_SUCCESS) {
cout->output_string(cout,
L"Could not open loaded image protocol");
return ret;
}
if ((void *)check_loaded_image_protocol <
loaded_image_protocol->image_base ||
(void *)check_loaded_image_protocol >=
loaded_image_protocol->image_base +
loaded_image_protocol->image_size) {
cout->output_string(cout,
L"Incorrect image_base or image_size\n");
return EFI_NOT_FOUND;
}
return EFI_SUCCESS;
+}
+/**
- Entry point of the EFI application.
- @handle: handle of the loaded image
- @systable: system table
- @return: status code
- */
+efi_status_t EFIAPI efi_main(efi_handle_t handle,
struct efi_system_table *systable)
+{
struct efi_simple_text_output_protocol *con_out = systable->con_out;
efi_status_t ret;
u16 text[] = EFI_ST_SUCCESS_STR;
con_out->output_string(con_out, L"EFI application calling Exit\n");
if (check_loaded_image_protocol(handle, systable) != EFI_SUCCESS) {
con_out->output_string(con_out,
L"Loaded image protocol missing\n");
ret = EFI_NOT_FOUND;
goto out;
}
/* This return value is expected by the calling test */
ret = EFI_UNSUPPORTED;
+out:
systable->boottime->exit(handle, ret, sizeof(text), text);
/*
* This statement should not be reached.
* To enable testing use a different return value.
*/
return EFI_SUCCESS;
+} diff --git a/lib/efi_selftest/efi_selftest_tcg2.c b/lib/efi_selftest/efi_selftest_tcg2.c index 1399309cec..50de735f5e 100644 --- a/lib/efi_selftest/efi_selftest_tcg2.c +++ b/lib/efi_selftest/efi_selftest_tcg2.c @@ -9,10 +9,495 @@
#include <efi_selftest.h> #include <efi_tcg2.h> +/* Include containing the miniapp.efi application */ +#include "efi_miniapp_file_image_measuredboot.h"
efi_miniapp_file_image_return.h
As I said above, I will prepare static PE/COFF image only for the measurement purpose.
+#include <linux/unaligned/access_ok.h> +#include <mapmem.h> +#include <smbios.h> +#include <tables_csum.h>
static struct efi_boot_services *boottime; static const efi_guid_t guid_tcg2 = EFI_TCG2_PROTOCOL_GUID;
+/* Block size of compressed disk image */ +#define COMPRESSED_DISK_IMAGE_BLOCK_SIZE 8
+static efi_handle_t image_handle; +/* Decompressed file image */ +static u8 *image;
+/* One 8 byte block of the compressed disk image */ +struct line {
size_t addr;
char *line;
+};
+/* Compressed file image */ +struct compressed_file_image {
size_t length;
struct line lines[];
+};
+static struct compressed_file_image img = EFI_ST_DISK_IMG;
+static struct efi_tcg2_event *efi_tcg2_event;
+static struct efi_runtime_services *runtime; +#define BOOT_NAME_1000 u"Boot1000" +#define BOOT_NAME_1001 u"Boot1001" +#define BOOT_NAME_1002 u"Boot1002"
+#define DEFAULT_ATTR (EFI_VARIABLE_NON_VOLATILE | \
EFI_VARIABLE_BOOTSERVICE_ACCESS | \
EFI_VARIABLE_RUNTIME_ACCESS)
+/* "efidebug boot add -b 1000 test1000 virtio 0:1 /EFI/debian/grubaa64.efi" */ +static const u8 boot_1000[] = { +0x01, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, +0x74, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x04, 0x14, 0x00, 0xb9, 0x73, +0x1d, 0xe6, 0x84, 0xa3, 0xcc, 0x4a, 0xae, 0xab, 0x82, 0xe8, 0x28, 0xf3, +0x62, 0x8b, 0x01, 0x04, 0x15, 0x00, 0x92, 0x37, 0x29, 0x63, 0xf5, 0xad, +0x25, 0x93, 0xb9, 0x9f, 0x4e, 0x0e, 0x45, 0x5c, 0x1b, 0x1e, 0x00, 0x04, +0x01, 0x2a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, +0x5a, 0x47, 0xc2, 0x35, 0x27, 0x44, 0x47, 0x9f, 0x01, 0x67, 0xfe, 0xfa, +0x1d, 0x06, 0xae, 0x02, 0x02, 0x04, 0x04, 0x36, 0x00, 0x5c, 0x00, 0x45, +0x00, 0x46, 0x00, 0x49, 0x00, 0x5c, 0x00, 0x64, 0x00, 0x65, 0x00, 0x62, +0x00, 0x69, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x5c, 0x00, 0x67, 0x00, 0x72, +0x00, 0x75, 0x00, 0x62, 0x00, 0x61, 0x00, 0x61, 0x00, 0x36, 0x00, 0x34, +0x00, 0x2e, 0x00, 0x65, 0x00, 0x66, 0x00, 0x69, 0x00, 0x00, 0x00, 0x7f, +0xff, 0x04, 0x00 };
+/* "efidebug boot add -b 1001 test1001 virtio 0:1 /EFI/debian/grubaa64.efi" */ +static const u8 boot_1001[] = { +0x01, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, +0x74, 0x00, 0x31, 0x00, 0x00, 0x00, 0x01, 0x04, 0x14, 0x00, 0xb9, 0x73, +0x1d, 0xe6, 0x84, 0xa3, 0xcc, 0x4a, 0xae, 0xab, 0x82, 0xe8, 0x28, 0xf3, +0x62, 0x8b, 0x01, 0x04, 0x15, 0x00, 0x92, 0x37, 0x29, 0x63, 0xf5, 0xad, +0x25, 0x93, 0xb9, 0x9f, 0x4e, 0x0e, 0x45, 0x5c, 0x1b, 0x1e, 0x00, 0x04, +0x01, 0x2a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, +0x5a, 0x47, 0xc2, 0x35, 0x27, 0x44, 0x47, 0x9f, 0x01, 0x67, 0xfe, 0xfa, +0x1d, 0x06, 0xae, 0x02, 0x02, 0x04, 0x04, 0x36, 0x00, 0x5c, 0x00, 0x45, +0x00, 0x46, 0x00, 0x49, 0x00, 0x5c, 0x00, 0x64, 0x00, 0x65, 0x00, 0x62, +0x00, 0x69, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x5c, 0x00, 0x67, 0x00, 0x72, +0x00, 0x75, 0x00, 0x62, 0x00, 0x61, 0x00, 0x61, 0x00, 0x36, 0x00, 0x34, +0x00, 0x2e, 0x00, 0x65, 0x00, 0x66, 0x00, 0x69, 0x00, 0x00, 0x00, 0x7f, +0xff, 0x04, 0x00 };
+/* "efidebug boot add -b 1002 test1002 virtio 0:1 /EFI/debian/grubaa64.efi" */ +static const u8 boot_1002[] = { +0x01, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, +0x74, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x04, 0x14, 0x00, 0xb9, 0x73, +0x1d, 0xe6, 0x84, 0xa3, 0xcc, 0x4a, 0xae, 0xab, 0x82, 0xe8, 0x28, 0xf3, +0x62, 0x8b, 0x01, 0x04, 0x15, 0x00, 0x92, 0x37, 0x29, 0x63, 0xf5, 0xad, +0x25, 0x93, 0xb9, 0x9f, 0x4e, 0x0e, 0x45, 0x5c, 0x1b, 0x1e, 0x00, 0x04, +0x01, 0x2a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, +0x5a, 0x47, 0xc2, 0x35, 0x27, 0x44, 0x47, 0x9f, 0x01, 0x67, 0xfe, 0xfa, +0x1d, 0x06, 0xae, 0x02, 0x02, 0x04, 0x04, 0x36, 0x00, 0x5c, 0x00, 0x45, +0x00, 0x46, 0x00, 0x49, 0x00, 0x5c, 0x00, 0x64, 0x00, 0x65, 0x00, 0x62, +0x00, 0x69, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x5c, 0x00, 0x67, 0x00, 0x72, +0x00, 0x75, 0x00, 0x62, 0x00, 0x61, 0x00, 0x61, 0x00, 0x36, 0x00, 0x34, +0x00, 0x2e, 0x00, 0x65, 0x00, 0x66, 0x00, 0x69, 0x00, 0x00, 0x00, 0x7f, +0xff, 0x04, 0x00};
+/* "efidebug boot order 1002 1000 1001" */ +static u8 boot_order[] = {0x02, 0x10, 0x00, 0x10, 0x01, 0x10};
+static void *orig_smbios_table; +static u64 dmi_addr = U32_MAX; +#define SMBIOS_ENTRY_HEADER_SIZE 0x20 +/* smbios table for the measurement test */ +static u8 smbios_table_test[] = { +0x5f, 0x53, 0x4d, 0x5f, 0x2c, 0x1f, 0x03, 0x00, 0x54, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x5f, 0x44, 0x4d, 0x49, 0x5f, 0xe4, 0x5c, 0x01, +0x20, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, +0x01, 0x02, 0x00, 0x00, 0x03, 0x00, 0x80, 0x08, 0x01, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x0c, 0x15, 0x0a, 0xff, 0xff, 0x55, 0x2d, 0x42, 0x6f, +0x6f, 0x74, 0x00, 0x32, 0x30, 0x32, 0x31, 0x2e, 0x31, 0x30, 0x2d, 0x72, +0x63, 0x34, 0x2d, 0x30, 0x30, 0x30, 0x30, 0x35, 0x2d, 0x67, 0x37, 0x32, +0x37, 0x63, 0x33, 0x66, 0x33, 0x32, 0x35, 0x39, 0x2d, 0x64, 0x69, 0x72, +0x74, 0x79, 0x00, 0x31, 0x30, 0x2f, 0x30, 0x31, 0x2f, 0x32, 0x30, 0x32, +0x31, 0x00, 0x00, 0x01, 0x1b, 0x01, 0x00, 0x01, 0x02, 0x00, 0x03, 0x31, +0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, +0x6e, 0x00, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x20, 0x50, 0x72, +0x6f, 0x64, 0x75, 0x63, 0x74, 0x00, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, +0x37, 0x38, 0x00, 0x00, 0x02, 0x0e, 0x02, 0x00, 0x01, 0x02, 0x00, 0x04, +0x03, 0x01, 0x01, 0x01, 0x00, 0x0a, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, +0x6e, 0x00, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x20, 0x50, 0x72, +0x6f, 0x64, 0x75, 0x63, 0x74, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, +0x33, 0x33, 0x00, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x00, +0x00, 0x03, 0x15, 0x03, 0x00, 0x01, 0x03, 0x00, 0x02, 0x03, 0x03, 0x03, +0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x6e, +0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x00, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, +0x37, 0x38, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, +0x00, 0x04, 0x30, 0x04, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x01, 0x06, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x03, 0x04, +0x04, 0x04, 0x08, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x08, 0x00, 0x01, +0x00, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x00, 0x31, 0x32, 0x33, +0x34, 0x35, 0x36, 0x37, 0x38, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, +0x33, 0x33, 0x00, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x00, +0x00, 0x20, 0x0b, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7f, 0x04, 0x06, 0x00, 0x00, 0x00 +};
+#define TPM2_CMD_BUF_SIZE 64 +/* TPM command is big endian */ +#define __MSB(x) ((x) >> 8) +#define __LSB(x) ((x) & 0xFF) +#define tpm_u16(x) __MSB(x), __LSB(x) +#define tpm_u32(x) tpm_u16((x) >> 16), tpm_u16((x) & 0xFFFF) +#define TPM2_PCR_READ_HEADER_SIZE 30
+static u8 *pcrs; +static u8 expected_pcrs[EFI_TCG2_MAX_PCR_INDEX + 1][TPM2_SHA256_DIGEST_SIZE] = {
{0x91, 0x21, 0x37, 0xc7, 0x1a, 0x49, 0x19, 0xc8,
0xf1, 0xfb, 0xa9, 0x84, 0x5c, 0x65, 0xa9, 0xdd,
0x7b, 0xb9, 0xfe, 0xa1, 0xcd, 0x64, 0x49, 0xdd,
0xed, 0xe2, 0x65, 0x82, 0xc5, 0x3e, 0xf4, 0xc4},
{0xf5, 0x79, 0xf3, 0x20, 0x62, 0x6e, 0x8b, 0x58,
0x62, 0xa3, 0x4e, 0x2f, 0xb7, 0x10, 0xac, 0x34,
0x4e, 0x68, 0x94, 0x37, 0x87, 0x29, 0xc4, 0xbe,
0xa3, 0xc4, 0xd9, 0x14, 0x2b, 0x66, 0x79, 0x9b},
{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea,
0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d,
0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a,
0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69},
{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea,
0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d,
0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a,
0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69},
{0xbe, 0xea, 0xdc, 0xe0, 0x44, 0x5b, 0x5f, 0x14,
0xef, 0x24, 0x5d, 0x13, 0x15, 0xfe, 0x41, 0x86,
0xc2, 0xd5, 0xdc, 0x0d, 0x04, 0x2f, 0xd4, 0x04,
0x0d, 0x02, 0x62, 0xc0, 0x34, 0x80, 0xee, 0xd5},
{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea,
0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d,
0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a,
0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69},
{0x8d, 0x28, 0xde, 0x72, 0x22, 0x3e, 0x88, 0x1a,
0x37, 0xfa, 0x47, 0x12, 0x68, 0x45, 0xdf, 0x71,
0x50, 0x8f, 0xab, 0x59, 0x50, 0x7b, 0x52, 0x32,
0xa6, 0xaa, 0x03, 0x3d, 0x4e, 0x22, 0x89, 0xd7},
{0x96, 0x74, 0xae, 0xcd, 0x3f, 0x40, 0xb4, 0xa9,
0x36, 0xae, 0x19, 0xc8, 0x84, 0x8a, 0xb9, 0x5a,
0x87, 0x99, 0xd8, 0x89, 0x7f, 0xfc, 0x40, 0x48,
0x05, 0x99, 0x65, 0x2e, 0x55, 0xd4, 0x93, 0x32},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+};
+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)},
+};
+/*
- 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;
+}
+/*
- Configure dummy boot variables.
/**
- 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;
u8 dummy;
This variable is superfluous.
for (i = 0; i < ARRAY_SIZE(boot_variable_test); i++) {
size = 1;
Please, set size to 0.
ret = runtime->get_variable(boot_variable_test[i].name,
&efi_global_variable_guid,
&boot_variable_test[i].attr,
&size,
&dummy);
Instead of dummy you can use NULL if size = 0.
if (ret == EFI_BUFFER_TOO_SMALL) {
/* Variable exists, save the current vaiable */
%s/vaiable/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("fail to allocate buffer for boot variable\n");
In all other tests we use 'Failed to'
%s/fail/Failed/
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("fail to get current boot variable\n");
%s/fail/Failed/
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("### fail to set test boot variable(%d)n", i);
%s/### fail/Failed/
return ret;
}
}
return 0;
+}
+/*
/**
- efi_status_t restore_boot_variable() - restore original values
- Restore the variable values saved in setup_boot_variable().
- Restore original boot variables.
- @return status code
- */
+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("### fail 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("### fail to delete boot variable\n");
%s/### fail/Failed/
return ret;
}
}
}
return EFI_SUCCESS;
+}
+/**
- 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;
+}
+/**
- Prepare the dummy SMBIOS table
- @systable system table
- @return status code
- */
+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 +508,171 @@ 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);
return EFI_ST_SUCCESS;
+}
+/**
- 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;
+}
+/**
- 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;
u8 idx_array_sz = 3; /* support 24 PCRs */
This is a constant.
#define IDX_ARRAY_SZ 3
You can move it close to the TPM2_CMD_BUF_SIZE definition.
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);
u8 *dst;
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;
}
dst = pcrs + (idx * TPM2_SHA256_DIGEST_SIZE);
boottime->copy_mem(dst, &resp[TPM2_PCR_READ_HEADER_SIZE],
TPM2_SHA256_DIGEST_SIZE);
return ret;
+}
+/**
- Compare the expected and actual pcrs
- @return status code
- */
+static int validate_pcrs(void) +{
u32 i;
u8 *expected = (u8 *)expected_pcrs;
u8 *result = pcrs;
Making expected_pcrs and pcrs arrays with elements of size TPM2_SHA256_DIGEST_SIZE can replace these pointers.
/*
* - 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
* it varies depending on the platform.
%s/it varies/vary/
*/
for (i = 0; i < (EFI_TCG2_MAX_PCR_INDEX + 1); i++) {
for (i = 1; i < (EFI_TCG2_MAX_PCR_INDEX + 1); ++i) { if (i != 7) continue; if (memcmp(pcr[i], expected_pcr[i], PM2_SHA256_DIGEST_SIZE)) { if (memcmp(expected, result, TPM2_SHA256_DIGEST_SIZE)) { efi_st_printf("PCR[%d] is not the expected value\n", i); return EFI_ST_FAILURE; } } }
result = pcrs + (TPM2_SHA256_DIGEST_SIZE * i);
if (i == 0 || i == 7) {
expected += TPM2_SHA256_DIGEST_SIZE;
result += TPM2_SHA256_DIGEST_SIZE;
continue; /* skip validation */
}
if (memcmp(expected, result, TPM2_SHA256_DIGEST_SIZE)) {
efi_st_printf("PCR[%d] is not the expected value\n", i);
return EFI_ST_FAILURE;
}
expected += TPM2_SHA256_DIGEST_SIZE;
result += TPM2_SHA256_DIGEST_SIZE;
} return EFI_ST_SUCCESS;
}
@@ -31,7 +680,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 +690,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; }
/* 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 +724,154 @@ 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(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 */
lib/efi_selftest/efi_selftest_block_device.c shows how to setup a memory based block device.
Thank you for the information. I tried to copy efi_selftest_block_device but I encountered error.
To test GPT measurement, I need to add the device path node having following type. dp->type == DEVICE_PATH_TYPE_MEDIA_DEVICE dp->sub_type == DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH If I added this node in the device path, boottime->connect_controller() returns EFI_NOT_FOUND and I'm investigating how to use connect_controller.
For other comments, I will include fixes in the next version.
Thanks, Masahisa Kojima
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;
+/*
- Tear down unit test.
/**
- efi_st_tcg2_teardown() - tear down unit test
Overall the design looks good to me.
Best regards
Heinrich
- @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,

On 10/25/21 09:59, Masahisa Kojima wrote:
On Sat, 23 Oct 2021 at 18:42, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 10/22/21 13:24, Masahisa Kojima wrote:
This commit adds the missing EFI_TCG2_PROTOCOL selftest and Measured Boot selftest in lib/efi_selftest.
Signed-off-by: Masahisa Kojima masahisa.kojima@linaro.org
lib/efi_selftest/Makefile | 10 + .../efi_selftest_miniapp_measuredboot.c | 93 ++ lib/efi_selftest/efi_selftest_tcg2.c | 804 +++++++++++++++++- 3 files changed, 906 insertions(+), 1 deletion(-) create mode 100644 lib/efi_selftest/efi_selftest_miniapp_measuredboot.c
diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 9ff6e1760c..09950ee028 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -14,6 +14,8 @@ CFLAGS_efi_selftest_miniapp_exception.o := $(CFLAGS_EFI) -Os -ffreestanding CFLAGS_REMOVE_efi_selftest_miniapp_exception.o := $(CFLAGS_NON_EFI) CFLAGS_efi_selftest_miniapp_exit.o := $(CFLAGS_EFI) -Os -ffreestanding CFLAGS_REMOVE_efi_selftest_miniapp_exit.o := $(CFLAGS_NON_EFI) +CFLAGS_efi_selftest_miniapp_measuredboot.o := $(CFLAGS_EFI) -Os -ffreestanding +CFLAGS_REMOVE_efi_selftest_miniapp_measuredboot.o := $(CFLAGS_NON_EFI) CFLAGS_efi_selftest_miniapp_return.o := $(CFLAGS_EFI) -Os -ffreestanding CFLAGS_REMOVE_efi_selftest_miniapp_return.o := $(CFLAGS_NON_EFI) CFLAGS_initrddump_exit.o := $(CFLAGS_EFI) -Os -ffreestanding @@ -78,9 +80,11 @@ obj-$(CONFIG_EFI_ESRT) += efi_selftest_esrt.o targets += \ efi_miniapp_file_image_exception.h \ efi_miniapp_file_image_exit.h \ +efi_miniapp_file_image_measuredboot.h \ efi_miniapp_file_image_return.h \ efi_selftest_miniapp_exception.efi \ efi_selftest_miniapp_exit.efi \ +efi_selftest_miniapp_measuredboot.efi \ efi_selftest_miniapp_return.efi
ifeq ($(CONFIG_GENERATE_ACPI_TABLE),) @@ -99,6 +103,10 @@ $(obj)/efi_miniapp_file_image_exit.h: $(obj)/efi_selftest_miniapp_exit.efi $(obj)/../../tools/file2include $(obj)/efi_selftest_miniapp_exit.efi > \ $(obj)/efi_miniapp_file_image_exit.h
+$(obj)/efi_miniapp_file_image_measuredboot.h: $(obj)/efi_selftest_miniapp_measuredboot.efi
$(obj)/../../tools/file2include $(obj)/efi_selftest_miniapp_measuredboot.efi > \
$(obj)/efi_miniapp_file_image_measuredboot.h
- $(obj)/efi_miniapp_file_image_return.h: $(obj)/efi_selftest_miniapp_return.efi $(obj)/../../tools/file2include $(obj)/efi_selftest_miniapp_return.efi > \ $(obj)/efi_miniapp_file_image_return.h
@@ -112,3 +120,5 @@ $(obj)/efi_selftest_loadimage.o: $(obj)/efi_miniapp_file_image_exit.h $(obj)/efi_selftest_startimage_exit.o: $(obj)/efi_miniapp_file_image_exit.h
$(obj)/efi_selftest_startimage_return.o: $(obj)/efi_miniapp_file_image_return.h
+$(obj)/efi_selftest_tcg2.o: $(obj)/efi_miniapp_file_image_measuredboot.h diff --git a/lib/efi_selftest/efi_selftest_miniapp_measuredboot.c b/lib/efi_selftest/efi_selftest_miniapp_measuredboot.c
Thank you for going the extra mile and adding the test.
Which image is actually loaded seems to be irrelevant for the test. Can we reuse an existing one, e.g. efi_miniapp_file_image_return.h?
I guess the PCR related to the loaded image is not checked as it will depend on the build tools and date.
Sorry, I'm doing wrong. Actually this selftest verifies the PE/COFF image measurement, so measuremt will be different depending on the build tools and date. # In my build environment, timestamp is set to all zero.
To test the PE/COFF image measurement, I must prepare the static PE/COFF image. I plan to add efi_miniapp_file_image_measuredboot.h as a pre-compiled small static PE/COFF image for the measurement test, instead of adding efi_selftest_miniapp_measuredboot.c or reusing existing one.
You will need one image per UEFI architecture (ia32, x64, arm, aa64, riscv32, riscv64). You could present the image via the EFI_LOAD_FILE2_PROTOCOL, see lib/efi_selftest/efi_selftest_load_file.c.
Here is how to detect the target architecture:
#if defined(__arm__) #include efi_miniapp_tcg2_arm.h #elif defined(__aarch64__) #include efi_miniapp_tcg2_aarch64.h #elif defined(__i386__) #include efi_miniapp_tcg2_ia32.h #elif defined(__x86_64__) #include efi_miniapp_tcg2_x64.h #elif defined(__riscv) && (__riscv_xlen == 32) #include efi_miniapp_tcg2_riscv32.h #elif defined(__riscv) && (__riscv_xlen == 64) #include efi_miniapp_tcg2_riscv64.h #endif
Best regards
Heinrich
new file mode 100644 index 0000000000..926713c1c2 --- /dev/null +++ b/lib/efi_selftest/efi_selftest_miniapp_measuredboot.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- efi_selftest_miniapp_measuredboot
- Copyright (c) 2018 Heinrich Schuchardt
- Copyright (c) 2021 Masahisa Kojima
- This EFI application is run by the StartImage selftest.
This is incorrect due to copy and paste.
- It uses the Exit boot service to return and used for
- Measured Boot selftest.
- */
+#include <common.h> +#include <efi_selftest.h>
+static efi_guid_t loaded_image_protocol_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
+/**
- check_loaded_image_protocol() - check image_base/image_size
- Try to open the loaded image protocol. Check that this function is located
- between image_base and image_base + image_size.
- @image_handle: handle of the loaded image
- @systable: system table
- @return: status code
- */
+static efi_status_t EFIAPI check_loaded_image_protocol
(efi_handle_t image_handle, struct efi_system_table *systable)
+{
struct efi_simple_text_output_protocol *cout = systable->con_out;
struct efi_boot_services *boottime = systable->boottime;
struct efi_loaded_image *loaded_image_protocol;
efi_status_t ret;
/*
* Open the loaded image protocol.
*/
ret = boottime->open_protocol
(image_handle, &loaded_image_protocol_guid,
(void **)&loaded_image_protocol, NULL,
NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (ret != EFI_SUCCESS) {
cout->output_string(cout,
L"Could not open loaded image protocol");
return ret;
}
if ((void *)check_loaded_image_protocol <
loaded_image_protocol->image_base ||
(void *)check_loaded_image_protocol >=
loaded_image_protocol->image_base +
loaded_image_protocol->image_size) {
cout->output_string(cout,
L"Incorrect image_base or image_size\n");
return EFI_NOT_FOUND;
}
return EFI_SUCCESS;
+}
+/**
- Entry point of the EFI application.
- @handle: handle of the loaded image
- @systable: system table
- @return: status code
- */
+efi_status_t EFIAPI efi_main(efi_handle_t handle,
struct efi_system_table *systable)
+{
struct efi_simple_text_output_protocol *con_out = systable->con_out;
efi_status_t ret;
u16 text[] = EFI_ST_SUCCESS_STR;
con_out->output_string(con_out, L"EFI application calling Exit\n");
if (check_loaded_image_protocol(handle, systable) != EFI_SUCCESS) {
con_out->output_string(con_out,
L"Loaded image protocol missing\n");
ret = EFI_NOT_FOUND;
goto out;
}
/* This return value is expected by the calling test */
ret = EFI_UNSUPPORTED;
+out:
systable->boottime->exit(handle, ret, sizeof(text), text);
/*
* This statement should not be reached.
* To enable testing use a different return value.
*/
return EFI_SUCCESS;
+} diff --git a/lib/efi_selftest/efi_selftest_tcg2.c b/lib/efi_selftest/efi_selftest_tcg2.c index 1399309cec..50de735f5e 100644 --- a/lib/efi_selftest/efi_selftest_tcg2.c +++ b/lib/efi_selftest/efi_selftest_tcg2.c @@ -9,10 +9,495 @@
#include <efi_selftest.h> #include <efi_tcg2.h> +/* Include containing the miniapp.efi application */ +#include "efi_miniapp_file_image_measuredboot.h"
efi_miniapp_file_image_return.h
As I said above, I will prepare static PE/COFF image only for the measurement purpose.
+#include <linux/unaligned/access_ok.h> +#include <mapmem.h> +#include <smbios.h> +#include <tables_csum.h>
static struct efi_boot_services *boottime; static const efi_guid_t guid_tcg2 = EFI_TCG2_PROTOCOL_GUID;
+/* Block size of compressed disk image */ +#define COMPRESSED_DISK_IMAGE_BLOCK_SIZE 8
+static efi_handle_t image_handle; +/* Decompressed file image */ +static u8 *image;
+/* One 8 byte block of the compressed disk image */ +struct line {
size_t addr;
char *line;
+};
+/* Compressed file image */ +struct compressed_file_image {
size_t length;
struct line lines[];
+};
+static struct compressed_file_image img = EFI_ST_DISK_IMG;
+static struct efi_tcg2_event *efi_tcg2_event;
+static struct efi_runtime_services *runtime; +#define BOOT_NAME_1000 u"Boot1000" +#define BOOT_NAME_1001 u"Boot1001" +#define BOOT_NAME_1002 u"Boot1002"
+#define DEFAULT_ATTR (EFI_VARIABLE_NON_VOLATILE | \
EFI_VARIABLE_BOOTSERVICE_ACCESS | \
EFI_VARIABLE_RUNTIME_ACCESS)
+/* "efidebug boot add -b 1000 test1000 virtio 0:1 /EFI/debian/grubaa64.efi" */ +static const u8 boot_1000[] = { +0x01, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, +0x74, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x04, 0x14, 0x00, 0xb9, 0x73, +0x1d, 0xe6, 0x84, 0xa3, 0xcc, 0x4a, 0xae, 0xab, 0x82, 0xe8, 0x28, 0xf3, +0x62, 0x8b, 0x01, 0x04, 0x15, 0x00, 0x92, 0x37, 0x29, 0x63, 0xf5, 0xad, +0x25, 0x93, 0xb9, 0x9f, 0x4e, 0x0e, 0x45, 0x5c, 0x1b, 0x1e, 0x00, 0x04, +0x01, 0x2a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, +0x5a, 0x47, 0xc2, 0x35, 0x27, 0x44, 0x47, 0x9f, 0x01, 0x67, 0xfe, 0xfa, +0x1d, 0x06, 0xae, 0x02, 0x02, 0x04, 0x04, 0x36, 0x00, 0x5c, 0x00, 0x45, +0x00, 0x46, 0x00, 0x49, 0x00, 0x5c, 0x00, 0x64, 0x00, 0x65, 0x00, 0x62, +0x00, 0x69, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x5c, 0x00, 0x67, 0x00, 0x72, +0x00, 0x75, 0x00, 0x62, 0x00, 0x61, 0x00, 0x61, 0x00, 0x36, 0x00, 0x34, +0x00, 0x2e, 0x00, 0x65, 0x00, 0x66, 0x00, 0x69, 0x00, 0x00, 0x00, 0x7f, +0xff, 0x04, 0x00 };
+/* "efidebug boot add -b 1001 test1001 virtio 0:1 /EFI/debian/grubaa64.efi" */ +static const u8 boot_1001[] = { +0x01, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, +0x74, 0x00, 0x31, 0x00, 0x00, 0x00, 0x01, 0x04, 0x14, 0x00, 0xb9, 0x73, +0x1d, 0xe6, 0x84, 0xa3, 0xcc, 0x4a, 0xae, 0xab, 0x82, 0xe8, 0x28, 0xf3, +0x62, 0x8b, 0x01, 0x04, 0x15, 0x00, 0x92, 0x37, 0x29, 0x63, 0xf5, 0xad, +0x25, 0x93, 0xb9, 0x9f, 0x4e, 0x0e, 0x45, 0x5c, 0x1b, 0x1e, 0x00, 0x04, +0x01, 0x2a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, +0x5a, 0x47, 0xc2, 0x35, 0x27, 0x44, 0x47, 0x9f, 0x01, 0x67, 0xfe, 0xfa, +0x1d, 0x06, 0xae, 0x02, 0x02, 0x04, 0x04, 0x36, 0x00, 0x5c, 0x00, 0x45, +0x00, 0x46, 0x00, 0x49, 0x00, 0x5c, 0x00, 0x64, 0x00, 0x65, 0x00, 0x62, +0x00, 0x69, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x5c, 0x00, 0x67, 0x00, 0x72, +0x00, 0x75, 0x00, 0x62, 0x00, 0x61, 0x00, 0x61, 0x00, 0x36, 0x00, 0x34, +0x00, 0x2e, 0x00, 0x65, 0x00, 0x66, 0x00, 0x69, 0x00, 0x00, 0x00, 0x7f, +0xff, 0x04, 0x00 };
+/* "efidebug boot add -b 1002 test1002 virtio 0:1 /EFI/debian/grubaa64.efi" */ +static const u8 boot_1002[] = { +0x01, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, +0x74, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x04, 0x14, 0x00, 0xb9, 0x73, +0x1d, 0xe6, 0x84, 0xa3, 0xcc, 0x4a, 0xae, 0xab, 0x82, 0xe8, 0x28, 0xf3, +0x62, 0x8b, 0x01, 0x04, 0x15, 0x00, 0x92, 0x37, 0x29, 0x63, 0xf5, 0xad, +0x25, 0x93, 0xb9, 0x9f, 0x4e, 0x0e, 0x45, 0x5c, 0x1b, 0x1e, 0x00, 0x04, +0x01, 0x2a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, +0x5a, 0x47, 0xc2, 0x35, 0x27, 0x44, 0x47, 0x9f, 0x01, 0x67, 0xfe, 0xfa, +0x1d, 0x06, 0xae, 0x02, 0x02, 0x04, 0x04, 0x36, 0x00, 0x5c, 0x00, 0x45, +0x00, 0x46, 0x00, 0x49, 0x00, 0x5c, 0x00, 0x64, 0x00, 0x65, 0x00, 0x62, +0x00, 0x69, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x5c, 0x00, 0x67, 0x00, 0x72, +0x00, 0x75, 0x00, 0x62, 0x00, 0x61, 0x00, 0x61, 0x00, 0x36, 0x00, 0x34, +0x00, 0x2e, 0x00, 0x65, 0x00, 0x66, 0x00, 0x69, 0x00, 0x00, 0x00, 0x7f, +0xff, 0x04, 0x00};
+/* "efidebug boot order 1002 1000 1001" */ +static u8 boot_order[] = {0x02, 0x10, 0x00, 0x10, 0x01, 0x10};
+static void *orig_smbios_table; +static u64 dmi_addr = U32_MAX; +#define SMBIOS_ENTRY_HEADER_SIZE 0x20 +/* smbios table for the measurement test */ +static u8 smbios_table_test[] = { +0x5f, 0x53, 0x4d, 0x5f, 0x2c, 0x1f, 0x03, 0x00, 0x54, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x5f, 0x44, 0x4d, 0x49, 0x5f, 0xe4, 0x5c, 0x01, +0x20, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, +0x01, 0x02, 0x00, 0x00, 0x03, 0x00, 0x80, 0x08, 0x01, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x0c, 0x15, 0x0a, 0xff, 0xff, 0x55, 0x2d, 0x42, 0x6f, +0x6f, 0x74, 0x00, 0x32, 0x30, 0x32, 0x31, 0x2e, 0x31, 0x30, 0x2d, 0x72, +0x63, 0x34, 0x2d, 0x30, 0x30, 0x30, 0x30, 0x35, 0x2d, 0x67, 0x37, 0x32, +0x37, 0x63, 0x33, 0x66, 0x33, 0x32, 0x35, 0x39, 0x2d, 0x64, 0x69, 0x72, +0x74, 0x79, 0x00, 0x31, 0x30, 0x2f, 0x30, 0x31, 0x2f, 0x32, 0x30, 0x32, +0x31, 0x00, 0x00, 0x01, 0x1b, 0x01, 0x00, 0x01, 0x02, 0x00, 0x03, 0x31, +0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, +0x6e, 0x00, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x20, 0x50, 0x72, +0x6f, 0x64, 0x75, 0x63, 0x74, 0x00, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, +0x37, 0x38, 0x00, 0x00, 0x02, 0x0e, 0x02, 0x00, 0x01, 0x02, 0x00, 0x04, +0x03, 0x01, 0x01, 0x01, 0x00, 0x0a, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, +0x6e, 0x00, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x20, 0x50, 0x72, +0x6f, 0x64, 0x75, 0x63, 0x74, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, +0x33, 0x33, 0x00, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x00, +0x00, 0x03, 0x15, 0x03, 0x00, 0x01, 0x03, 0x00, 0x02, 0x03, 0x03, 0x03, +0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x6e, +0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x00, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, +0x37, 0x38, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, +0x00, 0x04, 0x30, 0x04, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x01, 0x06, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x03, 0x04, +0x04, 0x04, 0x08, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x08, 0x00, 0x01, +0x00, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x00, 0x31, 0x32, 0x33, +0x34, 0x35, 0x36, 0x37, 0x38, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, +0x33, 0x33, 0x00, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x00, +0x00, 0x20, 0x0b, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7f, 0x04, 0x06, 0x00, 0x00, 0x00 +};
+#define TPM2_CMD_BUF_SIZE 64 +/* TPM command is big endian */ +#define __MSB(x) ((x) >> 8) +#define __LSB(x) ((x) & 0xFF) +#define tpm_u16(x) __MSB(x), __LSB(x) +#define tpm_u32(x) tpm_u16((x) >> 16), tpm_u16((x) & 0xFFFF) +#define TPM2_PCR_READ_HEADER_SIZE 30
+static u8 *pcrs; +static u8 expected_pcrs[EFI_TCG2_MAX_PCR_INDEX + 1][TPM2_SHA256_DIGEST_SIZE] = {
{0x91, 0x21, 0x37, 0xc7, 0x1a, 0x49, 0x19, 0xc8,
0xf1, 0xfb, 0xa9, 0x84, 0x5c, 0x65, 0xa9, 0xdd,
0x7b, 0xb9, 0xfe, 0xa1, 0xcd, 0x64, 0x49, 0xdd,
0xed, 0xe2, 0x65, 0x82, 0xc5, 0x3e, 0xf4, 0xc4},
{0xf5, 0x79, 0xf3, 0x20, 0x62, 0x6e, 0x8b, 0x58,
0x62, 0xa3, 0x4e, 0x2f, 0xb7, 0x10, 0xac, 0x34,
0x4e, 0x68, 0x94, 0x37, 0x87, 0x29, 0xc4, 0xbe,
0xa3, 0xc4, 0xd9, 0x14, 0x2b, 0x66, 0x79, 0x9b},
{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea,
0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d,
0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a,
0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69},
{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea,
0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d,
0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a,
0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69},
{0xbe, 0xea, 0xdc, 0xe0, 0x44, 0x5b, 0x5f, 0x14,
0xef, 0x24, 0x5d, 0x13, 0x15, 0xfe, 0x41, 0x86,
0xc2, 0xd5, 0xdc, 0x0d, 0x04, 0x2f, 0xd4, 0x04,
0x0d, 0x02, 0x62, 0xc0, 0x34, 0x80, 0xee, 0xd5},
{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea,
0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d,
0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a,
0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69},
{0x8d, 0x28, 0xde, 0x72, 0x22, 0x3e, 0x88, 0x1a,
0x37, 0xfa, 0x47, 0x12, 0x68, 0x45, 0xdf, 0x71,
0x50, 0x8f, 0xab, 0x59, 0x50, 0x7b, 0x52, 0x32,
0xa6, 0xaa, 0x03, 0x3d, 0x4e, 0x22, 0x89, 0xd7},
{0x96, 0x74, 0xae, 0xcd, 0x3f, 0x40, 0xb4, 0xa9,
0x36, 0xae, 0x19, 0xc8, 0x84, 0x8a, 0xb9, 0x5a,
0x87, 0x99, 0xd8, 0x89, 0x7f, 0xfc, 0x40, 0x48,
0x05, 0x99, 0x65, 0x2e, 0x55, 0xd4, 0x93, 0x32},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+};
+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)},
+};
+/*
- 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;
+}
+/*
- Configure dummy boot variables.
/**
- 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;
u8 dummy;
This variable is superfluous.
for (i = 0; i < ARRAY_SIZE(boot_variable_test); i++) {
size = 1;
Please, set size to 0.
ret = runtime->get_variable(boot_variable_test[i].name,
&efi_global_variable_guid,
&boot_variable_test[i].attr,
&size,
&dummy);
Instead of dummy you can use NULL if size = 0.
if (ret == EFI_BUFFER_TOO_SMALL) {
/* Variable exists, save the current vaiable */
%s/vaiable/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("fail to allocate buffer for boot variable\n");
In all other tests we use 'Failed to'
%s/fail/Failed/
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("fail to get current boot variable\n");
%s/fail/Failed/
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("### fail to set test boot variable(%d)n", i);
%s/### fail/Failed/
return ret;
}
}
return 0;
+}
+/*
/**
- efi_status_t restore_boot_variable() - restore original values
- Restore the variable values saved in setup_boot_variable().
- Restore original boot variables.
- @return status code
- */
+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("### fail 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("### fail to delete boot variable\n");
%s/### fail/Failed/
return ret;
}
}
}
return EFI_SUCCESS;
+}
+/**
- 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;
+}
+/**
- Prepare the dummy SMBIOS table
- @systable system table
- @return status code
- */
+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 +508,171 @@ 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);
return EFI_ST_SUCCESS;
+}
+/**
- 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;
+}
+/**
- 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;
u8 idx_array_sz = 3; /* support 24 PCRs */
This is a constant.
#define IDX_ARRAY_SZ 3
You can move it close to the TPM2_CMD_BUF_SIZE definition.
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);
u8 *dst;
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;
}
dst = pcrs + (idx * TPM2_SHA256_DIGEST_SIZE);
boottime->copy_mem(dst, &resp[TPM2_PCR_READ_HEADER_SIZE],
TPM2_SHA256_DIGEST_SIZE);
return ret;
+}
+/**
- Compare the expected and actual pcrs
- @return status code
- */
+static int validate_pcrs(void) +{
u32 i;
u8 *expected = (u8 *)expected_pcrs;
u8 *result = pcrs;
Making expected_pcrs and pcrs arrays with elements of size TPM2_SHA256_DIGEST_SIZE can replace these pointers.
/*
* - 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
* it varies depending on the platform.
%s/it varies/vary/
*/
for (i = 0; i < (EFI_TCG2_MAX_PCR_INDEX + 1); i++) {
for (i = 1; i < (EFI_TCG2_MAX_PCR_INDEX + 1); ++i) { if (i != 7) continue; if (memcmp(pcr[i], expected_pcr[i], PM2_SHA256_DIGEST_SIZE)) { if (memcmp(expected, result, TPM2_SHA256_DIGEST_SIZE)) { efi_st_printf("PCR[%d] is not the expected value\n", i); return EFI_ST_FAILURE; } } }
result = pcrs + (TPM2_SHA256_DIGEST_SIZE * i);
if (i == 0 || i == 7) {
expected += TPM2_SHA256_DIGEST_SIZE;
result += TPM2_SHA256_DIGEST_SIZE;
continue; /* skip validation */
}
if (memcmp(expected, result, TPM2_SHA256_DIGEST_SIZE)) {
efi_st_printf("PCR[%d] is not the expected value\n", i);
return EFI_ST_FAILURE;
}
expected += TPM2_SHA256_DIGEST_SIZE;
result += TPM2_SHA256_DIGEST_SIZE;
} return EFI_ST_SUCCESS;
}
@@ -31,7 +680,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 +690,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; }
/* 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 +724,154 @@ 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(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 */
lib/efi_selftest/efi_selftest_block_device.c shows how to setup a memory based block device.
Thank you for the information. I tried to copy efi_selftest_block_device but I encountered error.
To test GPT measurement, I need to add the device path node having following type. dp->type == DEVICE_PATH_TYPE_MEDIA_DEVICE dp->sub_type == DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH If I added this node in the device path, boottime->connect_controller() returns EFI_NOT_FOUND and I'm investigating how to use connect_controller.
For other comments, I will include fixes in the next version.
Thanks, Masahisa Kojima
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;
+/*
- Tear down unit test.
/**
- efi_st_tcg2_teardown() - tear down unit test
Overall the design looks good to me.
Best regards
Heinrich
- @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,

Hi Heinrich
[...]
+$(obj)/efi_selftest_tcg2.o: $(obj)/efi_miniapp_file_image_measuredboot.h diff --git a/lib/efi_selftest/efi_selftest_miniapp_measuredboot.c b/lib/efi_selftest/efi_selftest_miniapp_measuredboot.c
Thank you for going the extra mile and adding the test.
Which image is actually loaded seems to be irrelevant for the test. Can we reuse an existing one, e.g. efi_miniapp_file_image_return.h?
I guess the PCR related to the loaded image is not checked as it will depend on the build tools and date.
Sorry, I'm doing wrong. Actually this selftest verifies the PE/COFF image measurement, so measuremt will be different depending on the build tools and date. # In my build environment, timestamp is set to all zero.
To test the PE/COFF image measurement, I must prepare the static PE/COFF image. I plan to add efi_miniapp_file_image_measuredboot.h as a pre-compiled small static PE/COFF image for the measurement test, instead of adding efi_selftest_miniapp_measuredboot.c or reusing existing one.
You will need one image per UEFI architecture (ia32, x64, arm, aa64, riscv32, riscv64). You could present the image via the EFI_LOAD_FILE2_PROTOCOL, see lib/efi_selftest/efi_selftest_load_file.c.
The EFI TCG2 is governed by a spec. What it basically does is extend a number of hardware PCRs with a sha1/256/384/512 for a given image. Wouldn't performing the selftest for arm/arm64 be enough? What am I missing?
[...]
Regards /Ilias

Am 30. Oktober 2021 08:02:02 MESZ schrieb Ilias Apalodimas ilias.apalodimas@linaro.org:
Hi Heinrich
[...]
+$(obj)/efi_selftest_tcg2.o: $(obj)/efi_miniapp_file_image_measuredboot.h diff --git a/lib/efi_selftest/efi_selftest_miniapp_measuredboot.c b/lib/efi_selftest/efi_selftest_miniapp_measuredboot.c
Thank you for going the extra mile and adding the test.
Which image is actually loaded seems to be irrelevant for the test. Can we reuse an existing one, e.g. efi_miniapp_file_image_return.h?
I guess the PCR related to the loaded image is not checked as it will depend on the build tools and date.
Sorry, I'm doing wrong. Actually this selftest verifies the PE/COFF image measurement, so measuremt will be different depending on the build tools and date. # In my build environment, timestamp is set to all zero.
To test the PE/COFF image measurement, I must prepare the static PE/COFF image. I plan to add efi_miniapp_file_image_measuredboot.h as a pre-compiled small static PE/COFF image for the measurement test, instead of adding efi_selftest_miniapp_measuredboot.c or reusing existing one.
You will need one image per UEFI architecture (ia32, x64, arm, aa64, riscv32, riscv64). You could present the image via the EFI_LOAD_FILE2_PROTOCOL, see lib/efi_selftest/efi_selftest_load_file.c.
The EFI TCG2 is governed by a spec. What it basically does is extend a number of hardware PCRs with a sha1/256/384/512 for a given image. Wouldn't performing the selftest for arm/arm64 be enough? What am I missing?
People on other architectures should be able to run the selftest on a real device (not QEMU). If you have trouble building for RISC-V, I can help.
Regards
Heinrich
[...]
Regards /Ilias

Hi Heinrich, Ilias,
On Sat, 30 Oct 2021 at 15:18, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
Am 30. Oktober 2021 08:02:02 MESZ schrieb Ilias Apalodimas ilias.apalodimas@linaro.org:
Hi Heinrich
[...]
+$(obj)/efi_selftest_tcg2.o: $(obj)/efi_miniapp_file_image_measuredboot.h diff --git a/lib/efi_selftest/efi_selftest_miniapp_measuredboot.c b/lib/efi_selftest/efi_selftest_miniapp_measuredboot.c
Thank you for going the extra mile and adding the test.
Which image is actually loaded seems to be irrelevant for the test. Can we reuse an existing one, e.g. efi_miniapp_file_image_return.h?
I guess the PCR related to the loaded image is not checked as it will depend on the build tools and date.
Sorry, I'm doing wrong. Actually this selftest verifies the PE/COFF image measurement, so measuremt will be different depending on the build tools and date. # In my build environment, timestamp is set to all zero.
To test the PE/COFF image measurement, I must prepare the static PE/COFF image. I plan to add efi_miniapp_file_image_measuredboot.h as a pre-compiled small static PE/COFF image for the measurement test, instead of adding efi_selftest_miniapp_measuredboot.c or reusing existing one.
You will need one image per UEFI architecture (ia32, x64, arm, aa64, riscv32, riscv64). You could present the image via the EFI_LOAD_FILE2_PROTOCOL, see lib/efi_selftest/efi_selftest_load_file.c.
The EFI TCG2 is governed by a spec. What it basically does is extend a number of hardware PCRs with a sha1/256/384/512 for a given image. Wouldn't performing the selftest for arm/arm64 be enough? What am I missing?
People on other architectures should be able to run the selftest on a real device (not QEMU). If you have trouble building for RISC-V, I can help.
I am encountering errors in x86_64, riscv32 and riscv64.
[x86_64] - swtpm does not work on x86_64 qemu, It is probably U-Boot side issue but I could not run tcg2 efi_selftest for x86_64. ===== U-Boot 2021.10-00965-g2c308dc11a (Nov 01 2021 - 14:24:18 +0900)
CPU: QEMU Virtual CPU version 2.5+ DRAM: 128 MiB Loading Environment from nowhere... OK Incorrect expansion ROM header signature 4daa Model: QEMU x86 (I440FX) Net: e1000: 52:54:00:12:34:56 eth0: e1000#0 Hit any key to stop autoboot: 0 => => tpm2 startup TPM2_SU_CLEAR Couldn't set TPM 0 (rc = 1) =====
[riscv32/riscv64] - riscv32/riscv64 QEMU seems not to support TPM device, qemu-system-riscv32 and qemu-system-riscv64 ends with the error "No TPM backend types are available". - The available backend types are "passthrough" or "emulator", "emulator" must be used for swtpm. ===== ubuntu@ubuntu-W331AU:~/src/test/u-boot$ qemu-system-riscv32 -nographic -machine virt -bios u-boot -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock -tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-tis,tpmdev=tpm0 qemu-system-riscv32: -tpmdev emulator,id=tpm0,chardev=chrtpm: Parameter 'type' expects a TPM backend type No TPM backend types are available ===== ===== ubuntu@ubuntu-W331AU:~/src/test/u-boot$ qemu-system-riscv64 -nographic -machine virt -bios u-boot -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock -tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-tis,tpmdev=tpm0 qemu-system-riscv64: -tpmdev emulator,id=tpm0,chardev=chrtpm: Parameter 'type' expects a TPM backend type No TPM backend types are available =====
Is it OK if I add the tcg2 efi_selftest for arm/arm64 for now?
Thanks, Masahisa Kojima
Regards
Heinrich
[...]
Regards /Ilias

Hi Masahisa,
On Fri, 22 Oct 2021 at 05:23, Masahisa Kojima masahisa.kojima@linaro.org wrote:
This patch series adds the selftest for the EFI_TCG2_PROTOCOL and Measured Boot flow. This selftest is verified on qemu with swtpm.
Is this in CI? Where are the instructions for doing this?
I have expressed my preference for expanding the in-tree emulator to handle this.
Regards, Simon
This covers most of the functionalities, but there are some limitations and TODO items.
[Limitation]
- tcg2 selftest must run at the beginning of the efi_selftest because some measurement occurs in efi_tcg2_register() and boottime->image_load(). Need to configure the efi_selftest with "setenv efi_selftest tcg2; bootefi selftest"
- Skip ExitBootService measurement test
- EFI application can not read PCR after calling ExitBootService
- Skip EventLog Validation
- Measured Boot measures U-Boot version, so EventLog varies every build having different commit hash.
- Skip PCR[0] validation
- PCR[0] include U-Boot version measurement, this value varies every build having different commit hash.
- Skip PCR[7] validation
- Secure Boot Variables can not be updated through efi_selftest.
- The initial PCR value of PCR[17 - 22] is all 0xff, I'm not sure it is expected or not.
[TODO]
- GPT measurement test
- Secure Boot Variable test
- Eventlog validation
Masahisa Kojima (2): efi_loader: add missing const qualifier efi_selftest: add selftest for EFI_TCG2_PROTOCOL and Measured Boot
include/efi_api.h | 2 +- lib/efi_loader/efi_boottime.c | 5 +- lib/efi_selftest/Makefile | 10 + .../efi_selftest_miniapp_measuredboot.c | 93 ++ lib/efi_selftest/efi_selftest_tcg2.c | 804 +++++++++++++++++- 5 files changed, 910 insertions(+), 4 deletions(-) create mode 100644 lib/efi_selftest/efi_selftest_miniapp_measuredboot.c
-- 2.17.1

Hi Simon,
On Mon, 25 Oct 2021 at 04:54, Simon Glass sjg@chromium.org wrote:
Hi Masahisa,
On Fri, 22 Oct 2021 at 05:23, Masahisa Kojima masahisa.kojima@linaro.org wrote:
This patch series adds the selftest for the EFI_TCG2_PROTOCOL and Measured Boot flow. This selftest is verified on qemu with swtpm.
Is this in CI? Where are the instructions for doing this?
Not yet included in CI. For the instructions, Ilias is preparing the documentation at: https://github.com/apalos/u-boot/commit/6edcf3c02996edf8c50a38632aac1091f8bc...
I have expressed my preference for expanding the in-tree emulator to handle this.
For the measured boot selftest, I need to access the efi internal data such as SMBIOS table, that is why I chose the C based efi_selftest. Tcg2 efi_selftest does not rely on the specific TPM backend.
Thanks, Masahisa Kojima
Regards, Simon
This covers most of the functionalities, but there are some limitations and TODO items.
[Limitation]
- tcg2 selftest must run at the beginning of the efi_selftest because some measurement occurs in efi_tcg2_register() and boottime->image_load(). Need to configure the efi_selftest with "setenv efi_selftest tcg2; bootefi selftest"
- Skip ExitBootService measurement test
- EFI application can not read PCR after calling ExitBootService
- Skip EventLog Validation
- Measured Boot measures U-Boot version, so EventLog varies every build having different commit hash.
- Skip PCR[0] validation
- PCR[0] include U-Boot version measurement, this value varies every build having different commit hash.
- Skip PCR[7] validation
- Secure Boot Variables can not be updated through efi_selftest.
- The initial PCR value of PCR[17 - 22] is all 0xff, I'm not sure it is expected or not.
[TODO]
- GPT measurement test
- Secure Boot Variable test
- Eventlog validation
Masahisa Kojima (2): efi_loader: add missing const qualifier efi_selftest: add selftest for EFI_TCG2_PROTOCOL and Measured Boot
include/efi_api.h | 2 +- lib/efi_loader/efi_boottime.c | 5 +- lib/efi_selftest/Makefile | 10 + .../efi_selftest_miniapp_measuredboot.c | 93 ++ lib/efi_selftest/efi_selftest_tcg2.c | 804 +++++++++++++++++- 5 files changed, 910 insertions(+), 4 deletions(-) create mode 100644 lib/efi_selftest/efi_selftest_miniapp_measuredboot.c
-- 2.17.1

Hi Masahisa,
On Tue, 2 Nov 2021 at 02:03, Masahisa Kojima masahisa.kojima@linaro.org wrote:
Hi Simon,
On Mon, 25 Oct 2021 at 04:54, Simon Glass sjg@chromium.org wrote:
Hi Masahisa,
On Fri, 22 Oct 2021 at 05:23, Masahisa Kojima masahisa.kojima@linaro.org wrote:
This patch series adds the selftest for the EFI_TCG2_PROTOCOL and Measured Boot flow. This selftest is verified on qemu with swtpm.
Is this in CI? Where are the instructions for doing this?
Not yet included in CI. For the instructions, Ilias is preparing the documentation at: https://github.com/apalos/u-boot/commit/6edcf3c02996edf8c50a38632aac1091f8bc...
OK I see.
I have expressed my preference for expanding the in-tree emulator to handle this.
For the measured boot selftest, I need to access the efi internal data such as SMBIOS table, that is why I chose the C based efi_selftest. Tcg2 efi_selftest does not rely on the specific TPM backend.
I don't understand this answer. I would still like to know how much code we would be talking about if we expand the TPM emulator in U-Boot for these extra features. From my understanding, the TPMs themselves are not that complicated and don't have a lot of code in them, particularly for the features we use. I am willing to believe that this might not be feasible, or be too much effort, but I have not seen anyone attempt it, or part of it, so I don't know. With a TPM emulator we can encode any sort of test behaviour we want. It is much harder with QEMU. But I have not seen an answer for what is actually involved in doing this.
I know Ilias talked about bringing in swtpm to U-Boot. It seems like a lot of code so I am not sure if it is worth it. Perhaps it could be built against U-Boot sandbox as an option...I'm not sure. But the goal here is not to emulate a TPM, but to provide test coverage in an easily maintainable way.
So to put my mind at ease, what would be involved in running this on sandbox? Are we talking hundreds of lines of code (which I think is worth it) or thousands (which is not)?
Regards, Simon
Thanks, Masahisa Kojima
Regards, Simon
This covers most of the functionalities, but there are some limitations and TODO items.
[Limitation]
- tcg2 selftest must run at the beginning of the efi_selftest because some measurement occurs in efi_tcg2_register() and boottime->image_load(). Need to configure the efi_selftest with "setenv efi_selftest tcg2; bootefi selftest"
- Skip ExitBootService measurement test
- EFI application can not read PCR after calling ExitBootService
- Skip EventLog Validation
- Measured Boot measures U-Boot version, so EventLog varies every build having different commit hash.
- Skip PCR[0] validation
- PCR[0] include U-Boot version measurement, this value varies every build having different commit hash.
- Skip PCR[7] validation
- Secure Boot Variables can not be updated through efi_selftest.
- The initial PCR value of PCR[17 - 22] is all 0xff, I'm not sure it is expected or not.
[TODO]
- GPT measurement test
- Secure Boot Variable test
- Eventlog validation
Masahisa Kojima (2): efi_loader: add missing const qualifier efi_selftest: add selftest for EFI_TCG2_PROTOCOL and Measured Boot
include/efi_api.h | 2 +- lib/efi_loader/efi_boottime.c | 5 +- lib/efi_selftest/Makefile | 10 + .../efi_selftest_miniapp_measuredboot.c | 93 ++ lib/efi_selftest/efi_selftest_tcg2.c | 804 +++++++++++++++++- 5 files changed, 910 insertions(+), 4 deletions(-) create mode 100644 lib/efi_selftest/efi_selftest_miniapp_measuredboot.c
-- 2.17.1

Hi Simon.
On Tue, 2 Nov 2021 at 16:55, Simon Glass sjg@chromium.org wrote:
Hi Masahisa,
On Tue, 2 Nov 2021 at 02:03, Masahisa Kojima masahisa.kojima@linaro.org wrote:
Hi Simon,
On Mon, 25 Oct 2021 at 04:54, Simon Glass sjg@chromium.org wrote:
Hi Masahisa,
On Fri, 22 Oct 2021 at 05:23, Masahisa Kojima masahisa.kojima@linaro.org wrote:
This patch series adds the selftest for the EFI_TCG2_PROTOCOL and Measured Boot flow. This selftest is verified on qemu with swtpm.
Is this in CI? Where are the instructions for doing this?
Not yet included in CI. For the instructions, Ilias is preparing the documentation at: https://github.com/apalos/u-boot/commit/6edcf3c02996edf8c50a38632aac1091f8bc...
OK I see.
I have expressed my preference for expanding the in-tree emulator to handle this.
For the measured boot selftest, I need to access the efi internal data such as SMBIOS table, that is why I chose the C based efi_selftest. Tcg2 efi_selftest does not rely on the specific TPM backend.
I don't understand this answer. I would still like to know how much code we would be talking about if we expand the TPM emulator in U-Boot for these extra features. From my understanding, the TPMs themselves are not that complicated and don't have a lot of code in them, particularly for the features we use. I am willing to believe that this might not be feasible, or be too much effort, but I have not seen anyone attempt it, or part of it, so I don't know.
I don't have an exact answer for that either. It's definitely more than the effort we need for the QEMU though.
With a TPM emulator we can encode any sort of test behaviour we want. It is much harder with QEMU. But I have not seen an answer for what is actually involved in doing this.
QEMU just provides access to a standard (TIS compliant) TPM. So I can't think of any tests that aren't already covered.
I know Ilias talked about bringing in swtpm to U-Boot. It seems like a lot of code so I am not sure if it is worth it.
Just for clarification U-Boot is will get *zero* code for this wrt to the TPM interface it self. The only thing you need is an MMIO TPM driver for U-Boot, but that's not only usable in QEMU. There are devices supported by U-Boot which have an MMIO based TPM (e.g the synquacer box), so we need that driver regardless. Apart from that patchset (which I'll resend within the week) you need a QEMU instance with swtpm support described here [1]
Perhaps it could be built against U-Boot sandbox as an option...I'm not sure. But the goal here is not to emulate a TPM, but to provide test coverage in an easily maintainable way.
So to put my mind at ease, what would be involved in running this on sandbox? Are we talking hundreds of lines of code (which I think is worth it) or thousands (which is not)?
Probably hundreds. I've responded here [2] with the basic functionality that's missing.
[1] https://github.com/apalos/u-boot/commit/6edcf3c02996edf8c50a38632aac1091f8bc... [2] https://lore.kernel.org/u-boot/CAC_iWjLY-qH0ckQHh=WhvbVc2pa_a2COjr=g3cp8ZEdV...
Regards /Ilias
Regards, Simon
Thanks, Masahisa Kojima
Regards, Simon
This covers most of the functionalities, but there are some limitations and TODO items.
[Limitation]
- tcg2 selftest must run at the beginning of the efi_selftest because some measurement occurs in efi_tcg2_register() and boottime->image_load(). Need to configure the efi_selftest with "setenv efi_selftest tcg2; bootefi selftest"
- Skip ExitBootService measurement test
- EFI application can not read PCR after calling ExitBootService
- Skip EventLog Validation
- Measured Boot measures U-Boot version, so EventLog varies every build having different commit hash.
- Skip PCR[0] validation
- PCR[0] include U-Boot version measurement, this value varies every build having different commit hash.
- Skip PCR[7] validation
- Secure Boot Variables can not be updated through efi_selftest.
- The initial PCR value of PCR[17 - 22] is all 0xff, I'm not sure it is expected or not.
[TODO]
- GPT measurement test
- Secure Boot Variable test
- Eventlog validation
Masahisa Kojima (2): efi_loader: add missing const qualifier efi_selftest: add selftest for EFI_TCG2_PROTOCOL and Measured Boot
include/efi_api.h | 2 +- lib/efi_loader/efi_boottime.c | 5 +- lib/efi_selftest/Makefile | 10 + .../efi_selftest_miniapp_measuredboot.c | 93 ++ lib/efi_selftest/efi_selftest_tcg2.c | 804 +++++++++++++++++- 5 files changed, 910 insertions(+), 4 deletions(-) create mode 100644 lib/efi_selftest/efi_selftest_miniapp_measuredboot.c
-- 2.17.1

Hi Ilias,
On Tue, 2 Nov 2021 at 10:28, Ilias Apalodimas ilias.apalodimas@linaro.org wrote:
Hi Simon.
On Tue, 2 Nov 2021 at 16:55, Simon Glass sjg@chromium.org wrote:
Hi Masahisa,
On Tue, 2 Nov 2021 at 02:03, Masahisa Kojima masahisa.kojima@linaro.org wrote:
Hi Simon,
On Mon, 25 Oct 2021 at 04:54, Simon Glass sjg@chromium.org wrote:
Hi Masahisa,
On Fri, 22 Oct 2021 at 05:23, Masahisa Kojima masahisa.kojima@linaro.org wrote:
This patch series adds the selftest for the EFI_TCG2_PROTOCOL and Measured Boot flow. This selftest is verified on qemu with swtpm.
Is this in CI? Where are the instructions for doing this?
Not yet included in CI. For the instructions, Ilias is preparing the documentation at: https://github.com/apalos/u-boot/commit/6edcf3c02996edf8c50a38632aac1091f8bc...
OK I see.
I have expressed my preference for expanding the in-tree emulator to handle this.
For the measured boot selftest, I need to access the efi internal data such as SMBIOS table, that is why I chose the C based efi_selftest. Tcg2 efi_selftest does not rely on the specific TPM backend.
I don't understand this answer. I would still like to know how much code we would be talking about if we expand the TPM emulator in U-Boot for these extra features. From my understanding, the TPMs themselves are not that complicated and don't have a lot of code in them, particularly for the features we use. I am willing to believe that this might not be feasible, or be too much effort, but I have not seen anyone attempt it, or part of it, so I don't know.
I don't have an exact answer for that either. It's definitely more than the effort we need for the QEMU though.
OK. How about implementing one thing so the test gets a little way along, to understand the effort? Or I could try it if you give instructions on how to run it. Because there is a benefit, it is not just all a cost.
With a TPM emulator we can encode any sort of test behaviour we want. It is much harder with QEMU. But I have not seen an answer for what is actually involved in doing this.
QEMU just provides access to a standard (TIS compliant) TPM. So I can't think of any tests that aren't already covered.
Failures?
I know Ilias talked about bringing in swtpm to U-Boot. It seems like a lot of code so I am not sure if it is worth it.
Just for clarification U-Boot is will get *zero* code for this wrt to the TPM interface it self. The only thing you need is an MMIO TPM driver for U-Boot, but that's not only usable in QEMU. There are devices supported by U-Boot which have an MMIO based TPM (e.g the synquacer box), so we need that driver regardless. Apart from that patchset (which I'll resend within the week) you need a QEMU instance with swtpm support described here [1]
Yes I understand.
Perhaps it could be built against U-Boot sandbox as an option...I'm not sure. But the goal here is not to emulate a TPM, but to provide test coverage in an easily maintainable way.
So to put my mind at ease, what would be involved in running this on sandbox? Are we talking hundreds of lines of code (which I think is worth it) or thousands (which is not)?
Probably hundreds. I've responded here [2] with the basic functionality that's missing.
OK I can use that. So how do I to run this test on sandbox?
- Simon
[1] https://github.com/apalos/u-boot/commit/6edcf3c02996edf8c50a38632aac1091f8bc... [2] https://lore.kernel.org/u-boot/CAC_iWjLY-qH0ckQHh=WhvbVc2pa_a2COjr=g3cp8ZEdV...
Regards /Ilias
Regards, Simon
Thanks, Masahisa Kojima
Regards, Simon
This covers most of the functionalities, but there are some limitations and TODO items.
[Limitation]
- tcg2 selftest must run at the beginning of the efi_selftest because some measurement occurs in efi_tcg2_register() and boottime->image_load(). Need to configure the efi_selftest with "setenv efi_selftest tcg2; bootefi selftest"
- Skip ExitBootService measurement test
- EFI application can not read PCR after calling ExitBootService
- Skip EventLog Validation
- Measured Boot measures U-Boot version, so EventLog varies every build having different commit hash.
- Skip PCR[0] validation
- PCR[0] include U-Boot version measurement, this value varies every build having different commit hash.
- Skip PCR[7] validation
- Secure Boot Variables can not be updated through efi_selftest.
- The initial PCR value of PCR[17 - 22] is all 0xff, I'm not sure it is expected or not.
[TODO]
- GPT measurement test
- Secure Boot Variable test
- Eventlog validation
Masahisa Kojima (2): efi_loader: add missing const qualifier efi_selftest: add selftest for EFI_TCG2_PROTOCOL and Measured Boot
include/efi_api.h | 2 +- lib/efi_loader/efi_boottime.c | 5 +- lib/efi_selftest/Makefile | 10 + .../efi_selftest_miniapp_measuredboot.c | 93 ++ lib/efi_selftest/efi_selftest_tcg2.c | 804 +++++++++++++++++- 5 files changed, 910 insertions(+), 4 deletions(-) create mode 100644 lib/efi_selftest/efi_selftest_miniapp_measuredboot.c
-- 2.17.1
participants (4)
-
Heinrich Schuchardt
-
Ilias Apalodimas
-
Masahisa Kojima
-
Simon Glass