xref: /cloud-hypervisor/tpm/src/emulator.rs (revision 3541cebbf1f934165945ca21651ed33342a3ffea)
119fdf8bcSPraveen K Paladugu // Copyright © 2022, Microsoft Corporation
219fdf8bcSPraveen K Paladugu //
319fdf8bcSPraveen K Paladugu // SPDX-License-Identifier: Apache-2.0
419fdf8bcSPraveen K Paladugu //
519fdf8bcSPraveen K Paladugu 
619fdf8bcSPraveen K Paladugu use std::os::unix::io::RawFd;
719fdf8bcSPraveen K Paladugu use std::path::Path;
819fdf8bcSPraveen K Paladugu use std::{mem, ptr};
988a9f799SRob Bradford 
1088a9f799SRob Bradford use anyhow::anyhow;
1161e57e1cSRuoqing He use libc::{c_void, sockaddr_storage, socklen_t};
1219fdf8bcSPraveen K Paladugu use thiserror::Error;
1319fdf8bcSPraveen K Paladugu 
1488a9f799SRob Bradford use crate::socket::SocketDev;
1561e57e1cSRuoqing He use crate::{
1661e57e1cSRuoqing He     Commands, MemberType, Ptm, PtmCap, PtmEst, PtmInit, PtmResult, PtmSetBufferSize,
1761e57e1cSRuoqing He     TPM_CRB_BUFFER_MAX, TPM_SUCCESS,
1861e57e1cSRuoqing He };
1988a9f799SRob Bradford 
2019fdf8bcSPraveen K Paladugu const TPM_REQ_HDR_SIZE: usize = 10;
2119fdf8bcSPraveen K Paladugu 
2219fdf8bcSPraveen K Paladugu /* capability flags returned by PTM_GET_CAPABILITY */
2319fdf8bcSPraveen K Paladugu const PTM_CAP_INIT: u64 = 1;
2419fdf8bcSPraveen K Paladugu const PTM_CAP_SHUTDOWN: u64 = 1 << 1;
2519fdf8bcSPraveen K Paladugu const PTM_CAP_GET_TPMESTABLISHED: u64 = 1 << 2;
2619fdf8bcSPraveen K Paladugu const PTM_CAP_SET_LOCALITY: u64 = 1 << 3;
2719fdf8bcSPraveen K Paladugu const PTM_CAP_CANCEL_TPM_CMD: u64 = 1 << 5;
2819fdf8bcSPraveen K Paladugu const PTM_CAP_RESET_TPMESTABLISHED: u64 = 1 << 7;
2919fdf8bcSPraveen K Paladugu const PTM_CAP_STOP: u64 = 1 << 10;
3019fdf8bcSPraveen K Paladugu const PTM_CAP_SET_DATAFD: u64 = 1 << 12;
3119fdf8bcSPraveen K Paladugu const PTM_CAP_SET_BUFFERSIZE: u64 = 1 << 13;
3219fdf8bcSPraveen K Paladugu 
3319fdf8bcSPraveen K Paladugu ///Check if the input command is selftest
3419fdf8bcSPraveen K Paladugu ///
is_selftest(input: &[u8]) -> bool35cffde0ffSWei Liu pub fn is_selftest(input: &[u8]) -> bool {
36cffde0ffSWei Liu     if input.len() >= TPM_REQ_HDR_SIZE {
3719fdf8bcSPraveen K Paladugu         let ordinal: &[u8; 4] = input[6..6 + 4]
3819fdf8bcSPraveen K Paladugu             .try_into()
3919fdf8bcSPraveen K Paladugu             .expect("slice with incorrect length");
4019fdf8bcSPraveen K Paladugu 
4119fdf8bcSPraveen K Paladugu         return u32::from_ne_bytes(*ordinal).to_be() == 0x143;
4219fdf8bcSPraveen K Paladugu     }
4319fdf8bcSPraveen K Paladugu     false
4419fdf8bcSPraveen K Paladugu }
4519fdf8bcSPraveen K Paladugu 
4619fdf8bcSPraveen K Paladugu #[derive(Error, Debug)]
4719fdf8bcSPraveen K Paladugu pub enum Error {
48*3541cebbSPhilipp Schuster     #[error("Could not initialize emulator's backend")]
4919fdf8bcSPraveen K Paladugu     InitializeEmulator(#[source] anyhow::Error),
50*3541cebbSPhilipp Schuster     #[error("Failed to create data fd to pass to swtpm")]
5119fdf8bcSPraveen K Paladugu     PrepareDataFd(#[source] anyhow::Error),
52*3541cebbSPhilipp Schuster     #[error("Failed to run Control Cmd")]
5319fdf8bcSPraveen K Paladugu     RunControlCmd(#[source] anyhow::Error),
54*3541cebbSPhilipp Schuster     #[error("Emulator doesn't implement min required capabilities")]
5519fdf8bcSPraveen K Paladugu     CheckCaps(#[source] anyhow::Error),
56*3541cebbSPhilipp Schuster     #[error("Emulator failed to deliver request")]
5719fdf8bcSPraveen K Paladugu     DeliverRequest(#[source] anyhow::Error),
58*3541cebbSPhilipp Schuster     #[error("Emulator failed to send/receive msg on data fd")]
5919fdf8bcSPraveen K Paladugu     SendReceive(#[source] anyhow::Error),
60*3541cebbSPhilipp Schuster     #[error("Incorrect response to Self Test")]
6119fdf8bcSPraveen K Paladugu     SelfTest(#[source] anyhow::Error),
6219fdf8bcSPraveen K Paladugu }
6319fdf8bcSPraveen K Paladugu 
6419fdf8bcSPraveen K Paladugu type Result<T> = anyhow::Result<T, Error>;
6519fdf8bcSPraveen K Paladugu 
66cffde0ffSWei Liu pub struct BackendCmd<'a> {
67cffde0ffSWei Liu     // This buffer is used for both input and output.
68cffde0ffSWei Liu     // When used for input, the length of the data is input_len.
69cffde0ffSWei Liu     pub buffer: &'a mut [u8],
7019fdf8bcSPraveen K Paladugu     pub input_len: usize,
7119fdf8bcSPraveen K Paladugu }
7219fdf8bcSPraveen K Paladugu 
7319fdf8bcSPraveen K Paladugu pub struct Emulator {
7419fdf8bcSPraveen K Paladugu     caps: PtmCap, /* capabilities of the TPM */
7519fdf8bcSPraveen K Paladugu     control_socket: SocketDev,
7619fdf8bcSPraveen K Paladugu     data_fd: RawFd,
7719fdf8bcSPraveen K Paladugu     established_flag_cached: bool,
7819fdf8bcSPraveen K Paladugu     established_flag: bool,
7919fdf8bcSPraveen K Paladugu }
8019fdf8bcSPraveen K Paladugu 
8119fdf8bcSPraveen K Paladugu impl Emulator {
8219fdf8bcSPraveen K Paladugu     /// Create Emulator Instance
8319fdf8bcSPraveen K Paladugu     ///
8419fdf8bcSPraveen K Paladugu     /// # Arguments
8519fdf8bcSPraveen K Paladugu     ///
8619fdf8bcSPraveen K Paladugu     /// * `path` - A path to the Unix Domain Socket swtpm is listening on
8719fdf8bcSPraveen K Paladugu     ///
new(path: String) -> Result<Self>8819fdf8bcSPraveen K Paladugu     pub fn new(path: String) -> Result<Self> {
8919fdf8bcSPraveen K Paladugu         if !Path::new(&path).exists() {
9019fdf8bcSPraveen K Paladugu             return Err(Error::InitializeEmulator(anyhow!(
9119fdf8bcSPraveen K Paladugu                 "The input TPM Socket path: {:?} does not exist",
9219fdf8bcSPraveen K Paladugu                 path
9319fdf8bcSPraveen K Paladugu             )));
9419fdf8bcSPraveen K Paladugu         }
9519fdf8bcSPraveen K Paladugu         let mut socket = SocketDev::new();
9619fdf8bcSPraveen K Paladugu         socket.init(path).map_err(|e| {
9719fdf8bcSPraveen K Paladugu             Error::InitializeEmulator(anyhow!("Failed while initializing tpm emulator: {:?}", e))
9819fdf8bcSPraveen K Paladugu         })?;
9919fdf8bcSPraveen K Paladugu 
10019fdf8bcSPraveen K Paladugu         let mut emulator = Self {
10119fdf8bcSPraveen K Paladugu             caps: 0,
10219fdf8bcSPraveen K Paladugu             control_socket: socket,
10319fdf8bcSPraveen K Paladugu             data_fd: -1,
10419fdf8bcSPraveen K Paladugu             established_flag_cached: false,
10519fdf8bcSPraveen K Paladugu             established_flag: false,
10619fdf8bcSPraveen K Paladugu         };
10719fdf8bcSPraveen K Paladugu 
10819fdf8bcSPraveen K Paladugu         emulator.prepare_data_fd()?;
10919fdf8bcSPraveen K Paladugu 
11019fdf8bcSPraveen K Paladugu         emulator.probe_caps()?;
11119fdf8bcSPraveen K Paladugu         if !emulator.check_caps() {
11219fdf8bcSPraveen K Paladugu             return Err(Error::InitializeEmulator(anyhow!(
11319fdf8bcSPraveen K Paladugu                 "Required capabilities not supported by tpm backend"
11419fdf8bcSPraveen K Paladugu             )));
11519fdf8bcSPraveen K Paladugu         }
11619fdf8bcSPraveen K Paladugu 
11719fdf8bcSPraveen K Paladugu         if !emulator.get_established_flag() {
11819fdf8bcSPraveen K Paladugu             return Err(Error::InitializeEmulator(anyhow!(
11919fdf8bcSPraveen K Paladugu                 "TPM not in established state"
12019fdf8bcSPraveen K Paladugu             )));
12119fdf8bcSPraveen K Paladugu         }
12219fdf8bcSPraveen K Paladugu 
12319fdf8bcSPraveen K Paladugu         Ok(emulator)
12419fdf8bcSPraveen K Paladugu     }
12519fdf8bcSPraveen K Paladugu 
12619fdf8bcSPraveen K Paladugu     /// Create socketpair, assign one socket/FD as data_fd to Control Socket
12719fdf8bcSPraveen K Paladugu     /// The other socket/FD will be assigned to msg_fd, which will be sent to swtpm
12819fdf8bcSPraveen K Paladugu     /// via CmdSetDatafd control command
prepare_data_fd(&mut self) -> Result<()>12919fdf8bcSPraveen K Paladugu     fn prepare_data_fd(&mut self) -> Result<()> {
13019fdf8bcSPraveen K Paladugu         let mut res: PtmResult = 0;
13119fdf8bcSPraveen K Paladugu 
13219fdf8bcSPraveen K Paladugu         let mut fds = [-1, -1];
1337f4b5dfaSWei Liu         // SAFETY: FFI calls and return value of the unsafe call is checked
13419fdf8bcSPraveen K Paladugu         unsafe {
13519fdf8bcSPraveen K Paladugu             let ret = libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr());
13619fdf8bcSPraveen K Paladugu             if ret == -1 {
13719fdf8bcSPraveen K Paladugu                 return Err(Error::PrepareDataFd(anyhow!(
13819fdf8bcSPraveen K Paladugu                     "Failed to prepare data fd for tpm emulator. Error Code {:?}",
13919fdf8bcSPraveen K Paladugu                     std::io::Error::last_os_error()
14019fdf8bcSPraveen K Paladugu                 )));
14119fdf8bcSPraveen K Paladugu             }
14219fdf8bcSPraveen K Paladugu         }
14319fdf8bcSPraveen K Paladugu         self.control_socket.set_msgfd(fds[1]);
14419fdf8bcSPraveen K Paladugu         debug!("data fd to be configured in swtpm = {:?}", fds[1]);
14519fdf8bcSPraveen K Paladugu         self.run_control_cmd(Commands::CmdSetDatafd, &mut res, 0, mem::size_of::<u32>())?;
14619fdf8bcSPraveen K Paladugu         debug!("data fd in cloud-hypervisor = {:?}", fds[0]);
14719fdf8bcSPraveen K Paladugu         self.data_fd = fds[0];
1481143d54eSPraveen K Paladugu 
1491143d54eSPraveen K Paladugu         // SAFETY: FFI calls and return value of the unsafe call is checked
1501143d54eSPraveen K Paladugu         unsafe {
1511143d54eSPraveen K Paladugu             let tv = net_gen::iff::timeval {
1521143d54eSPraveen K Paladugu                 tv_sec: 0,
1531143d54eSPraveen K Paladugu                 tv_usec: 100000, // Set recv timeout to 100ms
1541143d54eSPraveen K Paladugu             };
1551143d54eSPraveen K Paladugu             let ret = net_gen::setsockopt(
1561143d54eSPraveen K Paladugu                 fds[0],
1571143d54eSPraveen K Paladugu                 net_gen::iff::SOL_SOCKET as i32,
1581143d54eSPraveen K Paladugu                 net_gen::iff::SO_RCVTIMEO as i32,
1591143d54eSPraveen K Paladugu                 &tv as *const _ as *const libc::c_void,
1601143d54eSPraveen K Paladugu                 std::mem::size_of::<net_gen::iff::timeval>() as u32,
1611143d54eSPraveen K Paladugu             );
1621143d54eSPraveen K Paladugu             if ret == -1 {
1631143d54eSPraveen K Paladugu                 return Err(Error::PrepareDataFd(anyhow!(
1641143d54eSPraveen K Paladugu                     "Failed to set receive timeout on data fd socket. Error Code {:?}",
1651143d54eSPraveen K Paladugu                     std::io::Error::last_os_error()
1661143d54eSPraveen K Paladugu                 )));
1671143d54eSPraveen K Paladugu             }
1681143d54eSPraveen K Paladugu         }
16919fdf8bcSPraveen K Paladugu         self.control_socket.set_datafd(fds[0]);
17019fdf8bcSPraveen K Paladugu         Ok(())
17119fdf8bcSPraveen K Paladugu     }
17219fdf8bcSPraveen K Paladugu 
17319fdf8bcSPraveen K Paladugu     /// Gather TPM Capabilities and cache them in Emulator
17419fdf8bcSPraveen K Paladugu     ///
probe_caps(&mut self) -> Result<()>17519fdf8bcSPraveen K Paladugu     fn probe_caps(&mut self) -> Result<()> {
17619fdf8bcSPraveen K Paladugu         let mut caps: u64 = 0;
17719fdf8bcSPraveen K Paladugu         self.run_control_cmd(
17819fdf8bcSPraveen K Paladugu             Commands::CmdGetCapability,
17919fdf8bcSPraveen K Paladugu             &mut caps,
18019fdf8bcSPraveen K Paladugu             0,
18119fdf8bcSPraveen K Paladugu             mem::size_of::<u64>(),
18219fdf8bcSPraveen K Paladugu         )?;
18319fdf8bcSPraveen K Paladugu         self.caps = caps;
18419fdf8bcSPraveen K Paladugu         Ok(())
18519fdf8bcSPraveen K Paladugu     }
18619fdf8bcSPraveen K Paladugu 
18742e9632cSJosh Soref     /// Check if minimum set of capabilities are supported
check_caps(&mut self) -> bool18819fdf8bcSPraveen K Paladugu     fn check_caps(&mut self) -> bool {
18919fdf8bcSPraveen K Paladugu         /* min. required capabilities for TPM 2.0*/
19019fdf8bcSPraveen K Paladugu         let caps: PtmCap = PTM_CAP_INIT
19119fdf8bcSPraveen K Paladugu             | PTM_CAP_SHUTDOWN
19219fdf8bcSPraveen K Paladugu             | PTM_CAP_GET_TPMESTABLISHED
19319fdf8bcSPraveen K Paladugu             | PTM_CAP_SET_LOCALITY
19419fdf8bcSPraveen K Paladugu             | PTM_CAP_RESET_TPMESTABLISHED
19519fdf8bcSPraveen K Paladugu             | PTM_CAP_SET_DATAFD
19619fdf8bcSPraveen K Paladugu             | PTM_CAP_STOP
19719fdf8bcSPraveen K Paladugu             | PTM_CAP_SET_BUFFERSIZE;
19819fdf8bcSPraveen K Paladugu 
19919fdf8bcSPraveen K Paladugu         if (self.caps & caps) != caps {
20019fdf8bcSPraveen K Paladugu             return false;
20119fdf8bcSPraveen K Paladugu         }
20219fdf8bcSPraveen K Paladugu         true
20319fdf8bcSPraveen K Paladugu     }
20419fdf8bcSPraveen K Paladugu 
20519fdf8bcSPraveen K Paladugu     ///
20619fdf8bcSPraveen K Paladugu     /// # Arguments
20719fdf8bcSPraveen K Paladugu     ///
20819fdf8bcSPraveen K Paladugu     /// * `cmd` - Control Command to run
20919fdf8bcSPraveen K Paladugu     /// * `msg` - Optional msg to be sent along with Control Command
21019fdf8bcSPraveen K Paladugu     /// * `msg_len_in` - len of 'msg' in bytes, if passed
21119fdf8bcSPraveen K Paladugu     /// * `msg_len_out` - length of expected output from Control Command in bytes
21219fdf8bcSPraveen K Paladugu     ///
run_control_cmd( &mut self, cmd: Commands, msg: &mut dyn Ptm, msg_len_in: usize, msg_len_out: usize, ) -> Result<()>21319fdf8bcSPraveen K Paladugu     fn run_control_cmd(
21419fdf8bcSPraveen K Paladugu         &mut self,
21519fdf8bcSPraveen K Paladugu         cmd: Commands,
21619fdf8bcSPraveen K Paladugu         msg: &mut dyn Ptm,
21719fdf8bcSPraveen K Paladugu         msg_len_in: usize,
21819fdf8bcSPraveen K Paladugu         msg_len_out: usize,
21919fdf8bcSPraveen K Paladugu     ) -> Result<()> {
22019fdf8bcSPraveen K Paladugu         debug!("Control Cmd to send : {:02X?}", cmd);
22119fdf8bcSPraveen K Paladugu 
22219fdf8bcSPraveen K Paladugu         let cmd_no = (cmd as u32).to_be_bytes();
2238e996ff2SWei Liu         let n = mem::size_of::<u32>() + msg_len_in;
22419fdf8bcSPraveen K Paladugu 
22519fdf8bcSPraveen K Paladugu         let converted_req = msg.ptm_to_request();
22619fdf8bcSPraveen K Paladugu         debug!("converted request: {:02X?}", converted_req);
22719fdf8bcSPraveen K Paladugu 
2288e996ff2SWei Liu         let mut buf = Vec::<u8>::with_capacity(n);
22919fdf8bcSPraveen K Paladugu 
23019fdf8bcSPraveen K Paladugu         buf.extend(cmd_no);
23119fdf8bcSPraveen K Paladugu         buf.extend(converted_req);
23219fdf8bcSPraveen K Paladugu         debug!("full Control request {:02X?}", buf);
23319fdf8bcSPraveen K Paladugu 
2345646a917SWei Liu         let written = self.control_socket.write(&buf).map_err(|e| {
23519fdf8bcSPraveen K Paladugu             Error::RunControlCmd(anyhow!(
23619fdf8bcSPraveen K Paladugu                 "Failed while running {:02X?} Control Cmd. Error: {:?}",
23719fdf8bcSPraveen K Paladugu                 cmd,
23819fdf8bcSPraveen K Paladugu                 e
23919fdf8bcSPraveen K Paladugu             ))
24019fdf8bcSPraveen K Paladugu         })?;
24119fdf8bcSPraveen K Paladugu 
2425646a917SWei Liu         if written < buf.len() {
2435646a917SWei Liu             return Err(Error::RunControlCmd(anyhow!(
2445646a917SWei Liu                 "Truncated write while running {:02X?} Control Cmd",
2455646a917SWei Liu                 cmd,
2465646a917SWei Liu             )));
2475646a917SWei Liu         }
2485646a917SWei Liu 
2496e22f238SWei Liu         // The largest response is 16 bytes so far.
2506e22f238SWei Liu         if msg_len_out > 16 {
2516e22f238SWei Liu             return Err(Error::RunControlCmd(anyhow!(
2526e22f238SWei Liu                 "Response size is too large for Cmd {:02X?}, max 16 wanted {}",
2536e22f238SWei Liu                 cmd,
2546e22f238SWei Liu                 msg_len_out
2556e22f238SWei Liu             )));
2566e22f238SWei Liu         }
2576e22f238SWei Liu 
2586e22f238SWei Liu         let mut output = [0u8; 16];
25919fdf8bcSPraveen K Paladugu 
26019fdf8bcSPraveen K Paladugu         // Every Control Cmd gets at least a result code in response. Read it
26119fdf8bcSPraveen K Paladugu         let read_size = self.control_socket.read(&mut output).map_err(|e| {
26219fdf8bcSPraveen K Paladugu             Error::RunControlCmd(anyhow!(
26319fdf8bcSPraveen K Paladugu                 "Failed while reading response for Control Cmd: {:02X?}. Error: {:?}",
26419fdf8bcSPraveen K Paladugu                 cmd,
26519fdf8bcSPraveen K Paladugu                 e
26619fdf8bcSPraveen K Paladugu             ))
26719fdf8bcSPraveen K Paladugu         })?;
26819fdf8bcSPraveen K Paladugu 
26919fdf8bcSPraveen K Paladugu         if msg_len_out != 0 {
27019fdf8bcSPraveen K Paladugu             msg.update_ptm_with_response(&output[0..read_size])
27119fdf8bcSPraveen K Paladugu                 .map_err(|e| {
27219fdf8bcSPraveen K Paladugu                     Error::RunControlCmd(anyhow!(
27319fdf8bcSPraveen K Paladugu                         "Failed while converting response of Control Cmd: {:02X?} to PTM. Error: {:?}",
27419fdf8bcSPraveen K Paladugu                         cmd,
27519fdf8bcSPraveen K Paladugu                         e
27619fdf8bcSPraveen K Paladugu                     ))
27719fdf8bcSPraveen K Paladugu                 })?;
27819fdf8bcSPraveen K Paladugu         } else {
27919fdf8bcSPraveen K Paladugu             // No response expected, only handle return code
28019fdf8bcSPraveen K Paladugu             msg.set_member_type(MemberType::Response);
28119fdf8bcSPraveen K Paladugu         }
28219fdf8bcSPraveen K Paladugu 
28319fdf8bcSPraveen K Paladugu         if msg.get_result_code() != TPM_SUCCESS {
28419fdf8bcSPraveen K Paladugu             return Err(Error::RunControlCmd(anyhow!(
28519fdf8bcSPraveen K Paladugu                 "Control Cmd returned error code : {:?}",
28619fdf8bcSPraveen K Paladugu                 msg.get_result_code()
28719fdf8bcSPraveen K Paladugu             )));
28819fdf8bcSPraveen K Paladugu         }
28919fdf8bcSPraveen K Paladugu         debug!("Control Cmd Response : {:02X?}", &output[0..read_size]);
29019fdf8bcSPraveen K Paladugu         Ok(())
29119fdf8bcSPraveen K Paladugu     }
29219fdf8bcSPraveen K Paladugu 
get_established_flag(&mut self) -> bool29319fdf8bcSPraveen K Paladugu     pub fn get_established_flag(&mut self) -> bool {
29419fdf8bcSPraveen K Paladugu         let mut est: PtmEst = PtmEst::new();
29519fdf8bcSPraveen K Paladugu 
29619fdf8bcSPraveen K Paladugu         if self.established_flag_cached {
29719fdf8bcSPraveen K Paladugu             return self.established_flag;
29819fdf8bcSPraveen K Paladugu         }
29919fdf8bcSPraveen K Paladugu 
30019fdf8bcSPraveen K Paladugu         if let Err(e) = self.run_control_cmd(
30119fdf8bcSPraveen K Paladugu             Commands::CmdGetTpmEstablished,
30219fdf8bcSPraveen K Paladugu             &mut est,
30319fdf8bcSPraveen K Paladugu             0,
30419fdf8bcSPraveen K Paladugu             2 * mem::size_of::<u32>(),
30519fdf8bcSPraveen K Paladugu         ) {
30619fdf8bcSPraveen K Paladugu             error!(
30719fdf8bcSPraveen K Paladugu                 "Failed to run CmdGetTpmEstablished Control Cmd. Error: {:?}",
30819fdf8bcSPraveen K Paladugu                 e
30919fdf8bcSPraveen K Paladugu             );
31019fdf8bcSPraveen K Paladugu             return false;
31119fdf8bcSPraveen K Paladugu         }
31219fdf8bcSPraveen K Paladugu 
31319fdf8bcSPraveen K Paladugu         self.established_flag_cached = true;
31489e658d9SRob Bradford         self.established_flag = est.resp.bit == 0;
31519fdf8bcSPraveen K Paladugu 
31619fdf8bcSPraveen K Paladugu         self.established_flag
31719fdf8bcSPraveen K Paladugu     }
31819fdf8bcSPraveen K Paladugu 
31919fdf8bcSPraveen K Paladugu     /// Function to write to data socket and read the response from it
deliver_request(&mut self, cmd: &mut BackendCmd) -> Result<()>320cffde0ffSWei Liu     pub fn deliver_request(&mut self, cmd: &mut BackendCmd) -> Result<()> {
3217f4b5dfaSWei Liu         // SAFETY: type "sockaddr_storage" is valid with an all-zero byte-pattern value
32219fdf8bcSPraveen K Paladugu         let mut addr: sockaddr_storage = unsafe { mem::zeroed() };
32319fdf8bcSPraveen K Paladugu         let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
32473af65f4SWei Liu         let isselftest = is_selftest(&cmd.buffer[0..cmd.input_len]);
32519fdf8bcSPraveen K Paladugu 
32619fdf8bcSPraveen K Paladugu         debug!(
32719fdf8bcSPraveen K Paladugu             "Send cmd: {:02X?}  of len {:?} on data_ioc ",
328cffde0ffSWei Liu             cmd.buffer, cmd.input_len
32919fdf8bcSPraveen K Paladugu         );
33019fdf8bcSPraveen K Paladugu 
33119fdf8bcSPraveen K Paladugu         let data_vecs = [libc::iovec {
332cffde0ffSWei Liu             iov_base: cmd.buffer.as_ptr() as *mut libc::c_void,
333cffde0ffSWei Liu             iov_len: cmd.input_len,
33419fdf8bcSPraveen K Paladugu         }; 1];
33519fdf8bcSPraveen K Paladugu 
3367f4b5dfaSWei Liu         // SAFETY: all zero values from the unsafe method are updated before usage
33719fdf8bcSPraveen K Paladugu         let mut msghdr: libc::msghdr = unsafe { mem::zeroed() };
33819fdf8bcSPraveen K Paladugu         msghdr.msg_name = ptr::null_mut();
33919fdf8bcSPraveen K Paladugu         msghdr.msg_namelen = 0;
34019fdf8bcSPraveen K Paladugu         msghdr.msg_iov = data_vecs.as_ptr() as *mut libc::iovec;
34119fdf8bcSPraveen K Paladugu         msghdr.msg_iovlen = data_vecs.len() as _;
34219fdf8bcSPraveen K Paladugu         msghdr.msg_control = ptr::null_mut();
34319fdf8bcSPraveen K Paladugu         msghdr.msg_controllen = 0;
34419fdf8bcSPraveen K Paladugu         msghdr.msg_flags = 0;
3457f4b5dfaSWei Liu         // SAFETY: FFI call and the return value of the unsafe method is checked
34619fdf8bcSPraveen K Paladugu         unsafe {
34719fdf8bcSPraveen K Paladugu             let ret = libc::sendmsg(self.data_fd, &msghdr, 0);
34819fdf8bcSPraveen K Paladugu             if ret == -1 {
34919fdf8bcSPraveen K Paladugu                 return Err(Error::SendReceive(anyhow!(
35019fdf8bcSPraveen K Paladugu                     "Failed to send tpm command over Data FD. Error Code {:?}",
35119fdf8bcSPraveen K Paladugu                     std::io::Error::last_os_error()
35219fdf8bcSPraveen K Paladugu                 )));
35319fdf8bcSPraveen K Paladugu             }
35419fdf8bcSPraveen K Paladugu         }
35519fdf8bcSPraveen K Paladugu 
356cffde0ffSWei Liu         let output_len;
3577f4b5dfaSWei Liu         // SAFETY: FFI calls and return value from unsafe method is checked
35819fdf8bcSPraveen K Paladugu         unsafe {
35919fdf8bcSPraveen K Paladugu             let ret = libc::recvfrom(
36019fdf8bcSPraveen K Paladugu                 self.data_fd,
361cffde0ffSWei Liu                 cmd.buffer.as_mut_ptr() as *mut c_void,
362cffde0ffSWei Liu                 cmd.buffer.len(),
36319fdf8bcSPraveen K Paladugu                 0,
36419fdf8bcSPraveen K Paladugu                 &mut addr as *mut libc::sockaddr_storage as *mut libc::sockaddr,
36519fdf8bcSPraveen K Paladugu                 &mut len as *mut socklen_t,
36619fdf8bcSPraveen K Paladugu             );
36719fdf8bcSPraveen K Paladugu             if ret == -1 {
36819fdf8bcSPraveen K Paladugu                 return Err(Error::SendReceive(anyhow!(
36919fdf8bcSPraveen K Paladugu                     "Failed to receive response for tpm command over Data FD. Error Code {:?}",
37019fdf8bcSPraveen K Paladugu                     std::io::Error::last_os_error()
37119fdf8bcSPraveen K Paladugu                 )));
37219fdf8bcSPraveen K Paladugu             }
373cffde0ffSWei Liu             output_len = ret as usize;
37419fdf8bcSPraveen K Paladugu         }
37519fdf8bcSPraveen K Paladugu         debug!(
37619fdf8bcSPraveen K Paladugu             "response = {:02X?} len = {:?} selftest = {:?}",
377cffde0ffSWei Liu             cmd.buffer, output_len, isselftest
37819fdf8bcSPraveen K Paladugu         );
37919fdf8bcSPraveen K Paladugu 
38073af65f4SWei Liu         if isselftest && output_len < 10 {
38119fdf8bcSPraveen K Paladugu             return Err(Error::SelfTest(anyhow!(
38219fdf8bcSPraveen K Paladugu                 "Self test response should have 10 bytes. Only {:?} returned",
383cffde0ffSWei Liu                 output_len
38419fdf8bcSPraveen K Paladugu             )));
38519fdf8bcSPraveen K Paladugu         }
38619fdf8bcSPraveen K Paladugu 
38719fdf8bcSPraveen K Paladugu         Ok(())
38819fdf8bcSPraveen K Paladugu     }
38919fdf8bcSPraveen K Paladugu 
cancel_cmd(&mut self) -> Result<()>39019fdf8bcSPraveen K Paladugu     pub fn cancel_cmd(&mut self) -> Result<()> {
39119fdf8bcSPraveen K Paladugu         let mut res: PtmResult = 0;
39219fdf8bcSPraveen K Paladugu 
39319fdf8bcSPraveen K Paladugu         // Check if emulator implements Cancel Cmd
39419fdf8bcSPraveen K Paladugu         if (self.caps & PTM_CAP_CANCEL_TPM_CMD) != PTM_CAP_CANCEL_TPM_CMD {
39519fdf8bcSPraveen K Paladugu             return Err(Error::CheckCaps(anyhow!(
39619fdf8bcSPraveen K Paladugu                 "Emulator does not implement 'Cancel Command' Capability"
39719fdf8bcSPraveen K Paladugu             )));
39819fdf8bcSPraveen K Paladugu         }
39919fdf8bcSPraveen K Paladugu         self.run_control_cmd(
40019fdf8bcSPraveen K Paladugu             Commands::CmdCancelTpmCmd,
40119fdf8bcSPraveen K Paladugu             &mut res,
40219fdf8bcSPraveen K Paladugu             0,
40319fdf8bcSPraveen K Paladugu             mem::size_of::<u32>(),
40419fdf8bcSPraveen K Paladugu         )?;
40519fdf8bcSPraveen K Paladugu         Ok(())
40619fdf8bcSPraveen K Paladugu     }
40719fdf8bcSPraveen K Paladugu 
40819fdf8bcSPraveen K Paladugu     /// Configure buffersize to use while communicating with swtpm
set_buffer_size(&mut self, wantedsize: usize) -> Result<usize>4091ce1fe73SWei Liu     fn set_buffer_size(&mut self, wantedsize: usize) -> Result<usize> {
41019fdf8bcSPraveen K Paladugu         let mut psbs: PtmSetBufferSize = PtmSetBufferSize::new(wantedsize as u32);
41119fdf8bcSPraveen K Paladugu 
41219fdf8bcSPraveen K Paladugu         self.stop_tpm()?;
41319fdf8bcSPraveen K Paladugu 
41419fdf8bcSPraveen K Paladugu         self.run_control_cmd(
41519fdf8bcSPraveen K Paladugu             Commands::CmdSetBufferSize,
41619fdf8bcSPraveen K Paladugu             &mut psbs,
41719fdf8bcSPraveen K Paladugu             mem::size_of::<u32>(),
41819fdf8bcSPraveen K Paladugu             4 * mem::size_of::<u32>(),
41919fdf8bcSPraveen K Paladugu         )?;
42019fdf8bcSPraveen K Paladugu 
4211ce1fe73SWei Liu         Ok(psbs.get_bufsize() as usize)
42219fdf8bcSPraveen K Paladugu     }
42319fdf8bcSPraveen K Paladugu 
startup_tpm(&mut self, buffersize: usize) -> Result<()>42419fdf8bcSPraveen K Paladugu     pub fn startup_tpm(&mut self, buffersize: usize) -> Result<()> {
42519fdf8bcSPraveen K Paladugu         let mut init: PtmInit = PtmInit::new();
42619fdf8bcSPraveen K Paladugu 
42719fdf8bcSPraveen K Paladugu         if buffersize != 0 {
4281ce1fe73SWei Liu             let actual_size = self.set_buffer_size(buffersize)?;
4291ce1fe73SWei Liu             debug!("set tpm buffersize to {:?} during Startup", actual_size);
43019fdf8bcSPraveen K Paladugu         }
43119fdf8bcSPraveen K Paladugu 
43219fdf8bcSPraveen K Paladugu         self.run_control_cmd(
43319fdf8bcSPraveen K Paladugu             Commands::CmdInit,
43419fdf8bcSPraveen K Paladugu             &mut init,
43519fdf8bcSPraveen K Paladugu             mem::size_of::<u32>(),
43619fdf8bcSPraveen K Paladugu             mem::size_of::<u32>(),
43719fdf8bcSPraveen K Paladugu         )?;
43819fdf8bcSPraveen K Paladugu 
43919fdf8bcSPraveen K Paladugu         Ok(())
44019fdf8bcSPraveen K Paladugu     }
44119fdf8bcSPraveen K Paladugu 
stop_tpm(&mut self) -> Result<()>44219fdf8bcSPraveen K Paladugu     fn stop_tpm(&mut self) -> Result<()> {
44319fdf8bcSPraveen K Paladugu         let mut res: PtmResult = 0;
44419fdf8bcSPraveen K Paladugu 
44519fdf8bcSPraveen K Paladugu         self.run_control_cmd(Commands::CmdStop, &mut res, 0, mem::size_of::<u32>())?;
44619fdf8bcSPraveen K Paladugu 
44719fdf8bcSPraveen K Paladugu         Ok(())
44819fdf8bcSPraveen K Paladugu     }
44919fdf8bcSPraveen K Paladugu 
get_buffer_size(&mut self) -> usize45060425471SWei Liu     pub fn get_buffer_size(&mut self) -> usize {
4511ce1fe73SWei Liu         self.set_buffer_size(0).unwrap_or(TPM_CRB_BUFFER_MAX)
45219fdf8bcSPraveen K Paladugu     }
45319fdf8bcSPraveen K Paladugu }
454