1 // Copyright © 2022, Microsoft Corporation 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 // 5 6 use crate::socket::SocketDev; 7 use crate::{Commands, MemberType, Ptm, PtmCap, PtmEst, PtmInit, PtmResult, PtmSetBufferSize}; 8 use crate::{TPM_CRB_BUFFER_MAX, TPM_SUCCESS}; 9 use anyhow::anyhow; 10 use libc::c_void; 11 use libc::{sockaddr_storage, socklen_t}; 12 use std::os::unix::io::RawFd; 13 use std::path::Path; 14 use std::{mem, ptr}; 15 use thiserror::Error; 16 17 const TPM_REQ_HDR_SIZE: usize = 10; 18 19 /* capability flags returned by PTM_GET_CAPABILITY */ 20 const PTM_CAP_INIT: u64 = 1; 21 const PTM_CAP_SHUTDOWN: u64 = 1 << 1; 22 const PTM_CAP_GET_TPMESTABLISHED: u64 = 1 << 2; 23 const PTM_CAP_SET_LOCALITY: u64 = 1 << 3; 24 const PTM_CAP_CANCEL_TPM_CMD: u64 = 1 << 5; 25 const PTM_CAP_RESET_TPMESTABLISHED: u64 = 1 << 7; 26 const PTM_CAP_STOP: u64 = 1 << 10; 27 const PTM_CAP_SET_DATAFD: u64 = 1 << 12; 28 const PTM_CAP_SET_BUFFERSIZE: u64 = 1 << 13; 29 30 ///Check if the input command is selftest 31 /// 32 pub fn is_selftest(input: &[u8]) -> bool { 33 if input.len() >= TPM_REQ_HDR_SIZE { 34 let ordinal: &[u8; 4] = input[6..6 + 4] 35 .try_into() 36 .expect("slice with incorrect length"); 37 38 return u32::from_ne_bytes(*ordinal).to_be() == 0x143; 39 } 40 false 41 } 42 43 #[derive(Error, Debug)] 44 pub enum Error { 45 #[error("Could not initialize emulator's backend: {0}")] 46 InitializeEmulator(#[source] anyhow::Error), 47 #[error("Failed to create data fd to pass to swtpm: {0}")] 48 PrepareDataFd(#[source] anyhow::Error), 49 #[error("Failed to run Control Cmd: {0}")] 50 RunControlCmd(#[source] anyhow::Error), 51 #[error("Emulator doesn't implement min required capabilities: {0}")] 52 CheckCaps(#[source] anyhow::Error), 53 #[error("Emulator failed to deliver request: {0}")] 54 DeliverRequest(#[source] anyhow::Error), 55 #[error("Emulator failed to send/receive msg on data fd: {0}")] 56 SendReceive(#[source] anyhow::Error), 57 #[error("Incorrect response to Self Test: {0}")] 58 SelfTest(#[source] anyhow::Error), 59 } 60 61 type Result<T> = anyhow::Result<T, Error>; 62 63 pub struct BackendCmd<'a> { 64 // This buffer is used for both input and output. 65 // When used for input, the length of the data is input_len. 66 pub buffer: &'a mut [u8], 67 pub input_len: usize, 68 } 69 70 pub struct Emulator { 71 caps: PtmCap, /* capabilities of the TPM */ 72 control_socket: SocketDev, 73 data_fd: RawFd, 74 established_flag_cached: bool, 75 established_flag: bool, 76 } 77 78 impl Emulator { 79 /// Create Emulator Instance 80 /// 81 /// # Arguments 82 /// 83 /// * `path` - A path to the Unix Domain Socket swtpm is listening on 84 /// 85 pub fn new(path: String) -> Result<Self> { 86 if !Path::new(&path).exists() { 87 return Err(Error::InitializeEmulator(anyhow!( 88 "The input TPM Socket path: {:?} does not exist", 89 path 90 ))); 91 } 92 let mut socket = SocketDev::new(); 93 socket.init(path).map_err(|e| { 94 Error::InitializeEmulator(anyhow!("Failed while initializing tpm emulator: {:?}", e)) 95 })?; 96 97 let mut emulator = Self { 98 caps: 0, 99 control_socket: socket, 100 data_fd: -1, 101 established_flag_cached: false, 102 established_flag: false, 103 }; 104 105 emulator.prepare_data_fd()?; 106 107 emulator.probe_caps()?; 108 if !emulator.check_caps() { 109 return Err(Error::InitializeEmulator(anyhow!( 110 "Required capabilities not supported by tpm backend" 111 ))); 112 } 113 114 if !emulator.get_established_flag() { 115 return Err(Error::InitializeEmulator(anyhow!( 116 "TPM not in established state" 117 ))); 118 } 119 120 Ok(emulator) 121 } 122 123 /// Create socketpair, assign one socket/FD as data_fd to Control Socket 124 /// The other socket/FD will be assigned to msg_fd, which will be sent to swtpm 125 /// via CmdSetDatafd control command 126 fn prepare_data_fd(&mut self) -> Result<()> { 127 let mut res: PtmResult = 0; 128 129 let mut fds = [-1, -1]; 130 // SAFETY: FFI calls and return value of the unsafe call is checked 131 unsafe { 132 let ret = libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()); 133 if ret == -1 { 134 return Err(Error::PrepareDataFd(anyhow!( 135 "Failed to prepare data fd for tpm emulator. Error Code {:?}", 136 std::io::Error::last_os_error() 137 ))); 138 } 139 } 140 self.control_socket.set_msgfd(fds[1]); 141 debug!("data fd to be configured in swtpm = {:?}", fds[1]); 142 self.run_control_cmd(Commands::CmdSetDatafd, &mut res, 0, mem::size_of::<u32>())?; 143 debug!("data fd in cloud-hypervisor = {:?}", fds[0]); 144 self.data_fd = fds[0]; 145 146 // SAFETY: FFI calls and return value of the unsafe call is checked 147 unsafe { 148 let tv = net_gen::iff::timeval { 149 tv_sec: 0, 150 tv_usec: 100000, // Set recv timeout to 100ms 151 }; 152 let ret = net_gen::setsockopt( 153 fds[0], 154 net_gen::iff::SOL_SOCKET as i32, 155 net_gen::iff::SO_RCVTIMEO as i32, 156 &tv as *const _ as *const libc::c_void, 157 std::mem::size_of::<net_gen::iff::timeval>() as u32, 158 ); 159 if ret == -1 { 160 return Err(Error::PrepareDataFd(anyhow!( 161 "Failed to set receive timeout on data fd socket. Error Code {:?}", 162 std::io::Error::last_os_error() 163 ))); 164 } 165 } 166 self.control_socket.set_datafd(fds[0]); 167 Ok(()) 168 } 169 170 /// Gather TPM Capabilities and cache them in Emulator 171 /// 172 fn probe_caps(&mut self) -> Result<()> { 173 let mut caps: u64 = 0; 174 self.run_control_cmd( 175 Commands::CmdGetCapability, 176 &mut caps, 177 0, 178 mem::size_of::<u64>(), 179 )?; 180 self.caps = caps; 181 Ok(()) 182 } 183 184 /// Check if minimum set of capabilities are supported 185 fn check_caps(&mut self) -> bool { 186 /* min. required capabilities for TPM 2.0*/ 187 let caps: PtmCap = PTM_CAP_INIT 188 | PTM_CAP_SHUTDOWN 189 | PTM_CAP_GET_TPMESTABLISHED 190 | PTM_CAP_SET_LOCALITY 191 | PTM_CAP_RESET_TPMESTABLISHED 192 | PTM_CAP_SET_DATAFD 193 | PTM_CAP_STOP 194 | PTM_CAP_SET_BUFFERSIZE; 195 196 if (self.caps & caps) != caps { 197 return false; 198 } 199 true 200 } 201 202 /// 203 /// # Arguments 204 /// 205 /// * `cmd` - Control Command to run 206 /// * `msg` - Optional msg to be sent along with Control Command 207 /// * `msg_len_in` - len of 'msg' in bytes, if passed 208 /// * `msg_len_out` - length of expected output from Control Command in bytes 209 /// 210 fn run_control_cmd( 211 &mut self, 212 cmd: Commands, 213 msg: &mut dyn Ptm, 214 msg_len_in: usize, 215 msg_len_out: usize, 216 ) -> Result<()> { 217 debug!("Control Cmd to send : {:02X?}", cmd); 218 219 let cmd_no = (cmd as u32).to_be_bytes(); 220 let n = mem::size_of::<u32>() + msg_len_in; 221 222 let converted_req = msg.ptm_to_request(); 223 debug!("converted request: {:02X?}", converted_req); 224 225 let mut buf = Vec::<u8>::with_capacity(n); 226 227 buf.extend(cmd_no); 228 buf.extend(converted_req); 229 debug!("full Control request {:02X?}", buf); 230 231 let written = self.control_socket.write(&buf).map_err(|e| { 232 Error::RunControlCmd(anyhow!( 233 "Failed while running {:02X?} Control Cmd. Error: {:?}", 234 cmd, 235 e 236 )) 237 })?; 238 239 if written < buf.len() { 240 return Err(Error::RunControlCmd(anyhow!( 241 "Truncated write while running {:02X?} Control Cmd", 242 cmd, 243 ))); 244 } 245 246 // The largest response is 16 bytes so far. 247 if msg_len_out > 16 { 248 return Err(Error::RunControlCmd(anyhow!( 249 "Response size is too large for Cmd {:02X?}, max 16 wanted {}", 250 cmd, 251 msg_len_out 252 ))); 253 } 254 255 let mut output = [0u8; 16]; 256 257 // Every Control Cmd gets at least a result code in response. Read it 258 let read_size = self.control_socket.read(&mut output).map_err(|e| { 259 Error::RunControlCmd(anyhow!( 260 "Failed while reading response for Control Cmd: {:02X?}. Error: {:?}", 261 cmd, 262 e 263 )) 264 })?; 265 266 if msg_len_out != 0 { 267 msg.update_ptm_with_response(&output[0..read_size]) 268 .map_err(|e| { 269 Error::RunControlCmd(anyhow!( 270 "Failed while converting response of Control Cmd: {:02X?} to PTM. Error: {:?}", 271 cmd, 272 e 273 )) 274 })?; 275 } else { 276 // No response expected, only handle return code 277 msg.set_member_type(MemberType::Response); 278 } 279 280 if msg.get_result_code() != TPM_SUCCESS { 281 return Err(Error::RunControlCmd(anyhow!( 282 "Control Cmd returned error code : {:?}", 283 msg.get_result_code() 284 ))); 285 } 286 debug!("Control Cmd Response : {:02X?}", &output[0..read_size]); 287 Ok(()) 288 } 289 290 pub fn get_established_flag(&mut self) -> bool { 291 let mut est: PtmEst = PtmEst::new(); 292 293 if self.established_flag_cached { 294 return self.established_flag; 295 } 296 297 if let Err(e) = self.run_control_cmd( 298 Commands::CmdGetTpmEstablished, 299 &mut est, 300 0, 301 2 * mem::size_of::<u32>(), 302 ) { 303 error!( 304 "Failed to run CmdGetTpmEstablished Control Cmd. Error: {:?}", 305 e 306 ); 307 return false; 308 } 309 310 self.established_flag_cached = true; 311 self.established_flag = est.resp.bit == 0; 312 313 self.established_flag 314 } 315 316 /// Function to write to data socket and read the response from it 317 pub fn deliver_request(&mut self, cmd: &mut BackendCmd) -> Result<()> { 318 // SAFETY: type "sockaddr_storage" is valid with an all-zero byte-pattern value 319 let mut addr: sockaddr_storage = unsafe { mem::zeroed() }; 320 let mut len = mem::size_of::<sockaddr_storage>() as socklen_t; 321 let isselftest = is_selftest(&cmd.buffer[0..cmd.input_len]); 322 323 debug!( 324 "Send cmd: {:02X?} of len {:?} on data_ioc ", 325 cmd.buffer, cmd.input_len 326 ); 327 328 let data_vecs = [libc::iovec { 329 iov_base: cmd.buffer.as_ptr() as *mut libc::c_void, 330 iov_len: cmd.input_len, 331 }; 1]; 332 333 // SAFETY: all zero values from the unsafe method are updated before usage 334 let mut msghdr: libc::msghdr = unsafe { mem::zeroed() }; 335 msghdr.msg_name = ptr::null_mut(); 336 msghdr.msg_namelen = 0; 337 msghdr.msg_iov = data_vecs.as_ptr() as *mut libc::iovec; 338 msghdr.msg_iovlen = data_vecs.len() as _; 339 msghdr.msg_control = ptr::null_mut(); 340 msghdr.msg_controllen = 0; 341 msghdr.msg_flags = 0; 342 // SAFETY: FFI call and the return value of the unsafe method is checked 343 unsafe { 344 let ret = libc::sendmsg(self.data_fd, &msghdr, 0); 345 if ret == -1 { 346 return Err(Error::SendReceive(anyhow!( 347 "Failed to send tpm command over Data FD. Error Code {:?}", 348 std::io::Error::last_os_error() 349 ))); 350 } 351 } 352 353 let output_len; 354 // SAFETY: FFI calls and return value from unsafe method is checked 355 unsafe { 356 let ret = libc::recvfrom( 357 self.data_fd, 358 cmd.buffer.as_mut_ptr() as *mut c_void, 359 cmd.buffer.len(), 360 0, 361 &mut addr as *mut libc::sockaddr_storage as *mut libc::sockaddr, 362 &mut len as *mut socklen_t, 363 ); 364 if ret == -1 { 365 return Err(Error::SendReceive(anyhow!( 366 "Failed to receive response for tpm command over Data FD. Error Code {:?}", 367 std::io::Error::last_os_error() 368 ))); 369 } 370 output_len = ret as usize; 371 } 372 debug!( 373 "response = {:02X?} len = {:?} selftest = {:?}", 374 cmd.buffer, output_len, isselftest 375 ); 376 377 if isselftest && output_len < 10 { 378 return Err(Error::SelfTest(anyhow!( 379 "Self test response should have 10 bytes. Only {:?} returned", 380 output_len 381 ))); 382 } 383 384 Ok(()) 385 } 386 387 pub fn cancel_cmd(&mut self) -> Result<()> { 388 let mut res: PtmResult = 0; 389 390 // Check if emulator implements Cancel Cmd 391 if (self.caps & PTM_CAP_CANCEL_TPM_CMD) != PTM_CAP_CANCEL_TPM_CMD { 392 return Err(Error::CheckCaps(anyhow!( 393 "Emulator does not implement 'Cancel Command' Capability" 394 ))); 395 } 396 self.run_control_cmd( 397 Commands::CmdCancelTpmCmd, 398 &mut res, 399 0, 400 mem::size_of::<u32>(), 401 )?; 402 Ok(()) 403 } 404 405 /// Configure buffersize to use while communicating with swtpm 406 fn set_buffer_size(&mut self, wantedsize: usize) -> Result<usize> { 407 let mut psbs: PtmSetBufferSize = PtmSetBufferSize::new(wantedsize as u32); 408 409 self.stop_tpm()?; 410 411 self.run_control_cmd( 412 Commands::CmdSetBufferSize, 413 &mut psbs, 414 mem::size_of::<u32>(), 415 4 * mem::size_of::<u32>(), 416 )?; 417 418 Ok(psbs.get_bufsize() as usize) 419 } 420 421 pub fn startup_tpm(&mut self, buffersize: usize) -> Result<()> { 422 let mut init: PtmInit = PtmInit::new(); 423 424 if buffersize != 0 { 425 let actual_size = self.set_buffer_size(buffersize)?; 426 debug!("set tpm buffersize to {:?} during Startup", actual_size); 427 } 428 429 self.run_control_cmd( 430 Commands::CmdInit, 431 &mut init, 432 mem::size_of::<u32>(), 433 mem::size_of::<u32>(), 434 )?; 435 436 Ok(()) 437 } 438 439 fn stop_tpm(&mut self) -> Result<()> { 440 let mut res: PtmResult = 0; 441 442 self.run_control_cmd(Commands::CmdStop, &mut res, 0, mem::size_of::<u32>())?; 443 444 Ok(()) 445 } 446 447 pub fn get_buffer_size(&mut self) -> usize { 448 self.set_buffer_size(0).unwrap_or(TPM_CRB_BUFFER_MAX) 449 } 450 } 451