[PATCH v9 4/6] bootm: Support boot measurement
Eddie James
eajames at linux.ibm.com
Mon Aug 7 16:43:11 CEST 2023
On 8/4/23 13:10, Sean Edmond wrote:
> On 2023-03-08 1:25 p.m., Eddie James wrote:
>> Add a configuration option to measure the boot through the bootm
>> function. Add the measurement state to the booti and bootz paths
>> as well.
>>
>> Signed-off-by: Eddie James <eajames at linux.ibm.com>
>> Reviewed-by: Simon Glass <sjg at chromium.org>
>> ---
>> Changes since v8:
>> - Added a configuration option to select to ignore any existing
>> event log. This would only be selected for systems that know
>> that U-Boot is the first stage bootloader. This is necessary
>> because the reserved memory region may persist through resets
>> and so U-Boot attempts to append to the previous boot's log.
>>
>> Changes since v6:
>> - Added comment for bootm_measure
>> - Fixed line length in bootm_measure
>>
>> boot/Kconfig | 32 +++++++++++++++++++++
>> boot/bootm.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++
>> cmd/booti.c | 1 +
>> cmd/bootm.c | 2 ++
>> cmd/bootz.c | 1 +
>> include/bootm.h | 11 ++++++++
>> include/image.h | 1 +
>> 7 files changed, 122 insertions(+)
>>
>> diff --git a/boot/Kconfig b/boot/Kconfig
>> index 5f491625c8..8119519c9f 100644
>> --- a/boot/Kconfig
>> +++ b/boot/Kconfig
>> @@ -629,6 +629,38 @@ config LEGACY_IMAGE_FORMAT
>> loaded. If a board needs the legacy image format support in this
>> case, enable it here.
>> +config MEASURED_BOOT
>> + bool "Measure boot images and configuration to TPM and event log"
>> + depends on HASH && TPM_V2
>> + help
>> + This option enables measurement of the boot process. Measurement
>> + involves creating cryptographic hashes of the binary images that
>> + are booting and storing them in the TPM. In addition, a log of
>> + these hashes is stored in memory for the OS to verify the booted
>> + images and configuration. Enable this if the OS has configured
>> + some memory area for the event log and you intend to use some
>> + attestation tools on your system.
>> +
>> +if MEASURED_BOOT
>> + config MEASURE_DEVICETREE
>> + bool "Measure the devicetree image"
>> + default y if MEASURED_BOOT
>> + help
>> + On some platforms, the devicetree is not static as it may contain
>> + random MAC addresses or other such data that changes each boot.
>> + Therefore, it should not be measured into the TPM. In that case,
>> + disable the measurement here.
>> +
>> + config MEASURE_IGNORE_LOG
>> + bool "Ignore the existing event log"
>> + default n
>> + help
>> + On platforms that use an event log memory region that persists
>> + through system resets and are the first stage bootloader, then
>> + this option should be enabled to ignore any existing data in the
>> + event log memory region.
>> +endif # MEASURED_BOOT
>> +
>> config SUPPORT_RAW_INITRD
>> bool "Enable raw initrd images"
>> help
>> diff --git a/boot/bootm.c b/boot/bootm.c
>> index 2eec60ec7b..2685bdbd74 100644
>> --- a/boot/bootm.c
>> +++ b/boot/bootm.c
>> @@ -22,6 +22,7 @@
>> #include <asm/global_data.h>
>> #include <asm/io.h>
>> #include <linux/sizes.h>
>> +#include <tpm-v2.h>
>> #if defined(CONFIG_CMD_USB)
>> #include <usb.h>
>> #endif
>> @@ -659,6 +660,75 @@ int bootm_process_cmdline_env(int flags)
>> return 0;
>> }
>> +int bootm_measure(struct bootm_headers *images)
>> +{
>> + int ret = 0;
>> +
>> + /* Skip measurement if EFI is going to do it */
>> + if (images->os.os == IH_OS_EFI &&
>> + IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL) &&
>> + IS_ENABLED(CONFIG_BOOTM_EFI))
>> + return ret;
>> +
>
> it looks like your measured boot implementation is hardcoding the
> following PCR indexes:
>
> PCR #8 - kernel image measurement
> PCR #9 - initrd measurement
> PCR #0 - kernel DTB measurement
> PCR #1 - bootargs measurement
Hi,
Yes, I followed this document as closely as I could:
https://trustedcomputinggroup.org/wp-content/uploads/TCG_ServerManagementDomainFirmwareProfile_v1p00_11aug2020.pdf
Which provides what should go in what PCR. I can understand users
wanting a different setup, but as you say, that's probably out of the
scope of this series.
Thanks,
Eddie
>
> I wasn't able to find any specificaton on this measured boot
> "profile". Are you able to provide a reference?
>
> We've implemented our own version of measured boot, which maps
> measurements to different PCR indexes. In many cases, the data we're
> measuring is also different.
>
> To make this feature more usable by others it would be nice to see a
> more generic interface that would allow the user to specify the PCR
> indexes, and the data to hash into these indexes. This would allow
> everyone to create their own custom measured boot "profile". This
> request is probably beyond the scope of your current efforts, but I
> except this implementation to evolve significantly if/when it's accepted.
>
>> + if (IS_ENABLED(CONFIG_MEASURED_BOOT)) {
>> + struct tcg2_event_log elog;
>> + struct udevice *dev;
>> + void *initrd_buf;
>> + void *image_buf;
>> + const char *s;
>> + u32 rd_len;
>> + bool ign;
>> +
>> + elog.log_size = 0;
>> + ign = IS_ENABLED(CONFIG_MEASURE_IGNORE_LOG);
>> + ret = tcg2_measurement_init(&dev, &elog, ign);
>> + if (ret)
>> + return ret;
>> +
>> + image_buf = map_sysmem(images->os.image_start,
>> + images->os.image_len);
>> + ret = tcg2_measure_data(dev, &elog, 8, images->os.image_len,
>> + image_buf, EV_COMPACT_HASH,
>> + strlen("linux") + 1, (u8 *)"linux");
>> + if (ret)
>> + goto unmap_image;
>> +
>> + rd_len = images->rd_end - images->rd_start;
>> + initrd_buf = map_sysmem(images->rd_start, rd_len);
>> + ret = tcg2_measure_data(dev, &elog, 9, rd_len, initrd_buf,
>> + EV_COMPACT_HASH, strlen("initrd") + 1,
>> + (u8 *)"initrd");
>> + if (ret)
>> + goto unmap_initrd;
>> +
>> + if (IS_ENABLED(CONFIG_MEASURE_DEVICETREE)) {
>> + ret = tcg2_measure_data(dev, &elog, 0, images->ft_len,
>> + (u8 *)images->ft_addr,
>> + EV_TABLE_OF_DEVICES,
>> + strlen("dts") + 1,
>> + (u8 *)"dts");
>> + if (ret)
>> + goto unmap_initrd;
>> + }
>> +
>> + s = env_get("bootargs");
>> + if (!s)
>> + s = "";
>> + ret = tcg2_measure_data(dev, &elog, 1, strlen(s) + 1, (u8 *)s,
>> + EV_PLATFORM_CONFIG_FLAGS,
>> + strlen(s) + 1, (u8 *)s);
>> +
>> +unmap_initrd:
>> + unmap_sysmem(initrd_buf);
>> +
>> +unmap_image:
>> + unmap_sysmem(image_buf);
>> + tcg2_measurement_term(dev, &elog, ret != 0);
>> + }
>> +
>> + return ret;
>> +}
>> +
>> /**
>> * Execute selected states of the bootm command.
>> *
>> @@ -710,6 +780,10 @@ int do_bootm_states(struct cmd_tbl *cmdtp, int
>> flag, int argc,
>> if (!ret && (states & BOOTM_STATE_FINDOTHER))
>> ret = bootm_find_other(cmdtp, flag, argc, argv);
>> + if (IS_ENABLED(CONFIG_MEASURED_BOOT) && !ret &&
>> + (states & BOOTM_STATE_MEASURE))
>> + bootm_measure(images);
>> +
>> /* Load the OS */
>> if (!ret && (states & BOOTM_STATE_LOADOS)) {
>> iflag = bootm_disable_interrupts();
>> diff --git a/cmd/booti.c b/cmd/booti.c
>> index 6ac39193db..659bb10549 100644
>> --- a/cmd/booti.c
>> +++ b/cmd/booti.c
>> @@ -127,6 +127,7 @@ int do_booti(struct cmd_tbl *cmdtp, int flag, int
>> argc, char *const argv[])
>> #ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
>> BOOTM_STATE_RAMDISK |
>> #endif
>> + BOOTM_STATE_MEASURE |
>> BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |
>> BOOTM_STATE_OS_GO,
>> &images, 1);
>> diff --git a/cmd/bootm.c b/cmd/bootm.c
>> index 37c2af96e0..0c4a713e02 100644
>> --- a/cmd/bootm.c
>> +++ b/cmd/bootm.c
>> @@ -161,6 +161,8 @@ int do_bootm(struct cmd_tbl *cmdtp, int flag, int
>> argc, char *const argv[])
>> BOOTM_STATE_OS_GO;
>> if (IS_ENABLED(CONFIG_SYS_BOOT_RAMDISK_HIGH))
>> states |= BOOTM_STATE_RAMDISK;
>> + if (IS_ENABLED(CONFIG_MEASURED_BOOT))
>> + states |= BOOTM_STATE_MEASURE;
>> if (IS_ENABLED(CONFIG_PPC) || IS_ENABLED(CONFIG_MIPS))
>> states |= BOOTM_STATE_OS_CMDLINE;
>> ret = do_bootm_states(cmdtp, flag, argc, argv, states, &images,
>> 1);
>> diff --git a/cmd/bootz.c b/cmd/bootz.c
>> index f1423573d2..87922bfc3c 100644
>> --- a/cmd/bootz.c
>> +++ b/cmd/bootz.c
>> @@ -81,6 +81,7 @@ int do_bootz(struct cmd_tbl *cmdtp, int flag, int
>> argc, char *const argv[])
>> #ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
>> BOOTM_STATE_RAMDISK |
>> #endif
>> + BOOTM_STATE_MEASURE |
>> BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |
>> BOOTM_STATE_OS_GO,
>> &images, 1);
>> diff --git a/include/bootm.h b/include/bootm.h
>> index 044a4797ed..76e8e38c82 100644
>> --- a/include/bootm.h
>> +++ b/include/bootm.h
>> @@ -55,6 +55,17 @@ ulong bootm_disable_interrupts(void);
>> int bootm_find_images(int flag, int argc, char *const argv[], ulong
>> start,
>> ulong size);
>> +/*
>> + * Measure the boot images. Measurement is the process of hashing
>> some binary
>> + * data and storing it into secure memory, i.e. TPM PCRs. In
>> addition, each
>> + * measurement is logged into the platform event log such that the
>> operating
>> + * system can access it and perform attestation of the boot.
>> + *
>> + * @images: The structure containing the various images to boot
>> (linux,
>> + * initrd, dts, etc.)
>> + */
>> +int bootm_measure(struct bootm_headers *images);
>> +
>> int do_bootm_states(struct cmd_tbl *cmdtp, int flag, int argc,
>> char *const argv[], int states, struct bootm_headers
>> *images,
>> int boot_progress);
>> diff --git a/include/image.h b/include/image.h
>> index 7717a4c13d..f7414b5338 100644
>> --- a/include/image.h
>> +++ b/include/image.h
>> @@ -407,6 +407,7 @@ struct bootm_headers {
>> #define BOOTM_STATE_OS_FAKE_GO 0x00000200 /* 'Almost' run the
>> OS */
>> #define BOOTM_STATE_OS_GO 0x00000400
>> #define BOOTM_STATE_PRE_LOAD 0x00000800
>> +#define BOOTM_STATE_MEASURE 0x00001000
>> int state;
>> #if defined(CONFIG_LMB) && !defined(USE_HOSTCC)
>
>
More information about the U-Boot
mailing list