Skip to content
Merged
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
44 changes: 43 additions & 1 deletion dstack/verifier/src/verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,18 @@ impl CvmVerifier {
.join(format!("{cache_key}.json"))
}

/// Hash only what the measurement reads: `image` and the measurement documents
/// are caller-controlled and unused, so they must not be able to force a miss.
/// Clear them rather than allowlisting, so new `VmConfig` fields stay in the key.
fn vm_config_cache_key(vm_config: &VmConfig) -> Result<String> {
let serialized = serde_json::to_vec(vm_config)
let vm_config = VmConfig {
image: None,
tdx_measurement: None,
gcp_measurement: None,
aws_measurement: None,
..vm_config.clone()
};
let serialized = serde_json::to_vec(&vm_config)
.context("Failed to serialize VM config for cache key computation")?;
Ok(hex::encode(Sha256::digest(&serialized)))
}
Expand Down Expand Up @@ -1723,6 +1733,38 @@ mod tests {
assert_eq!(entries.len(), 1, "temporary cache files must not survive");
}

#[test]
fn measurement_cache_key_ignores_unmeasured_fields() {
let base: VmConfig = serde_json::from_value(serde_json::json!({
"os_image_hash": "11".repeat(32),
"cpu_count": 2,
"memory_size": 0x8000_0000u64,
}))
.unwrap();
let key = |config: &VmConfig| CvmVerifier::vm_config_cache_key(config).unwrap();
let blob = || vec![0xaa; 4096];

let mut padded = base.clone();
padded.image = Some("x".repeat(4096));
padded.tdx_measurement = Some(dstack_types::TdxOsImageMeasurementDocument::new(
blob(),
blob(),
));
padded.gcp_measurement = Some(dstack_types::GcpOsImageMeasurementDocument::new(
blob(),
blob(),
));
padded.aws_measurement = Some(dstack_types::AwsOsImageMeasurementDocument::new(
blob(),
blob(),
));
assert_eq!(key(&padded), key(&base));

let mut resized = base.clone();
resized.cpu_count += 1;
assert_ne!(key(&resized), key(&base));
}

#[test]
fn image_cache_pruning_keeps_checksum_identity() {
let dir = tempfile::tempdir().expect("temp image directory");
Expand Down
Loading