]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
bootm: Support boot measurement
authorEddie James <eajames@linux.ibm.com>
Tue, 24 Oct 2023 15:43:50 +0000 (10:43 -0500)
committerIlias Apalodimas <ilias.apalodimas@linaro.org>
Fri, 27 Oct 2023 10:15:57 +0000 (13:15 +0300)
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>
boot/Kconfig
boot/bootm.c
cmd/booti.c
cmd/bootm.c
cmd/bootz.c
include/bootm.h
include/image.h

index a01e6cb8aafe934f7c85816f0434db61207bd52c..fbc49c5bca47b84ad0c3aaf62d9ca3c0be2ef5b7 100644 (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
index b1c3afe0a3adafbce9ec99b734befa464633c5f2..11b6b3c2921390730a7e37a147051d8038b518b5 100644 (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();
index 6ac39193db80bf0b0f46bdce44ff9e0ac69313cb..659bb10549881496a10995f4088a71b05a02da73 100644 (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);
index 7968415b6d1e7c58560c586aa0b4933c6e4d0a4e..2bf2e9f6763430f9998e68ebd3d86402caa16f76 100644 (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);
index f1423573d23dcf2d7f2ed80e9d9e4ee2aab6690d..87922bfc3c6f5efac98a4470a66542d84a0cf55a 100644 (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);
index c3c7336207b166a8fea6ea477a707ba3b282d647..10a1bd65a754bd9fbc8e445450a8fc9bb82149b1 100644 (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);
index 5f85bf84a2dc52a803400dd9cb91c38ecc563b9b..2e3cf839ee36051af25d7aabec993fca2cdc31ba 100644 (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)