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