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 ///
is_selftest(input: &[u8]) -> bool35 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")]
49 InitializeEmulator(#[source] anyhow::Error),
50 #[error("Failed to create data fd to pass to swtpm")]
51 PrepareDataFd(#[source] anyhow::Error),
52 #[error("Failed to run Control Cmd")]
53 RunControlCmd(#[source] anyhow::Error),
54 #[error("Emulator doesn't implement min required capabilities")]
55 CheckCaps(#[source] anyhow::Error),
56 #[error("Emulator failed to deliver request")]
57 DeliverRequest(#[source] anyhow::Error),
58 #[error("Emulator failed to send/receive msg on data fd")]
59 SendReceive(#[source] anyhow::Error),
60 #[error("Incorrect response to Self Test")]
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 ///
new(path: String) -> Result<Self>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
prepare_data_fd(&mut self) -> Result<()>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 ///
probe_caps(&mut self) -> Result<()>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
check_caps(&mut self) -> bool188 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 ///
run_control_cmd( &mut self, cmd: Commands, msg: &mut dyn Ptm, msg_len_in: usize, msg_len_out: usize, ) -> Result<()>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
get_established_flag(&mut self) -> bool293 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
deliver_request(&mut self, cmd: &mut BackendCmd) -> Result<()>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
cancel_cmd(&mut self) -> Result<()>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
set_buffer_size(&mut self, wantedsize: usize) -> Result<usize>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
startup_tpm(&mut self, buffersize: usize) -> Result<()>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
stop_tpm(&mut self) -> Result<()>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
get_buffer_size(&mut self) -> usize450 pub fn get_buffer_size(&mut self) -> usize {
451 self.set_buffer_size(0).unwrap_or(TPM_CRB_BUFFER_MAX)
452 }
453 }
454