From: Lennart Poettering Date: Mon, 9 Mar 2026 17:53:09 +0000 (+0100) Subject: core: introduce ConditionSecurity=measured-os X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=cd911bec6eec21a2cc775c98bf599ea38cb1fa1f;p=thirdparty%2Fsystemd.git core: introduce ConditionSecurity=measured-os So far we always conditioned our TPM magic on the UKI having detected TPM support in the firmware. This is a bit limiting when we want to support a software TPM that is not visible to the firmware. Hence let's split this up, and add a separate control that can be set via the kernel command line. However, as before, let's by default inherit the firmare TPM discovery state into it, to retain the current behaviour unless overriden. With this in place, boot with "systemd.tpm2_measured_os=1 systemd.tpm2_software_fallback=1" on the kernel cmdline to get the swtpm fallback and then a measured OS based on it. --- diff --git a/man/kernel-command-line.xml b/man/kernel-command-line.xml index 1292bbfbee1..088ce241540 100644 --- a/man/kernel-command-line.xml +++ b/man/kernel-command-line.xml @@ -792,6 +792,18 @@ + + systemd.tpm2_measured_os= + + Controls whether to execute various boot and runtime TPM PCR measurements. Takes a + boolean argument. If not specified explicitly this behaviour is enabled automatically in case + systemd-stub7 is + used and it succeeded in doing pre-boot measurements of the booted UKI, and otherwise + disabled. + + + + systemd.factory_reset= diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index 37022ecc1c3..8bbff2f210a 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -1605,6 +1605,10 @@ measured-uki Unified Kernel Image with PCR 11 Measurements, as per systemd-stub7. + + measured-os + OS PCR measurements enabled. This is typically equivalent to measured-uki, however may also be set explicitly via the systemd.tpm2_measured_os= kernel command line switch, see kernel-command-line7 for details. The various system services doing boot and runtime measurements are conditioned on this flag. + diff --git a/src/bootctl/bootctl-status.c b/src/bootctl/bootctl-status.c index 4184e3d4249..178bffb3652 100644 --- a/src/bootctl/bootctl-status.c +++ b/src/bootctl/bootctl-status.c @@ -477,6 +477,16 @@ int verb_status(int argc, char *argv[], uintptr_t _data, void *userdata) { printf(" Measured UKI: %sfailed%s (%m)\n", ansi_highlight_red(), ansi_normal()); } + k = efi_measured_os(LOG_DEBUG); + if (k > 0) + printf(" Measured OS: %syes%s\n", ansi_highlight_green(), ansi_normal()); + else if (k == 0) + printf(" Measured OS: no\n"); + else { + errno = -k; + printf(" Measured OS: %sfailed%s (%m)\n", ansi_highlight_red(), ansi_normal()); + } + k = efi_get_reboot_to_firmware(); if (k > 0) printf(" Boot into FW: %sactive%s\n", ansi_highlight_yellow(), ansi_normal()); diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index bda9a8cc84a..64cd3813b87 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -1030,11 +1030,11 @@ static int measure_volume_key( return 0; } - r = efi_measured_uki(LOG_WARNING); + r = efi_measured_os(LOG_WARNING); if (r < 0) return r; if (r == 0) { - log_debug("Kernel stub did not measure kernel image into the expected PCR, skipping userspace volume key measurement, too."); + log_debug("OS measurements not explicitly requested and kernel stub did not measure kernel image into the expected PCR, skipping userspace volume key measurement, too."); return 0; } @@ -1109,11 +1109,11 @@ static int measure_keyslot( } #if HAVE_TPM2 - r = efi_measured_uki(LOG_WARNING); + r = efi_measured_os(LOG_WARNING); if (r < 0) return r; if (r == 0) { - log_debug("Kernel stub did not measure kernel image into the expected PCR, skipping userspace key slot measurement, too."); + log_debug("OS measurements not explicitly requested and kernel stub did not measure kernel image into the expected PCR, skipping userspace key slot measurement, too."); return 0; } diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index d60db7e9c1d..1bfebf3c408 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -672,9 +672,9 @@ static int add_mount( } if (flags & MOUNT_PCRFS) { - r = efi_measured_uki(LOG_WARNING); + r = efi_measured_os(LOG_WARNING); if (r == 0) - log_debug("Kernel stub did not measure kernel image into PCR, skipping userspace measurement, too."); + log_debug("OS measurements not explicitly requested and kernel stub did not measure kernel image into PCR, skipping userspace measurement, too."); else if (r > 0) { r = generator_hook_up_pcrfs(dest, where, target_unit); if (r < 0) diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index a87b5140805..6716a8d1aaf 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -115,11 +115,13 @@ static int add_cryptsetup( return log_oom(); } - r = efi_measured_uki(LOG_WARNING); - if (r > 0) + r = efi_measured_os(LOG_WARNING); + if (r > 0) { /* Enable TPM2 based unlocking automatically, if we have a TPM. See #30176. */ if (!strextend_with_separator(&options, ",", "tpm2-device=auto")) return log_oom(); + } else if (r == 0) + log_debug("Will not enable TPM based unlocking of volume '%s', OS measurements are not explicitly requested and not booted via systemd-stub with measurements enabled.", id); if (FLAGS_SET(flags, MOUNT_MEASURE)) { /* We only measure the root volume key into PCR 15 if we are booted with sd-stub (i.e. in a @@ -130,7 +132,7 @@ static int add_cryptsetup( if (!strextend_with_separator(&options, ",", "tpm2-measure-pcr=yes,tpm2-measure-keyslot-nvpcr=yes")) return log_oom(); if (r == 0) - log_debug("Will not measure volume key of volume '%s', not booted via systemd-stub with measurements enabled.", id); + log_debug("Will not measure volume key of volume '%s', as OS measurements are not explicitly requested and not booted via systemd-stub with measurements enabled.", id); } r = generator_write_cryptsetup_service_section(f, id, what, NULL, options); @@ -240,11 +242,11 @@ static int add_veritysetup( return log_oom(); if (FLAGS_SET(flags, MOUNT_MEASURE)) { - r = efi_measured_uki(LOG_WARNING); + r = efi_measured_os(LOG_WARNING); if (r > 0 && !strextend_with_separator(&options, ",", "tpm2-measure-nvpcr=yes")) return log_oom(); - if (r == 0) - log_debug("Will not measure root hash/signature of volume '%s', not booted via systemd-stub with measurements enabled.", id); + else if (r == 0) + log_debug("Will not measure root hash/signature of volume '%s', OS measurements not explicitly requested and not booted via systemd-stub with measurements enabled.", id); } r = generator_write_veritysetup_service_section( diff --git a/src/hibernate-resume/hibernate-resume-generator.c b/src/hibernate-resume/hibernate-resume-generator.c index 79c7d41bb45..998c8e84d95 100644 --- a/src/hibernate-resume/hibernate-resume-generator.c +++ b/src/hibernate-resume/hibernate-resume-generator.c @@ -86,7 +86,7 @@ static int add_dissected_swap_cryptsetup(void) { r = generator_write_cryptsetup_service_section( f, "swap", DISSECTED_SWAP_LUKS_DEVICE, /* key_file= */ NULL, - efi_measured_uki(LOG_DEBUG) > 0 ? "tpm2-device=auto" : NULL); + efi_measured_os(LOG_DEBUG) > 0 ? "tpm2-device=auto" : NULL); if (r < 0) return r; diff --git a/src/pcrextend/pcrextend.c b/src/pcrextend/pcrextend.c index c0b111a0964..8ec0a733c68 100644 --- a/src/pcrextend/pcrextend.c +++ b/src/pcrextend/pcrextend.c @@ -536,12 +536,12 @@ static int run(int argc, char *argv[]) { return EXIT_SUCCESS; } - /* Skip logic if sd-stub is not used, after all PCR 11 might have a very different purpose then. */ - r = efi_measured_uki(LOG_ERR); + /* Skip logic if measured OS functionality is not enabled. */ + r = efi_measured_os(LOG_ERR); if (r < 0) return r; if (r == 0) { - log_info("Kernel stub did not measure kernel image into PCR %i, skipping userspace measurement, too.", TPM2_PCR_KERNEL_BOOT); + log_info("OS measurements not explicitly requested and kernel stub did not measure kernel image into PCR %i, skipping userspace measurement, too.", TPM2_PCR_KERNEL_BOOT); return EXIT_SUCCESS; } diff --git a/src/shared/condition.c b/src/shared/condition.c index 903662edf1a..dd720c55bd9 100644 --- a/src/shared/condition.c +++ b/src/shared/condition.c @@ -741,6 +741,8 @@ static int condition_test_security(Condition *c, char **env) { return detect_confidential_virtualization() > 0; if (streq(c->parameter, "measured-uki")) return efi_measured_uki(LOG_DEBUG); + if (streq(c->parameter, "measured-os")) + return efi_measured_os(LOG_DEBUG); return false; } diff --git a/src/shared/efi-loader.c b/src/shared/efi-loader.c index 1f4fc665c03..ce10a44d34c 100644 --- a/src/shared/efi-loader.c +++ b/src/shared/efi-loader.c @@ -8,6 +8,7 @@ #include "log.h" #include "parse-util.h" #include "path-util.h" +#include "proc-cmdline.h" #include "stat-util.h" #include "string-util.h" #include "strv.h" @@ -312,6 +313,30 @@ int efi_measured_uki(int log_level) { #endif } +int efi_measured_os(int log_level) { +#if ENABLE_EFI + static int cached = -1; + int r; + + /* Returns if we shall enable our measurement machinery */ + + if (cached >= 0) + return cached; + + bool b; + r = proc_cmdline_get_bool("systemd.tpm2_measured_os", /* flags= */ 0, &b); + if (r < 0) + log_debug_errno(r, "Failed to parse systemd.tpm2_measured_os= kernel command line argument, ignoring: %m"); + else if (r > 0) + return (cached = b); + + /* If nothing is explicitly configured, just assume that if we booted with a measured UKI we also want a measured OS */ + return (cached = efi_measured_uki(log_level)); +#else + return log_full_errno(log_level, SYNTHETIC_ERRNO(EOPNOTSUPP), "Compiled without support for EFI"); +#endif +} + int efi_loader_get_config_timeout_one_shot(usec_t *ret) { #if ENABLE_EFI _cleanup_free_ char *v = NULL; diff --git a/src/shared/efi-loader.h b/src/shared/efi-loader.h index 5b614cd0a7e..abf8bdc49ef 100644 --- a/src/shared/efi-loader.h +++ b/src/shared/efi-loader.h @@ -15,6 +15,7 @@ int efi_loader_get_features(uint64_t *ret); int efi_stub_get_features(uint64_t *ret); int efi_measured_uki(int log_level); +int efi_measured_os(int log_level); int efi_loader_get_config_timeout_one_shot(usec_t *ret); int efi_loader_update_entry_one_shot_cache(char **cache, struct stat *cache_stat); diff --git a/units/systemd-pcrextend.socket b/units/systemd-pcrextend.socket index d429150eda0..0f4ab11e2fd 100644 --- a/units/systemd-pcrextend.socket +++ b/units/systemd-pcrextend.socket @@ -13,7 +13,7 @@ Documentation=man:systemd-pcrextend(8) DefaultDependencies=no After=tpm2.target Before=sockets.target -ConditionSecurity=measured-uki +ConditionSecurity=measured-os [Socket] ListenStream=/run/systemd/io.systemd.PCRExtend diff --git a/units/systemd-pcrfs-root.service.in b/units/systemd-pcrfs-root.service.in index f774c4c8bf6..88551d7ed08 100644 --- a/units/systemd-pcrfs-root.service.in +++ b/units/systemd-pcrfs-root.service.in @@ -15,7 +15,7 @@ Conflicts=shutdown.target After=tpm2.target systemd-pcrmachine.service Before=shutdown.target ConditionPathExists=!/etc/initrd-release -ConditionSecurity=measured-uki +ConditionSecurity=measured-os FailureAction=reboot-force [Service] diff --git a/units/systemd-pcrfs@.service.in b/units/systemd-pcrfs@.service.in index 3d18fe4d30e..38cc41976f6 100644 --- a/units/systemd-pcrfs@.service.in +++ b/units/systemd-pcrfs@.service.in @@ -16,7 +16,7 @@ Conflicts=shutdown.target After=%i.mount tpm2.target systemd-pcrfs-root.service Before=shutdown.target ConditionPathExists=!/etc/initrd-release -ConditionSecurity=measured-uki +ConditionSecurity=measured-os FailureAction=reboot-force [Service] diff --git a/units/systemd-pcrmachine.service.in b/units/systemd-pcrmachine.service.in index ea2561ef79e..d97afa69655 100644 --- a/units/systemd-pcrmachine.service.in +++ b/units/systemd-pcrmachine.service.in @@ -15,7 +15,7 @@ Conflicts=shutdown.target After=tpm2.target Before=sysinit.target shutdown.target ConditionPathExists=!/etc/initrd-release -ConditionSecurity=measured-uki +ConditionSecurity=measured-os FailureAction=reboot-force [Service] diff --git a/units/systemd-pcrnvdone.service.in b/units/systemd-pcrnvdone.service.in index e0dd9a88209..7593dedfed1 100644 --- a/units/systemd-pcrnvdone.service.in +++ b/units/systemd-pcrnvdone.service.in @@ -14,7 +14,7 @@ DefaultDependencies=no Conflicts=shutdown.target After=systemd-tpm2-setup-early.service systemd-tpm2-setup.service Before=sysinit.target shutdown.target -ConditionSecurity=measured-uki +ConditionSecurity=measured-os ConditionPathExists=!/etc/initrd-release FailureAction=reboot-force diff --git a/units/systemd-pcrphase-factory-reset.service.in b/units/systemd-pcrphase-factory-reset.service.in index 5dbcb0f53f1..2efd8830d32 100644 --- a/units/systemd-pcrphase-factory-reset.service.in +++ b/units/systemd-pcrphase-factory-reset.service.in @@ -14,7 +14,7 @@ DefaultDependencies=no Conflicts=shutdown.target After=tpm2.target Before=shutdown.target factory-reset.target -ConditionSecurity=measured-uki +ConditionSecurity=measured-os FailureAction=reboot-force [Service] diff --git a/units/systemd-pcrphase-initrd.service.in b/units/systemd-pcrphase-initrd.service.in index 5aba32128c0..cbb83314701 100644 --- a/units/systemd-pcrphase-initrd.service.in +++ b/units/systemd-pcrphase-initrd.service.in @@ -15,7 +15,7 @@ Conflicts=shutdown.target initrd-switch-root.target After=tpm2.target Before=sysinit.target cryptsetup-pre.target cryptsetup.target shutdown.target initrd-switch-root.target systemd-sysext.service ConditionPathExists=/etc/initrd-release -ConditionSecurity=measured-uki +ConditionSecurity=measured-os FailureAction=reboot-force [Service] diff --git a/units/systemd-pcrphase-storage-target-mode.service.in b/units/systemd-pcrphase-storage-target-mode.service.in index 52b53e5b819..b4330c560f5 100644 --- a/units/systemd-pcrphase-storage-target-mode.service.in +++ b/units/systemd-pcrphase-storage-target-mode.service.in @@ -15,7 +15,7 @@ Conflicts=shutdown.target After=tpm2.target Before=shutdown.target ConditionPathExists=/etc/initrd-release -ConditionSecurity=measured-uki +ConditionSecurity=measured-os FailureAction=reboot-force [Service] diff --git a/units/systemd-pcrphase-sysinit.service.in b/units/systemd-pcrphase-sysinit.service.in index 4a01279159d..aa4d3640981 100644 --- a/units/systemd-pcrphase-sysinit.service.in +++ b/units/systemd-pcrphase-sysinit.service.in @@ -15,7 +15,7 @@ Conflicts=shutdown.target After=sysinit.target tpm2.target Before=basic.target shutdown.target ConditionPathExists=!/etc/initrd-release -ConditionSecurity=measured-uki +ConditionSecurity=measured-os FailureAction=reboot-force [Service] diff --git a/units/systemd-pcrphase.service.in b/units/systemd-pcrphase.service.in index 43459a2fccb..b2f925d40f4 100644 --- a/units/systemd-pcrphase.service.in +++ b/units/systemd-pcrphase.service.in @@ -13,7 +13,7 @@ Documentation=man:systemd-pcrphase.service(8) After=remote-fs.target remote-cryptsetup.target tpm2.target Before=systemd-user-sessions.service ConditionPathExists=!/etc/initrd-release -ConditionSecurity=measured-uki +ConditionSecurity=measured-os FailureAction=reboot-force [Service] diff --git a/units/systemd-pcrproduct.service.in b/units/systemd-pcrproduct.service.in index 09e446c2a01..2562dea18fe 100644 --- a/units/systemd-pcrproduct.service.in +++ b/units/systemd-pcrproduct.service.in @@ -16,7 +16,7 @@ After=tpm2.target Before=sysinit.target shutdown.target RequiresMountsFor=/var/lib/systemd/nvpcr ConditionPathExists=!/etc/initrd-release -ConditionSecurity=measured-uki +ConditionSecurity=measured-os [Service] Type=oneshot diff --git a/units/systemd-tpm2-clear.service.in b/units/systemd-tpm2-clear.service.in index a47d99ac8e7..501846180c9 100644 --- a/units/systemd-tpm2-clear.service.in +++ b/units/systemd-tpm2-clear.service.in @@ -22,7 +22,7 @@ ConditionPathExists=/sys/class/tpm/tpm0/ppi/request # derive here from the fact that UKIs are used. Because if they do they are OK # with our SRK initialization and our PCR measurements, and hence should also # be OK with our TPM resets. -ConditionSecurity=measured-uki +ConditionSecurity=measured-os [Service] Type=oneshot diff --git a/units/systemd-tpm2-setup-early.service.in b/units/systemd-tpm2-setup-early.service.in index ce1ee94cc49..6b7ef34b8c0 100644 --- a/units/systemd-tpm2-setup-early.service.in +++ b/units/systemd-tpm2-setup-early.service.in @@ -14,7 +14,7 @@ DefaultDependencies=no Conflicts=shutdown.target After=tpm2.target systemd-pcrphase-initrd.service Before=sysinit.target shutdown.target -ConditionSecurity=measured-uki +ConditionSecurity=measured-os ConditionPathExists=!/run/systemd/tpm2-srk-public-key.pem [Service] diff --git a/units/systemd-tpm2-setup.service.in b/units/systemd-tpm2-setup.service.in index dff516832d3..4593211c1ef 100644 --- a/units/systemd-tpm2-setup.service.in +++ b/units/systemd-tpm2-setup.service.in @@ -15,7 +15,7 @@ Conflicts=shutdown.target After=tpm2.target systemd-tpm2-setup-early.service systemd-remount-fs.service Before=sysinit.target shutdown.target RequiresMountsFor=/var/lib/systemd -ConditionSecurity=measured-uki +ConditionSecurity=measured-os ConditionPathExists=!/etc/initrd-release [Service]