blob: a9478b2f7ba4119cb0a7440984d416ef2eda8c7f [file] [log] [blame]
// Copyright 2024 The Fuchsia Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#![allow(dead_code)]
use anyhow::Error;
use tee_internal_impl::binding::{TEE_Param, TEE_Result};
pub type SessionContext = *mut ::std::os::raw::c_void;
pub trait TAInterface {
fn create(&self) -> TEE_Result;
fn destroy(&self);
fn open_session(
&self,
param_types: u32,
params: *mut TEE_Param,
session_context: *mut SessionContext,
) -> TEE_Result;
fn close_session(&self, session_context: SessionContext);
fn invoke_command(
&self,
session_context: SessionContext,
command_id: u32,
param_types: u32,
params: *mut TEE_Param,
) -> TEE_Result;
}
struct TAFunctions {
create_fn: fn() -> TEE_Result,
destroy_fn: fn(),
open_session_fn: fn(
param_types: u32,
params: *mut TEE_Param,
session_context: *mut SessionContext,
) -> TEE_Result,
close_session_fn: fn(session_context: SessionContext),
invoke_command_fn: fn(
session_context: SessionContext,
command_id: u32,
param_types: u32,
params: *mut TEE_Param,
) -> TEE_Result,
}
impl TAInterface for TAFunctions {
fn create(&self) -> TEE_Result {
(self.create_fn)()
}
fn destroy(&self) {
(self.destroy_fn)()
}
fn open_session(
&self,
param_types: u32,
params: *mut TEE_Param,
session_context: *mut SessionContext,
) -> TEE_Result {
(self.open_session_fn)(param_types, params, session_context)
}
fn close_session(&self, session_context: SessionContext) {
(self.close_session_fn)(session_context)
}
fn invoke_command(
&self,
session_context: SessionContext,
command_id: u32,
param_types: u32,
params: *mut TEE_Param,
) -> TEE_Result {
(self.invoke_command_fn)(session_context, command_id, param_types, params)
}
}
fn load_sym(handle: *mut libc::c_void, name: &std::ffi::CStr) -> Result<*const (), Error> {
let fun = unsafe { libc::dlsym(handle, name.as_ptr()) };
if fun.is_null() {
anyhow::bail!("Could not find symbol {name:?}: {:?}", std::io::Error::last_os_error());
}
Ok(fun as *const ())
}
pub fn load_ta(name: &std::ffi::CStr) -> Result<impl TAInterface, Error> {
let handle = unsafe { libc::dlopen(name.as_ptr(), libc::RTLD_NOW | libc::RTLD_LOCAL) };
if handle.is_null() {
anyhow::bail!("Could not load {name:?}: {:?}", std::io::Error::last_os_error());
}
Ok(TAFunctions {
create_fn: unsafe { std::mem::transmute(load_sym(handle, c"TA_CreateEntryPoint")?) },
destroy_fn: unsafe { std::mem::transmute(load_sym(handle, c"TA_DestroyEntryPoint")?) },
open_session_fn: unsafe {
std::mem::transmute(load_sym(handle, c"TA_OpenSessionEntryPoint")?)
},
close_session_fn: unsafe {
std::mem::transmute(load_sym(handle, c"TA_CloseSessionEntryPoint")?)
},
invoke_command_fn: unsafe {
std::mem::transmute(load_sym(handle, c"TA_InvokeCommandEntryPoint")?)
},
})
}
#[cfg(test)]
mod test {
use super::*;
// The C string literal syntax c"foo" isn't supported by #[fuchsia::test] so
// we use a helper function instead to construct &CStrs from literals.
// TODO(https://fxbug.dev/332964901): Remove this and use C-string literals
// once supported.
fn c_str<'a>(s: &'a [u8]) -> &'a std::ffi::CStr {
std::ffi::CStr::from_bytes_with_nul(s).unwrap()
}
#[fuchsia::test]
fn load_missing_so() {
let result = load_ta(c_str(b"libta_loader_test_missing.so\0"));
assert!(result.is_err());
}
#[fuchsia::test]
fn load_ta_missing_entry_points() {
let result = load_ta(c_str(b"libta_loader_test_missing_entry_points.so\0"));
assert!(result.is_err());
}
#[fuchsia::test]
fn load_ta_complete() {
let result = load_ta(c_str(b"libta_loader_test_complete.so\0"));
assert!(!result.is_err());
}
}