Skip to content

Commit b22f575

Browse files
committed
fix(verity): measure attached volume device count
1 parent 77ac69d commit b22f575

7 files changed

Lines changed: 78 additions & 1 deletion

File tree

dstack/dstack-mr/cli/src/main.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ struct MachineConfig {
7070
#[arg(long, default_value = "1")]
7171
num_nics: u32,
7272

73+
/// Number of virtio-blk verity volumes
74+
#[arg(long, default_value = "0")]
75+
num_verity_volumes: u32,
76+
7377
/// Disable hotplug
7478
#[arg(long, default_value = "false")]
7579
hotplug_off: Bool,
@@ -138,6 +142,7 @@ fn main() -> Result<()> {
138142
.num_gpus(config.num_gpus)
139143
.num_nvswitches(config.num_nvswitches)
140144
.num_nics(config.num_nics)
145+
.num_verity_volumes(config.num_verity_volumes)
141146
.hotplug_off(config.hotplug_off)
142147
.root_verity(config.root_verity)
143148
.maybe_qemu_version(config.qemu_version.clone())

dstack/dstack-mr/src/acpi.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,16 @@ impl Machine<'_> {
5757
"virtio-blk-pci,drive=hd1",
5858
]);
5959

60+
// Verity volumes are emitted after hd1 and before networking, matching
61+
// dstack-vmm's QEMU device order.
62+
for i in 0..self.num_verity_volumes {
63+
let id = format!("vol{i}");
64+
cmd.arg("-drive").arg(format!(
65+
"file={dummy_disk},if=none,id={id},format=raw,readonly=on"
66+
));
67+
cmd.arg("-device").arg(format!("virtio-blk-pci,drive={id}"));
68+
}
69+
6070
// One virtio-net-pci per NIC. Emitted at the same position and, for the
6171
// default single-NIC case, with the exact same args as the previous
6272
// hardcoded layout so RTMR0 stays byte-for-byte unchanged.

dstack/dstack-mr/src/machine.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ pub struct Machine<'a> {
3333
/// predate this field keep the historical single-NIC layout.
3434
#[builder(default = 1)]
3535
pub num_nics: u32,
36+
/// Number of virtio-blk verity volumes attached before the NICs.
37+
#[builder(default)]
38+
pub num_verity_volumes: u32,
3639
pub hotplug_off: bool,
3740
pub root_verity: bool,
3841
#[builder(default)]

dstack/dstack-mr/src/tdx.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ fn select_mrtd(measurement: &TdxOsImageMeasurement, vm_config: &VmConfig) -> Res
8383
.hugepages(vm_config.hugepages)
8484
.num_gpus(vm_config.num_gpus)
8585
.num_nics(vm_config.num_nics)
86+
.num_verity_volumes(vm_config.num_verity_volumes)
8687
.num_nvswitches(vm_config.num_nvswitches)
8788
.host_share_mode(vm_config.host_share_mode.clone())
8889
.ovmf_variant(measurement.tdvf.ovmf_variant)
@@ -474,6 +475,7 @@ pub fn tdx_measurements_for_image_dir_without_rtmr0(
474475
.hugepages(vm_config.hugepages)
475476
.num_gpus(vm_config.num_gpus)
476477
.num_nics(vm_config.num_nics)
478+
.num_verity_volumes(vm_config.num_verity_volumes)
477479
.num_nvswitches(vm_config.num_nvswitches)
478480
.host_share_mode(vm_config.host_share_mode.clone())
479481
.ovmf_variant(ovmf_variant)
@@ -570,6 +572,7 @@ pub fn tdx_measurements_for_image_dir_with_acpi_hashes(
570572
.hugepages(vm_config.hugepages)
571573
.num_gpus(vm_config.num_gpus)
572574
.num_nics(vm_config.num_nics)
575+
.num_verity_volumes(vm_config.num_verity_volumes)
573576
.num_nvswitches(vm_config.num_nvswitches)
574577
.host_share_mode(vm_config.host_share_mode.clone())
575578
.ovmf_variant(ovmf_variant)

dstack/dstack-types/src/lib.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,10 @@ fn is_default_num_nics(n: &u32) -> bool {
792792
*n == default_num_nics()
793793
}
794794

795+
fn is_zero(n: &u32) -> bool {
796+
*n == 0
797+
}
798+
795799
#[derive(Deserialize, Serialize, Debug, Clone)]
796800
pub struct VmConfig {
797801
#[serde(with = "hex_bytes", default)]
@@ -825,6 +829,11 @@ pub struct VmConfig {
825829
skip_serializing_if = "is_default_num_nics"
826830
)]
827831
pub num_nics: u32,
832+
/// Number of read-only verity volume devices attached to the guest. Each
833+
/// volume adds a virtio-blk PCI device before the NICs and therefore
834+
/// changes the measured ACPI/DSDT layout.
835+
#[serde(default, skip_serializing_if = "is_zero")]
836+
pub num_verity_volumes: u32,
828837
#[serde(default)]
829838
pub hotplug_off: bool,
830839
#[serde(default, skip_serializing_if = "Option::is_none")]
@@ -1819,7 +1828,7 @@ mod platform_tests {
18191828
}
18201829

18211830
#[cfg(test)]
1822-
mod vm_config_num_nics_tests {
1831+
mod vm_config_device_count_tests {
18231832
use super::VmConfig;
18241833

18251834
fn legacy_json() -> serde_json::Value {
@@ -1835,6 +1844,7 @@ mod vm_config_num_nics_tests {
18351844
fn legacy_config_without_num_nics_defaults_to_one() {
18361845
let cfg: VmConfig = serde_json::from_value(legacy_json()).unwrap();
18371846
assert_eq!(cfg.num_nics, 1);
1847+
assert_eq!(cfg.num_verity_volumes, 0);
18381848
}
18391849

18401850
#[test]
@@ -1857,4 +1867,20 @@ mod vm_config_num_nics_tests {
18571867
let serialized = serde_json::to_value(&cfg).unwrap();
18581868
assert_eq!(serialized.get("num_nics").and_then(|v| v.as_u64()), Some(2));
18591869
}
1870+
1871+
#[test]
1872+
fn verity_volume_count_is_serialized_only_when_nonzero() {
1873+
let mut cfg: VmConfig = serde_json::from_value(legacy_json()).unwrap();
1874+
let serialized = serde_json::to_value(&cfg).unwrap();
1875+
assert!(serialized.get("num_verity_volumes").is_none());
1876+
1877+
cfg.num_verity_volumes = 2;
1878+
let serialized = serde_json::to_value(&cfg).unwrap();
1879+
assert_eq!(
1880+
serialized
1881+
.get("num_verity_volumes")
1882+
.and_then(|v| v.as_u64()),
1883+
Some(2)
1884+
);
1885+
}
18601886
}

dstack/verifier/src/verification.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ impl CvmVerifier {
341341
.hugepages(vm_config.hugepages)
342342
.num_gpus(vm_config.num_gpus)
343343
.num_nics(vm_config.num_nics)
344+
.num_verity_volumes(vm_config.num_verity_volumes)
344345
.num_nvswitches(vm_config.num_nvswitches)
345346
.host_share_mode(vm_config.host_share_mode.clone())
346347
.ovmf_variant(ovmf_variant)

dstack/vmm/src/app.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1400,6 +1400,7 @@ fn make_vm_config(
14001400
// ACPI/DSDT layout and therefore RTMR0. Measure the interface count so the
14011401
// verifier reconstructs the exact device layout.
14021402
let num_nics = resolved_networks(manifest, &cfg.cvm).len() as u32;
1403+
let num_verity_volumes = manifest.volumes.len() as u32;
14031404
let mut config = serde_json::to_value(dstack_types::VmConfig {
14041405
os_image_hash,
14051406
cpu_count: effective_vcpus,
@@ -1412,6 +1413,7 @@ fn make_vm_config(
14121413
num_gpus: gpus.gpus.len() as u32,
14131414
num_nvswitches: gpus.bridges.len() as u32,
14141415
num_nics,
1416+
num_verity_volumes,
14151417
host_share_mode: cfg.cvm.host_share_mode.clone(),
14161418
hotplug_off: cfg.cvm.qemu_hotplug_off,
14171419
image: Some(manifest.image.clone()),
@@ -1732,6 +1734,33 @@ mod tests {
17321734
Ok(())
17331735
}
17341736

1737+
#[test]
1738+
fn vm_measurement_config_includes_verity_volume_count() -> Result<()> {
1739+
let config = test_tdx_config()?;
1740+
let mut manifest = test_manifest(2048);
1741+
manifest.volumes = vec![
1742+
VmVolume {
1743+
source: "/volumes/a.img".into(),
1744+
read_only: true,
1745+
},
1746+
VmVolume {
1747+
source: "/volumes/b.img".into(),
1748+
read_only: true,
1749+
},
1750+
];
1751+
let vm_config = make_vm_config(
1752+
&config,
1753+
&manifest,
1754+
&test_tdx_image(true),
1755+
&hex_of(0x22, 32),
1756+
None,
1757+
None,
1758+
)?;
1759+
1760+
assert_eq!(vm_config["num_verity_volumes"], 2);
1761+
Ok(())
1762+
}
1763+
17351764
#[test]
17361765
fn tdx_auto_variant_uses_legacy_for_low_non_2g_memory() -> Result<()> {
17371766
let config = test_tdx_config()?;

0 commit comments

Comments
 (0)