Skip to content

Commit d5d9770

Browse files
committed
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.
2 parents 913d830 + 4fd7d27 commit d5d9770

24 files changed

+1490
-1062
lines changed

arch/sandbox/dts/sandbox.dtsi

+13
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,23 @@
44
* and sandbox64 builds.
55
*/
66

7+
#include <config.h>
78
#include <dt-bindings/input/input.h>
89

910
#define USB_CLASS_HUB 9
1011

1112
/ {
13+
reserved-memory {
14+
#address-cells = <1>;
15+
#size-cells = <1>;
16+
ranges;
17+
18+
event_log: tcg_event_log {
19+
no-map;
20+
reg = <(CFG_SYS_SDRAM_SIZE - 0x2000) 0x2000>;
21+
};
22+
};
23+
1224
binman {
1325
};
1426

@@ -342,6 +354,7 @@
342354

343355
tpm2 {
344356
compatible = "sandbox,tpm2";
357+
memory-region = <&event_log>;
345358
};
346359

347360
triangle {

arch/sandbox/dts/test.dts

+13
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
/dts-v1/;
1111

12+
#include <config.h>
1213
#include <dt-bindings/gpio/gpio.h>
1314
#include <dt-bindings/gpio/sandbox-gpio.h>
1415
#include <dt-bindings/input/input.h>
@@ -69,6 +70,17 @@
6970
osd0 = "/osd";
7071
};
7172

73+
reserved-memory {
74+
#address-cells = <1>;
75+
#size-cells = <1>;
76+
ranges;
77+
78+
event_log: tcg_event_log {
79+
no-map;
80+
reg = <(CFG_SYS_SDRAM_SIZE - 0x2000) 0x2000>;
81+
};
82+
};
83+
7284
binman: binman {
7385
};
7486

@@ -1436,6 +1448,7 @@
14361448

14371449
tpm2 {
14381450
compatible = "sandbox,tpm2";
1451+
memory-region = <&event_log>;
14391452
};
14401453

14411454
tpm {

boot/Kconfig

+32
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,38 @@ config LEGACY_IMAGE_FORMAT
685685
loaded. If a board needs the legacy image format support in this
686686
case, enable it here.
687687

688+
config MEASURED_BOOT
689+
bool "Measure boot images and configuration when booting without EFI"
690+
depends on HASH && TPM_V2
691+
help
692+
This option enables measurement of the boot process when booting
693+
without UEFI . Measurement involves creating cryptographic hashes
694+
of the binary images that are booting and storing them in the TPM.
695+
In addition, a log of these hashes is stored in memory for the OS
696+
to verify the booted images and configuration. Enable this if the
697+
OS has configured some memory area for the event log and you intend
698+
to use some attestation tools on your system.
699+
700+
if MEASURED_BOOT
701+
config MEASURE_DEVICETREE
702+
bool "Measure the devicetree image"
703+
default y if MEASURED_BOOT
704+
help
705+
On some platforms, the devicetree is not static as it may contain
706+
random MAC addresses or other such data that changes each boot.
707+
Therefore, it should not be measured into the TPM. In that case,
708+
disable the measurement here.
709+
710+
config MEASURE_IGNORE_LOG
711+
bool "Ignore the existing event log"
712+
default n
713+
help
714+
On platforms that use an event log memory region that persists
715+
through system resets and are the first stage bootloader, then
716+
this option should be enabled to ignore any existing data in the
717+
event log memory region.
718+
endif # MEASURED_BOOT
719+
688720
config SUPPORT_RAW_INITRD
689721
bool "Enable raw initrd images"
690722
help

boot/bootm.c

+74
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <asm/global_data.h>
2424
#include <asm/io.h>
2525
#include <linux/sizes.h>
26+
#include <tpm-v2.h>
2627
#if defined(CONFIG_CMD_USB)
2728
#include <usb.h>
2829
#endif
@@ -673,6 +674,75 @@ int bootm_process_cmdline_env(int flags)
673674
return 0;
674675
}
675676

677+
int bootm_measure(struct bootm_headers *images)
678+
{
679+
int ret = 0;
680+
681+
/* Skip measurement if EFI is going to do it */
682+
if (images->os.os == IH_OS_EFI &&
683+
IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL) &&
684+
IS_ENABLED(CONFIG_BOOTM_EFI))
685+
return ret;
686+
687+
if (IS_ENABLED(CONFIG_MEASURED_BOOT)) {
688+
struct tcg2_event_log elog;
689+
struct udevice *dev;
690+
void *initrd_buf;
691+
void *image_buf;
692+
const char *s;
693+
u32 rd_len;
694+
bool ign;
695+
696+
elog.log_size = 0;
697+
ign = IS_ENABLED(CONFIG_MEASURE_IGNORE_LOG);
698+
ret = tcg2_measurement_init(&dev, &elog, ign);
699+
if (ret)
700+
return ret;
701+
702+
image_buf = map_sysmem(images->os.image_start,
703+
images->os.image_len);
704+
ret = tcg2_measure_data(dev, &elog, 8, images->os.image_len,
705+
image_buf, EV_COMPACT_HASH,
706+
strlen("linux") + 1, (u8 *)"linux");
707+
if (ret)
708+
goto unmap_image;
709+
710+
rd_len = images->rd_end - images->rd_start;
711+
initrd_buf = map_sysmem(images->rd_start, rd_len);
712+
ret = tcg2_measure_data(dev, &elog, 9, rd_len, initrd_buf,
713+
EV_COMPACT_HASH, strlen("initrd") + 1,
714+
(u8 *)"initrd");
715+
if (ret)
716+
goto unmap_initrd;
717+
718+
if (IS_ENABLED(CONFIG_MEASURE_DEVICETREE)) {
719+
ret = tcg2_measure_data(dev, &elog, 0, images->ft_len,
720+
(u8 *)images->ft_addr,
721+
EV_TABLE_OF_DEVICES,
722+
strlen("dts") + 1,
723+
(u8 *)"dts");
724+
if (ret)
725+
goto unmap_initrd;
726+
}
727+
728+
s = env_get("bootargs");
729+
if (!s)
730+
s = "";
731+
ret = tcg2_measure_data(dev, &elog, 1, strlen(s) + 1, (u8 *)s,
732+
EV_PLATFORM_CONFIG_FLAGS,
733+
strlen(s) + 1, (u8 *)s);
734+
735+
unmap_initrd:
736+
unmap_sysmem(initrd_buf);
737+
738+
unmap_image:
739+
unmap_sysmem(image_buf);
740+
tcg2_measurement_term(dev, &elog, ret != 0);
741+
}
742+
743+
return ret;
744+
}
745+
676746
/**
677747
* Execute selected states of the bootm command.
678748
*
@@ -724,6 +794,10 @@ int do_bootm_states(struct cmd_tbl *cmdtp, int flag, int argc,
724794
if (!ret && (states & BOOTM_STATE_FINDOTHER))
725795
ret = bootm_find_other(cmdtp, flag, argc, argv);
726796

797+
if (IS_ENABLED(CONFIG_MEASURED_BOOT) && !ret &&
798+
(states & BOOTM_STATE_MEASURE))
799+
bootm_measure(images);
800+
727801
/* Load the OS */
728802
if (!ret && (states & BOOTM_STATE_LOADOS)) {
729803
iflag = bootm_disable_interrupts();

cmd/booti.c

+1
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ int do_booti(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
127127
#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
128128
BOOTM_STATE_RAMDISK |
129129
#endif
130+
BOOTM_STATE_MEASURE |
130131
BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |
131132
BOOTM_STATE_OS_GO,
132133
&images, 1);

cmd/bootm.c

+2
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ int do_bootm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
147147
BOOTM_STATE_OS_GO;
148148
if (IS_ENABLED(CONFIG_SYS_BOOT_RAMDISK_HIGH))
149149
states |= BOOTM_STATE_RAMDISK;
150+
if (IS_ENABLED(CONFIG_MEASURED_BOOT))
151+
states |= BOOTM_STATE_MEASURE;
150152
if (IS_ENABLED(CONFIG_PPC) || IS_ENABLED(CONFIG_MIPS))
151153
states |= BOOTM_STATE_OS_CMDLINE;
152154
ret = do_bootm_states(cmdtp, flag, argc, argv, states, &images, 1);

cmd/bootz.c

+1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ int do_bootz(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
8181
#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
8282
BOOTM_STATE_RAMDISK |
8383
#endif
84+
BOOTM_STATE_MEASURE |
8485
BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |
8586
BOOTM_STATE_OS_GO,
8687
&images, 1);

configs/sandbox_defconfig

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ CONFIG_FIT_RSASSA_PSS=y
1414
CONFIG_FIT_CIPHER=y
1515
CONFIG_FIT_VERBOSE=y
1616
CONFIG_LEGACY_IMAGE_FORMAT=y
17+
CONFIG_MEASURED_BOOT=y
1718
CONFIG_DISTRO_DEFAULTS=y
1819
CONFIG_BOOTSTAGE=y
1920
CONFIG_BOOTSTAGE_REPORT=y

doc/usage/index.rst

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Use U-Boot
1414
partitions
1515
cmdline
1616
semihosting
17+
measured_boot
1718

1819
Shell commands
1920
--------------

doc/usage/measured_boot.rst

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
.. SPDX-License-Identifier: GPL-2.0+
2+
3+
Measured Boot
4+
=====================
5+
6+
U-Boot can perform a measured boot, the process of hashing various components
7+
of the boot process, extending the results in the TPM and logging the
8+
component's measurement in memory for the operating system to consume.
9+
10+
By default, U-Boot will measure the operating system (linux) image, the
11+
initrd image, and the "bootargs" environment variable. By enabling
12+
CONFIG_MEASURE_DEVICETREE, U-Boot will also measure the devicetree image.
13+
14+
The operating system typically would verify that the hashes found in the
15+
TPM PCRs match the contents of the event log. This can further be checked
16+
against the hash results of previous boots.
17+
18+
Requirements
19+
---------------------
20+
21+
* A hardware TPM 2.0 supported by the U-Boot drivers
22+
* CONFIG_TPM=y
23+
* CONFIG_MEASURED_BOOT=y
24+
* Device-tree configuration of the TPM device to specify the memory area
25+
for event logging. The TPM device node must either contain a phandle to
26+
a reserved memory region or "linux,sml-base" and "linux,sml-size"
27+
indicating the address and size of the memory region. An example can be
28+
found in arch/sandbox/dts/test.dts
29+
* The operating system must also be configured to use the memory regions
30+
specified in the U-Boot device-tree in order to make use of the event
31+
log.

0 commit comments

Comments
 (0)