88use anyhow:: { bail, Context , Result } ;
99use log:: debug;
1010use scale:: Decode ;
11+ use std:: os:: unix:: fs:: FileTypeExt ;
12+ use std:: path:: PathBuf ;
13+ use std:: process:: { Child , Command , Stdio } ;
14+ use std:: sync:: atomic:: { AtomicU64 , Ordering } ;
15+ use std:: thread;
16+ use std:: time:: Duration ;
1117
1218use crate :: Machine ;
1319
1420const LDR_LENGTH : usize = 4096 ;
1521const FIXED_STRING_LEN : usize = 56 ;
22+ static SWTPM_ID : AtomicU64 = AtomicU64 :: new ( 0 ) ;
23+
24+ struct SwtpmGuard {
25+ child : Child ,
26+ state_dir : PathBuf ,
27+ socket : PathBuf ,
28+ }
29+
30+ impl Drop for SwtpmGuard {
31+ fn drop ( & mut self ) {
32+ let _ = self . child . kill ( ) ;
33+ let _ = self . child . wait ( ) ;
34+ let _ = fs:: remove_dir_all ( & self . state_dir ) ;
35+ }
36+ }
37+
38+ fn start_measurement_swtpm ( ) -> Result < SwtpmGuard > {
39+ let id = SWTPM_ID . fetch_add ( 1 , Ordering :: Relaxed ) ;
40+ let state_dir =
41+ std:: env:: temp_dir ( ) . join ( format ! ( "dstack-mr-swtpm-{}-{id}" , std:: process:: id( ) ) ) ;
42+ fs:: create_dir_all ( & state_dir) . context ( "failed to create measurement swtpm state directory" ) ?;
43+ let socket = state_dir. join ( "swtpm.sock" ) ;
44+ let child = Command :: new ( "swtpm" )
45+ . args ( [ "socket" , "--tpm2" , "--tpmstate" ] )
46+ . arg ( format ! ( "dir={}" , state_dir. display( ) ) )
47+ . arg ( "--ctrl" )
48+ . arg ( format ! ( "type=unixio,path={}" , socket. display( ) ) )
49+ . args ( [ "--flags" , "startup-clear" ] )
50+ . stdin ( Stdio :: null ( ) )
51+ . stdout ( Stdio :: null ( ) )
52+ . stderr ( Stdio :: null ( ) )
53+ . spawn ( )
54+ . inspect_err ( |_| {
55+ let _ = fs:: remove_dir_all ( & state_dir) ;
56+ } )
57+ . context ( "failed to start swtpm for ACPI measurement" ) ?;
58+ let mut guard = SwtpmGuard {
59+ child,
60+ state_dir,
61+ socket,
62+ } ;
63+
64+ for _ in 0 ..100 {
65+ if fs:: metadata ( & guard. socket ) . is_ok_and ( |metadata| metadata. file_type ( ) . is_socket ( ) ) {
66+ return Ok ( guard) ;
67+ }
68+ if guard. child . try_wait ( ) ?. is_some ( ) {
69+ bail ! ( "measurement swtpm exited before its socket was ready" ) ;
70+ }
71+ thread:: sleep ( Duration :: from_millis ( 10 ) ) ;
72+ }
73+ bail ! ( "timed out waiting for measurement swtpm socket" )
74+ }
1675
1776#[ derive( Debug , Clone ) ]
1877pub struct Tables {
@@ -33,7 +92,7 @@ impl Machine<'_> {
3392 let shared_dir = "/bin" ;
3493
3594 // Prepare the command arguments
36- let mut cmd = std :: process :: Command :: new ( "dstack-acpi-tables" ) ;
95+ let mut cmd = Command :: new ( "dstack-acpi-tables" ) ;
3796 cmd. args ( [
3897 "-cpu" ,
3998 "qemu64" ,
@@ -76,6 +135,18 @@ impl Machine<'_> {
76135 . arg ( format ! ( "virtio-net-pci,netdev=net{i}" ) ) ;
77136 }
78137
138+ let swtpm = self . qemu_swtpm . then ( start_measurement_swtpm) . transpose ( ) ?;
139+ if let Some ( swtpm) = & swtpm {
140+ cmd. arg ( "-chardev" )
141+ . arg ( format ! ( "socket,id=chrtpm,path={}" , swtpm. socket. display( ) ) )
142+ . args ( [
143+ "-tpmdev" ,
144+ "emulator,id=tpm0,chardev=chrtpm" ,
145+ "-device" ,
146+ "tpm-tis,tpmdev=tpm0" ,
147+ ] ) ;
148+ }
149+
79150 cmd. args ( [
80151 "-object" ,
81152 "tdx-guest,id=tdx" ,
0 commit comments