use log::debug;
use super::{safe_ptr, shared_memory::SharedMemoryManager};
use crate::{Error, ErrorKind, Result, raw};
use teec_protocol::{TEE_ParamType, TEE_Parameters};
pub(super) struct OperationParams {
operation: *mut raw::TEEC_Operation,
}
impl OperationParams {
pub(super) fn new(operation: *mut raw::TEEC_Operation) -> Result<Self> {
let _ = safe_ptr::deref_mut(operation)?;
Ok(Self { operation })
}
pub(super) 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)
}
pub(super) 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)) }
}
pub(super) 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(())
}
pub(super) 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())
}
}
pub(super) 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(())
}
pub(super) 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)
}
pub(super) 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]))
}
}
pub(super) 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(())
}
pub(super) 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))
}
}
pub(super) 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(())
}
}
pub 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)
}
pub 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(())
}
#[cfg(test)]
mod operation_tests {
use super::*;
use std::ffi::c_void;
#[test]
fn test_operation_params_value() {
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), "应该能正确设置值参数");
}
#[test]
fn test_operation_params_tmpref() {
let mut tmp_buf = vec![0u8; 6];
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(),
},
};
op.params[1] = raw::TEEC_Parameter {
tmpref: raw::TEEC_TempMemoryReference {
buffer: tmp_buf.as_mut_ptr() as *mut c_void,
size: tmp_buf.len(),
},
};
let op_ptr: *mut raw::TEEC_Operation = &mut op;
let op_params = OperationParams::new(op_ptr).unwrap();
let to_write = [9u8, 8, 7];
op_params.set_tmpref_data(1, &to_write).unwrap();
assert_eq!(tmp_buf[0..3], to_write[..], "应该正确写入临时内存");
let got = op_params.get_tmpref_data(1).unwrap();
assert_eq!(got, to_write.to_vec(), "应该正确读取临时内存");
}
#[test]
fn test_operation_params_null() {
let result = OperationParams::new(std::ptr::null_mut());
assert!(result.is_err());
}
#[test]
fn test_build_parameters_from_operation() {
let mut op = raw::TEEC_Operation {
started: 0,
paramTypes: raw::TEEC_VALUE_INPUT,
params: [raw::TEEC_Parameter {
value: raw::TEEC_Value { a: 42, b: 100 },
}; 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 params = build_parameters_from_operation(op_ptr).unwrap();
assert_eq!(params.0.param_type as u32, raw::TEEC_VALUE_INPUT);
}
#[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_tmpref_null_buffer() {
let mut op = raw::TEEC_Operation {
started: 0,
paramTypes: 0,
params: [raw::TEEC_Parameter {
tmpref: raw::TEEC_TempMemoryReference {
buffer: std::ptr::null_mut(),
size: 10, },
}; 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_tmpref_data(0).is_err(),
"缓冲区为空但有大小应该返回错误"
);
}
#[test]
fn test_build_parameters_with_all_param_types() {
use teec_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 teec_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_operation_params_new_null_ptr() {
let result = OperationParams::new(std::ptr::null_mut());
assert!(result.is_err(), "空指针应该导致失败");
}
#[test]
fn test_get_value_all_invalid_indices() {
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.get_value(100).is_err());
assert!(op_params.get_value(usize::MAX).is_err());
}
#[test]
fn test_set_value_all_invalid_indices() {
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
.set_value(raw::TEEC_CONFIG_PAYLOAD_REF_COUNT, 1, 2)
.is_err()
);
assert!(op_params.set_value(100, 1, 2).is_err());
assert!(op_params.set_value(usize::MAX, 1, 2).is_err());
}
#[test]
#[allow(unused_assignments)]
fn test_get_tmpref_data_all_error_paths() {
let mut op = raw::TEEC_Operation {
started: 0,
paramTypes: 0,
params: [raw::TEEC_Parameter {
tmpref: raw::TEEC_TempMemoryReference {
buffer: std::ptr::null_mut(),
size: 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_tmpref_data(raw::TEEC_CONFIG_PAYLOAD_REF_COUNT)
.is_err()
);
assert!(op_params.get_tmpref_data(100).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());
op.params[0] = raw::TEEC_Parameter {
tmpref: raw::TEEC_TempMemoryReference {
buffer: std::ptr::null_mut(),
size: 0,
},
};
let result = op_params.get_tmpref_data(0);
assert!(result.is_ok());
assert_eq!(result.unwrap().len(), 0);
}
#[test]
#[allow(unused_assignments)]
fn test_set_tmpref_data_all_error_paths() {
let mut op = raw::TEEC_Operation {
started: 0,
paramTypes: 0,
params: [raw::TEEC_Parameter {
tmpref: raw::TEEC_TempMemoryReference {
buffer: std::ptr::null_mut(),
size: 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();
let data = vec![1u8, 2, 3];
assert!(
op_params
.set_tmpref_data(raw::TEEC_CONFIG_PAYLOAD_REF_COUNT, &data)
.is_err()
);
assert!(op_params.set_tmpref_data(100, &data).is_err());
let mut buffer = vec![0u8; 10];
op.params[0] = raw::TEEC_Parameter {
tmpref: raw::TEEC_TempMemoryReference {
buffer: buffer.as_mut_ptr() as *mut std::ffi::c_void,
size: buffer.len(),
},
};
let small_data = vec![1u8, 2, 3];
let result = op_params.set_tmpref_data(0, &small_data);
assert!(result.is_ok());
}
#[test]
fn test_param_types_null_operation() {
let op_params = OperationParams {
operation: std::ptr::null_mut(),
};
let result = op_params.param_types();
assert!(result.is_err(), "空指针操作应该失败");
}
#[test]
fn test_build_parameters_null_operation() {
let result = build_parameters_from_operation(std::ptr::null_mut());
assert!(result.is_err(), "空指针应该导致失败");
}
#[test]
fn test_update_operation_null_operation() {
use teec_protocol::{TEE_Param, TEE_ParamType, TEE_Parameter, TEE_Value};
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::default(),
TEE_Parameter::default(),
TEE_Parameter::default(),
);
let result = update_operation_from_parameters(std::ptr::null_mut(), params);
assert!(result.is_err(), "空指针应该导致失败");
}
#[test]
fn test_mixed_valid_and_invalid_operations() {
let mut op = raw::TEEC_Operation {
started: 0,
paramTypes: raw::TEEC_PARAM_TYPES(
raw::TEEC_VALUE_INPUT,
raw::TEEC_NONE,
raw::TEEC_NONE,
raw::TEEC_NONE,
),
params: [
raw::TEEC_Parameter {
value: raw::TEEC_Value { a: 42, b: 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_ptr: *mut raw::TEEC_Operation = &mut op;
let op_params = OperationParams::new(op_ptr).unwrap();
assert!(op_params.get_value(0).is_ok());
assert!(op_params.set_value(0, 1, 2).is_ok());
assert!(op_params.get_value(4).is_err());
assert!(op_params.set_value(4, 1, 2).is_err());
}
#[test]
fn test_memref_partial_operations() {
use std::ptr;
let mut parent_buffer = vec![0u8; 100];
for i in 0..100 {
parent_buffer[i] = i as u8;
}
let mut parent_shm = raw::TEEC_SharedMemory {
buffer: parent_buffer.as_mut_ptr() as *mut _,
size: 100,
flags: raw::TEEC_MEM_INPUT | raw::TEEC_MEM_OUTPUT,
imp: raw::TEEC_SharedMemory__Imp {
id: 1,
registered_fd: -1,
shadow_buffer: ptr::null_mut(),
alloced_size: 100,
flags: 1,
},
};
let mut op = raw::TEEC_Operation {
started: 0,
paramTypes: raw::TEEC_PARAM_TYPES(
raw::TEEC_MEMREF_PARTIAL_INPUT,
raw::TEEC_NONE,
raw::TEEC_NONE,
raw::TEEC_NONE,
),
params: [
raw::TEEC_Parameter {
memref: raw::TEEC_RegisteredMemoryReference {
parent: &mut parent_shm as *mut _,
size: 10,
offset: 5,
},
},
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: ptr::null_mut(),
},
};
let op_ptr: *mut raw::TEEC_Operation = &mut op;
let op_params = OperationParams::new(op_ptr).unwrap();
let data = op_params.get_memref_data_partial(0, raw::TEEC_MEM_INPUT);
assert!(data.is_ok());
let data = data.unwrap();
assert_eq!(data.len(), 10);
for (i, &byte) in data.iter().enumerate() {
assert_eq!(byte, (i + 5) as u8);
}
let write_data = vec![0xFF; 10];
let result = op_params.set_memref_data_partial(0, &write_data);
assert!(result.is_ok());
for i in 5..15 {
assert_eq!(parent_buffer[i], 0xFF);
}
}
#[test]
fn test_build_parameters_memref_output() {
use std::ptr;
let mut buffer = vec![0u8; 50];
let mut op = raw::TEEC_Operation {
started: 0,
paramTypes: raw::TEEC_PARAM_TYPES(
raw::TEEC_MEMREF_TEMP_OUTPUT,
raw::TEEC_NONE,
raw::TEEC_NONE,
raw::TEEC_NONE,
),
params: [
raw::TEEC_Parameter {
tmpref: raw::TEEC_TempMemoryReference {
buffer: buffer.as_mut_ptr() as *mut _,
size: 50,
},
},
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: ptr::null_mut(),
},
};
let params = build_parameters_from_operation(&mut op).unwrap();
assert_eq!(params.0.param_type, TEE_ParamType::MemrefOutput);
assert_eq!(params.0.param.data.len(), 0);
}
#[test]
fn test_update_operation_memref_output() {
use std::ptr;
use teec_protocol::{TEE_Param, TEE_Parameter};
let mut output_buffer = vec![0u8; 20];
let mut op = raw::TEEC_Operation {
started: 0,
paramTypes: raw::TEEC_PARAM_TYPES(
raw::TEEC_MEMREF_TEMP_OUTPUT,
raw::TEEC_NONE,
raw::TEEC_NONE,
raw::TEEC_NONE,
),
params: [
raw::TEEC_Parameter {
tmpref: raw::TEEC_TempMemoryReference {
buffer: output_buffer.as_mut_ptr() as *mut _,
size: 20,
},
},
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: ptr::null_mut(),
},
};
let returned_data = vec![0xAA; 10];
let params = TEE_Parameters(
TEE_Parameter {
param_type: TEE_ParamType::MemrefOutput,
param: TEE_Param {
data: returned_data.clone(),
value: Default::default(),
},
},
Default::default(),
Default::default(),
Default::default(),
);
let result = update_operation_from_parameters(&mut op, params);
assert!(result.is_ok());
for i in 0..10 {
assert_eq!(output_buffer[i], 0xAA);
}
}
}