Re: [PATCH v7 4/6] bootm: Support boot measurement
Hi Eddie, [...] > > +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; This is nice. Basically measuring becomes the boot command responsibility. > + > + 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; > + > + elog.log_size = 0; > + ret = tcg2_measurement_init(&dev, &elog); > + 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 +778,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/boo
[PATCH v7 4/6] bootm: Support boot measurement
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 Reviewed-by: Simon Glass --- Changes since v6: - Added comment for bootm_measure - Fixed line length in bootm_measure boot/Kconfig| 23 boot/bootm.c| 72 + cmd/booti.c | 1 + cmd/bootm.c | 2 ++ cmd/bootz.c | 1 + include/bootm.h | 11 include/image.h | 1 + 7 files changed, 111 insertions(+) diff --git a/boot/Kconfig b/boot/Kconfig index 5f491625c8..d0d5e5794c 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -629,6 +629,29 @@ 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. +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..e3ef18166d 100644 --- a/boot/bootm.c +++ b/boot/bootm.c @@ -22,6 +22,7 @@ #include #include #include +#include #if defined(CONFIG_CMD_USB) #include #endif @@ -659,6 +660,73 @@ 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; + + 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; + + elog.log_size = 0; + ret = tcg2_measurement_init(&dev, &elog); + 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 +778,10 @@ int do_bootm_states(struct cmd_tbl *cmdtp, int flag, int