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