diff --git a/man/systemd-cryptenroll.xml b/man/systemd-cryptenroll.xml
index 8e1b9857a7..4a5127b02d 100644
--- a/man/systemd-cryptenroll.xml
+++ b/man/systemd-cryptenroll.xml
@@ -296,6 +296,11 @@
The IMA project measures its runtime state into this PCR.
+
+ 11
+ systemd-stub7 measures the ELF kernel image, embedded initrd and other payload of the PE image it is placed in into this PCR. Unlike PCR 4 (where the same data should be measured into), this PCR value should be easy to pre-calculate, as this only contains static parts of the PE binary. Use this PCR to bind TPM policies to a specific kernel image, possibly with an embedded initial RAM disk (initrd).
+
+
12
systemd-boot7 measures any specified kernel command line into this PCR. systemd-stub7 measures any manually specified kernel command line (i.e. a kernel command line that overrides the one embedded in the unified PE image) and loaded credentials into this PCR. (Note that if systemd-boot and systemd-stub are used in combination the command line might be measured twice!)
diff --git a/man/systemd-stub.xml b/man/systemd-stub.xml
index 955fa6f98f..df7cabcf50 100644
--- a/man/systemd-stub.xml
+++ b/man/systemd-stub.xml
@@ -53,6 +53,10 @@
The ELF Linux kernel images will be looked for in the .linux PE
section of the executed image.
+ OS release information, i.e. the
+ os-release5 file of
+ the OS the kernel belongs to, in the .osrel PE section.
+
The initial RAM disk (initrd) will be looked for in the .initrd PE
section.
@@ -76,6 +80,9 @@
If a DeviceTree is embedded in the .dtb section, it replaces an existing
DeviceTree in the corresponding EFI configuration table. systemd-stub will ask the firmware via the
EFI_DT_FIXUP_PROTOCOL for hardware specific fixups to the DeviceTree.
+
+ The contents of these six PE sections are measured into TPM PCR 11, that is otherwise not
+ used. Thus, it can be pre-calculated without too much effort.
@@ -133,10 +140,10 @@
core kernel, the embedded initrd and kernel command line (see above for a full list).
Also note that the Linux kernel will measure all initrds it receives into TPM PCR 9. This means
- every type of initrd will be measured twice: the initrd embedded in the kernel image will be measured to
- both PCR 4 and PCR 9; the initrd synthesized from credentials will be measured to both PCR 12 and PCR 9;
- the initrd synthesized from system extensions will be measured to both PCR 4 and PCR 9. Let's summarize
- the OS resources and the PCRs they are measured to:
+ every type of initrd will be measured two or three times: the initrd embedded in the kernel image will be
+ measured to PCR 4, PCR 9 and PCR 11; the initrd synthesized from credentials will be measured to both PCR
+ 9 and PCR 12; the initrd synthesized from system extensions will be measured to both PCR 4 and PCR
+ 9. Let's summarize the OS resources and the PCRs they are measured to:
OS Resource PCR Summary
@@ -160,22 +167,22 @@
Boot splash (embedded in the unified PE binary)
- 4
+ 4 + 11
Core kernel code (embedded in unified PE binary)
- 4
+ 4 + 11
Main initrd (embedded in unified PE binary)
- 4 + 9
+ 4 + 9 + 11
Default kernel command line (embedded in unified PE binary)
- 4
+ 4 + 11
@@ -240,6 +247,15 @@
this data.
+
+ StubPcrKernelImage
+
+ The PCR register index the ELF kernel image/initial RAM disk image/boot
+ splash/devicetree database/embedded command line are measured into, formatted as decimal ASCII string
+ (i.e. 11). This variable is set if a measurement was successfully completed, and
+ remains unset otherwise.
+
+
StubPcrKernelParameters
diff --git a/src/boot/efi/measure.h b/src/boot/efi/measure.h
index 5da160f8c8..df7f04c9fb 100644
--- a/src/boot/efi/measure.h
+++ b/src/boot/efi/measure.h
@@ -5,6 +5,12 @@
#include
#include
+/* This TPM PCR is where we extend the sd-stub "payloads" into, before using them. i.e. the kernel ELF image,
+ * embedded initrd, and so on. In contrast to PCR 4 (which also contains this data, given the whole
+ * surrounding PE image is measured into it) this should be reasonably pre-calculatable, because it *only*
+ * consists of static data from the kernel PE image. */
+#define TPM_PCR_INDEX_KERNEL_IMAGE 11U
+
/* This TPM PCR is where sd-stub extends the kernel command line and any passed credentials into. */
#define TPM_PCR_INDEX_KERNEL_PARAMETERS 12U
diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c
index 3673d16345..9ec01d1baa 100644
--- a/src/boot/efi/stub.c
+++ b/src/boot/efi/stub.c
@@ -149,7 +149,7 @@ static void export_variables(EFI_LOADED_IMAGE_PROTOCOL *loaded_image) {
EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
- enum {
+ enum Section {
SECTION_CMDLINE,
SECTION_LINUX,
SECTION_INITRD,
@@ -178,7 +178,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
UINTN szs[_SECTION_MAX] = {};
char *cmdline = NULL;
_cleanup_free_ char *cmdline_owned = NULL;
- int parameters_measured = -1;
+ int sections_measured = -1, parameters_measured = -1;
EFI_STATUS err;
bool m;
@@ -204,6 +204,41 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
return log_error_status_stall(err, L"Unable to locate embedded .linux section: %r", err);
}
+ /* Measure all "payload" of this PE image into a separate PCR (i.e. where nothing else is written
+ * into so far), so that we have one PCR that we can nicely write policies against because it
+ * contains all static data of this image, and thus can be easily be pre-calculated. */
+ for (enum Section section = 0; section < _SECTION_MAX; section++) {
+ m = false;
+
+ if (szs[section] == 0) /* not found */
+ continue;
+
+ /* First measure the name of the section */
+ (void) tpm_log_event_ascii(
+ TPM_PCR_INDEX_KERNEL_IMAGE,
+ POINTER_TO_PHYSICAL_ADDRESS(sections[section]),
+ strsize8(sections[section]), /* including NUL byte */
+ sections[section],
+ &m);
+
+ sections_measured = sections_measured < 0 ? m : (sections_measured && m);
+
+ /* Then measure the data of the section */
+ (void) tpm_log_event_ascii(
+ TPM_PCR_INDEX_KERNEL_IMAGE,
+ POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[section],
+ szs[section],
+ sections[section],
+ &m);
+
+ sections_measured = sections_measured < 0 ? m : (sections_measured && m);
+ }
+
+ /* After we are done, set an EFI variable that tells userspace this was done successfully, and encode
+ * in it which PCR was used. */
+ if (sections_measured > 0)
+ (void) efivar_set_uint_string(LOADER_GUID, L"StubPcrKernelImage", TPM_PCR_INDEX_KERNEL_IMAGE, 0);
+
/* Show splash screen as early as possible */
graphics_splash((const uint8_t*) loaded_image->ImageBase + addrs[SECTION_SPLASH], szs[SECTION_SPLASH], NULL);