]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: trust SMBIOS credentials under Intel TDX 42835/head
authorPaul Meyer <katexochen0@gmail.com>
Tue, 30 Jun 2026 11:30:08 +0000 (13:30 +0200)
committerPaul Meyer <katexochen0@gmail.com>
Wed, 1 Jul 2026 14:09:27 +0000 (16:09 +0200)
SMBIOS OEM strings are host-controlled and normally distrusted by PID1
in confidential VMs. Under TDX, however, the SMBIOS table (including
Type 11) is measured into RTMR0 by the firmware (TDVF), so a remote
verifier can detect host tampering with credentials delivered this
way. Accept them there, while keeping fw_cfg distrusted as those
items are not measured even on TDX.

This lets systemd-vmspawn deliver credentials to TDX guests via the
normal SMBIOS path, unlike SNP which requires the initrd cpio channel.

Signed-off-by: Paul Meyer <katexochen0@gmail.com>
man/systemd-vmspawn.xml
src/core/import-creds.c
src/vmspawn/vmspawn.c

index 64cfab8294c4cbbc8560dac1b00b4e9b8b810a4e..d8afb9d0e157fe4a0597a3f302929c0ab0295173 100644 (file)
           When booting a UKI, the whole UKI PE is measured into RTMR 1, and the loaded sections are
           measured individually by <command>systemd-stub</command> into RTMR 2. For direct linux boot,
           firmware measures the kernel PE into RTMR 1, and the Linux EFI stub measures initrd and
-          command line into RTMR 2. A vTPM, if attached via <option>--tpm=</option>, must be treated
-          as untrusted by the guest. To obtain TD Quotes for remote attestation, the guest is wired
-          to the host's local TDX Quote Generation Service automatically: the unix socket
-          up <filename>/run/tdx-qgs/qgs.socket</filename> is used if it exists, otherwise vsock port 4050
-          on the host (cid 2). If the QGS is listening on neither channel, the guest's quote requests will
-          fail.
+          command line into RTMR 2. Credentials passed via <option>--set-credential=</option> or
+          <option>--load-credential=</option> are delivered through SMBIOS Type 11 OEM strings, which the
+          firmware (TDVF) measures into RTMR 0. This channel is measured but not confidential with respect
+          to the host or VMM, since the host assembles the SMBIOS table. A vTPM, if attached via
+          <option>--tpm=</option>, must be treated as untrusted by the guest. To obtain TD Quotes for
+          remote attestation, the guest is wired to the host's local TDX Quote Generation Service
+          automatically: the unix socket up <filename>/run/tdx-qgs/qgs.socket</filename> is used if it
+          exists, otherwise vsock port 4050 on the host (cid 2). If the QGS is listening on neither
+          channel, the guest's quote requests will fail.
           <xi:include href="version-info.xml" xpointer="v262"/></para>
 
           <xi:include href="version-info.xml" xpointer="v261"/></listitem>
index 98675d2fc52e4b0d42f7ea96c498a3eb5d99c779..b8db23b85a40cdfab7bc9c1185dc13b7b9051a8c 100644 (file)
@@ -622,7 +622,14 @@ static int import_credentials_smbios(ImportCredentialsContext *c) {
         if (detect_container() > 0) /* don't access /sys/ in a container */
                 return 0;
 
-        if (detect_confidential_virtualization() > 0) /* don't trust firmware if confidential VMs */
+        /* SMBIOS OEM strings are host-controlled, so by default we don't trust them in a confidential VM.
+         * Exception: under Intel TDX the SMBIOS table (including Type 11) is measured into RTMR0 by the
+         * firmware (TDVF's SmbiosMeasurementDxe) on direct boot, and additionally by systemd-stub on UKI
+         * boot, so a remote verifier can detect host tampering with these credentials. As with the kernel
+         * command line (also host-influenced but measured), we can't and needn't locally verify the
+         * measurement actually happened; the verifier anchors the firmware's behaviour via MRTD. */
+        ConfidentialVirtualization cv = detect_confidential_virtualization();
+        if (cv > 0 && cv != CONFIDENTIAL_VIRTUALIZATION_TDX)
                 return 0;
 
         for (unsigned i = 0;; i++) {
index 2c35fef032043340df36935f5bea522e155f1c44..00df10874ca026d929cab5cd1da94504bee05a64 100644 (file)
@@ -3579,7 +3579,7 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
          * confidential VMs. Instead, package credentials into a cpio archive appended to the initrd
          * (mirroring what systemd-stub does for ESP credentials) so they enter the launch measurement
          * via QEMU's "kernel-hashes=on". The new initrd path requires a guest PID1 that knows about
-         * /.extra/system_credentials/, so we keep this scoped to SNP for now. Non-CoCo guests
+         * /.extra/system_credentials/, so we keep this scoped to SNP for now. Non-SNP guests
          * continue to use the SMBIOS path below, which works with older systemd versions too.
          * Must run after all credential-mutating calls above so the cpio captures the complete set. */
         bool use_initrd_cpio = arg_confidential_computing == COCO_AMD_SEV_SNP &&