diff --git a/docs/BOOT_LOADER_INTERFACE.md b/docs/BOOT_LOADER_INTERFACE.md index a3a79bbf86c..ac964d771e6 100644 --- a/docs/BOOT_LOADER_INTERFACE.md +++ b/docs/BOOT_LOADER_INTERFACE.md @@ -191,11 +191,11 @@ Variables will be listed below using the Linux efivarfs naming, NUL-terminated UTF-16 string, e.g. `1`) into which the boot loader measured select SMBIOS structures: type 1 (system information, with the volatile "Wake-up Type" field zeroed out), type 2 (baseboard information) and type 11 - (OEM strings). This is a volatile (non-persistent) variable, set only if a - measurement was successfully completed, and remains unset otherwise. Both - `systemd-boot` and `systemd-stub` perform this measurement; whichever runs - first sets the variable, and its presence suppresses a second measurement of - the same data into the same PCR during the same boot. + (OEM strings). This is a volatile (non-persistent) variable, set only if all + of these structures were measured successfully, and remains unset otherwise. + Both `systemd-boot` and `systemd-stub` perform this measurement; whichever + runs first sets the variable, and its presence suppresses a second + measurement of the same data into the same PCR during the same boot. * The EFI variable `LoaderInfo-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f` contains the version string of the boot loader that was booted, diff --git a/docs/TPM2_PCR_MEASUREMENTS.md b/docs/TPM2_PCR_MEASUREMENTS.md index ce5dca66efa..9ffe7d867c0 100644 --- a/docs/TPM2_PCR_MEASUREMENTS.md +++ b/docs/TPM2_PCR_MEASUREMENTS.md @@ -156,11 +156,12 @@ described above. This measurement is also performed by `systemd-stub` (see below), so that systems that boot a UKI directly, bypassing `systemd-boot`, still get it. Whichever -component runs first performs the measurement and sets the volatile -`LoaderPcrSMBIOS` EFI variable to the PCR index used; its presence suppresses a -second measurement of the same data into the same PCR during the same boot. Note -that the firmware itself typically also extends PCR 1, so its final value is not -solely determined by this measurement. +component runs first performs the measurement and, if all structures were +measured successfully, sets the volatile `LoaderPcrSMBIOS` EFI variable to the +PCR index used; its presence suppresses a second measurement of the same data +into the same PCR during the same boot. Note that the firmware itself typically +also extends PCR 1, so its final value is not solely determined by this +measurement. ### PCR 5, `EV_EVENT_TAG`, `loader.conf` diff --git a/man/systemd-boot.xml b/man/systemd-boot.xml index 6f8ae255605..d81910b0cb8 100644 --- a/man/systemd-boot.xml +++ b/man/systemd-boot.xml @@ -631,9 +631,9 @@ extra /6a9857a393724b7a981ebb5b8495b9ea/1.2.3/baz.confext.rawThe PCR register index select SMBIOS structures are measured into — type 1 (system information, with the volatile "Wake-up Type" field zeroed out), type 2 (baseboard information) and type 11 (OEM strings). Formatted as decimal ASCII string (e.g. - 1). Set by the boot loader if a measurement was successfully completed, and remains - unset otherwise. (Note that systemd-stub performs the same measurement when booted - directly, bypassing the boot loader.) + 1). Set by the boot loader only if all of these structures were measured + successfully, and remains unset otherwise. (Note that systemd-stub performs the + same measurement when booted directly, bypassing the boot loader.) diff --git a/man/systemd-stub.xml b/man/systemd-stub.xml index 966a700fe92..66171a5f982 100644 --- a/man/systemd-stub.xml +++ b/man/systemd-stub.xml @@ -671,10 +671,10 @@ The PCR register index select SMBIOS structures are measured into — type 1 (system information, with the volatile "Wake-up Type" field zeroed out), type 2 (baseboard information) and type 11 (OEM strings). Formatted as decimal ASCII string (e.g. - 1). This variable is set if a measurement was successfully completed, and remains - unset otherwise. systemd-stub performs this measurement only if it has not already - been done in the same boot (e.g. by the boot loader), as indicated by this variable being set - already. + 1). This variable is set only if all of these structures were measured + successfully, and remains unset otherwise. systemd-stub performs this measurement + only if it has not already been done in the same boot (e.g. by the boot loader), as indicated by this + variable being set already. diff --git a/src/boot/measure-smbios.c b/src/boot/measure-smbios.c index 89da7d9e8f9..0b46e4951bb 100644 --- a/src/boot/measure-smbios.c +++ b/src/boot/measure-smbios.c @@ -8,19 +8,24 @@ #include "tpm2-pcr.h" #include "util.h" +typedef struct MeasureSmbiosContext { + bool measured; /* At least one structure was measured */ + bool failed; /* At least one measurement failed */ +} MeasureSmbiosContext; + static void measure_smbios_raw( const void *p, size_t size, uint32_t event_id, const char16_t *description, - bool *measured) { + MeasureSmbiosContext *ctx) { EFI_STATUS err; bool m = false; assert(p); assert(description); - assert(measured); + assert(ctx); err = tpm_log_tagged_event( TPM2_PCR_PLATFORM_CONFIG, @@ -29,15 +34,18 @@ static void measure_smbios_raw( event_id, description, &m); - if (err != EFI_SUCCESS) - log_error_status(err, "Unable to measure SMBIOS structure (%ls), ignoring: %m", description); + if (err != EFI_SUCCESS) { + log_error_status(err, "Unable to measure SMBIOS structure (%ls): %m", description); + ctx->failed = true; + return; + } - *measured = *measured || m; + ctx->measured = ctx->measured || m; } -static void measure_smbios_type1(const SmbiosHeader *header, size_t size, bool *measured) { +static void measure_smbios_type1(const SmbiosHeader *header, size_t size, MeasureSmbiosContext *ctx) { assert(header); - assert(measured); + assert(ctx); /* The wake-up type field varies depending on how the machine was powered on (cold boot, resume * from sleep, AC restore, …), which would make the measurement non-reproducible. Hence measure a @@ -61,24 +69,24 @@ static void measure_smbios_type1(const SmbiosHeader *header, size_t size, bool * p = copy; } - measure_smbios_raw(p, size, SMBIOS_TYPE1_EVENT_TAG_ID, u"smbios:type1", measured); + measure_smbios_raw(p, size, SMBIOS_TYPE1_EVENT_TAG_ID, u"smbios:type1", ctx); } static bool measure_smbios_object(const SmbiosHeader *header, size_t size, void *userdata) { - bool *measured = ASSERT_PTR(userdata); + MeasureSmbiosContext *ctx = ASSERT_PTR(userdata); switch (header->type) { case 1: /* System Information */ - measure_smbios_type1(header, size, measured); + measure_smbios_type1(header, size, ctx); break; case 2: /* Baseboard Information */ - measure_smbios_raw(header, size, SMBIOS_TYPE2_EVENT_TAG_ID, u"smbios:type2", measured); + measure_smbios_raw(header, size, SMBIOS_TYPE2_EVENT_TAG_ID, u"smbios:type2", ctx); break; case 11: /* OEM Strings */ - measure_smbios_raw(header, size, SMBIOS_TYPE11_EVENT_TAG_ID, u"smbios:type11", measured); + measure_smbios_raw(header, size, SMBIOS_TYPE11_EVENT_TAG_ID, u"smbios:type11", ctx); break; default: @@ -89,7 +97,7 @@ static bool measure_smbios_object(const SmbiosHeader *header, size_t size, void } void measure_smbios(void) { - bool measured = false; + MeasureSmbiosContext ctx = {}; if (!runtime_measurement_available()) return; @@ -101,9 +109,9 @@ void measure_smbios(void) { /* Measure SMBIOS type 1 (system information), type 2 (baseboard information) and type 11 (OEM * strings) into PCR 1, in a single pass over the SMBIOS table. */ - smbios_foreach(measure_smbios_object, &measured); + smbios_foreach(measure_smbios_object, &ctx); - /* If we measured something, tell the OS which PCR we used (and suppress a second pass). */ - if (measured) + /* Tell the OS which PCR we used (and suppress a second pass), but only if every structure was measured. */ + if (ctx.measured && !ctx.failed) (void) efivar_set_uint64_str16(MAKE_GUID_PTR(LOADER), u"LoaderPcrSMBIOS", TPM2_PCR_PLATFORM_CONFIG, /* flags= */ 0); } diff --git a/src/boot/measure-smbios.h b/src/boot/measure-smbios.h index 758b2c45b43..35f98e7d584 100644 --- a/src/boot/measure-smbios.h +++ b/src/boot/measure-smbios.h @@ -1,8 +1,9 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -/* Measures SMBIOS type 1 (system information, with the volatile "Wake-up Type" field masked) and all - * type 11 (OEM strings) structures into PCR 1, and records the PCR index in the transient - * LoaderPcrSMBIOS EFI variable. Called by both sd-boot and sd-stub; the presence of LoaderPcrSMBIOS - * suppresses a redundant second measurement when both run during the same boot. */ +/* Measures SMBIOS type 1 (system information, with the volatile "Wake-up Type" field masked), type 2 + * (baseboard information) and all type 11 (OEM strings) structures into PCR 1, and records the PCR + * index in the transient LoaderPcrSMBIOS EFI variable if all of them were measured successfully. + * Called by both sd-boot and sd-stub; the presence of LoaderPcrSMBIOS suppresses a redundant second + * measurement when both run during the same boot. */ void measure_smbios(void); diff --git a/src/shared/efi-loader.c b/src/shared/efi-loader.c index e05afb1da1d..ae8f9699e16 100644 --- a/src/shared/efi-loader.c +++ b/src/shared/efi-loader.c @@ -347,8 +347,9 @@ int efi_measured_smbios(int log_level) { if (cached >= 0) return cached; - /* Whether sd-boot or sd-stub measured the SMBIOS table (types 1, 2, and 11) into PCR 1. Firmware - * does not do this for OEM strings: edk2's SmbiosMeasurementDxe zeros type 11 before hashing. */ + /* Whether sd-boot or sd-stub measured the SMBIOS table (types 1, 2, and 11) into PCR 1. The loader + * sets the variable only if all of these structures were measured. Firmware does not do this for + * OEM strings: edk2's SmbiosMeasurementDxe zeros type 11 before hashing. */ r = efi_get_variable_string(EFI_LOADER_VARIABLE_STR("LoaderPcrSMBIOS"), &pcr_string); if (r == -ENOENT)