diff --git a/man/systemd-vmspawn.xml b/man/systemd-vmspawn.xml
index 66c49352a9..64cfab8294 100644
--- a/man/systemd-vmspawn.xml
+++ b/man/systemd-vmspawn.xml
@@ -379,7 +379,11 @@
measured individually by systemd-stub 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 , must be treated
- as untrusted by the guest.
+ 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 /run/tdx-qgs/qgs.socket 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.
diff --git a/src/vmspawn/vmspawn.c b/src/vmspawn/vmspawn.c
index 41cf611aa9..2c35fef032 100644
--- a/src/vmspawn/vmspawn.c
+++ b/src/vmspawn/vmspawn.c
@@ -105,6 +105,13 @@
#define DISK_SERIAL_MAX_LEN_NVME 20
#define DISK_SERIAL_MAX_LEN_VIRTIO_BLK 20
+/* Well-known endpoints for the host's TDX Quote Generation Service (qgsd), auto-discovered so the
+ * guest can obtain TD Quotes. The Intel reference qgsd listens on a unix socket; the common
+ * deployment listens on vsock port 4050 (cid 2 = host). */
+#define TDX_QGS_UNIX_SOCKET_PATH "/run/tdx-qgs/qgs.socket"
+#define TDX_QGS_VSOCK_CID "2"
+#define TDX_QGS_VSOCK_PORT "4050"
+
/* First and one-past-last pcie.0 device-numbers used for multifunction-packed
* pcie-root-ports. Sits above the auto-assigned virtio devices (0x01-0x03) and
* below 0x1f, which q35 reserves for ICH9 LPC at 0x1f.0 (single-function). */
@@ -2936,6 +2943,36 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
"qom-type", "tdx-guest");
if (r < 0)
return r;
+
+ /* The guest needs a connection to the TDX Quote Generation Service (QGS) running on
+ * the host to obtain TD Quotes (e.g. via the systemd-report-sign-tsm). There are two
+ * well-known interfaces for QGS: a well-known unix socket, or vsock port 4050. QEMU
+ * only connects on a GetQuote request, and pointing at an absent QGS is harmless,
+ * the request just fails and the guest gets no quote. */
+ r = is_socket(TDX_QGS_UNIX_SOCKET_PATH);
+ if (r < 0)
+ log_debug_errno(r, "Failed to check for QGS socket '%s', falling back to vsock: %m", TDX_QGS_UNIX_SOCKET_PATH);
+ if (r > 0) {
+ r = qemu_config_key(config_file, "quote-generation-socket.type", "unix");
+ if (r < 0)
+ return r;
+ r = qemu_config_key(config_file, "quote-generation-socket.path", TDX_QGS_UNIX_SOCKET_PATH);
+ if (r < 0)
+ return r;
+ log_debug("Using TDX Quote Generation Service at unix socket %s.", TDX_QGS_UNIX_SOCKET_PATH);
+ } else {
+ r = qemu_config_key(config_file, "quote-generation-socket.type", "vsock");
+ if (r < 0)
+ return r;
+ r = qemu_config_key(config_file, "quote-generation-socket.cid", TDX_QGS_VSOCK_CID);
+ if (r < 0)
+ return r;
+ r = qemu_config_key(config_file, "quote-generation-socket.port", TDX_QGS_VSOCK_PORT);
+ if (r < 0)
+ return r;
+ log_debug("No QGS unix socket found, pointing TDX quote generation at vsock %s:%s.",
+ TDX_QGS_VSOCK_CID, TDX_QGS_VSOCK_PORT);
+ }
}
unsigned child_cid = arg_vsock_cid;