#![allow(dead_code)]
#![allow(non_camel_case_types)]
#![allow(non_upper_case_globals)]
#![allow(non_snake_case)]
use std::{
ffi::{c_char, c_void},
ptr,
sync::{
Arc, Mutex,
atomic::{AtomicI32, Ordering},
},
};
use dashmap::DashMap;
use log::{debug, warn};
use once_cell::sync::Lazy;
use postcard::{take_from_bytes, to_allocvec};
use uuid::Uuid;
use crate::cc_client::client::CcClient;
use crate::common::protocol::{
PacketType, TEE_ParamType, TEE_Parameters, TEE_Request, TEE_Response,
};
use crate::{Error, ErrorKind, ErrorOrigin, Result, raw};
const SHM_FLAG_BUFFER_ALLOCED: u32 = 1 << 0;
type ContextMap = DashMap<i32, Arc<Mutex<CcClient>>>;
type SharedMemoryMap = DashMap<i32, Vec<u8>>;
static TEEC_MUTEX: Lazy<Mutex<()>> = Lazy::new(|| Mutex::new(()));
static CONTEXT_ID_COUNTER: Lazy<AtomicI32> = Lazy::new(|| AtomicI32::new(-1));
static CONTEXTS: Lazy<ContextMap> = Lazy::new(DashMap::new);
static SHMS: Lazy<SharedMemoryMap> = Lazy::new(DashMap::new);
mod safe_ptr {
use super::{Error, ErrorKind, ErrorOrigin, Result};
use std::ptr::NonNull;
pub fn deref_mut<T>(ptr: *mut T) -> Result<NonNull<T>> {
NonNull::new(ptr).ok_or(Error::new(ErrorKind::BadParameters).with_origin(ErrorOrigin::API))
}
pub fn deref<T>(ptr: *const T) -> Result<NonNull<T>> {
NonNull::new(ptr as *mut T)
.ok_or(Error::new(ErrorKind::BadParameters).with_origin(ErrorOrigin::API))
}
pub fn write_raw<T>(ptr: *mut T, value: T) -> Result<()> {
let nn = NonNull::new(ptr)
.ok_or(Error::new(ErrorKind::BadParameters).with_origin(ErrorOrigin::API))?;
unsafe { nn.as_ptr().write(value) };
Ok(())
}
pub fn read_raw<T: Copy>(ptr: *const T) -> Result<T> {
let nn = NonNull::new(ptr as *mut T)
.ok_or(Error::new(ErrorKind::BadParameters).with_origin(ErrorOrigin::API))?;
Ok(unsafe { *nn.as_ptr() })
}
pub fn read_to_vec<T: Copy>(src: *const T, len: usize) -> Result<Vec<T>> {
if src.is_null() && len > 0 {
return Err(Error::new(ErrorKind::BadParameters).with_origin(ErrorOrigin::API));
}
let _nn = NonNull::new(src as *mut T)
.ok_or(Error::new(ErrorKind::BadParameters).with_origin(ErrorOrigin::API))?;
let slice = unsafe { std::slice::from_raw_parts(src, len) };
Ok(slice.to_vec())
}
pub fn write_from_slice<T: Copy>(dst: *mut T, src: &[T]) -> Result<()> {
if dst.is_null() && !src.is_empty() {
return Err(Error::new(ErrorKind::BadParameters).with_origin(ErrorOrigin::API));
}
if src.is_empty() {
return Err(Error::new(ErrorKind::BadFormat).with_origin(ErrorOrigin::API));
}
let _nn = NonNull::new(dst)
.ok_or(Error::new(ErrorKind::BadParameters).with_origin(ErrorOrigin::API))?;
let dst_slice = unsafe { std::slice::from_raw_parts_mut(dst, src.len()) };
dst_slice.copy_from_slice(src);
Ok(())
}
pub fn add_ptr<T>(ptr: *const T, offset: usize) -> *const T {
unsafe { ptr.add(offset) }
}
pub fn add_ptr_mut<T>(ptr: *mut T, offset: usize) -> *mut T {
unsafe { ptr.add(offset) }
}
}
struct ContextManager;
impl ContextManager {
fn add_context(ctx: *mut raw::TEEC_Context, client: CcClient) -> Result<()> {
let mut ctx_nn = safe_ptr::deref_mut(ctx)?;
let ctx_ref = unsafe { ctx_nn.as_mut() };
let ctx_id: i32 = ctx_ref.imp.fd;
let client_arc = Arc::new(Mutex::new(client));
CONTEXTS.insert(ctx_id, client_arc);
Ok(())
}
fn remove_context(ctx: *mut raw::TEEC_Context) {
if let Ok(mut ctx_nn) = safe_ptr::deref_mut(ctx) {
let ctx_ref = unsafe { ctx_nn.as_mut() };
let ctx_id = ctx_ref.imp.fd;
CONTEXTS.remove(&ctx_id);
ctx_ref.imp.fd = -1;
}
}
fn get_client(ctx: *mut raw::TEEC_Context) -> Result<Arc<Mutex<CcClient>>> {
let ctx_nn = safe_ptr::deref_mut(ctx)?;
let ctx_ref = unsafe { ctx_nn.as_ref() };
let ctx_id = ctx_ref.imp.fd;
CONTEXTS
.get(&ctx_id)
.map(|entry| entry.value().clone())
.ok_or_else(|| Error::new(ErrorKind::Generic).with_origin(ErrorOrigin::API))
}
}
struct SharedMemoryManager;
impl SharedMemoryManager {
fn allocate(
ctx: *mut raw::TEEC_Context,
shm: *mut raw::TEEC_SharedMemory,
registe: bool,
) -> Result<()> {
let mut shm_nn = safe_ptr::deref_mut(shm)?;
let ctx_nn = safe_ptr::deref(ctx)?;
let shm_ref = unsafe { shm_nn.as_mut() };
let ctx_ref = unsafe { ctx_nn.as_ref() };
let flags = shm_ref.flags;
let size = shm_ref.size;
if size == 0 || flags == 0 || flags & !(raw::TEEC_MEM_INPUT | raw::TEEC_MEM_OUTPUT) != 0 {
return Err(Error::new(ErrorKind::BadParameters));
}
let mut buffer = vec![0u8; size];
if registe {
if shm_ref.buffer.is_null() {
return Err(Error::new(ErrorKind::BadParameters));
}
buffer = safe_ptr::read_to_vec(shm_ref.buffer as *const u8, size)?;
}
let ptr = buffer.as_mut_ptr() as *mut c_void;
if ptr.is_null() {
return Err(Error::new(ErrorKind::OutOfMemory));
}
let id = ctx_ref.imp.fd;
shm_ref.buffer = ptr;
shm_ref.imp.id = id;
shm_ref.imp.registered_fd = -1;
shm_ref.imp.shadow_buffer = ptr::null_mut();
shm_ref.imp.alloced_size = size;
shm_ref.imp.flags = SHM_FLAG_BUFFER_ALLOCED;
SHMS.insert(id, buffer);
Ok(())
}
fn release(shm: *mut raw::TEEC_SharedMemory) {
if let Ok(mut shm_nn) = safe_ptr::deref_mut(shm) {
let shm_ref = unsafe { shm_nn.as_mut() };
if shm_ref.imp.id < 0 {
return;
}
let id = shm_ref.imp.id;
shm_ref.imp.id = -1;
shm_ref.size = 0;
shm_ref.flags = 0;
shm_ref.buffer = ptr::null_mut();
SHMS.remove(&id);
}
}
fn get_buffer(shm: *const raw::TEEC_SharedMemory) -> Option<Vec<u8>> {
if shm.is_null() {
return None;
}
let id = unsafe { (*shm).imp.id };
SHMS.get(&id).map(|entry| entry.value().clone())
}
}
fn uuid_to_string(uuid: &raw::TEEC_UUID) -> Result<String> {
let bytes: [u8; 16] = [
(uuid.timeLow >> 24) as u8,
(uuid.timeLow >> 16) as u8,
(uuid.timeLow >> 8) as u8,
uuid.timeLow as u8,
(uuid.timeMid >> 8) as u8,
uuid.timeMid as u8,
(uuid.timeHiAndVersion >> 8) as u8,
uuid.timeHiAndVersion as u8,
uuid.clockSeqAndNode[0],
uuid.clockSeqAndNode[1],
uuid.clockSeqAndNode[2],
uuid.clockSeqAndNode[3],
uuid.clockSeqAndNode[4],
uuid.clockSeqAndNode[5],
uuid.clockSeqAndNode[6],
uuid.clockSeqAndNode[7],
];
Uuid::from_slice(&bytes)
.map(|u| u.to_string())
.map_err(|_| Error::new(ErrorKind::BadFormat))
}
struct OperationParams {
operation: *mut raw::TEEC_Operation,
}
impl OperationParams {
fn new(operation: *mut raw::TEEC_Operation) -> Result<Self> {
let _ = safe_ptr::deref_mut(operation)?;
Ok(Self { operation })
}
fn param_types(&self) -> Result<u32> {
let op_nn = safe_ptr::deref(self.operation)?;
let op_ref = unsafe { op_nn.as_ref() };
Ok(op_ref.paramTypes)
}
fn get_value(&self, idx: usize) -> Result<(u32, u32)> {
if idx >= raw::TEEC_CONFIG_PAYLOAD_REF_COUNT {
return Err(Error::new(ErrorKind::BadParameters));
}
let op_nn = safe_ptr::deref(self.operation)?;
let op_ref = unsafe { op_nn.as_ref() };
let param = &op_ref.params[idx];
unsafe { Ok((param.value.a, param.value.b)) }
}
fn set_value(&self, idx: usize, a: u32, b: u32) -> Result<()> {
if idx >= raw::TEEC_CONFIG_PAYLOAD_REF_COUNT {
return Err(Error::new(ErrorKind::BadParameters));
}
let mut op_nn = safe_ptr::deref_mut(self.operation)?;
let op_ref = unsafe { op_nn.as_mut() };
let param = &mut op_ref.params[idx];
param.value.a = a;
param.value.b = b;
Ok(())
}
fn get_tmpref_data(&self, idx: usize) -> Result<Vec<u8>> {
if idx >= raw::TEEC_CONFIG_PAYLOAD_REF_COUNT {
return Err(Error::new(ErrorKind::BadParameters));
}
let op_nn = safe_ptr::deref(self.operation)?;
let op_ref = unsafe { op_nn.as_ref() };
let tmp = unsafe { &op_ref.params[idx].tmpref };
if tmp.buffer.is_null() && tmp.size > 0 {
return Err(Error::new(ErrorKind::BadParameters));
}
if tmp.size > 0 && !tmp.buffer.is_null() {
safe_ptr::read_to_vec(tmp.buffer as *const u8, tmp.size)
} else {
Ok(Vec::new())
}
}
fn set_tmpref_data(&self, idx: usize, data: &[u8]) -> Result<()> {
if idx >= raw::TEEC_CONFIG_PAYLOAD_REF_COUNT {
return Err(Error::new(ErrorKind::BadParameters));
}
let mut op_nn = safe_ptr::deref_mut(self.operation)?;
let op_ref = unsafe { op_nn.as_mut() };
let tmp = unsafe { &mut op_ref.params[idx].tmpref };
if tmp.buffer.is_null() {
return Err(Error::new(ErrorKind::BadParameters));
}
let dest_len = data.len().min(tmp.size);
if dest_len > 0 {
safe_ptr::write_from_slice(tmp.buffer as *mut u8, &data[..dest_len])?;
}
tmp.size = dest_len;
Ok(())
}
fn get_memref_parent_flags(&self, idx: usize) -> Result<u32> {
if idx >= raw::TEEC_CONFIG_PAYLOAD_REF_COUNT {
return Err(Error::new(ErrorKind::BadParameters));
}
let op_nn = safe_ptr::deref(self.operation)?;
let op_ref = unsafe { op_nn.as_ref() };
let mem: &raw::TEEC_RegisteredMemoryReference = unsafe { &op_ref.params[idx].memref };
if mem.parent.is_null() {
return Err(Error::new(ErrorKind::BadParameters));
}
let parent_nn = safe_ptr::deref(mem.parent)?;
let parent = unsafe { parent_nn.as_ref() };
Ok(parent.flags)
}
fn get_memref_data_whole(&self, idx: usize) -> Result<Vec<u8>> {
if idx >= raw::TEEC_CONFIG_PAYLOAD_REF_COUNT {
return Err(Error::new(ErrorKind::BadParameters));
}
let op_nn = safe_ptr::deref(self.operation)?;
let op_ref = unsafe { op_nn.as_ref() };
let mem: &raw::TEEC_RegisteredMemoryReference = unsafe { &op_ref.params[idx].memref };
if mem.parent.is_null() {
return Err(Error::new(ErrorKind::BadParameters));
}
let parent_nn = safe_ptr::deref(mem.parent)?;
let parent = unsafe { parent_nn.as_ref() };
let mem_size = mem.size;
if !parent.buffer.is_null() {
safe_ptr::read_to_vec(parent.buffer as *const u8, mem_size)
} else {
Ok(SharedMemoryManager::get_buffer(mem.parent).unwrap_or_else(|| vec![0u8; mem_size]))
}
}
fn set_memref_data_whole(&self, idx: usize, data: &[u8]) -> Result<()> {
if idx >= raw::TEEC_CONFIG_PAYLOAD_REF_COUNT {
return Err(Error::new(ErrorKind::BadParameters));
}
let op_nn = safe_ptr::deref(self.operation)?;
let op_ref = unsafe { op_nn.as_ref() };
let mem = unsafe { &op_ref.params[idx].memref };
if mem.parent.is_null() {
return Err(Error::new(ErrorKind::BadParameters));
}
let mut parent_nn = safe_ptr::deref_mut(mem.parent)?;
let parent = unsafe { parent_nn.as_mut() };
if parent.buffer.is_null() {
return Err(Error::new(ErrorKind::BadParameters));
}
if !data.is_empty() {
safe_ptr::write_from_slice(parent.buffer as *mut u8, data)?;
}
Ok(())
}
fn get_memref_data_partial(&self, idx: usize, req_flags: u32) -> Result<Vec<u8>> {
if idx >= raw::TEEC_CONFIG_PAYLOAD_REF_COUNT {
return Err(Error::new(ErrorKind::BadParameters));
}
let op_nn = safe_ptr::deref(self.operation)?;
let op_ref = unsafe { op_nn.as_ref() };
let mem: &raw::TEEC_RegisteredMemoryReference = unsafe { &op_ref.params[idx].memref };
if mem.parent.is_null() {
return Err(Error::new(ErrorKind::BadParameters));
}
let parent_nn = safe_ptr::deref(mem.parent)?;
let parent = unsafe { parent_nn.as_ref() };
if parent.flags & req_flags != req_flags {
return Err(Error::new(ErrorKind::BadParameters));
}
if mem.offset.saturating_add(mem.size) > parent.size {
return Err(Error::new(ErrorKind::BadParameters));
}
let mem_size = mem.size;
let offset = mem.offset;
if !parent.buffer.is_null() {
let start_ptr = safe_ptr::add_ptr(parent.buffer as *const u8, offset);
safe_ptr::read_to_vec(start_ptr, mem_size)
} else {
Err(Error::new(ErrorKind::BadParameters))
}
}
fn set_memref_data_partial(&self, idx: usize, data: &[u8]) -> Result<()> {
if idx >= raw::TEEC_CONFIG_PAYLOAD_REF_COUNT {
return Err(Error::new(ErrorKind::BadParameters));
}
let op_nn = safe_ptr::deref(self.operation)?;
let op_ref = unsafe { op_nn.as_ref() };
let mem = unsafe { &op_ref.params[idx].memref };
if mem.parent.is_null() {
return Err(Error::new(ErrorKind::BadParameters));
}
let mut parent_nn = safe_ptr::deref_mut(mem.parent)?;
let parent = unsafe { parent_nn.as_mut() };
if parent.buffer.is_null() {
return Err(Error::new(ErrorKind::BadParameters));
}
if !data.is_empty() {
let offset = mem.offset;
let start_ptr = safe_ptr::add_ptr_mut(parent.buffer as *mut u8, offset);
safe_ptr::write_from_slice(start_ptr, data)?;
}
Ok(())
}
}
fn set_ret_origin(p: *mut u32, v: u32) -> Result<()> {
safe_ptr::write_raw(p, v)
}
fn handle_error<T>(result: Result<T>, ret_origin: *mut u32) -> u32 {
match result {
Ok(_) => raw::TEEC_SUCCESS,
Err(e) => {
let _ = set_ret_origin(ret_origin, e.origin().unwrap_or(ErrorOrigin::API).into());
e.raw_code()
}
}
}
fn build_parameters_from_operation(operation: *mut raw::TEEC_Operation) -> Result<TEE_Parameters> {
let op_params = OperationParams::new(operation)?;
let param_types = op_params.param_types()?;
let mut params = TEE_Parameters::default();
let param_tuples = [
(&mut params.0, 0),
(&mut params.1, 1),
(&mut params.2, 2),
(&mut params.3, 3),
];
for (param, idx) in param_tuples {
let param_type = raw::TEEC_PARAM_TYPE_GET(param_types, idx);
match param_type {
raw::TEEC_NONE => {
param.param_type = TEE_ParamType::None;
}
raw::TEEC_VALUE_INPUT => {
param.param_type = TEE_ParamType::ValueInput;
if let Ok((a, b)) = op_params.get_value(idx) {
param.param.value.a = a;
param.param.value.b = b;
}
}
raw::TEEC_VALUE_OUTPUT => {
param.param_type = TEE_ParamType::ValueOutput;
}
raw::TEEC_VALUE_INOUT => {
param.param_type = TEE_ParamType::ValueInout;
if let Ok((a, b)) = op_params.get_value(idx) {
param.param.value.a = a;
param.param.value.b = b;
}
}
raw::TEEC_MEMREF_TEMP_INPUT => {
param.param_type = TEE_ParamType::MemrefInput;
if let Ok(data) = op_params.get_tmpref_data(idx) {
param.param.data = data;
}
}
raw::TEEC_MEMREF_TEMP_OUTPUT => {
param.param_type = TEE_ParamType::MemrefOutput;
let op_nn = safe_ptr::deref(operation)?;
let op_ref = unsafe { op_nn.as_ref() };
let tmp = unsafe { &op_ref.params[idx].tmpref };
param.param.value.a = tmp.size as u32;
debug!(
"TEEC_MEMREF_TEMP_OUTPUT: size={}, value.a={}",
tmp.size, param.param.value.a
);
}
raw::TEEC_MEMREF_TEMP_INOUT => {
param.param_type = TEE_ParamType::MemrefInout;
if let Ok(data) = op_params.get_tmpref_data(idx) {
param.param.data = data;
}
}
raw::TEEC_MEMREF_WHOLE => {
const INOUT: u32 = raw::TEEC_MEM_INPUT | raw::TEEC_MEM_OUTPUT;
let flags = op_params.get_memref_parent_flags(idx)? & INOUT;
if flags == INOUT {
param.param_type = TEE_ParamType::MemrefInout;
} else if flags & raw::TEEC_MEM_INPUT != 0 {
param.param_type = TEE_ParamType::MemrefInput;
} else if flags & raw::TEEC_MEM_OUTPUT != 0 {
param.param_type = TEE_ParamType::MemrefOutput;
let op_nn = safe_ptr::deref(operation)?;
let op_ref = unsafe { op_nn.as_ref() };
let mem = unsafe { &op_ref.params[idx].memref };
param.param.value.a = mem.size as u32;
debug!(
"TEEC_MEMREF_WHOLE OUTPUT: size={}, value.a={}",
mem.size, param.param.value.a
);
} else {
return Err(Error::new(ErrorKind::BadParameters));
}
if flags & raw::TEEC_MEM_INPUT != 0
&& let Ok(data) = op_params.get_memref_data_whole(idx)
{
param.param.data = data;
}
}
raw::TEEC_MEMREF_PARTIAL_INPUT => {
param.param_type = TEE_ParamType::MemrefInput;
let req_flags = raw::TEEC_MEM_INPUT;
if let Ok(data) = op_params.get_memref_data_partial(idx, req_flags) {
param.param.data = data;
}
}
raw::TEEC_MEMREF_PARTIAL_OUTPUT => {
param.param_type = TEE_ParamType::MemrefOutput;
let op_nn = safe_ptr::deref(operation)?;
let op_ref = unsafe { op_nn.as_ref() };
let mem = unsafe { &op_ref.params[idx].memref };
param.param.value.a = mem.size as u32;
debug!(
"TEEC_MEMREF_PARTIAL_OUTPUT: size={}, value.a={}",
mem.size, param.param.value.a
);
}
raw::TEEC_MEMREF_PARTIAL_INOUT => {
param.param_type = TEE_ParamType::MemrefInout;
let req_flags = raw::TEEC_MEM_INPUT | raw::TEEC_MEM_OUTPUT;
if let Ok(data) = op_params.get_memref_data_partial(idx, req_flags) {
param.param.data = data;
}
}
_ => {
debug!("Unsupported parameter type: {param_type}");
return Err(Error::new(ErrorKind::BadParameters));
}
}
}
Ok(params)
}
fn update_operation_from_parameters(
operation: *mut raw::TEEC_Operation,
params: TEE_Parameters,
) -> Result<()> {
let op_params = OperationParams::new(operation)?;
let param_types = op_params.param_types()?;
let param_slice = [¶ms.0, ¶ms.1, ¶ms.2, ¶ms.3];
for (idx, param) in param_slice
.iter()
.enumerate()
.take(raw::TEEC_CONFIG_PAYLOAD_REF_COUNT)
{
let param_type = raw::TEEC_PARAM_TYPE_GET(param_types, idx);
match param_type {
raw::TEEC_NONE
| raw::TEEC_VALUE_INPUT
| raw::TEEC_MEMREF_TEMP_INPUT
| raw::TEEC_MEMREF_PARTIAL_INPUT => {
}
raw::TEEC_VALUE_OUTPUT | raw::TEEC_VALUE_INOUT => {
let value = ¶m.param.value;
op_params.set_value(idx, value.a, value.b)?;
}
raw::TEEC_MEMREF_TEMP_OUTPUT | raw::TEEC_MEMREF_TEMP_INOUT => {
let data = ¶m.param.data;
op_params.set_tmpref_data(idx, data)?;
}
raw::TEEC_MEMREF_WHOLE => {
let data = ¶m.param.data;
op_params.set_memref_data_whole(idx, data)?;
}
raw::TEEC_MEMREF_PARTIAL_OUTPUT | raw::TEEC_MEMREF_PARTIAL_INOUT => {
let data = ¶m.param.data;
op_params.set_memref_data_partial(idx, data)?;
}
_ => {
debug!("Unsupported parameter type: {param_type}");
return Err(Error::new(ErrorKind::BadParameters));
}
}
}
Ok(())
}
fn send_request_and_recv_response(
ctx: *mut raw::TEEC_Context,
packet_type: PacketType,
request: &TEE_Request,
) -> Result<TEE_Response> {
let client_arc = ContextManager::get_client(ctx)?;
let mut client = client_arc
.lock()
.map_err(|_| Error::new(ErrorKind::Generic).with_origin(ErrorOrigin::API))?;
let request_data = to_allocvec(request).map_err(|e| {
warn!("序列化请求失败:{e}");
Error::new(ErrorKind::BadFormat).with_origin(ErrorOrigin::API)
})?;
client
.send_data_with_header(packet_type, &request_data)
.map_err(|e| {
warn!("发送请求失败:{e}");
Error::new(ErrorKind::Communication).with_origin(ErrorOrigin::COMMS)
})?;
let mut len_buf = [0u8; 4];
client.recv_data(&mut len_buf).map_err(|e| {
warn!("接收响应长度失败:{e}");
Error::new(ErrorKind::Communication).with_origin(ErrorOrigin::COMMS)
})?;
let response_len = u32::from_ne_bytes(len_buf) as usize;
let mut response_data = vec![0u8; response_len];
client.recv_data(&mut response_data).map_err(|e| {
warn!("接收响应数据失败:{e}");
Error::new(ErrorKind::Communication).with_origin(ErrorOrigin::COMMS)
})?;
take_from_bytes::<TEE_Response>(&response_data)
.map(|(response, _)| response)
.map_err(|e| {
warn!("反序列化响应失败:{e}");
Error::new(ErrorKind::BadFormat).with_origin(ErrorOrigin::API)
})
}
#[unsafe(no_mangle)]
pub extern "C" fn TEEC_InitializeContext(
_name: *const c_char,
ctx: *mut raw::TEEC_Context,
) -> raw::TEEC_Result {
debug!("TEEC_InitializeContext");
let result = (|| -> Result<()> {
let mut ctx_nn = safe_ptr::deref_mut(ctx)?;
let ctx_ref = unsafe { ctx_nn.as_mut() };
let client = CcClient::init().map_err(|e| {
warn!("TEEC_InitializeContext:初始化机密通信上下文失败:{e}");
Error::new(ErrorKind::Communication)
})?;
let id = CONTEXT_ID_COUNTER.fetch_add(1, Ordering::SeqCst);
ctx_ref.imp.fd = id;
ctx_ref.imp.reg_mem = true;
ctx_ref.imp.memref_null = true;
ContextManager::add_context(ctx, client)
})();
match result {
Ok(_) => raw::TEEC_SUCCESS,
Err(e) => e.raw_code(),
}
}
#[unsafe(no_mangle)]
pub extern "C" fn TEEC_FinalizeContext(ctx: *mut raw::TEEC_Context) {
debug!("TEEC_FinalizeContext");
ContextManager::remove_context(ctx);
}
#[unsafe(no_mangle)]
pub extern "C" fn TEEC_OpenSession(
ctx: *mut raw::TEEC_Context,
session: *mut raw::TEEC_Session,
destination: *const raw::TEEC_UUID,
connection_method: u32,
_connection_data: *const c_void,
operation: *mut raw::TEEC_Operation,
ret_origin: *mut u32,
) -> raw::TEEC_Result {
debug!("TEEC_OpenSession");
let result = (|| -> Result<u32> {
let _ = safe_ptr::deref_mut(ctx)?;
let _ = safe_ptr::deref_mut(session)?;
let uuid_nn = safe_ptr::deref(destination)?;
let uuid = unsafe { uuid_nn.as_ref() };
let uuid_str = uuid_to_string(uuid)?;
let params = if operation.is_null() {
TEE_Parameters::default()
} else {
build_parameters_from_operation(operation)?
};
let request = TEE_Request::OpenSession {
uuid: uuid_str,
connection_method,
params,
};
let mut session_nn = safe_ptr::deref_mut(session)?;
let session_ref = unsafe { session_nn.as_mut() };
let response = send_request_and_recv_response(ctx, PacketType::OpenSession, &request)?;
match response {
TEE_Response::OpenSession { session_id, result } => {
debug!("TEEC_OpenSession: 接收 session_id 和结果: {session_id}, {result}");
session_ref.imp.ctx = ctx;
session_ref.imp.session_id = session_id;
let _ = set_ret_origin(ret_origin, ErrorOrigin::TEE.into());
Ok(result)
}
_ => Err(Error::new(ErrorKind::BadParameters).with_origin(ErrorOrigin::API)),
}
})();
handle_error(result, ret_origin)
}
#[unsafe(no_mangle)]
pub extern "C" fn TEEC_CloseSession(session: *mut raw::TEEC_Session) {
debug!("TEEC_CloseSession");
let result = (|| -> Result<()> {
let mut session_nn = safe_ptr::deref_mut(session)?;
let session_ref = unsafe { session_nn.as_mut() };
let session_id = session_ref.imp.session_id;
let ctx = session_ref.imp.ctx;
if ctx.is_null() {
return Err(Error::new(ErrorKind::BadParameters));
}
let request = TEE_Request::CloseSession { session_id };
let response = send_request_and_recv_response(ctx, PacketType::CloseSession, &request)?;
match response {
TEE_Response::CloseSession { result } => {
debug!("TEEC_CloseSession: 接收结果: {result}");
session_ref.imp.ctx = ptr::null_mut();
session_ref.imp.session_id = 0;
Ok(())
}
_ => Err(Error::new(ErrorKind::BadParameters)),
}
})();
if let Err(e) = result {
warn!("TEEC_CloseSession:{e}");
}
}
#[unsafe(no_mangle)]
pub extern "C" fn TEEC_InvokeCommand(
session: *mut raw::TEEC_Session,
cmd_id: u32,
operation: *mut raw::TEEC_Operation,
error_origin: *mut u32,
) -> raw::TEEC_Result {
debug!("TEEC_InvokeCommand");
let result = (|| -> Result<u32> {
let mut session_nn = safe_ptr::deref_mut(session)?;
let session_ref = unsafe { session_nn.as_mut() };
let session_id = session_ref.imp.session_id;
let ctx = session_ref.imp.ctx;
if ctx.is_null() {
return Err(Error::new(ErrorKind::BadParameters));
}
let params = if operation.is_null() {
TEE_Parameters::default()
} else {
let mut operation_nn = safe_ptr::deref_mut(operation)?;
let operation_ref = unsafe { operation_nn.as_mut() };
let _lock = TEEC_MUTEX
.lock()
.map_err(|_| Error::new(ErrorKind::Generic))?;
operation_ref.imp.session = session;
drop(_lock);
build_parameters_from_operation(operation)?
};
let request = TEE_Request::InvokeCommand {
session_id,
cmd_id,
params,
};
let response = send_request_and_recv_response(ctx, PacketType::InvokeCommand, &request)?;
match response {
TEE_Response::InvokeCommand { params, result } => {
if result != raw::TEEC_SUCCESS {
return Err(Error::new(ErrorKind::from(result)).with_origin(ErrorOrigin::API));
}
if !operation.is_null() {
update_operation_from_parameters(operation, params)?;
}
Ok(result)
}
_ => Err(Error::new(ErrorKind::BadParameters).with_origin(ErrorOrigin::API)),
}
})();
handle_error(result, error_origin)
}
#[unsafe(no_mangle)]
pub extern "C" fn TEEC_RegisterSharedMemory(
ctx: *mut raw::TEEC_Context,
shm: *mut raw::TEEC_SharedMemory,
) -> raw::TEEC_Result {
debug!("TEEC_RegisterSharedMemory");
let result = SharedMemoryManager::allocate(ctx, shm, true);
match result {
Ok(_) => raw::TEEC_SUCCESS,
Err(e) => e.raw_code(),
}
}
#[unsafe(no_mangle)]
pub extern "C" fn TEEC_RegisterSharedMemoryFileDescriptor(
_ctx: *mut raw::TEEC_Context,
_shm: *mut raw::TEEC_SharedMemory,
_fd: i32,
) -> raw::TEEC_Result {
ErrorKind::NotImplemented.into()
}
#[unsafe(no_mangle)]
pub extern "C" fn TEEC_AllocateSharedMemory(
ctx: *mut raw::TEEC_Context,
shm: *mut raw::TEEC_SharedMemory,
) -> raw::TEEC_Result {
debug!("TEEC_AllocateSharedMemory");
match SharedMemoryManager::allocate(ctx, shm, false) {
Ok(_) => raw::TEEC_SUCCESS,
Err(e) => e.raw_code(),
}
}
#[unsafe(no_mangle)]
pub extern "C" fn TEEC_ReleaseSharedMemory(shm: *mut raw::TEEC_SharedMemory) {
debug!("TEEC_ReleaseSharedMemory");
SharedMemoryManager::release(shm);
}
#[unsafe(no_mangle)]
pub extern "C" fn TEEC_RequestCancellation(operation: *mut raw::TEEC_Operation) {
debug!("TEEC_RequestCancellation");
let result = (|| -> Result<()> {
let mut operation_nn = safe_ptr::deref_mut(operation)?;
let operation_ref = unsafe { operation_nn.as_mut() };
let _lock = TEEC_MUTEX
.lock()
.map_err(|_| Error::new(ErrorKind::Generic))?;
let session = operation_ref.imp.session;
drop(_lock);
if session.is_null() {
return Ok(());
}
let mut session_nn = safe_ptr::deref_mut(session)?;
let session_ref = unsafe { session_nn.as_mut() };
let session_id = session_ref.imp.session_id;
let ctx = session_ref.imp.ctx;
if ctx.is_null() {
return Ok(());
}
let request = TEE_Request::RequestCancellation { session_id };
let response =
send_request_and_recv_response(ctx, PacketType::RequestCancellation, &request)?;
match response {
TEE_Response::RequestCancellation { result: _ } => {
debug!("TEEC_RequestCancellation: 接收结果");
Ok(())
}
_ => Err(Error::new(ErrorKind::BadParameters)),
}
})();
if let Err(e) = result {
warn!("TEEC_RequestCancellation:{e}");
}
}
#[cfg(test)]
mod teec_priv_tests {
#[allow(unused_imports)]
use super::*;
use crate::common::protocol::{CHUNK_SIZE, PacketHeader, PacketType};
#[test]
fn test_write_and_read_raw() {
let mut v: u32 = 0;
let p: *mut u32 = &mut v as *mut u32;
safe_ptr::write_raw(p, 0xDEADBEEF).expect("写入原始数据应该成功");
let r = safe_ptr::read_raw(p as *const u32).expect("读取原始数据应该成功");
assert_eq!(r, 0xDEADBEEF, "写入后读取的值应该与写入值相同");
}
#[test]
fn test_read_to_vec_and_write_from_slice() {
let arr = [1u8, 2, 3, 4, 5];
let vec =
safe_ptr::read_to_vec(arr.as_ptr(), arr.len()).expect("从指针读取到 Vec 应该成功");
assert_eq!(vec, arr.to_vec(), "从数组读取的数据应该与原始数组相同");
let mut buf = [0u8; 5];
safe_ptr::write_from_slice(buf.as_mut_ptr(), &vec).expect("从切片写入指针应该成功");
assert_eq!(buf.to_vec(), vec, "写入缓冲区后应该与原始数据相同");
}
#[test]
fn test_add_ptr() {
let arr = [10u8, 20, 30, 40];
let p = arr.as_ptr();
let p2 = safe_ptr::add_ptr(p, 2);
assert_eq!(unsafe { *p2 }, 30, "偏移2个元素后应该指向第3个元素");
}
#[test]
fn test_add_ptr_mut_and_read() {
let mut arr = [5u8, 6, 7, 8];
let p = arr.as_mut_ptr();
let p2 = safe_ptr::add_ptr_mut(p, 1);
assert_eq!(unsafe { *p2 }, 6, "偏移1个元素后应该指向第2个元素");
}
#[test]
fn test_uuid_to_string_roundtrip() {
let uuid = raw::TEEC_UUID {
timeLow: 0x00112233,
timeMid: 0x4455,
timeHiAndVersion: 0x6677,
clockSeqAndNode: [0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff],
};
let s = uuid_to_string(&uuid).expect("UUID转换应该成功");
assert_eq!(
s, "00112233-4455-6677-8899-aabbccddeeff",
"转换后的UUID字符串应该符合标准格式"
);
}
#[test]
fn test_deref_and_deref_mut_null() {
use std::ptr;
assert!(
safe_ptr::deref(ptr::null::<u8>()).is_err(),
"对空指针解引用应该失败"
);
assert!(
safe_ptr::deref_mut(ptr::null_mut::<u8>()).is_err(),
"对空可变指针解引用应该失败"
);
}
#[test]
fn test_read_raw_and_read_to_vec_null_errors() {
use std::ptr;
assert!(
safe_ptr::read_raw(ptr::null::<u32>()).is_err(),
"从空指针读取值应该失败"
);
assert!(
safe_ptr::read_to_vec(ptr::null::<u8>(), 1).is_err(),
"从空指针读取向量应该失败"
);
}
#[test]
fn test_write_from_slice_null_dst_behaviour() {
use std::ptr;
let src = [9u8, 8, 7];
assert!(
safe_ptr::write_from_slice(ptr::null_mut(), &src).is_err(),
"向空指针写入非空切片应该失败"
);
let empty: [u8; 0] = [];
assert!(
safe_ptr::write_from_slice(ptr::null_mut(), &empty).is_err(),
"向空指针写入空切片也应该失败(根据实现逻辑)"
);
}
#[test]
fn test_shared_memory_allocate_release_get_buffer() {
let mut ctx = raw::TEEC_Context {
imp: raw::TEEC_Context__Imp {
fd: 4242, reg_mem: false,
memref_null: false,
},
};
let mut shm = raw::TEEC_SharedMemory {
buffer: std::ptr::null_mut(),
size: 8, flags: raw::TEEC_MEM_INPUT,
imp: raw::TEEC_SharedMemory__Imp {
id: -1, alloced_size: 0,
shadow_buffer: std::ptr::null_mut(),
registered_fd: -1,
flags: 0,
},
};
SharedMemoryManager::allocate(&mut ctx as *mut _, &mut shm as *mut _, false)
.expect("共享内存分配应该成功");
assert_eq!(shm.imp.id, 4242, "共享内存ID应该与上下文ID匹配");
assert!(!shm.buffer.is_null(), "分配的缓冲区指针不应该为空");
assert_eq!(shm.imp.alloced_size, 8usize, "分配的缓冲区大小应该正确");
let buf =
SharedMemoryManager::get_buffer(&shm as *const _).expect("应该能获取到共享内存缓冲区");
assert_eq!(buf.len(), 8, "获取的缓冲区大小应该正确");
assert_eq!(buf, vec![0u8; 8], "新分配的缓冲区应该初始化为0");
SharedMemoryManager::release(&mut shm as *mut _);
assert!(shm.buffer.is_null(), "释放后缓冲区指针应该置空");
assert_eq!(shm.flags, 0, "释放后标志位应该清零");
assert_eq!(shm.imp.id, -1, "释放后ID应该重置为-1");
}
#[test]
fn test_operation_params_value_and_tmpref_and_memref() {
use std::ffi::c_void;
let mut op = raw::TEEC_Operation {
started: 0,
paramTypes: 0,
params: [raw::TEEC_Parameter {
value: raw::TEEC_Value { a: 1, b: 2 },
}; raw::TEEC_CONFIG_PAYLOAD_REF_COUNT],
imp: raw::TEEC_Operation__Imp {
session: std::ptr::null_mut(),
},
};
let op_ptr: *mut raw::TEEC_Operation = &mut op;
let op_params = OperationParams::new(op_ptr).unwrap();
let (a, b) = op_params.get_value(0).unwrap();
assert_eq!((a, b), (1, 2), "应该能正确读取值参数");
op_params.set_value(0, 10, 20).unwrap();
let (a2, b2) = op_params.get_value(0).unwrap();
assert_eq!((a2, b2), (10, 20), "应该能正确设置值参数");
let mut tmp_buf = vec![0u8; 6];
let mut op2 = op;
op2.params[1] = raw::TEEC_Parameter {
tmpref: raw::TEEC_TempMemoryReference {
buffer: tmp_buf.as_mut_ptr() as *mut c_void,
size: tmp_buf.len(),
},
};
let op2_ptr: *mut raw::TEEC_Operation = &mut op2;
let op2_params = OperationParams::new(op2_ptr).unwrap();
let to_write = [9u8, 8, 7];
op2_params.set_tmpref_data(1, &to_write).unwrap();
assert_eq!(tmp_buf[0..3], to_write[..], "应该正确写入临时内存");
let got = op2_params.get_tmpref_data(1).unwrap();
assert_eq!(got, vec![9u8, 8, 7], "应该正确读取临时内存");
let mut parent_buf = vec![1u8, 2, 3, 4, 5, 6];
let mut parent = raw::TEEC_SharedMemory {
buffer: parent_buf.as_mut_ptr() as *mut c_void,
size: parent_buf.len(),
flags: raw::TEEC_MEM_INPUT | raw::TEEC_MEM_OUTPUT,
imp: raw::TEEC_SharedMemory__Imp {
id: 7777,
alloced_size: parent_buf.len(),
shadow_buffer: std::ptr::null_mut(),
registered_fd: -1,
flags: 0,
},
};
let memref = raw::TEEC_RegisteredMemoryReference {
parent: &mut parent as *mut _,
size: 3,
offset: 2, };
let mut op3 = op2;
op3.params[2] = raw::TEEC_Parameter { memref };
let op3_ptr: *mut raw::TEEC_Operation = &mut op3;
let op3_params = OperationParams::new(op3_ptr).unwrap();
let memdata = op3_params
.get_memref_data_partial(2, raw::TEEC_MEM_INPUT)
.unwrap();
assert_eq!(
memdata,
parent_buf[2..5].to_vec(),
"应该正确读取部分内存引用"
);
let to_set = [7u8, 7u8];
op3_params.set_memref_data_partial(2, &to_set).unwrap();
unsafe {
let start = parent.buffer as *mut u8;
assert_eq!(*start.add(2), 7u8, "偏移2处的值应该被修改");
assert_eq!(*start.add(3), 7u8, "偏移3处的值应该被修改");
assert_eq!(*start.add(4), 5u8, "偏移4处的值应该保持不变");
}
}
#[test]
fn test_build_and_update_operation_parameters() {
use crate::common::protocol::TEE_ParamType;
let mut ctx = raw::TEEC_Context {
imp: raw::TEEC_Context__Imp {
fd: 1001,
reg_mem: false,
memref_null: false,
},
};
let mut shm = raw::TEEC_SharedMemory {
buffer: std::ptr::null_mut(),
size: 10,
flags: raw::TEEC_MEM_INPUT | raw::TEEC_MEM_OUTPUT,
imp: raw::TEEC_SharedMemory__Imp {
id: 1001,
alloced_size: 10,
shadow_buffer: std::ptr::null_mut(),
registered_fd: -1,
flags: 0,
},
};
SharedMemoryManager::allocate(&mut ctx as *mut _, &mut shm as *mut _, false)
.expect("共享内存分配应该成功");
unsafe {
let buf_ptr = shm.buffer as *mut u8;
for i in 0..10 {
*buf_ptr.add(i) = i as u8;
}
}
let mut op = raw::TEEC_Operation {
started: 0,
paramTypes: 0,
params: [
raw::TEEC_Parameter {
value: raw::TEEC_Value {
a: 0x1234,
b: 0x5678,
},
},
raw::TEEC_Parameter {
tmpref: raw::TEEC_TempMemoryReference {
buffer: [1u8, 2, 3, 4].as_ptr() as *mut std::ffi::c_void,
size: 4,
},
},
raw::TEEC_Parameter {
memref: raw::TEEC_RegisteredMemoryReference {
parent: &mut shm as *mut _,
size: 3,
offset: 2, },
},
raw::TEEC_Parameter {
value: raw::TEEC_Value { a: 0, b: 0 },
},
],
imp: raw::TEEC_Operation__Imp {
session: std::ptr::null_mut(),
},
};
let param_types = raw::TEEC_PARAM_TYPES(
raw::TEEC_VALUE_INPUT,
raw::TEEC_MEMREF_TEMP_INPUT,
raw::TEEC_MEMREF_PARTIAL_INPUT,
raw::TEEC_NONE,
);
op.paramTypes = param_types;
let op_ptr: *mut raw::TEEC_Operation = &mut op;
let params = build_parameters_from_operation(op_ptr).unwrap();
assert_eq!(
params.0.param_type,
TEE_ParamType::ValueInput,
"参数0应该是值输入类型"
);
assert_eq!(params.0.param.value.a, 0x1234, "值参数a应该正确");
assert_eq!(params.0.param.value.b, 0x5678, "值参数b应该正确");
assert_eq!(
params.1.param_type,
TEE_ParamType::MemrefInput,
"参数1应该是临时内存输入类型"
);
assert_eq!(
params.1.param.data,
vec![1, 2, 3, 4],
"临时内存数据应该正确"
);
assert_eq!(
params.2.param_type,
TEE_ParamType::MemrefInput,
"参数2应该是内存引用输入类型"
);
assert_eq!(
params.2.param.data,
vec![2, 3, 4],
"部分内存引用数据应该正确"
);
assert_eq!(
params.3.param_type,
TEE_ParamType::None,
"参数3应该是无参数类型"
);
SharedMemoryManager::release(&mut shm as *mut _);
}
#[test]
fn test_error_handling_functions() {
let mut ret_origin = 0u32;
let success_result: Result<()> = Ok(());
let success_code = handle_error(success_result, &mut ret_origin as *mut u32);
assert_eq!(
success_code,
raw::TEEC_SUCCESS,
"成功结果应该返回TEEC_SUCCESS"
);
let error_result: Result<()> =
Err(Error::new(ErrorKind::BadParameters).with_origin(ErrorOrigin::API));
let error_code = handle_error(error_result, &mut ret_origin as *mut u32);
assert_ne!(
error_code,
raw::TEEC_SUCCESS,
"错误结果不应该返回TEEC_SUCCESS"
);
assert_eq!(ret_origin, ErrorOrigin::API.into(), "错误来源应该正确设置");
}
#[test]
fn test_edge_cases_and_boundary_conditions() {
let mut op = raw::TEEC_Operation {
started: 0,
paramTypes: 0,
params: [raw::TEEC_Parameter {
value: raw::TEEC_Value { a: 0, b: 0 },
}; raw::TEEC_CONFIG_PAYLOAD_REF_COUNT],
imp: raw::TEEC_Operation__Imp {
session: std::ptr::null_mut(),
},
};
let op_ptr: *mut raw::TEEC_Operation = &mut op;
let op_params = OperationParams::new(op_ptr).unwrap();
assert!(
op_params
.get_value(raw::TEEC_CONFIG_PAYLOAD_REF_COUNT)
.is_err(),
"超出范围的索引应该返回错误"
);
assert!(
op_params
.set_value(raw::TEEC_CONFIG_PAYLOAD_REF_COUNT, 1, 2)
.is_err(),
"超出范围的索引设置应该返回错误"
);
op.params[0] = raw::TEEC_Parameter {
tmpref: raw::TEEC_TempMemoryReference {
buffer: std::ptr::null_mut(),
size: 10, },
};
assert!(
op_params.get_tmpref_data(0).is_err(),
"缓冲区为空但有大小应该返回错误"
);
}
#[test]
fn test_context_manager_operations() {
let mut ctx = raw::TEEC_Context {
imp: raw::TEEC_Context__Imp {
fd: 9999,
reg_mem: false,
memref_null: false,
},
};
ctx.imp.fd = -1; ContextManager::remove_context(&mut ctx);
assert_eq!(ctx.imp.fd, -1);
}
#[test]
fn test_shared_memory_manager_allocate_errors() {
let mut ctx = raw::TEEC_Context {
imp: raw::TEEC_Context__Imp {
fd: 100,
reg_mem: false,
memref_null: false,
},
};
let mut shm = raw::TEEC_SharedMemory {
buffer: std::ptr::null_mut(),
size: 0, flags: raw::TEEC_MEM_INPUT,
imp: raw::TEEC_SharedMemory__Imp {
id: -1,
alloced_size: 0,
shadow_buffer: std::ptr::null_mut(),
registered_fd: -1,
flags: 0,
},
};
let result = SharedMemoryManager::allocate(&mut ctx, &mut shm, false);
assert!(result.is_err());
shm.size = 100;
shm.flags = 0; let result = SharedMemoryManager::allocate(&mut ctx, &mut shm, false);
assert!(result.is_err());
shm.flags = 0xFFFFFFFF; let result = SharedMemoryManager::allocate(&mut ctx, &mut shm, false);
assert!(result.is_err());
}
#[test]
fn test_shared_memory_manager_release_edge_cases() {
let mut shm = raw::TEEC_SharedMemory {
buffer: std::ptr::null_mut(),
size: 100,
flags: raw::TEEC_MEM_INPUT,
imp: raw::TEEC_SharedMemory__Imp {
id: -1, alloced_size: 100,
shadow_buffer: std::ptr::null_mut(),
registered_fd: -1,
flags: 0,
},
};
SharedMemoryManager::release(&mut shm);
assert_eq!(shm.imp.id, -1); }
#[test]
fn test_get_buffer_null_pointer() {
let result = SharedMemoryManager::get_buffer(std::ptr::null());
assert!(result.is_none());
}
#[test]
fn test_uuid_to_string_invalid_format() {
let uuid = raw::TEEC_UUID {
timeLow: 0x12345678,
timeMid: 0x1234,
timeHiAndVersion: 0x5678,
clockSeqAndNode: [0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0],
};
let result = uuid_to_string(&uuid);
assert!(result.is_ok());
let uuid_str = result.unwrap();
assert!(!uuid_str.is_empty());
}
#[test]
fn test_operation_params_index_boundary() {
let mut op = raw::TEEC_Operation {
started: 0,
paramTypes: 0,
params: [raw::TEEC_Parameter {
value: raw::TEEC_Value { a: 0, b: 0 },
}; raw::TEEC_CONFIG_PAYLOAD_REF_COUNT],
imp: raw::TEEC_Operation__Imp {
session: std::ptr::null_mut(),
},
};
let op_ptr: *mut raw::TEEC_Operation = &mut op;
let op_params = OperationParams::new(op_ptr).unwrap();
for i in 0..raw::TEEC_CONFIG_PAYLOAD_REF_COUNT {
let _ = op_params.get_value(i);
}
assert!(
op_params
.get_value(raw::TEEC_CONFIG_PAYLOAD_REF_COUNT)
.is_err()
);
assert!(
op_params
.set_value(raw::TEEC_CONFIG_PAYLOAD_REF_COUNT, 1, 2)
.is_err()
);
}
#[test]
fn test_set_ret_origin_function() {
let mut origin = 0u32;
let result = set_ret_origin(&mut origin as *mut u32, 123);
assert!(result.is_ok());
assert_eq!(origin, 123);
}
#[test]
fn test_handle_error_success_case() {
let mut ret_origin = 0u32;
let success_result: Result<()> = Ok(());
let code = handle_error(success_result, &mut ret_origin as *mut u32);
assert_eq!(code, raw::TEEC_SUCCESS);
assert_eq!(ret_origin, 0);
}
#[test]
fn test_build_parameters_with_all_param_types() {
use crate::common::protocol::TEE_ParamType;
let mut op = raw::TEEC_Operation {
started: 0,
paramTypes: 0,
params: [unsafe { std::mem::zeroed() }; 4],
imp: raw::TEEC_Operation__Imp {
session: std::ptr::null_mut(),
},
};
op.paramTypes = raw::TEEC_PARAM_TYPES(
raw::TEEC_NONE,
raw::TEEC_NONE,
raw::TEEC_NONE,
raw::TEEC_NONE,
);
let params = build_parameters_from_operation(&mut op).unwrap();
assert_eq!(params.0.param_type, TEE_ParamType::None);
assert_eq!(params.1.param_type, TEE_ParamType::None);
assert_eq!(params.2.param_type, TEE_ParamType::None);
assert_eq!(params.3.param_type, TEE_ParamType::None);
}
#[test]
fn test_update_operation_with_output_params() {
use crate::common::protocol::{TEE_Param, TEE_ParamType, TEE_Parameter, TEE_Value};
let mut tmp_buffer = [0u8; 10];
let mut op = raw::TEEC_Operation {
started: 0,
paramTypes: raw::TEEC_PARAM_TYPES(
raw::TEEC_VALUE_OUTPUT,
raw::TEEC_MEMREF_TEMP_OUTPUT,
raw::TEEC_NONE,
raw::TEEC_NONE,
),
params: [
raw::TEEC_Parameter {
value: raw::TEEC_Value { a: 0, b: 0 },
},
raw::TEEC_Parameter {
tmpref: raw::TEEC_TempMemoryReference {
buffer: tmp_buffer.as_mut_ptr() as *mut std::ffi::c_void,
size: tmp_buffer.len(),
},
},
raw::TEEC_Parameter {
value: raw::TEEC_Value { a: 0, b: 0 },
},
raw::TEEC_Parameter {
value: raw::TEEC_Value { a: 0, b: 0 },
},
],
imp: raw::TEEC_Operation__Imp {
session: std::ptr::null_mut(),
},
};
let params = TEE_Parameters(
TEE_Parameter {
param_type: TEE_ParamType::ValueOutput,
param: TEE_Param {
value: TEE_Value { a: 100, b: 200 },
data: vec![],
},
},
TEE_Parameter {
param_type: TEE_ParamType::MemrefOutput,
param: TEE_Param {
value: TEE_Value::default(),
data: vec![1, 2, 3],
},
},
TEE_Parameter::default(),
TEE_Parameter::default(),
);
let result = update_operation_from_parameters(&mut op, params);
assert!(result.is_ok());
unsafe {
assert_eq!(op.params[0].value.a, 100);
assert_eq!(op.params[0].value.b, 200);
}
}
#[test]
fn test_packet_type_comprehensive() {
assert_eq!(PacketType::from(0), PacketType::Unknown);
assert_eq!(PacketType::from(1), PacketType::OpenSession);
assert_eq!(PacketType::from(2), PacketType::CloseSession);
assert_eq!(PacketType::from(3), PacketType::InvokeCommand);
assert_eq!(PacketType::from(4), PacketType::RequestCancellation);
assert_eq!(PacketType::from(999), PacketType::Unknown);
assert_eq!(u64::from(PacketType::Unknown), 0);
assert_eq!(u64::from(PacketType::OpenSession), 1);
assert_eq!(u64::from(PacketType::CloseSession), 2);
assert_eq!(u64::from(PacketType::InvokeCommand), 3);
assert_eq!(u64::from(PacketType::RequestCancellation), 4);
let header = PacketHeader {
data_type: 1,
data_size: 1024,
};
let bytes = header.as_bytes();
assert_eq!(bytes.len(), 16);
let restored = PacketHeader::from_bytes(bytes);
assert_eq!(restored.data_type, 1);
assert_eq!(restored.data_size, 1024);
assert!(CHUNK_SIZE > 0);
}
#[test]
fn test_tee_cancellation_error_paths() {
let mut operation = raw::TEEC_Operation {
started: 0,
paramTypes: 0,
params: [unsafe { std::mem::zeroed() }; 4],
imp: raw::TEEC_Operation__Imp {
session: std::ptr::null_mut(), },
};
super::TEEC_RequestCancellation(&mut operation);
}
#[test]
fn test_shared_memory_edge_cases() {
let mut shm = raw::TEEC_SharedMemory {
buffer: std::ptr::null_mut(),
size: 100,
flags: raw::TEEC_MEM_INPUT,
imp: raw::TEEC_SharedMemory__Imp {
id: -1, alloced_size: 0,
shadow_buffer: std::ptr::null_mut(),
registered_fd: -1,
flags: 0,
},
};
SharedMemoryManager::release(&mut shm);
assert_eq!(shm.imp.id, -1);
}
#[test]
fn test_uuid_conversion_edge_cases() {
let zero_uuid = raw::TEEC_UUID {
timeLow: 0,
timeMid: 0,
timeHiAndVersion: 0,
clockSeqAndNode: [0; 8],
};
let result = uuid_to_string(&zero_uuid);
assert!(result.is_ok());
let uuid_str = result.unwrap();
assert!(!uuid_str.is_empty());
let max_uuid = raw::TEEC_UUID {
timeLow: u32::MAX,
timeMid: u16::MAX,
timeHiAndVersion: u16::MAX,
clockSeqAndNode: [u8::MAX; 8],
};
let result = uuid_to_string(&max_uuid);
assert!(result.is_ok());
}
#[test]
fn test_operation_params_null_pointer_handling() {
use std::ptr;
let null_op: *mut raw::TEEC_Operation = ptr::null_mut();
let result = OperationParams::new(null_op);
assert!(result.is_err());
}
#[test]
fn test_build_parameters_error_paths() {
let mut op = raw::TEEC_Operation {
started: 0,
paramTypes: raw::TEEC_PARAM_TYPES(
raw::TEEC_MEMREF_WHOLE, raw::TEEC_NONE,
raw::TEEC_NONE,
raw::TEEC_NONE,
),
params: [
raw::TEEC_Parameter {
memref: raw::TEEC_RegisteredMemoryReference {
parent: std::ptr::null_mut(), size: 100,
offset: 0,
},
},
raw::TEEC_Parameter {
value: raw::TEEC_Value { a: 0, b: 0 },
},
raw::TEEC_Parameter {
value: raw::TEEC_Value { a: 0, b: 0 },
},
raw::TEEC_Parameter {
value: raw::TEEC_Value { a: 0, b: 0 },
},
],
imp: raw::TEEC_Operation__Imp {
session: std::ptr::null_mut(),
},
};
let result = build_parameters_from_operation(&mut op);
assert!(result.is_err());
}
#[test]
fn test_update_operation_error_paths() {
use crate::common::protocol::{TEE_ParamType, TEE_Parameter};
let mut op = raw::TEEC_Operation {
started: 0,
paramTypes: raw::TEEC_PARAM_TYPES(
raw::TEEC_VALUE_OUTPUT, raw::TEEC_NONE,
raw::TEEC_NONE,
raw::TEEC_NONE,
),
params: [raw::TEEC_Parameter {
value: raw::TEEC_Value { a: 0, b: 0 },
}; 4],
imp: raw::TEEC_Operation__Imp {
session: std::ptr::null_mut(),
},
};
let params = TEE_Parameters(
TEE_Parameter {
param_type: TEE_ParamType::ValueOutput,
param: crate::common::protocol::TEE_Param {
value: crate::common::protocol::TEE_Value { a: 100, b: 200 },
data: vec![],
},
},
TEE_Parameter::default(),
TEE_Parameter::default(),
TEE_Parameter::default(),
);
let result = update_operation_from_parameters(&mut op, params);
assert!(result.is_ok());
unsafe {
assert_eq!(op.params[0].value.a, 100);
assert_eq!(op.params[0].value.b, 200);
}
}
#[test]
fn test_safe_ptr_error_conditions() {
use std::ptr;
let read_result = safe_ptr::read_raw::<u32>(ptr::null());
assert!(read_result.is_err());
let write_result = safe_ptr::write_raw(ptr::null_mut(), 42u32);
assert!(write_result.is_err());
let vec_result = safe_ptr::read_to_vec(ptr::null::<u8>(), 10);
assert!(vec_result.is_err());
let data = [1u8, 2, 3];
let slice_result = safe_ptr::write_from_slice(ptr::null_mut(), &data);
assert!(slice_result.is_err());
}
#[test]
fn test_tee_c_result_to_error_conversion() {
assert_eq!(raw::TEEC_SUCCESS, 0);
assert_ne!(raw::TEEC_ERROR_GENERIC, 0);
assert_ne!(raw::TEEC_ERROR_BAD_PARAMETERS, 0);
let success_code: u32 = raw::TEEC_SUCCESS;
let error_code: u32 = raw::TEEC_ERROR_GENERIC;
assert_eq!(success_code == 0, true);
assert_eq!(error_code != 0, true);
}
#[test]
fn test_session_error_handling() {
use std::ptr;
let null_session: *mut raw::TEEC_Session = ptr::null_mut();
assert!(null_session.is_null());
let _session = raw::TEEC_Session {
imp: raw::TEEC_Session__Imp {
ctx: ptr::null_mut(),
session_id: 0,
},
};
}
#[test]
fn test_shared_memory_normal_allocation_release() {
use std::ptr;
let mut ctx = raw::TEEC_Context {
imp: raw::TEEC_Context__Imp {
fd: -1, reg_mem: false, memref_null: false, },
};
let mut shm = raw::TEEC_SharedMemory {
buffer: ptr::null_mut(),
size: 1024,
flags: raw::TEEC_MEM_INPUT,
imp: raw::TEEC_SharedMemory__Imp {
id: -1,
alloced_size: 0,
shadow_buffer: ptr::null_mut(),
registered_fd: -1,
flags: 0,
},
};
let _result = SharedMemoryManager::allocate(&mut ctx, &mut shm, false);
SharedMemoryManager::release(&mut shm);
}
#[test]
fn test_uuid_to_string_format() {
let uuid = raw::TEEC_UUID {
timeLow: 0x12345678,
timeMid: 0xABCD,
timeHiAndVersion: 0xEF01,
clockSeqAndNode: [0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01],
};
let result = uuid_to_string(&uuid);
assert!(result.is_ok());
let uuid_str = result.unwrap();
assert_eq!(uuid_str.len(), 36);
assert!(uuid_str.contains('-'));
}
#[test]
fn test_build_parameters_memref_temp_input() {
let mut buffer = [0x01u8, 0x02, 0x03, 0x04];
let mut op = raw::TEEC_Operation {
started: 0,
paramTypes: raw::TEEC_PARAM_TYPES(
raw::TEEC_MEMREF_TEMP_INPUT,
raw::TEEC_NONE,
raw::TEEC_NONE,
raw::TEEC_NONE,
),
params: [
raw::TEEC_Parameter {
tmpref: raw::TEEC_TempMemoryReference {
buffer: buffer.as_mut_ptr() as *mut std::ffi::c_void,
size: buffer.len(),
},
},
raw::TEEC_Parameter {
value: raw::TEEC_Value { a: 0, b: 0 },
},
raw::TEEC_Parameter {
value: raw::TEEC_Value { a: 0, b: 0 },
},
raw::TEEC_Parameter {
value: raw::TEEC_Value { a: 0, b: 0 },
},
],
imp: raw::TEEC_Operation__Imp {
session: std::ptr::null_mut(),
},
};
let result = build_parameters_from_operation(&mut op);
assert!(result.is_ok());
let params = result.unwrap();
assert_eq!(params.0.param_type, TEE_ParamType::MemrefInput);
assert_eq!(params.0.param.data.len(), 4);
}
#[test]
fn test_get_memref_parent_flags_null_parent() {
let mut op = raw::TEEC_Operation {
started: 0,
paramTypes: raw::TEEC_PARAM_TYPES(
raw::TEEC_MEMREF_WHOLE,
raw::TEEC_NONE,
raw::TEEC_NONE,
raw::TEEC_NONE,
),
params: [
raw::TEEC_Parameter {
memref: raw::TEEC_RegisteredMemoryReference {
parent: std::ptr::null_mut(), size: 100,
offset: 0,
},
},
raw::TEEC_Parameter {
value: raw::TEEC_Value { a: 0, b: 0 },
},
raw::TEEC_Parameter {
value: raw::TEEC_Value { a: 0, b: 0 },
},
raw::TEEC_Parameter {
value: raw::TEEC_Value { a: 0, b: 0 },
},
],
imp: raw::TEEC_Operation__Imp {
session: std::ptr::null_mut(),
},
};
let op_params = OperationParams::new(&mut op).unwrap();
let result = op_params.get_memref_parent_flags(0);
assert!(result.is_err());
}
#[test]
fn test_set_tmpref_data_null_buffer() {
let mut op = raw::TEEC_Operation {
started: 0,
paramTypes: raw::TEEC_PARAM_TYPES(
raw::TEEC_MEMREF_TEMP_INPUT,
raw::TEEC_NONE,
raw::TEEC_NONE,
raw::TEEC_NONE,
),
params: [
raw::TEEC_Parameter {
tmpref: raw::TEEC_TempMemoryReference {
buffer: std::ptr::null_mut(), size: 100,
},
},
raw::TEEC_Parameter {
value: raw::TEEC_Value { a: 0, b: 0 },
},
raw::TEEC_Parameter {
value: raw::TEEC_Value { a: 0, b: 0 },
},
raw::TEEC_Parameter {
value: raw::TEEC_Value { a: 0, b: 0 },
},
],
imp: raw::TEEC_Operation__Imp {
session: std::ptr::null_mut(),
},
};
let op_params = OperationParams::new(&mut op).unwrap();
let result = op_params.get_tmpref_data(0);
assert!(result.is_err());
}
#[test]
fn test_build_parameters_value_inout() {
let mut op = raw::TEEC_Operation {
started: 0,
paramTypes: raw::TEEC_PARAM_TYPES(
raw::TEEC_VALUE_INOUT,
raw::TEEC_NONE,
raw::TEEC_NONE,
raw::TEEC_NONE,
),
params: [
raw::TEEC_Parameter {
value: raw::TEEC_Value { a: 123, b: 456 },
},
raw::TEEC_Parameter {
value: raw::TEEC_Value { a: 0, b: 0 },
},
raw::TEEC_Parameter {
value: raw::TEEC_Value { a: 0, b: 0 },
},
raw::TEEC_Parameter {
value: raw::TEEC_Value { a: 0, b: 0 },
},
],
imp: raw::TEEC_Operation__Imp {
session: std::ptr::null_mut(),
},
};
let result = build_parameters_from_operation(&mut op);
assert!(result.is_ok());
let params = result.unwrap();
assert_eq!(params.0.param_type, TEE_ParamType::ValueInout);
assert_eq!(params.0.param.value.a, 123);
assert_eq!(params.0.param.value.b, 456);
}
}