[PATCH v8 4/6] bootm: Support boot measurement

Heinrich Schuchardt xypron.glpk at gmx.de
Fri Mar 3 20:51:00 CET 2023


On 3/3/23 20:25, 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 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

It cannot be the OS that configures the memory area for the measurement
as we don't even know which OSes will be booted at configuration time.
It must be the device-tree that defines if such a memory area exists and
where it is located.

Some of the OSes booted by U-Boot may have a driver to read such a
memory area. OSes lacking such a driver will ignore that memory area
which does not stop them from booting.

> +	  attestation tools on your system.

@Ilias:

This description does not make it clear that this setting does not
enable measured boot for the EFI sub-system. We will need some follow up
patch to point to the EFI relevant setting.

Best regards

Heinrich

> +
> +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 <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,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 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