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