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