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