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 <eajames@linux.ibm.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Ilias: Added some info on Kconfig explaining this is when booting !EFI
Signed-off-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
This commit is contained in:
Eddie James 2023-10-24 10:43:50 -05:00 committed by Ilias Apalodimas
parent 97707f12fd
commit dec166d6b2
7 changed files with 122 additions and 0 deletions

View file

@ -685,6 +685,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 when booting without EFI"
depends on HASH && TPM_V2
help
This option enables measurement of the boot process when booting
without UEFI . 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

View file

@ -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
@ -673,6 +674,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;
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.
*
@ -724,6 +794,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();

View file

@ -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);

View file

@ -147,6 +147,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);

View file

@ -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);

View file

@ -56,6 +56,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);

View file

@ -409,6 +409,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)