From d262c812104fe6b808467976d69a4e7377222aaa Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Sat, 30 May 2026 13:42:30 -0700 Subject: [PATCH] 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 --- tpm/src/emulator.rs | 75 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/tpm/src/emulator.rs b/tpm/src/emulator.rs index bb795cbfd..5bea5a0bf 100644 --- a/tpm/src/emulator.rs +++ b/tpm/src/emulator.rs @@ -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::())?; + if let Err(e) = + self.run_control_cmd(Commands::CmdSetDatafd, &mut res, 0, mem::size_of::()) + { + // 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::(), )?; + 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; + } + } +}