From 867e64737a1761e313c371abfb43ab2c04b9e568 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Nov 2025 14:47:57 +0100 Subject: [PATCH] units: measure a separator event into PCR 9 after completing NvPCR initialization We do this in a separate service (rather than inside of systemd-tpm2-setup), since we want failures of this measurement to result in an instant reboot, like for most our measurements. Failures to initialize nvpcrs, or allocate an SRK are somewhat OK (and more likely), as long as this separator communicates clearly where they have to have taken place, if they worked. --- docs/TPM2_PCR_MEASUREMENTS.md | 9 +++++++++ man/rules/meson.build | 1 + man/systemd-pcrphase.service.xml | 5 +++++ src/shared/tpm2-util.c | 15 ++++++++------- src/shared/tpm2-util.h | 1 + units/meson.build | 5 +++++ units/systemd-pcrnvdone.service.in | 24 ++++++++++++++++++++++++ 7 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 units/systemd-pcrnvdone.service.in diff --git a/docs/TPM2_PCR_MEASUREMENTS.md b/docs/TPM2_PCR_MEASUREMENTS.md index 7b29069a7e..b05739a8c7 100644 --- a/docs/TPM2_PCR_MEASUREMENTS.md +++ b/docs/TPM2_PCR_MEASUREMENTS.md @@ -260,6 +260,15 @@ colon-separated strings, identifying the file system type, UUID, label as well as the GPT partition entry UUID, entry type UUID and entry label (in UTF-8, without trailing NUL bytes). +### PCR 9, NvPCR initialization separator + +After completion of `systemd-tpm2-setup.service` (which initializes all NvPCRs +and measures their initial state) at arly boot the `systemd-pcrnvdone.service` +service will measure a separator event into PCR 9, isolating the early-boot +NvPCR initializations from any later additions. + +→ **Measured hash** covers the string `nvpcr-separator`. + ## PCR/NvPCR Measurements Made by `systemd-cryptsetup` (Userspace) ### PCR 15, volume key diff --git a/man/rules/meson.build b/man/rules/meson.build index 26eddb7791..6ffc088453 100644 --- a/man/rules/meson.build +++ b/man/rules/meson.build @@ -1106,6 +1106,7 @@ manpages = [ 'systemd-pcrfs-root.service', 'systemd-pcrfs@.service', 'systemd-pcrmachine.service', + 'systemd-pcrnvdone.service', 'systemd-pcrphase-initrd.service', 'systemd-pcrphase-sysinit.service'], 'ENABLE_BOOTLOADER HAVE_OPENSSL HAVE_TPM2'], diff --git a/man/systemd-pcrphase.service.xml b/man/systemd-pcrphase.service.xml index 7832e10f85..1d543fe403 100644 --- a/man/systemd-pcrphase.service.xml +++ b/man/systemd-pcrphase.service.xml @@ -24,6 +24,7 @@ systemd-pcrproduct.service systemd-pcrfs-root.service systemd-pcrfs@.service + systemd-pcrnvdone.service systemd-pcrextend Measure boot phases, machine ID, product UUID and file system identity into TPM PCRs and NvPCRs @@ -35,6 +36,7 @@ systemd-pcrmachine.service systemd-pcrfs-root.service systemd-pcrfs@.service + systemd-pcrnvdone.service /usr/lib/systemd/systemd-pcrextend STRING @@ -54,6 +56,9 @@ product UUID (as provided by one of SMBIOS, Devicetree, …) into a NvPCR named hardware. + systemd-pcrnvdone.service is a system service that measures a separator event + into PCR 9 once all NvPCRs have completed initialization. + systemd-pcrfs-root.service and systemd-pcrfs@.service are services that measure file system identity information (i.e. mount point, file system type, label and UUID, partition label and UUID) into PCR 15. systemd-pcrfs-root.service does so for diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c index ad61fd1d8b..1603b5f316 100644 --- a/src/shared/tpm2-util.c +++ b/src/shared/tpm2-util.c @@ -6420,13 +6420,14 @@ static int json_dispatch_tpm2_algorithm(const char *name, sd_json_variant *varia } static const char* tpm2_userspace_event_type_table[_TPM2_USERSPACE_EVENT_TYPE_MAX] = { - [TPM2_EVENT_PHASE] = "phase", - [TPM2_EVENT_FILESYSTEM] = "filesystem", - [TPM2_EVENT_VOLUME_KEY] = "volume-key", - [TPM2_EVENT_MACHINE_ID] = "machine-id", - [TPM2_EVENT_PRODUCT_ID] = "product-id", - [TPM2_EVENT_KEYSLOT] = "keyslot", - [TPM2_EVENT_NVPCR_INIT] = "nvpcr-init", + [TPM2_EVENT_PHASE] = "phase", + [TPM2_EVENT_FILESYSTEM] = "filesystem", + [TPM2_EVENT_VOLUME_KEY] = "volume-key", + [TPM2_EVENT_MACHINE_ID] = "machine-id", + [TPM2_EVENT_PRODUCT_ID] = "product-id", + [TPM2_EVENT_KEYSLOT] = "keyslot", + [TPM2_EVENT_NVPCR_INIT] = "nvpcr-init", + [TPM2_EVENT_NVPCR_SEPARATOR] = "nvpcr-separator", }; DEFINE_STRING_TABLE_LOOKUP(tpm2_userspace_event_type, Tpm2UserspaceEventType); diff --git a/src/shared/tpm2-util.h b/src/shared/tpm2-util.h index 8dfe87af07..59b7ed9984 100644 --- a/src/shared/tpm2-util.h +++ b/src/shared/tpm2-util.h @@ -145,6 +145,7 @@ typedef enum Tpm2UserspaceEventType { TPM2_EVENT_PRODUCT_ID, TPM2_EVENT_KEYSLOT, TPM2_EVENT_NVPCR_INIT, + TPM2_EVENT_NVPCR_SEPARATOR, _TPM2_USERSPACE_EVENT_TYPE_MAX, _TPM2_USERSPACE_EVENT_TYPE_INVALID = -EINVAL, } Tpm2UserspaceEventType; diff --git a/units/meson.build b/units/meson.build index bd788f6d0b..8e5b645f91 100644 --- a/units/meson.build +++ b/units/meson.build @@ -581,6 +581,11 @@ units = [ 'conditions' : ['ENABLE_BOOTLOADER', 'HAVE_OPENSSL', 'HAVE_TPM2'], 'symlinks' : ['sysinit.target.wants/'], }, + { + 'file' : 'systemd-pcrnvdone.service.in', + 'conditions' : ['ENABLE_BOOTLOADER', 'HAVE_OPENSSL', 'HAVE_TPM2'], + 'symlinks' : ['sysinit.target.wants/'], + }, { 'file' : 'systemd-tpm2-clear.service.in', 'conditions' : ['ENABLE_BOOTLOADER', 'HAVE_OPENSSL', 'HAVE_TPM2'], diff --git a/units/systemd-pcrnvdone.service.in b/units/systemd-pcrnvdone.service.in new file mode 100644 index 0000000000..e0dd9a8820 --- /dev/null +++ b/units/systemd-pcrnvdone.service.in @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=TPM PCR NvPCR Initialization Separator +Documentation=man:systemd-pcrnvdone.service(8) +DefaultDependencies=no +Conflicts=shutdown.target +After=systemd-tpm2-setup-early.service systemd-tpm2-setup.service +Before=sysinit.target shutdown.target +ConditionSecurity=measured-uki +ConditionPathExists=!/etc/initrd-release +FailureAction=reboot-force + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart={{LIBEXECDIR}}/systemd-pcrextend --graceful --pcr=kernel-initrd --event-type=nvpcr-separator nvpcr-separator