summaryrefslogtreecommitdiff
path: root/boot
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2023-10-27 19:27:29 -0400
committerTom Rini <[email protected]>2023-10-27 19:27:29 -0400
commitd5d9770f58ce0ba620e4d311bbd756b97839480a (patch)
tree3d7eae28e5a8eb2846c90eb58714bb2ef3c8f5f1 /boot
parent913d830cf093c10ca3233038e81c11beb63ec802 (diff)
parent4fd7d27ccb763ce8b836a0e4c5dd005392d38e18 (diff)
Merge tag 'tpm-next-27102023' of https://source.denx.de/u-boot/custodians/u-boot-tpm
bootX measurements and measurement API moved to u-boot core: Up to now, U-Boot could perform measurements and EventLog creation as described by the TCG spec when booting via EFI. The EFI code was residing in lib/efi_loader/efi_tcg2.c and contained both EFI specific code + the API needed to access the TPM, extend PCRs and create an EventLog. The non-EFI part proved modular enough and moving it around to the TPM subsystem was straightforward. With that in place we can have a common API for measuring binaries regardless of the boot command, EFI or boot(m|i|z), and contructing an EventLog. I've tested all of the EFI cases -- booting with an empty EventLog and booting with a previous stage loader providing one and found no regressions. Eddie tested the bootX part. Eddie also fixed the sandbox TPM which couldn't be used for the EFI code and it now supports all the required capabilities. This had a slight sideeffect in our testing since the EFI subsystem initializes the TPM early and 'tpm2 init' failed during some python tests. That code only opens the device though, so we can replace it with 'tpm2 autostart' which doesn't error out and still allows you to perfom the rest of the tests but doesn't report an error if the device is already opened. There's a few minor issues with this PR as well but since testing and verifying the changes takes a considerable amount of time, I prefer merging it now. Heinrich has already sent a PR for -master containing "efi_loader: fix EFI_ENTRY point on get_active_pcr_banks" and I am not sure if that will cause any conflicts, but in any case they should be trivial to resolve. Both the EFI and non-EFI code have a Kconfig for measuring the loaded Device Tree. The reason this is optional is that we can't reason when/if devices add random info like kaslr-seed, mac addresses etc in the DT. In that case measurements are random, board specific and eventually useless. The reason it was difficult to fix it prior to this patchset is because the EFI subsystem and thus measurements was brought up late and DT fixups might have already been applied. With this patchset we can measure the DT really early in the future. Heinrich also pointed out that the two Kconfigs for the DTB measurements can be squashed in a single one and that the documentation only explains the non-EFI case. I agree on both but as I said this is a sane working version, so let's pull this first it's aleady big enough and painful to test.
Diffstat (limited to 'boot')
-rw-r--r--boot/Kconfig32
-rw-r--r--boot/bootm.c74
2 files changed, 106 insertions, 0 deletions
diff --git a/boot/Kconfig b/boot/Kconfig
index a01e6cb8aaf..fbc49c5bca4 100644
--- a/boot/Kconfig
+++ b/boot/Kconfig
@@ -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
diff --git a/boot/bootm.c b/boot/bootm.c
index 8f96a80d425..cb61485c226 100644
--- a/boot/bootm.c
+++ b/boot/bootm.c
@@ -23,6 +23,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();