Skip to content

Commit 77f4fe5

Browse files
committed
Add an initializer for static binaries to use
Signed-off-by: André Arko <andre@arko.net>
1 parent d715050 commit 77f4fe5

1 file changed

Lines changed: 96 additions & 2 deletions

File tree

tss-esapi/src/tcti_ldr.rs

Lines changed: 96 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,34 @@ const TABRMD: &str = "tabrmd";
2424
const LIBTPMS: &str = "libtpms";
2525
const TBS: &str = "tbs";
2626

27+
// libc malloc/free, declared inline to avoid a new dependency. Required for
28+
// Tss2_Tcti_Device_Init, which initialises a caller-
29+
// provided buffer in place, and on Drop we libc-free it ourselves.
30+
#[cfg(target_os = "linux")]
31+
unsafe extern "C" {
32+
fn malloc(size: usize) -> *mut std::ffi::c_void;
33+
fn free(p: *mut std::ffi::c_void);
34+
}
35+
36+
#[derive(Debug, Clone, Copy)]
37+
enum TctiInitMode {
38+
/// Allocated and initialized via `Tss2_TctiLdr_Initialize`; clean up
39+
/// with the matching `Tss2_TctiLdr_Finalize`.
40+
Loader,
41+
/// Allocated by us with `malloc` and initialized via
42+
/// `Tss2_Tcti_Device_Init`; clean up by calling the context's
43+
/// `finalize` fn pointer and then `free`-ing the buffer.
44+
#[cfg(target_os = "linux")]
45+
Direct,
46+
}
47+
2748
/// TCTI Context created via a TCTI Loader Library.
2849
/// Wrapper around the TSS2_TCTI_CONTEXT structure.
2950
#[derive(Debug)]
3051
#[allow(missing_copy_implementations)]
3152
pub struct TctiContext {
3253
tcti_context: *mut tss_esapi_sys::TSS2_TCTI_CONTEXT,
54+
init_mode: TctiInitMode,
3355
}
3456

3557
impl TctiContext {
@@ -48,7 +70,61 @@ impl TctiContext {
4870
},
4971
)?;
5072

51-
Ok(TctiContext { tcti_context })
73+
Ok(TctiContext {
74+
tcti_context,
75+
init_mode: TctiInitMode::Loader,
76+
})
77+
}
78+
79+
/// Allocate and initialize a Device TCTI context by calling
80+
/// `Tss2_Tcti_Device_Init` directly, bypassing the dlopen-based
81+
/// tctildr loader. Use this when the loader can't dlopen plugin
82+
/// shared objects — e.g. a statically-linked glibc binary.
83+
///
84+
/// Linux-only: depends on `/dev/tpm0` and on libtss2-tcti-device,
85+
/// neither of which exists on other platforms.
86+
#[cfg(target_os = "linux")]
87+
pub fn initialize_device_direct(device_path: &std::path::Path) -> Result<Self> {
88+
let conf = device_path
89+
.to_str()
90+
.and_then(|s| CString::new(s).ok())
91+
.ok_or(Error::WrapperError(WrapperErrorKind::InvalidParam))?;
92+
93+
unsafe {
94+
let mut size: tss_esapi_sys::size_t = 0;
95+
let ret = tss_esapi_sys::Tss2_Tcti_Device_Init(null_mut(), &mut size, conf.as_ptr());
96+
let ret = Error::from_tss_rc(ret);
97+
if !ret.is_success() {
98+
error!("Error querying Device TCTI size: {}", ret);
99+
return Err(ret);
100+
}
101+
102+
let buf = malloc(size as usize) as *mut tss_esapi_sys::TSS2_TCTI_CONTEXT;
103+
if buf.is_null() {
104+
return Err(Error::WrapperError(WrapperErrorKind::InternalError));
105+
}
106+
107+
let ret = tss_esapi_sys::Tss2_Tcti_Device_Init(buf, &mut size, conf.as_ptr());
108+
let ret = Error::from_tss_rc(ret);
109+
if !ret.is_success() {
110+
// The TSS2 TCTI spec requires init to be atomic: on a non-
111+
// success return, no externally-visible state (file
112+
// descriptors, allocations beyond the caller's buffer) is
113+
// owned by the partially-initialized context. libtss2's
114+
// device TCTI honors this — it closes the fd before
115+
// returning the error — so freeing the buffer without
116+
// calling the (possibly-uninitialized) finalize fn pointer
117+
// is the correct cleanup here.
118+
free(buf as *mut std::ffi::c_void);
119+
error!("Error initializing Device TCTI: {}", ret);
120+
return Err(ret);
121+
}
122+
123+
Ok(TctiContext {
124+
tcti_context: buf,
125+
init_mode: TctiInitMode::Direct,
126+
})
127+
}
52128
}
53129

54130
/// Get access to the inner C pointer
@@ -120,7 +196,25 @@ impl TctiInfo {
120196
impl Drop for TctiInfo {
121197
fn drop(&mut self) {
122198
unsafe {
123-
tss_esapi_sys::Tss2_TctiLdr_FreeInfo(&mut self.tcti_info);
199+
match self.init_mode {
200+
TctiInitMode::Loader => {
201+
tss_esapi_sys::Tss2_TctiLdr_Finalize(&mut self.tcti_context);
202+
}
203+
#[cfg(target_os = "linux")]
204+
TctiInitMode::Direct => {
205+
// Tss2_TctiLdr_Finalize would cast the buffer to a
206+
// TSS2_TCTILDR_CONTEXT and dereference loader-only fields
207+
// that don't exist here, leaking the TPM fd. Use the
208+
// TCTI's own finalize fn pointer (offset is identical in
209+
// V1, V2, and V3 layouts), then libc-free the buffer.
210+
let common =
211+
self.tcti_context as *mut tss_esapi_sys::TSS2_TCTI_CONTEXT_COMMON_V1;
212+
if let Some(finalize) = (*common).finalize {
213+
finalize(self.tcti_context);
214+
}
215+
free(self.tcti_context as *mut std::ffi::c_void);
216+
}
217+
}
124218
}
125219
}
126220
}

0 commit comments

Comments
 (0)