Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- os: the Yocto guest-OS backend (`os/yocto/`) is deprecated in favor of mkosi (`os/mkosi/`), which is now the default and recommended backend. `os/build.sh` defaults to `--backend mkosi`, and `make os-image` / `make os-repro-check` build with mkosi. The Yocto builds move to `make os-image-yocto` / `make os-repro-check-yocto`; `make os-image-mkosi` / `make os-repro-check-mkosi` remain as aliases. Every Yocto entrypoint prints a deprecation warning, and the backend is kept only to rebuild existing Yocto images. The mkosi build still reads patches, units and scripts from `os/yocto/`, so the directory stays until those files move

### Removed
- verifier: the `debug` request field and the `acpi_tables` / `rtmr_debug` response fields. The per-event RTMR diff never had the events it diffed, so it reported every expected digest as missing. Requests that still send `debug` are accepted and the field is ignored.
- sdk: `TlsKeyOptions.path` in the JavaScript SDK. `GetTlsKeyArgs` has no such field and `getTlsKey` never read it, so a caller who set it was silently ignored. Breaking at the type level only, and only for code whose value was already being discarded. `deriveKey`'s `path` is a real, deprecated Tappd-era parameter and stays; the Python, Rust and Go v0 TLS-key options never carried one
- guest-agent: the `EmitEvent` RPC no longer records anything -- runtime RTMR3 events are system-owned in 0.6.0, so an app can no longer extend the measurement chain. The method itself stays on the unversioned path and always fails with an error naming the removal, rather than being deleted outright: a deleted method answers HTTP 404 `Service not found: EmitEvent`, which tells a 0.5.x caller nothing about why its events stopped being recorded, while the kept stub fails with a message naming the removal and pointing at `report_data`. **Breaking:** any app extending RTMR3 at runtime must stop; bind app data through `report_data` instead, which is what most callers wanted anyway
- gateway: `core.debug.insecure_skip_attestation`. It turned off both checks that make a gateway cluster a trust boundary: the node stopped asking its guest agent for its own app id, and every WaveKV sync and push, plus `ensure_from_gateway`, stopped checking the peer's. With it set, anything that could reach the sync routes could insert entries that replicated to every gateway in the cluster. It existed only because the integration suites could not run without it; they now run against a guest agent simulator and verify quotes through the production path, so nothing sets it. `docs/security/security-model.md` argues dstack's development switches are acceptable because they are visible in attestation measurements or public contract state -- that argument cannot cover the switch deciding whether attestation happens at all, which is why this one is deleted rather than documented. There is no replacement. **Breaking:** the config struct does not use `deny_unknown_fields`, so a leftover line is ignored rather than rejected, and what follows depends on why it was set. On a TDX host with a guest agent the gateway starts normally and peers that cannot present a verifiable app id stop being accepted. On a host with no guest agent -- the usual reason to have set it -- the gateway no longer starts at all, failing with `Failed to get app info`, because `my_app_id` is what every peer check compares against and a node that cannot learn its own identity must not come up without one. Remove the line and make sure every node can attest
Expand Down
2 changes: 1 addition & 1 deletion dstack/dstack-mr/cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ fn run_diagnose(config: &DiagnoseConfig) -> Result<()> {
let initrd = image_dir.join(&image_info.initrd).display().to_string();
let cmdline = dstack_mr::tdx::measured_kernel_cmdline(&image_info.cmdline);

// Same resolution order as the verifier (see verifier::compute_measurement_details):
// Same resolution order as the verifier (see verifier::compute_measurements):
// explicit vm_config.ovmf_variant > image_info.ovmf_variant > legacy default.
let ovmf_variant = vm
.ovmf_variant
Expand Down
5 changes: 1 addition & 4 deletions dstack/dstack-mr/src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
//
// SPDX-License-Identifier: Apache-2.0

use crate::acpi::Tables;
use crate::tdvf::Tdvf;
use crate::util::debug_print_log;
use crate::{kernel, OvmfVariant, RtmrLogs, TdxMeasurements};
Expand Down Expand Up @@ -115,7 +114,6 @@ pub struct VersionedOptions {
pub struct TdxMeasurementDetails {
pub measurements: TdxMeasurements,
pub rtmr_logs: RtmrLogs,
pub acpi_tables: Tables,
}

impl Machine<'_> {
Expand All @@ -132,7 +130,7 @@ impl Machine<'_> {

let mrtd = tdvf.mrtd(self).context("Failed to compute MR TD")?;

let (rtmr0_log, acpi_tables) = tdvf
let rtmr0_log = tdvf
.rtmr0_log(self)
.context("Failed to compute RTMR0 log")?;
debug_print_log("RTMR0", &rtmr0_log);
Expand Down Expand Up @@ -163,7 +161,6 @@ impl Machine<'_> {
rtmr2,
},
rtmr_logs: [rtmr0_log, rtmr1_log, rtmr2_log],
acpi_tables,
})
}
}
13 changes: 3 additions & 10 deletions dstack/dstack-mr/src/tdvf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use hex_literal::hex;
use scale::Decode;
use sha2::{Digest, Sha384};

use crate::acpi::Tables;
use crate::num::read_le;
use crate::{measure_log, measure_sha384, utf16_encode, Machine, OvmfVariant, RtmrLog};

Expand Down Expand Up @@ -497,23 +496,17 @@ impl<'a> Tdvf<'a> {

#[allow(dead_code)]
pub fn rtmr0(&self, machine: &Machine) -> Result<Vec<u8>> {
let (rtmr0_log, _) = self.rtmr0_log(machine)?;
Ok(measure_log(&rtmr0_log))
Ok(measure_log(&self.rtmr0_log(machine)?))
}

pub fn rtmr0_log(&self, machine: &Machine) -> Result<(RtmrLog, Tables)> {
pub fn rtmr0_log(&self, machine: &Machine) -> Result<RtmrLog> {
let tables = machine.build_tables()?;
let acpi_hashes = AcpiTableHashes {
tables: measure_sha384(&tables.tables),
rsdp: measure_sha384(&tables.rsdp),
loader: measure_sha384(&tables.loader),
};
let log = self.rtmr0_log_with_acpi_hashes(
machine.memory_size,
machine.ovmf_variant,
&acpi_hashes,
)?;
Ok((log, tables))
self.rtmr0_log_with_acpi_hashes(machine.memory_size, machine.ovmf_variant, &acpi_hashes)
}

pub(crate) fn rtmr0_log_with_acpi_hashes(
Expand Down
2 changes: 1 addition & 1 deletion dstack/kms/src/main_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ impl RpcHandler {
let mut detail = VerificationDetails::default();
self.state
.verifier
.verify_os_image_hash(vm_config, report, false, &mut detail)
.verify_os_image_hash(vm_config, report, &mut detail)
.await
.context("Failed to verify os image hash")?;
Ok(())
Expand Down
2 changes: 1 addition & 1 deletion dstack/tests/e2e/attestation/run-platform.sh
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ if ! ATTESTATION_HEX=$(dstack-util attest --report-data "$REPORT_DATA" --hex); t
exit 1
fi
jq -n --arg attestation "$ATTESTATION_HEX" \
'{attestation: $attestation, debug: true}' > "$WORK/request.json"
'{attestation: $attestation}' > "$WORK/request.json"

cat > "$WORK/verifier.toml" <<EOF_CONFIG
address = "127.0.0.1"
Expand Down
5 changes: 1 addition & 4 deletions dstack/verifier/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,5 @@ mod verification;
// Re-export TdxMeasurements from dstack-mr for convenience
pub use dstack_mr::TdxMeasurements;

pub use types::{
AcpiTables, PolicyBootInfo, RtmrEventEntry, RtmrEventStatus, RtmrMismatch, VerificationDetails,
VerificationRequest, VerificationResponse,
};
pub use types::{PolicyBootInfo, VerificationDetails, VerificationRequest, VerificationResponse};
pub use verification::{policy_tcb_fields, CvmVerifier};
2 changes: 1 addition & 1 deletion dstack/verifier/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ async fn verify_cert_os_image_hash(
);
let mut details = VerificationDetails::default();
verifier
.verify_os_image_hash(String::new(), attestation, false, &mut details)
.verify_os_image_hash(String::new(), attestation, &mut details)
.await
.is_ok()
}
Expand Down
46 changes: 0 additions & 46 deletions dstack/verifier/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ pub struct VerificationRequest {
pub vm_config: Option<String>,
#[serde(with = "serde_bytes", default)]
pub attestation: Option<Vec<u8>>,
#[serde(default)]
pub debug: Option<bool>,
}

#[derive(Debug, Clone, Serialize)]
Expand Down Expand Up @@ -115,48 +113,6 @@ pub struct VerificationDetails {
/// Canonical auth-policy input matching the KMS bootAuth payload.
#[serde(skip_serializing_if = "Option::is_none")]
pub boot_info: Option<PolicyBootInfo>,
#[serde(skip_serializing_if = "Option::is_none")]
pub acpi_tables: Option<AcpiTables>,
#[serde(skip_serializing_if = "Option::is_none")]
pub rtmr_debug: Option<Vec<RtmrMismatch>>,
}

#[derive(Debug, Clone, Serialize)]
pub struct AcpiTables {
pub tables: String,
pub rsdp: String,
pub loader: String,
}

#[derive(Debug, Clone, Serialize)]
pub struct RtmrMismatch {
pub rtmr: String,
pub expected: String,
pub actual: String,
pub events: Vec<RtmrEventEntry>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub missing_expected_digests: Vec<String>,
}

#[derive(Debug, Clone, Serialize)]
pub struct RtmrEventEntry {
pub index: usize,
pub event_type: u32,
pub event_name: String,
pub actual_digest: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub expected_digest: Option<String>,
pub payload_len: usize,
pub status: RtmrEventStatus,
}

#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum RtmrEventStatus {
Match,
Mismatch,
Extra,
Missing,
}

#[cfg(test)]
Expand All @@ -176,7 +132,6 @@ mod tests {
assert_eq!(req.event_log.as_deref(), Some("[]"));
assert_eq!(req.vm_config.as_deref(), Some("{}"));
assert_eq!(req.attestation, None);
assert_eq!(req.debug, None);
}

#[test]
Expand All @@ -194,7 +149,6 @@ mod tests {
let req: VerificationRequest = serde_json::from_str("{}").unwrap();
assert_eq!(req.quote, None);
assert_eq!(req.attestation, None);
assert_eq!(req.debug, None);
}

#[test]
Expand Down
Loading
Loading