[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