Skip to content

Commit d7e6151

Browse files
committed
refactor(attestation): reject swtpm measurement
1 parent c884dbb commit d7e6151

15 files changed

Lines changed: 52 additions & 136 deletions

File tree

docs/tutorials/attestation-verification.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ cat /var/lib/dstack/images/dstack-0.5.7/metadata.json | jq .
254254
# Install QEMU build dependencies
255255
sudo apt-get update
256256
sudo apt-get install -y git libslirp-dev python3-pip ninja-build \
257-
pkg-config libglib2.0-dev build-essential flex bison swtpm
257+
pkg-config libglib2.0-dev build-essential flex bison
258258

259259
# Clone the custom QEMU fork
260260
cd ~/dstack

docs/tutorials/kms-build-configuration.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -378,10 +378,9 @@ FROM dstacktee/dstack-kms@sha256:11ac59f524a22462ccd2152219b0bec48a28ceb734e3250
378378
FROM ubuntu:24.04
379379
380380
# Install runtime dependencies
381-
# The QEMU libraries are required by dstack-acpi-tables. swtpm is used when
382-
# reconstructing ACPI tables for VMs that attached a QEMU TPM device.
381+
# libglib2.0-0t64, libpixman-1-0, and libslirp0 are required by dstack-acpi-tables (QEMU binary)
383382
RUN apt-get update && \
384-
apt-get install -y ca-certificates curl libglib2.0-0t64 libpixman-1-0 libslirp0 swtpm && \
383+
apt-get install -y ca-certificates curl libglib2.0-0t64 libpixman-1-0 libslirp0 && \
385384
rm -rf /var/lib/apt/lists/*
386385
387386
# Install Node.js 20.x for auth-eth

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ struct MachineConfig {
7676

7777
/// Attach a QEMU tpm-tis device backed by swtpm
7878
#[arg(long, default_value = "false")]
79-
qemu_swtpm: bool,
79+
swtpm: bool,
8080

8181
/// Disable hotplug
8282
#[arg(long, default_value = "false")]
@@ -147,7 +147,7 @@ fn main() -> Result<()> {
147147
.num_nvswitches(config.num_nvswitches)
148148
.num_nics(config.num_nics)
149149
.num_verity_volumes(config.num_verity_volumes)
150-
.qemu_swtpm(config.qemu_swtpm)
150+
.swtpm(config.swtpm)
151151
.hotplug_off(config.hotplug_off)
152152
.root_verity(config.root_verity)
153153
.maybe_qemu_version(config.qemu_version.clone())

dstack/dstack-mr/src/acpi.rs

Lines changed: 4 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -6,74 +6,14 @@
66
//! translated from an original Go implementation.
77
88
use anyhow::{bail, Context, Result};
9-
use fs_err as fs;
109
use log::debug;
1110
use scale::Decode;
12-
use std::os::unix::fs::FileTypeExt;
13-
use std::path::PathBuf;
14-
use std::process::{Child, Command, Stdio};
15-
use std::sync::atomic::{AtomicU64, Ordering};
16-
use std::thread;
17-
use std::time::Duration;
11+
use std::process::Command;
1812

1913
use crate::Machine;
2014

2115
const LDR_LENGTH: usize = 4096;
2216
const FIXED_STRING_LEN: usize = 56;
23-
static SWTPM_ID: AtomicU64 = AtomicU64::new(0);
24-
25-
struct SwtpmGuard {
26-
child: Child,
27-
state_dir: PathBuf,
28-
socket: PathBuf,
29-
}
30-
31-
impl Drop for SwtpmGuard {
32-
fn drop(&mut self) {
33-
let _ = self.child.kill();
34-
let _ = self.child.wait();
35-
let _ = fs::remove_dir_all(&self.state_dir);
36-
}
37-
}
38-
39-
fn start_measurement_swtpm() -> Result<SwtpmGuard> {
40-
let id = SWTPM_ID.fetch_add(1, Ordering::Relaxed);
41-
let state_dir =
42-
std::env::temp_dir().join(format!("dstack-mr-swtpm-{}-{id}", std::process::id()));
43-
fs::create_dir_all(&state_dir).context("failed to create measurement swtpm state directory")?;
44-
let socket = state_dir.join("swtpm.sock");
45-
let child = Command::new("swtpm")
46-
.args(["socket", "--tpm2", "--tpmstate"])
47-
.arg(format!("dir={}", state_dir.display()))
48-
.arg("--ctrl")
49-
.arg(format!("type=unixio,path={}", socket.display()))
50-
.args(["--flags", "startup-clear"])
51-
.stdin(Stdio::null())
52-
.stdout(Stdio::null())
53-
.stderr(Stdio::null())
54-
.spawn()
55-
.inspect_err(|_| {
56-
let _ = fs::remove_dir_all(&state_dir);
57-
})
58-
.context("failed to start swtpm for ACPI measurement")?;
59-
let mut guard = SwtpmGuard {
60-
child,
61-
state_dir,
62-
socket,
63-
};
64-
65-
for _ in 0..100 {
66-
if fs::metadata(&guard.socket).is_ok_and(|metadata| metadata.file_type().is_socket()) {
67-
return Ok(guard);
68-
}
69-
if guard.child.try_wait()?.is_some() {
70-
bail!("measurement swtpm exited before its socket was ready");
71-
}
72-
thread::sleep(Duration::from_millis(10));
73-
}
74-
bail!("timed out waiting for measurement swtpm socket")
75-
}
76-
7717
#[derive(Debug, Clone)]
7818
pub struct Tables {
7919
pub tables: Vec<u8>,
@@ -83,6 +23,9 @@ pub struct Tables {
8323

8424
impl Machine<'_> {
8525
fn create_tables(&self) -> Result<Vec<u8>> {
26+
if self.swtpm {
27+
bail!("swtpm measurement is not supported");
28+
}
8629
if self.cpu_count == 0 {
8730
bail!("cpuCount must be greater than 0");
8831
}
@@ -136,18 +79,6 @@ impl Machine<'_> {
13679
.arg(format!("virtio-net-pci,netdev=net{i}"));
13780
}
13881

139-
let swtpm = self.qemu_swtpm.then(start_measurement_swtpm).transpose()?;
140-
if let Some(swtpm) = &swtpm {
141-
cmd.arg("-chardev")
142-
.arg(format!("socket,id=chrtpm,path={}", swtpm.socket.display()))
143-
.args([
144-
"-tpmdev",
145-
"emulator,id=tpm0,chardev=chrtpm",
146-
"-device",
147-
"tpm-tis,tpmdev=tpm0",
148-
]);
149-
}
150-
15182
cmd.args([
15283
"-object",
15384
"tdx-guest,id=tdx",

dstack/dstack-mr/src/machine.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ pub struct Machine<'a> {
3838
pub num_verity_volumes: u32,
3939
/// Whether QEMU attaches a tpm-tis device backed by swtpm.
4040
#[builder(default)]
41-
pub qemu_swtpm: bool,
41+
pub swtpm: bool,
4242
pub hotplug_off: bool,
4343
pub root_verity: bool,
4444
#[builder(default)]

dstack/dstack-mr/src/tdx.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ fn select_mrtd(measurement: &TdxOsImageMeasurement, vm_config: &VmConfig) -> Res
8484
.num_gpus(vm_config.num_gpus)
8585
.num_nics(vm_config.num_nics)
8686
.num_verity_volumes(vm_config.num_verity_volumes)
87-
.qemu_swtpm(vm_config.qemu_swtpm)
87+
.swtpm(vm_config.swtpm)
8888
.num_nvswitches(vm_config.num_nvswitches)
8989
.host_share_mode(vm_config.host_share_mode.clone())
9090
.ovmf_variant(measurement.tdvf.ovmf_variant)
@@ -477,7 +477,7 @@ pub fn tdx_measurements_for_image_dir_without_rtmr0(
477477
.num_gpus(vm_config.num_gpus)
478478
.num_nics(vm_config.num_nics)
479479
.num_verity_volumes(vm_config.num_verity_volumes)
480-
.qemu_swtpm(vm_config.qemu_swtpm)
480+
.swtpm(vm_config.swtpm)
481481
.num_nvswitches(vm_config.num_nvswitches)
482482
.host_share_mode(vm_config.host_share_mode.clone())
483483
.ovmf_variant(ovmf_variant)
@@ -575,7 +575,7 @@ pub fn tdx_measurements_for_image_dir_with_acpi_hashes(
575575
.num_gpus(vm_config.num_gpus)
576576
.num_nics(vm_config.num_nics)
577577
.num_verity_volumes(vm_config.num_verity_volumes)
578-
.qemu_swtpm(vm_config.qemu_swtpm)
578+
.swtpm(vm_config.swtpm)
579579
.num_nvswitches(vm_config.num_nvswitches)
580580
.host_share_mode(vm_config.host_share_mode.clone())
581581
.ovmf_variant(ovmf_variant)

dstack/dstack-types/src/lib.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,7 +1078,7 @@ pub struct VmConfig {
10781078
/// Whether QEMU attaches a software TPM device. The TPM changes the ACPI
10791079
/// table layout and must therefore be included in TDX measurement inputs.
10801080
#[serde(default, skip_serializing_if = "is_false")]
1081-
pub qemu_swtpm: bool,
1081+
pub swtpm: bool,
10821082
#[serde(default)]
10831083
pub hotplug_off: bool,
10841084
#[serde(default, skip_serializing_if = "Option::is_none")]
@@ -2131,15 +2131,15 @@ mod vm_config_device_count_tests {
21312131
}
21322132

21332133
#[test]
2134-
fn qemu_swtpm_is_serialized_only_when_enabled() {
2134+
fn swtpm_is_serialized_only_when_enabled() {
21352135
let mut cfg: VmConfig = serde_json::from_value(legacy_json()).unwrap();
21362136
let serialized = serde_json::to_value(&cfg).unwrap();
2137-
assert!(serialized.get("qemu_swtpm").is_none());
2137+
assert!(serialized.get("swtpm").is_none());
21382138

2139-
cfg.qemu_swtpm = true;
2139+
cfg.swtpm = true;
21402140
let serialized = serde_json::to_value(&cfg).unwrap();
21412141
assert_eq!(
2142-
serialized.get("qemu_swtpm").and_then(|v| v.as_bool()),
2142+
serialized.get("swtpm").and_then(|v| v.as_bool()),
21432143
Some(true)
21442144
);
21452145
}

dstack/kms/dstack-app/builder/Dockerfile

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,7 @@ RUN ./pin-packages.sh ./qemu-pinned-packages.txt && \
4444
python3-sphinx-rtd-theme \
4545
build-essential \
4646
flex \
47-
bison \
48-
swtpm && \
47+
bison && \
4948
rm -rf /var/lib/apt/lists/* /var/log/* /var/cache/ldconfig/aux-cache
5049
RUN git clone https://github.com/kvinwang/qemu-tdx.git --depth 1 --branch dstack-qemu-9.2.1 --single-branch && \
5150
cd qemu-tdx && git fetch --depth 1 origin ${QEMU_REV} && \

dstack/kms/dstack-app/builder/shared/qemu-pinned-packages.txt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,6 @@ libtinfo6:amd64=6.4-4
159159
libtirpc-common=1.3.3+ds-1
160160
libtirpc-dev:amd64=1.3.3+ds-1
161161
libtirpc3:amd64=1.3.3+ds-1
162-
libtpms0:amd64=0.9.2-3.1+deb12u1
163162
libtsan2:amd64=12.2.0-14+deb12u1
164163
libubsan1:amd64=12.2.0-14+deb12u1
165164
libudev1:amd64=252.38-1~deb12u1
@@ -224,8 +223,6 @@ sed=4.9-1
224223
sgml-base=1.31
225224
sphinx-common=5.3.0-4
226225
sphinx-rtd-theme-common=1.2.0+dfsg-1
227-
swtpm-libs:amd64=0.7.1-1.3
228-
swtpm=0.7.1-1.3
229226
sysvinit-utils=3.06-4
230227
tar=1.34+dfsg-1.2+deb12u1
231228
tzdata=2025b-0+deb12u1

dstack/verifier/builder/Dockerfile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ RUN ./pin-packages.sh ./pinned-packages.txt && \
7676
curl \
7777
libglib2.0-0 \
7878
libslirp0 \
79-
swtpm \
8079
&& rm -rf /var/lib/apt/lists/* /var/log/* /var/cache/ldconfig/aux-cache
8180
COPY --from=verifier-builder /build/repo/dstack/target/x86_64-unknown-linux-musl/release/dstack-verifier /usr/local/bin/dstack-verifier
8281
COPY --from=verifier-builder /build/.GIT_REV /etc/

0 commit comments

Comments
 (0)