diff --git a/TODO.md b/TODO.md
index 6e7cc16112..8c59952ad9 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1212,12 +1212,6 @@ SPDX-License-Identifier: LGPL-2.1-or-later
- in pid1: include ExecStart= cmdlines (and other Exec*= cmdlines) in polkit
request, so that policies can match against command lines.
-- in sd-boot and sd-stub measure the SMBIOS vendor strings to some PCR (at
- least some subset of them that look like systemd stuff), because apparently
- some firmware does not, but systemd honours it. avoid duplicate measurement
- by sd-boot and sd-stub by adding LoaderFeatures/StubFeatures flag for this,
- so that sd-stub can avoid it if sd-boot already did it.
-
- in sd-id128: also parse UUIDs in RFC4122 URN syntax (i.e. chop off urn:uuid: prefix)
- in sd-stub: optionally add support for a new PE section .keyring or so that
@@ -1745,8 +1739,6 @@ SPDX-License-Identifier: LGPL-2.1-or-later
- measure all log-in attempts into a new nvpcr
-- measure credentials picked up from SMBIOS to some suitable PCR
-
- measure GPT and LUKS headers somewhere when we use them (i.e. in
systemd-gpt-auto-generator/systemd-repart and in systemd-cryptsetup?)
diff --git a/docs/BOOT_LOADER_INTERFACE.md b/docs/BOOT_LOADER_INTERFACE.md
index 36380f38f3..efe5c1cce2 100644
--- a/docs/BOOT_LOADER_INTERFACE.md
+++ b/docs/BOOT_LOADER_INTERFACE.md
@@ -145,6 +145,8 @@ Variables will be listed below using the Linux efivarfs naming,
* `1 << 19` → The boot loader supports the `LoaderEntryPreferred` variable when set.
* `1 << 20` → The boot loader reports the firmware-configured keyboard layout in the
EFI variable `LoaderKeyboardLayout-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f`.
+ * `1 << 21` → The boot loader measures SMBIOS information into a TPM2 PCR and reports the PCR index in the
+ EFI variable `LoaderPcrSMBIOS-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f`.
* The EFI variable `LoaderSystemToken-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f`
contains binary random data,
@@ -184,6 +186,17 @@ Variables will be listed below using the Linux efivarfs naming,
uses this as a lowest-priority fallback keyboard layout
when no explicit configuration is provided.
+* The EFI variable `LoaderPcrSMBIOS-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f`
+ contains the index of the TPM2 PCR (as a decimal ASCII string formatted as a
+ 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.
+
If `LoaderTimeInitUSec` and `LoaderTimeExecUSec` are set, `systemd-analyze`
will include them in its boot-time analysis. If `LoaderDevicePartUUID` is set,
systemd will mount the ESP that was used for the boot to `/boot`, but only if
diff --git a/docs/TPM2_PCR_MEASUREMENTS.md b/docs/TPM2_PCR_MEASUREMENTS.md
index 5d0801a907..8bdcd6979e 100644
--- a/docs/TPM2_PCR_MEASUREMENTS.md
+++ b/docs/TPM2_PCR_MEASUREMENTS.md
@@ -91,6 +91,45 @@ must be employed when designing a system that uses this feature.
## PCR Measurements Made by `systemd-boot` (UEFI)
+### PCR 1, `EV_EVENT_TAG`, SMBIOS information
+
+Select SMBIOS structures provided by the firmware are measured into PCR 1 (the
+TCG-defined register for platform configuration data), one tagged event per
+structure:
+
+* SMBIOS type 1 (system information). The volatile "Wake-up Type" field is
+ zeroed before measuring, since it varies depending on how the machine was
+ powered on (cold boot, resume from sleep, AC restore, …) and would otherwise
+ make the measurement non-reproducible.
+* SMBIOS type 2 (baseboard information).
+* SMBIOS type 11 (OEM strings). There may be more than one such structure; all
+ are measured.
+
+Note that these measurements are – strictly speaking – redundant, since
+firmwares are supposed to measure SMBIOS data anyway on their own. However, it
+has been found this is not the case on many real-life implementations. Since in
+particular SMBIOS type 11 may carry highly relevant input for the OS
+(e.g. system credentials), an explicit measurement is made here to ensure all
+parameters for the OS are comprehensively measured even on flaky firmwares.
+
+→ **Event Tag** `0xd5cb7cbc` for type 1, `0xe0d47bc8` for type 2, `0xc0b3bd23`
+for type 11.
+
+→ **Description** in the event log record is `smbios:type1`, `smbios:type2` or
+`smbios:type11` respectively, in UTF-16.
+
+→ **Measured hash** covers the raw bytes of the SMBIOS structure (formatted area
+plus trailing string set), with the type 1 "Wake-up Type" field zeroed out as
+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.
+
### PCR 5, `EV_EVENT_TAG`, `loader.conf`
The content of `systemd-boot`'s configuration file, `loader/loader.conf`, is
@@ -120,6 +159,14 @@ trailing NUL bytes).
## PCR Measurements Made by `systemd-stub` (UEFI)
+### PCR 1, `EV_EVENT_TAG`, SMBIOS information
+
+Identical to the SMBIOS measurement described above for `systemd-boot`. When
+`systemd-stub` is invoked by `systemd-boot`, the measurement has typically already
+been made (tracked via the `LoaderPcrSMBIOS` EFI variable) and is not repeated;
+when the UKI is booted directly by the firmware, `systemd-stub` performs it
+itself.
+
### PCR 11, `EV_IPL`, PE section name
A measurement is made for each PE section of the UKI that is defined by the
diff --git a/man/systemd-boot.xml b/man/systemd-boot.xml
index 1acf5d083e..2162c7ffb2 100644
--- a/man/systemd-boot.xml
+++ b/man/systemd-boot.xml
@@ -622,6 +622,19 @@ extra /6a9857a393724b7a981ebb5b8495b9ea/1.2.3/baz.confext.raw
+
+ LoaderPcrSMBIOS
+
+ 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). 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.)
+
+
+
+
LoaderImageIdentifier
diff --git a/man/systemd-stub.xml b/man/systemd-stub.xml
index 95f62ca66b..a5172fed1c 100644
--- a/man/systemd-stub.xml
+++ b/man/systemd-stub.xml
@@ -664,6 +664,20 @@
+
+ LoaderPcrSMBIOS
+
+ 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.
+
+
+
+
LoaderBootSecret
diff --git a/src/boot/boot.c b/src/boot/boot.c
index 9f833f02b1..3ba430a844 100644
--- a/src/boot/boot.c
+++ b/src/boot/boot.c
@@ -17,6 +17,7 @@
#include "iovec-util.h"
#include "line-edit.h"
#include "measure.h"
+#include "measure-smbios.h"
#include "memory-util.h"
#include "part-discovery.h"
#include "pe.h"
@@ -3267,6 +3268,7 @@ static void export_loader_variables(
EFI_LOADER_FEATURE_TYPE1_UKI_URL |
EFI_LOADER_FEATURE_TPM2_ACTIVE_PCR_BANKS |
EFI_LOADER_FEATURE_KEYBOARD_LAYOUT |
+ EFI_LOADER_FEATURE_SMBIOS_MEASURED |
0;
assert(loaded_image);
@@ -3434,6 +3436,10 @@ static EFI_STATUS run(EFI_HANDLE image) {
export_common_variables(loaded_image);
export_loader_variables(loaded_image, init_usec);
+ /* Measure SMBIOS data into PCR 1. This is done early, and suppressed if sd-stub later runs in
+ * the same boot (and vice versa), via the LoaderPcrSMBIOS EFI variable. */
+ measure_smbios();
+
(void) load_drivers(image, loaded_image, root_dir);
_cleanup_free_ char16_t *loaded_image_path = NULL;
diff --git a/src/boot/measure-smbios.c b/src/boot/measure-smbios.c
new file mode 100644
index 0000000000..2379f4de9e
--- /dev/null
+++ b/src/boot/measure-smbios.c
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "efi-efivars.h"
+#include "efi-log.h"
+#include "measure.h"
+#include "measure-smbios.h"
+#include "smbios.h"
+#include "tpm2-pcr.h"
+#include "util.h"
+
+static void measure_smbios_raw(
+ const void *p,
+ size_t size,
+ uint32_t event_id,
+ const char16_t *description,
+ bool *measured) {
+
+ EFI_STATUS err;
+ bool m = false;
+
+ assert(p);
+ assert(description);
+ assert(measured);
+
+ err = tpm_log_tagged_event(
+ TPM2_PCR_PLATFORM_CONFIG,
+ POINTER_TO_PHYSICAL_ADDRESS(p),
+ size,
+ event_id,
+ description,
+ &m);
+ if (err != EFI_SUCCESS)
+ log_error_status(err, "Unable to measure SMBIOS structure (%ls), ignoring: %m", description);
+
+ *measured = *measured || m;
+}
+
+static void measure_smbios_type1(const SmbiosHeader *header, size_t size, bool *measured) {
+ assert(header);
+ assert(measured);
+
+ /* 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
+ * copy with that field zeroed out. */
+
+ assert(size >= sizeof(SmbiosTableType1));
+
+ _cleanup_free_ SmbiosTableType1 *copy = xmemdup(header, size);
+ copy->wake_up_type = 0;
+
+ measure_smbios_raw(copy, size, SMBIOS_TYPE1_EVENT_TAG_ID, u"smbios:type1", measured);
+}
+
+static bool measure_smbios_object(const SmbiosHeader *header, size_t size, void *userdata) {
+ bool *measured = ASSERT_PTR(userdata);
+
+ switch (header->type) {
+
+ case 1: /* System Information */
+ measure_smbios_type1(header, size, measured);
+ break;
+
+ case 2: /* Baseboard Information */
+ measure_smbios_raw(header, size, SMBIOS_TYPE2_EVENT_TAG_ID, u"smbios:type2", measured);
+ break;
+
+ case 11: /* OEM Strings */
+ measure_smbios_raw(header, size, SMBIOS_TYPE11_EVENT_TAG_ID, u"smbios:type11", measured);
+ break;
+
+ default:
+ break;
+ }
+
+ return true; /* Keep iterating: there may be more than one matching structure (e.g. type 11). */
+}
+
+void measure_smbios(void) {
+ bool measured = false;
+
+ if (!tpm_present())
+ return;
+
+ /* If the measurement was already done this boot (e.g. by sd-boot before it chainloaded us), don't
+ * do it again — re-extending PCR 1 would invalidate the value. */
+ if (efivar_get_raw(MAKE_GUID_PTR(LOADER), u"LoaderPcrSMBIOS", /* ret_data= */ NULL, /* ret_size= */ NULL) == EFI_SUCCESS)
+ return;
+
+ /* 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);
+
+ /* If we measured something, tell the OS which PCR we used (and suppress a second pass). */
+ if (measured)
+ (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
new file mode 100644
index 0000000000..758b2c45b4
--- /dev/null
+++ b/src/boot/measure-smbios.h
@@ -0,0 +1,8 @@
+/* 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. */
+void measure_smbios(void);
diff --git a/src/boot/meson.build b/src/boot/meson.build
index 2dc9c64256..d2524145d0 100644
--- a/src/boot/meson.build
+++ b/src/boot/meson.build
@@ -323,6 +323,7 @@ libefi_sources = files(
'hii.c',
'initrd.c',
'measure.c',
+ 'measure-smbios.c',
'part-discovery.c',
'pe.c',
'random-seed.c',
diff --git a/src/boot/smbios.c b/src/boot/smbios.c
index 0bbcf30123..46e9817acc 100644
--- a/src/boot/smbios.c
+++ b/src/boot/smbios.c
@@ -39,12 +39,6 @@ typedef struct {
uint64_t table_address;
} _packed_ Smbios3EntryPoint;
-typedef struct {
- uint8_t type;
- uint8_t length;
- uint8_t handle[2];
-} _packed_ SmbiosHeader;
-
typedef struct {
SmbiosHeader header;
uint8_t vendor;
@@ -56,18 +50,6 @@ typedef struct {
uint8_t bios_characteristics_ext[2];
} _packed_ SmbiosTableType0;
-typedef struct {
- SmbiosHeader header;
- uint8_t manufacturer;
- uint8_t product_name;
- uint8_t version;
- uint8_t serial_number;
- EFI_GUID uuid;
- uint8_t wake_up_type;
- uint8_t sku_number;
- uint8_t family;
-} _packed_ SmbiosTableType1;
-
typedef struct {
SmbiosHeader header;
uint8_t manufacturer;
@@ -103,6 +85,44 @@ static const void* find_smbios_configuration_table(uint64_t *ret_size) {
return NULL;
}
+/* Given 'p' pointing at a structure header with 'size' bytes left in the table from there onwards,
+ * returns a pointer just past the end of this structure (i.e. the start of the next one), accounting
+ * for the formatted area and the trailing string set (terminated by a double NUL byte). Returns NULL
+ * if the structure is malformed or runs past the end of the table. */
+static const uint8_t* smbios_structure_end(const uint8_t *p, uint64_t size) {
+ assert(p);
+
+ if (size < sizeof(SmbiosHeader))
+ return NULL;
+
+ const SmbiosHeader *header = (const SmbiosHeader *) p;
+ if (size < header->length)
+ return NULL;
+
+ /* Skip over formatted area. */
+ const uint8_t *q = p + header->length;
+ size -= header->length;
+
+ /* Special case: if there are no strings appended, we'll see two NUL bytes. */
+ if (size >= 2 && q[0] == 0 && q[1] == 0)
+ return q + 2;
+
+ /* Skip over a populated string table. */
+ bool first = true;
+ for (;;) {
+ const uint8_t *e = memchr(q, 0, size);
+ if (!e)
+ return NULL;
+
+ if (!first && e == q) /* Double NUL byte means we've reached the end of the string table. */
+ return q + 1;
+
+ size -= e + 1 - q;
+ q = e + 1;
+ first = false;
+ }
+}
+
static const SmbiosHeader* get_smbios_table(uint8_t type, size_t min_size, uint64_t *ret_size_left) {
uint64_t size;
const uint8_t *p = find_smbios_configuration_table(&size);
@@ -132,34 +152,12 @@ static const SmbiosHeader* get_smbios_table(uint8_t type, size_t min_size, uint6
return header; /* Yay! */
}
- /* Skip over formatted area. */
- size -= header->length;
- p += header->length;
+ const uint8_t *next = smbios_structure_end(p, size);
+ if (!next)
+ goto not_found;
- /* Special case: if there are no strings appended, we'll see two NUL bytes, skip over them */
- if (size >= 2 && p[0] == 0 && p[1] == 0) {
- size -= 2;
- p += 2;
- continue;
- }
-
- /* Skip over a populated string table. */
- bool first = true;
- for (;;) {
- const uint8_t *e = memchr(p, 0, size);
- if (!e)
- goto not_found;
-
- if (!first && e == p) {/* Double NUL byte means we've reached the end of the string table. */
- p++;
- size--;
- break;
- }
-
- size -= e + 1 - p;
- p = e + 1;
- first = false;
- }
+ size -= next - p;
+ p = next;
}
not_found:
@@ -169,6 +167,40 @@ not_found:
return NULL;
}
+void smbios_foreach(SmbiosForeachFunc func, void *userdata) {
+ assert(func);
+
+ uint64_t size;
+ const uint8_t *p = find_smbios_configuration_table(&size);
+ if (!p)
+ return;
+
+ /* Walks the SMBIOS table exactly once, invoking 'func' for every structure. 'func' receives the
+ * structure's header (which carries its type) and the structure's total length (formatted area +
+ * trailing string set); returning false stops the iteration early. */
+
+ for (;;) {
+ if (size < sizeof(SmbiosHeader))
+ return;
+
+ const SmbiosHeader *header = (const SmbiosHeader *) p;
+
+ /* End of table. */
+ if (header->type == 127)
+ return;
+
+ const uint8_t *next = smbios_structure_end(p, size);
+ if (!next)
+ return;
+
+ if (!func(header, next - p, userdata))
+ return;
+
+ size -= next - p;
+ p = next;
+ }
+}
+
bool smbios_in_hypervisor(void) {
/* Look up BIOS Information (Type 0). */
const SmbiosTableType0 *type0 = (const SmbiosTableType0 *) get_smbios_table(0, sizeof(SmbiosTableType0), /* ret_size_left= */ NULL);
diff --git a/src/boot/smbios.h b/src/boot/smbios.h
index 694ef568e6..226ebf758f 100644
--- a/src/boot/smbios.h
+++ b/src/boot/smbios.h
@@ -3,10 +3,35 @@
#include "efi.h"
+typedef struct {
+ uint8_t type;
+ uint8_t length;
+ uint8_t handle[2];
+} _packed_ SmbiosHeader;
+
+typedef struct {
+ SmbiosHeader header;
+ uint8_t manufacturer;
+ uint8_t product_name;
+ uint8_t version;
+ uint8_t serial_number;
+ EFI_GUID uuid;
+ uint8_t wake_up_type;
+ uint8_t sku_number;
+ uint8_t family;
+} _packed_ SmbiosTableType1;
+
bool smbios_in_hypervisor(void);
const char* smbios_find_oem_string(const char *name, const char *after);
+/* Invoked by smbios_foreach() for each SMBIOS structure. 'header' points at the structure (which
+ * carries its type), and 'size' is the structure's total length (formatted area + trailing string
+ * set). Returning false stops the iteration. */
+typedef bool (*SmbiosForeachFunc)(const SmbiosHeader *header, size_t size, void *userdata);
+
+void smbios_foreach(SmbiosForeachFunc func, void *userdata);
+
typedef struct RawSmbiosInfo {
const char *manufacturer;
const char *product_name;
diff --git a/src/boot/stub.c b/src/boot/stub.c
index 6411102ec4..712a82e739 100644
--- a/src/boot/stub.c
+++ b/src/boot/stub.c
@@ -14,6 +14,7 @@
#include "iovec-util.h"
#include "linux.h"
#include "measure.h"
+#include "measure-smbios.h"
#include "memory-util.h"
#include "part-discovery.h"
#include "pe.h"
@@ -116,6 +117,7 @@ static void export_stub_variables(EFI_LOADED_IMAGE_PROTOCOL *loaded_image, unsig
EFI_STUB_FEATURE_MULTI_PROFILE_UKI | /* We grok the "@1" profile command line argument */
EFI_STUB_FEATURE_REPORT_STUB_PARTITION | /* We set StubDevicePartUUID + StubImageIdentifier */
EFI_STUB_FEATURE_REPORT_URL | /* We set StubDeviceURL + LoaderDeviceURL */
+ EFI_STUB_FEATURE_SMBIOS_MEASURED | /* We measure SMBIOS data into PCR 1 */
0;
assert(loaded_image);
@@ -1252,6 +1254,10 @@ static EFI_STATUS run(EFI_HANDLE image) {
export_common_variables(loaded_image);
export_stub_variables(loaded_image, profile);
+ /* Measure SMBIOS data into PCR 1, unless sd-boot already did so in the same boot (tracked via
+ * the LoaderPcrSMBIOS EFI variable). */
+ measure_smbios();
+
/* First load the base device tree, then fix it up using addons - global first, then per-UKI. */
install_embedded_devicetree(loaded_image, sections, &dt_state);
install_addon_devicetrees(&dt_state, dt_addons, n_dt_addons, ¶meters_measured);
diff --git a/src/bootctl/bootctl-status.c b/src/bootctl/bootctl-status.c
index 4aac25a74d..f1c75c4a65 100644
--- a/src/bootctl/bootctl-status.c
+++ b/src/bootctl/bootctl-status.c
@@ -408,6 +408,7 @@ int verb_status(int argc, char *argv[], uintptr_t _data, void *userdata) {
{ EFI_LOADER_FEATURE_TYPE1_UKI_URL, "Support Type #1 uki-url field" },
{ EFI_LOADER_FEATURE_TPM2_ACTIVE_PCR_BANKS, "Loader reports active TPM2 PCR banks" },
{ EFI_LOADER_FEATURE_KEYBOARD_LAYOUT, "Loader reports firmware keyboard layout" },
+ { EFI_LOADER_FEATURE_SMBIOS_MEASURED, "Loader measures SMBIOS information" },
};
static const struct {
uint64_t flag;
@@ -425,6 +426,7 @@ int verb_status(int argc, char *argv[], uintptr_t _data, void *userdata) {
{ EFI_STUB_FEATURE_CMDLINE_SMBIOS, "Pick up .cmdline from SMBIOS Type 11" },
{ EFI_STUB_FEATURE_DEVICETREE_ADDONS, "Pick up .dtb from addons" },
{ EFI_STUB_FEATURE_MULTI_PROFILE_UKI, "Stub understands profile selector" },
+ { EFI_STUB_FEATURE_SMBIOS_MEASURED, "Stub measures SMBIOS information" },
};
_cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL, *stub = NULL, *stub_path = NULL,
*current_entry = NULL, *oneshot_entry = NULL, *preferred_entry = NULL, *default_entry = NULL, *sysfail_entry = NULL,
diff --git a/src/fundamental/efivars.h b/src/fundamental/efivars.h
index eddda7c23a..88bc97d75d 100644
--- a/src/fundamental/efivars.h
+++ b/src/fundamental/efivars.h
@@ -30,6 +30,7 @@
#define EFI_LOADER_FEATURE_TPM2_ACTIVE_PCR_BANKS (UINT64_C(1) << 18)
#define EFI_LOADER_FEATURE_ENTRY_PREFERRED (UINT64_C(1) << 19)
#define EFI_LOADER_FEATURE_KEYBOARD_LAYOUT (UINT64_C(1) << 20)
+#define EFI_LOADER_FEATURE_SMBIOS_MEASURED (UINT64_C(1) << 21)
/* Features of the stub, i.e. systemd-stub */
#define EFI_STUB_FEATURE_REPORT_BOOT_PARTITION (UINT64_C(1) << 0)
@@ -44,6 +45,7 @@
#define EFI_STUB_FEATURE_MULTI_PROFILE_UKI (UINT64_C(1) << 9)
#define EFI_STUB_FEATURE_REPORT_STUB_PARTITION (UINT64_C(1) << 10)
#define EFI_STUB_FEATURE_REPORT_URL (UINT64_C(1) << 11)
+#define EFI_STUB_FEATURE_SMBIOS_MEASURED (UINT64_C(1) << 12)
typedef enum SecureBootMode {
SECURE_BOOT_UNSUPPORTED,
diff --git a/src/fundamental/tpm2-pcr.h b/src/fundamental/tpm2-pcr.h
index 1d39ba5959..72835e886b 100644
--- a/src/fundamental/tpm2-pcr.h
+++ b/src/fundamental/tpm2-pcr.h
@@ -56,3 +56,12 @@ enum {
/* The tag used for EV_EVENT_TAG event log records covering the selected UKI profile */
#define UKI_PROFILE_EVENT_TAG_ID UINT32_C(0x13aed6db)
+
+/* The tag used for EV_EVENT_TAG event log records covering the SMBIOS type 1 (system information) structure */
+#define SMBIOS_TYPE1_EVENT_TAG_ID UINT32_C(0xd5cb7cbc)
+
+/* The tag used for EV_EVENT_TAG event log records covering the SMBIOS type 2 (baseboard information) structure */
+#define SMBIOS_TYPE2_EVENT_TAG_ID UINT32_C(0xe0d47bc8)
+
+/* The tag used for EV_EVENT_TAG event log records covering SMBIOS type 11 (OEM strings) structures */
+#define SMBIOS_TYPE11_EVENT_TAG_ID UINT32_C(0xc0b3bd23)
diff --git a/src/pcrlock/pcrlock.c b/src/pcrlock/pcrlock.c
index fa2ee54c57..a0d415209c 100644
--- a/src/pcrlock/pcrlock.c
+++ b/src/pcrlock/pcrlock.c
@@ -8,6 +8,7 @@
#include "sd-varlink.h"
#include "alloc-util.h"
+#include "ansi-color.h"
#include "ask-password-api.h"
#include "bitfield.h"
#include "blockdev-util.h"
@@ -29,7 +30,9 @@
#include "format-table.h"
#include "format-util.h"
#include "fs-util.h"
+#include "glyph-util.h"
#include "gpt.h"
+#include "help-util.h"
#include "hexdecoct.h"
#include "initrd-util.h"
#include "json-util.h"
@@ -45,7 +48,6 @@
#include "pcrextend-util.h"
#include "pcrlock-firmware.h"
#include "pe-binary.h"
-#include "pretty-print.h"
#include "proc-cmdline.h"
#include "recovery-key.h"
#include "sort-util.h"
@@ -744,6 +746,23 @@ static int event_log_record_extract_firmware_description(EventLogRecord *rec) {
break;
}
+ /* SMBIOS structures measured by sd-boot/sd-stub. The tagged event payload is just a
+ * constant identifying string ("smbios:typeN"), hence don't show it. */
+ case SMBIOS_TYPE1_EVENT_TAG_ID:
+ if (!strextend_with_separator(&rec->description, ", ", "systemd: SMBIOS system information (type 1)"))
+ return log_oom();
+ break;
+
+ case SMBIOS_TYPE2_EVENT_TAG_ID:
+ if (!strextend_with_separator(&rec->description, ", ", "systemd: SMBIOS baseboard information (type 2)"))
+ return log_oom();
+ break;
+
+ case SMBIOS_TYPE11_EVENT_TAG_ID:
+ if (!strextend_with_separator(&rec->description, ", ", "systemd: SMBIOS OEM strings (type 11)"))
+ return log_oom();
+ break;
+
default: {
_cleanup_free_ char *s = NULL;
@@ -5132,14 +5151,9 @@ static int verb_lock_raw(int argc, char *argv[], uintptr_t _data, void *userdata
}
static int help(void) {
- _cleanup_free_ char *link = NULL;
_cleanup_(table_unrefp) Table *commands = NULL, *protections = NULL, *options = NULL;
int r;
- r = terminal_urlify_man("systemd-pcrlock", "8", &link);
- if (r < 0)
- return log_oom();
-
r = verbs_get_help_table(&commands);
if (r < 0)
return r;
@@ -5154,28 +5168,25 @@ static int help(void) {
(void) table_sync_column_widths(0, commands, protections, options);
- printf("%s [OPTIONS...] COMMAND ...\n"
- "\n%sManage a TPM2 PCR lock.%s\n",
- program_invocation_short_name,
- ansi_highlight(),
- ansi_normal());
+ help_cmdline("[OPTIONS...] COMMAND ...");
+ help_abstract("Manage a TPM2 PCR lock.");
- printf("\n%sCommands:%s\n", ansi_underline(), ansi_normal());
+ help_section("Commands");
r = table_print_or_warn(commands);
if (r < 0)
return r;
- printf("\n%sProtections:%s\n", ansi_underline(), ansi_normal());
+ help_section("Protections");
r = table_print_or_warn(protections);
if (r < 0)
return r;
- printf("\n%sOptions:%s\n", ansi_underline(), ansi_normal());
+ help_section("Options");
r = table_print_or_warn(options);
if (r < 0)
return r;
- printf("\nSee the %s for details.\n", link);
+ help_man_page_reference("systemd-pcrlock", "8");
return 0;
}