Skip to content

Commit

Permalink
Merge tag 'tpm-next-27102023' of https://source.denx.de/u-boot/custod…
Browse files Browse the repository at this point in the history
…ians/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.
  • Loading branch information
trini committed Oct 27, 2023
2 parents 913d830 + 4fd7d27 commit d5d9770
Show file tree
Hide file tree
Showing 24 changed files with 1,490 additions and 1,062 deletions.
13 changes: 13 additions & 0 deletions arch/sandbox/dts/sandbox.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,23 @@
* and sandbox64 builds.
*/

#include <config.h>
#include <dt-bindings/input/input.h>

#define USB_CLASS_HUB 9

/ {
reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
ranges;

event_log: tcg_event_log {
no-map;
reg = <(CFG_SYS_SDRAM_SIZE - 0x2000) 0x2000>;
};
};

binman {
};

Expand Down Expand Up @@ -342,6 +354,7 @@

tpm2 {
compatible = "sandbox,tpm2";
memory-region = <&event_log>;
};

triangle {
Expand Down
13 changes: 13 additions & 0 deletions arch/sandbox/dts/test.dts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

/dts-v1/;

#include <config.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/gpio/sandbox-gpio.h>
#include <dt-bindings/input/input.h>
Expand Down Expand Up @@ -69,6 +70,17 @@
osd0 = "/osd";
};

reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
ranges;

event_log: tcg_event_log {
no-map;
reg = <(CFG_SYS_SDRAM_SIZE - 0x2000) 0x2000>;
};
};

binman: binman {
};

Expand Down Expand Up @@ -1436,6 +1448,7 @@

tpm2 {
compatible = "sandbox,tpm2";
memory-region = <&event_log>;
};

tpm {
Expand Down
32 changes: 32 additions & 0 deletions boot/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
74 changes: 74 additions & 0 deletions boot/bootm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
*
Expand Down Expand Up @@ -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();
Expand Down
1 change: 1 addition & 0 deletions cmd/booti.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions cmd/bootm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions cmd/bootz.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions configs/sandbox_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ CONFIG_FIT_RSASSA_PSS=y
CONFIG_FIT_CIPHER=y
CONFIG_FIT_VERBOSE=y
CONFIG_LEGACY_IMAGE_FORMAT=y
CONFIG_MEASURED_BOOT=y
CONFIG_DISTRO_DEFAULTS=y
CONFIG_BOOTSTAGE=y
CONFIG_BOOTSTAGE_REPORT=y
Expand Down
1 change: 1 addition & 0 deletions doc/usage/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Use U-Boot
partitions
cmdline
semihosting
measured_boot

Shell commands
--------------
Expand Down
31 changes: 31 additions & 0 deletions doc/usage/measured_boot.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
.. SPDX-License-Identifier: GPL-2.0+
Measured Boot
=====================

U-Boot can perform a measured boot, the process of hashing various components
of the boot process, extending the results in the TPM and logging the
component's measurement in memory for the operating system to consume.

By default, U-Boot will measure the operating system (linux) image, the
initrd image, and the "bootargs" environment variable. By enabling
CONFIG_MEASURE_DEVICETREE, U-Boot will also measure the devicetree image.

The operating system typically would verify that the hashes found in the
TPM PCRs match the contents of the event log. This can further be checked
against the hash results of previous boots.

Requirements
---------------------

* A hardware TPM 2.0 supported by the U-Boot drivers
* CONFIG_TPM=y
* CONFIG_MEASURED_BOOT=y
* Device-tree configuration of the TPM device to specify the memory area
for event logging. The TPM device node must either contain a phandle to
a reserved memory region or "linux,sml-base" and "linux,sml-size"
indicating the address and size of the memory region. An example can be
found in arch/sandbox/dts/test.dts
* The operating system must also be configured to use the memory regions
specified in the U-Boot device-tree in order to make use of the event
log.
Loading

0 comments on commit d5d9770

Please sign in to comment.