From a2c156803fcfe8c2d5b4fe4c2cb0cde925aa2921 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Tue, 1 Sep 2026 23:25:12 -0700 Subject: [PATCH] docs(verifier): correct the acpi_tables_verified contract The doc on the response field says the opposite of what the code does: /// It remains false for TDX lite, which replays ACPI DATA digests from /// the event log without validating the table contents. TDX lite has validated them since "verify TDX lite ACPI tables against the declared VM shape" (7f63d5fe03): it recomputes the three RTMR0 ACPI DATA digests from the declared VM shape, bails on any mismatch, and rebuilds RTMR0 from the recomputed values, so host-reported table content never reaches the expected measurement. verification.rs sets the flag true on both TDX paths; the comment was not updated with the change. This matters more than an ordinary stale comment because the field is part of the verifier's response, so it is what someone reads to decide how much a lite attestation actually proves. Reading it today leads to the conclusion that lite skips the check entirely. State what is true instead: both dstack TDX paths verify, and the flag is false only where the check does not apply -- GCP TDX, which measures through the vTPM, and the SEV-SNP and Nitro Enclave paths. Also extend the note on expected_rtmr0_acpi_hashes. It was accurate but read as if the lite path only ever replays the reported digests; say that the verifier calls this on both paths and treats a mismatch, or a VM shape the generator cannot model, as fatal. --- dstack/dstack-mr/src/tdx.rs | 2 ++ dstack/verifier/src/types.rs | 13 +++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/dstack/dstack-mr/src/tdx.rs b/dstack/dstack-mr/src/tdx.rs index 06aeb2b1c..3cdec25a0 100644 --- a/dstack/dstack-mr/src/tdx.rs +++ b/dstack/dstack-mr/src/tdx.rs @@ -103,6 +103,8 @@ fn machine_from_vm_config(vm_config: &VmConfig, ovmf_variant: OvmfVariant) -> cr /// otherwise replays the digests the guest reported in its event log, which /// makes those three RTMR0 entries self-consistent but unconstrained; comparing /// against these expected digests is what turns them into a verified value. +/// The verifier does exactly that on both TDX paths, and treats a mismatch -- +/// and a VM shape this cannot model -- as fatal rather than unverified. pub fn expected_rtmr0_acpi_hashes( vm_config: &VmConfig, ovmf_variant: OvmfVariant, diff --git a/dstack/verifier/src/types.rs b/dstack/verifier/src/types.rs index 34665d27a..d9d71442b 100644 --- a/dstack/verifier/src/types.rs +++ b/dstack/verifier/src/types.rs @@ -90,10 +90,15 @@ pub struct VerificationDetails { pub os_image_hash_verified: bool, /// Indicates that TDX ACPI table contents were verified. /// - /// This is true for the full-image TDX path, where the verifier recomputes - /// ACPI tables and checks the resulting RTMRs against the quote. It remains - /// false for TDX lite, which replays ACPI DATA digests from the event log - /// without validating the table contents. + /// Both dstack TDX paths set this. The full-image path recomputes the + /// tables and checks the resulting RTMRs against the quote. The lite path + /// recomputes the three RTMR0 ACPI DATA digests from the declared VM shape + /// and rejects the attestation when they disagree with the ones the guest + /// reported, then rebuilds RTMR0 from the recomputed digests, so neither + /// path lets host-reported table content reach the expected value. + /// + /// It stays false where the check does not apply: GCP TDX, which measures + /// through the vTPM instead, and the SEV-SNP and Nitro Enclave paths. pub acpi_tables_verified: bool, /// dev vs prod OS image, from metadata.json (bound to os_image_hash). None if not exposed. pub os_image_is_dev: Option,