Skip to content

fix(attest): accept one vm_config, not competing copies - #1430

Merged
kvinwang merged 5 commits into
nextfrom
fix/kms-sign-cert-verified-app-info
Oct 9, 2026
Merged

kvinwang merged 5 commits into
nextfrom
fix/kms-sign-cert-verified-app-info

Conversation

@kvinwang

@kvinwang kvinwang commented Oct 3, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

A reader could find the VM config in more than one place, and different readers picked different copies:

  • Request vs attestation. KMS RPCs and the verifier receive a vm_config alongside an attestation that also carries one. Readers took the request copy whenever it was non-empty and never compared it with the attested one.
  • Top level vs nested. dstack-attest and dstack-mr also accepted a sys-config-shaped config, with the real config serialized under a vm_config key. The SEV-SNP parser in dstack-mr preferred the top-level fields, while the decoder in dstack-attest let the nested string replace the whole config. No producer in this repo emits that shape: attestations and requests both carry the flat sys_config.vm_config.

On SEV-SNP the second split is exploitable. Suppose a SignCert request carries the genuine top-level os_image_hash plus a nested {"os_image_hash": <other>}. Authorization checks the genuine hash against the launch measurement, and the certificate's app-info extension then claims <other>.

Fix

  • dstack_attest::resolve_vm_config(external, embedded): with one copy, use it; with two, require them to be identical. decode_vm_config, the SEV-SNP app-info decoder, the KMS SNP boot-info path and the verifier's launch binding all go through it.
  • Drop the nested vm_config shape from dstack-attest and dstack-mr, so a config has one layout and every field has one source. Inputs in the nested shape no longer parse.

Honest requests are unaffected, because every in-tree caller fills both copies from the same sys_config.vm_config string.

Compatibility

  • KMS now rejects a request vm_config that differs byte-for-byte from the attested one. Released guests never send such a pair: v0.5.6–v0.5.11 embed nothing during dstack-util setup and read the same .sys-config.json at runtime; v0.6.0 reads the same copy for both; older guests carry no embedded config.
  • Guests built from master between 1600846 and 08cc383 (Dec 2025 – Jan 2026, never tagged) embedded the whole sys-config and would now be rejected at runtime.
  • The verifier HTTP API is unaffected: it already ignores a top-level vm_config when an attestation is supplied.
  • The simulator's sys-config.json now carries the same vm_config its attestation fixture embeds.

Verification

  • New KMS test: build_boot_info_for_attestation rejects a request vm_config that differs from the attested one and accepts an identical copy.
  • cargo test --all-features passes for dstack-attest, dstack-mr, dstack-kms and dstack-verifier. cargo check --workspace --all-features --tests passes, and clippy (-D warnings) is clean on the touched crates.

@kvinwang kvinwang changed the title fix(kms): stamp the verified os_image_hash on SEV-SNP signed certs fix(attest): require every copy of the vm_config to agree Oct 3, 2026
@kvinwang
kvinwang force-pushed the fix/kms-sign-cert-verified-app-info branch 2 times, most recently from 891b798 to 88485ce Compare October 3, 2026 02:15
@kvinwang kvinwang changed the title fix(attest): require every copy of the vm_config to agree fix(attest): accept one vm_config, not competing copies Oct 3, 2026
@kvinwang kvinwang closed this Oct 3, 2026
@kvinwang
kvinwang force-pushed the fix/kms-sign-cert-verified-app-info branch from a24ab30 to 3c87784 Compare October 3, 2026 02:27
@kvinwang kvinwang reopened this Oct 3, 2026
…on embeds

The simulator served one vm_config from sys-config.json (Info, GetQuote,
the KMS cert client) while its attestation fixture embedded another. Now
that both copies must be identical, a request pairing the two would be
rejected.

Signed-off-by: Kevin Wang <wy721@qq.com>
Split parse_vm_config out of decode_vm_config_with_fallback so the SEV-SNP
decoder parses the already-resolved config directly, and let the verifier
decode the config it resolved instead of resolving it a second time.

Signed-off-by: Kevin Wang <wy721@qq.com>
@kvinwang
kvinwang merged commit d89cafe into next Oct 9, 2026
16 checks passed
@kvinwang
kvinwang deleted the fix/kms-sign-cert-verified-app-info branch October 9, 2026 06:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant