mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
tpm: fix swtpm reset handling
Windows reboot recreates the TPM device while the swtpm process keeps running. Leaving the transferred data fd open made a later CmdSetDatafd fail, and the backend could remain unstarted after CmdInit. Close both ends on setup failure, close the local transferred fd after success, close the data fd on drop, and issue TPM2_Startup(CLEAR) after CmdInit while tolerating an already-started TPM. Assisted-by: Copilot:GPT-5.5 Signed-off-by: Wei Liu <liuwe@microsoft.com>
This commit is contained in:
@@ -19,6 +19,13 @@ use crate::{
|
||||
};
|
||||
|
||||
const TPM_REQ_HDR_SIZE: usize = 10;
|
||||
const TPM_RC_INITIALIZE: u32 = 0x100;
|
||||
const TPM2_STARTUP_CLEAR: [u8; 12] = [
|
||||
0x80, 0x01, // TPM_ST_NO_SESSIONS
|
||||
0x00, 0x00, 0x00, 0x0c, // commandSize
|
||||
0x00, 0x00, 0x01, 0x44, // TPM_CC_Startup
|
||||
0x00, 0x00, // TPM_SU_CLEAR
|
||||
];
|
||||
|
||||
/* capability flags returned by PTM_GET_CAPABILITY */
|
||||
const PTM_CAP_INIT: u64 = 1;
|
||||
@@ -145,7 +152,35 @@ impl Emulator {
|
||||
}
|
||||
self.control_socket.set_msgfd(fds[1]);
|
||||
debug!("data fd to be configured in swtpm = {:?}", fds[1]);
|
||||
self.run_control_cmd(Commands::CmdSetDatafd, &mut res, 0, mem::size_of::<u32>())?;
|
||||
if let Err(e) =
|
||||
self.run_control_cmd(Commands::CmdSetDatafd, &mut res, 0, mem::size_of::<u32>())
|
||||
{
|
||||
// SAFETY: FFI calls and return values of the unsafe calls are checked
|
||||
unsafe {
|
||||
if libc::close(fds[0]) == -1 {
|
||||
error!(
|
||||
"Failed to close TPM data fd after CmdSetDatafd failure: {:?}",
|
||||
std::io::Error::last_os_error()
|
||||
);
|
||||
}
|
||||
if libc::close(fds[1]) == -1 {
|
||||
error!(
|
||||
"Failed to close TPM swtpm fd after CmdSetDatafd failure: {:?}",
|
||||
std::io::Error::last_os_error()
|
||||
);
|
||||
}
|
||||
}
|
||||
return Err(e);
|
||||
}
|
||||
// SAFETY: FFI call and return value of the unsafe call is checked
|
||||
unsafe {
|
||||
if libc::close(fds[1]) == -1 {
|
||||
error!(
|
||||
"Failed to close local TPM swtpm fd: {:?}",
|
||||
std::io::Error::last_os_error()
|
||||
);
|
||||
}
|
||||
}
|
||||
debug!("data fd in cloud-hypervisor = {:?}", fds[0]);
|
||||
self.data_fd = fds[0];
|
||||
|
||||
@@ -470,6 +505,27 @@ impl Emulator {
|
||||
mem::size_of::<u32>(),
|
||||
)?;
|
||||
|
||||
self.tpm2_startup_clear()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn tpm2_startup_clear(&mut self) -> Result<()> {
|
||||
let mut buffer = TPM2_STARTUP_CLEAR;
|
||||
let mut cmd = BackendCmd {
|
||||
buffer: &mut buffer,
|
||||
input_len: TPM2_STARTUP_CLEAR.len(),
|
||||
};
|
||||
|
||||
self.deliver_request(&mut cmd)?;
|
||||
|
||||
let response_code = u32::from_be_bytes(buffer[6..10].try_into().unwrap());
|
||||
if response_code != TPM_SUCCESS && response_code != TPM_RC_INITIALIZE {
|
||||
return Err(Error::DeliverRequest(anyhow!(
|
||||
"TPM2_Startup(CLEAR) returned error code: {response_code:#X}"
|
||||
)));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -485,3 +541,20 @@ impl Emulator {
|
||||
self.set_buffer_size(0).unwrap_or(TPM_CRB_BUFFER_MAX)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Emulator {
|
||||
fn drop(&mut self) {
|
||||
if self.data_fd >= 0 {
|
||||
// SAFETY: FFI call and return value of the unsafe call is checked
|
||||
unsafe {
|
||||
if libc::close(self.data_fd) == -1 {
|
||||
error!(
|
||||
"Failed to close TPM data fd: {:?}",
|
||||
std::io::Error::last_os_error()
|
||||
);
|
||||
}
|
||||
}
|
||||
self.data_fd = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user