OP-TEE REE侧存储接口深度分析
本文档深入分析OP-TEE在REE侧的存储接口实现,包括TEE Supplicant文件系统服务、RPC通信协议、安全机制和性能优化等核心技术。REE侧存储架构深度解析
架构层次和数据流
Copy
┌────────────────────────────────────────────────────────────┐
│ TEE World │
│ tee_ree_fs.c --> tee_fs_rpc.c --> RPC Call │
└─────────────────────────────┬─────────────────────────────┘
│ Secure Monitor / ARM TrustZone
┌─────────────────────────────┴─────────────────────────────┐
│ REE World │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ TEE Supplicant Daemon │ │ ← 用户空间守护进程
│ │ tee_supp_fs.c - 文件系统服务实现 │ │
│ │ handle_db.c - 句柄管理和资源追踪 │ │
│ │ rpmb.c - RPMB硬件接口实现 │ │
│ └────────────────────────────────────────────────────────┘ │
│ │ /dev/tee0 ioctl、shared memory │
│ ┌────────────▼────────────────────────────────────────────┐ │
│ │ OP-TEE Driver │ │ ← 内核驱动
│ │ optee_rpc.c - RPC消息处理和路由 │ │
│ │ optee_smc.c - SMC调用和上下文切换 │ │
│ └────────────────────────────────────────────────────────┘ │
│ │ SMC (Secure Monitor Call) │
│ ┌────────────▼────────────────────────────────────────────┐ │
│ │ Linux Filesystem Layer │ │ ← 文件系统层
│ │ VFS -> ext4/f2fs -> Block Layer -> Storage Device │ │
│ └────────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────┘
1. TEE Supplicant高级文件系统服务架构
服务组件和职责分工
- 核心服务:
optee_client/tee-supplicant/src/tee_supp_fs.c - 服务模式: 守护进程,为TEE提供可信的REE存储服务
- 通信机制: 基于RPC的异步调用模型,支持零拷贝和大数据块传输
高级服务初始化和配置
Copy
// TEE文件系统服务的全局配置结构
struct tee_fs_service_config {
char root_path[PATH_MAX]; // 存储根目录
mode_t dir_mode; // 目录权限模式
mode_t file_mode; // 文件权限模式
bool sync_on_write; // 写入时立即同步
size_t max_file_size; // 最大文件大小限制
size_t io_buffer_size; // I/O缓冲区大小
uint32_t security_flags; // 安全特性标志
struct {
size_t max_open_files; // 最大同时打开文件数
size_t max_open_dirs; // 最大同时打开目录数
uint32_t handle_timeout_ms; // 句柄超时时间
} limits;
};
static struct tee_fs_service_config g_fs_config;
static bool g_fs_service_initialized = false;
static pthread_mutex_t g_fs_init_mutex = PTHREAD_MUTEX_INITIALIZER;
// 高级初始化函数
static int tee_supp_fs_advanced_init(const char *parent_path)
{
int ret = 0;
struct stat st;
pthread_mutex_lock(&g_fs_init_mutex);
if (g_fs_service_initialized) {
pthread_mutex_unlock(&g_fs_init_mutex);
return 0;
}
// 1. 初始化配置结构
memset(&g_fs_config, 0, sizeof(g_fs_config));
snprintf(g_fs_config.root_path, sizeof(g_fs_config.root_path),
"%s/", parent_path ? parent_path : "/data/tee");
g_fs_config.dir_mode = 0700; // 仅所有者可访问
g_fs_config.file_mode = 0600; // 仅所有者可读写
g_fs_config.sync_on_write = true; // 安全模式:立即同步
g_fs_config.max_file_size = 256 * 1024 * 1024; // 256MB限制
g_fs_config.io_buffer_size = 64 * 1024; // 64KB I/O缓冲
g_fs_config.limits.max_open_files = 256;
g_fs_config.limits.max_open_dirs = 64;
g_fs_config.limits.handle_timeout_ms = 30000; // 30秒超时
// 2. 创建根目录结构
ret = mkpath(g_fs_config.root_path, g_fs_config.dir_mode);
if (ret != 0) {
EMSG("Failed to create root directory: %s", g_fs_config.root_path);
goto exit;
}
// 3. 验证目录权限和所有权
if (stat(g_fs_config.root_path, &st) != 0) {
EMSG("Cannot stat root directory: %s", strerror(errno));
ret = -1;
goto exit;
}
if (!S_ISDIR(st.st_mode)) {
EMSG("Root path is not a directory: %s", g_fs_config.root_path);
ret = -1;
goto exit;
}
// 4. 检查读写权限
if (access(g_fs_config.root_path, R_OK | W_OK | X_OK) != 0) {
EMSG("Insufficient permissions for root directory: %s",
strerror(errno));
ret = -1;
goto exit;
}
// 5. 初始化句柄管理器
ret = init_handle_databases();
if (ret != 0) {
EMSG("Failed to initialize handle databases");
goto exit;
}
// 6. 初始化统计和监控
init_fs_statistics();
g_fs_service_initialized = true;
IMSG("TEE filesystem service initialized: %s", g_fs_config.root_path);
exit:
pthread_mutex_unlock(&g_fs_init_mutex);
return ret;
}
#### 复杂的资源管理和句柄系统
```c
// 全局句柄管理器结构
struct tee_fs_handle_manager {
struct handle_db file_handles; // 文件句柄数据库
struct handle_db dir_handles; // 目录句柄数据库
pthread_mutex_t global_mutex; // 全局互斥锁
// 资源统计和限制
struct {
atomic_uint open_files; // 当前打开文件数
atomic_uint open_dirs; // 当前打开目录数
uint64_t total_bytes_read; // 累计读取字节数
uint64_t total_bytes_written; // 累计写入字节数
uint64_t total_operations; // 累计操作次数
} stats;
// 句柄生命周期管理
struct {
time_t *creation_times; // 句柄创建时间数组
time_t *last_access_times; // 最后访问时间数组
size_t max_handles; // 最大句柄数
pthread_t cleanup_thread; // 清理线程
bool cleanup_running; // 清理线程运行标志
} lifecycle;
};
static struct tee_fs_handle_manager g_handle_mgr;
// 高级句柄分配函数
static int allocate_file_handle(int fd, const char *path)
{
int handle_id;
time_t now = time(NULL);
pthread_mutex_lock(&g_handle_mgr.global_mutex);
// 1. 检查资源限制
if (atomic_load(&g_handle_mgr.stats.open_files) >=
g_fs_config.limits.max_open_files) {
EMSG("Too many open files: %u >= %zu",
atomic_load(&g_handle_mgr.stats.open_files),
g_fs_config.limits.max_open_files);
pthread_mutex_unlock(&g_handle_mgr.global_mutex);
return -EMFILE;
}
// 2. 分配句柄ID
handle_id = handle_get(&g_handle_mgr.file_handles, (void *)(uintptr_t)fd);
if (handle_id < 0) {
EMSG("Failed to allocate handle for fd %d", fd);
pthread_mutex_unlock(&g_handle_mgr.global_mutex);
return handle_id;
}
// 3. 记录生命周期信息
if (handle_id < g_handle_mgr.lifecycle.max_handles) {
g_handle_mgr.lifecycle.creation_times[handle_id] = now;
g_handle_mgr.lifecycle.last_access_times[handle_id] = now;
}
// 4. 更新统计信息
atomic_fetch_add(&g_handle_mgr.stats.open_files, 1);
atomic_fetch_add(&g_handle_mgr.stats.total_operations, 1);
DMSG("Allocated file handle %d for fd %d, path: %s",
handle_id, fd, path);
pthread_mutex_unlock(&g_handle_mgr.global_mutex);
return handle_id;
}
// 句柄超时清理线程
static void *handle_cleanup_thread(void *arg)
{
time_t now, threshold;
int handle_id;
while (g_handle_mgr.lifecycle.cleanup_running) {
sleep(30); // 每30秒检查一次
now = time(NULL);
threshold = now - (g_fs_config.limits.handle_timeout_ms / 1000);
pthread_mutex_lock(&g_handle_mgr.global_mutex);
// 清理超时的文件句柄
for (handle_id = 0; handle_id < g_handle_mgr.lifecycle.max_handles; handle_id++) {
if (g_handle_mgr.lifecycle.last_access_times[handle_id] > 0 &&
g_handle_mgr.lifecycle.last_access_times[handle_id] < threshold) {
void *ptr = handle_lookup(&g_handle_mgr.file_handles, handle_id);
if (ptr) {
int fd = (int)(uintptr_t)ptr;
DMSG("Cleaning up stale file handle %d (fd %d)", handle_id, fd);
close(fd);
handle_put(&g_handle_mgr.file_handles, handle_id);
g_handle_mgr.lifecycle.last_access_times[handle_id] = 0;
atomic_fetch_sub(&g_handle_mgr.stats.open_files, 1);
}
}
}
pthread_mutex_unlock(&g_handle_mgr.global_mutex);
}
return NULL;
}
2. 高级RPC通信协议设计
完整的文件系统RPC命令集
位置:/tee-supplicant/src/optee_msg_supplicant.h
Copy
#define OPTEE_MSG_RPC_CMD_FS 2 // 文件系统RPC命令
// 核心文件操作命令
#define OPTEE_MRF_OPEN 0 // 打开文件
#define OPTEE_MRF_CREATE 1 // 创建文件
#define OPTEE_MRF_CLOSE 2 // 关闭文件
#define OPTEE_MRF_READ 3 // 读文件
#define OPTEE_MRF_WRITE 4 // 写文件
#define OPTEE_MRF_TRUNCATE 5 // 截断文件
#define OPTEE_MRF_REMOVE 6 // 删除文件
#define OPTEE_MRF_RENAME 7 // 重命名文件
// 目录操作命令
#define OPTEE_MRF_OPENDIR 8 // 打开目录
#define OPTEE_MRF_CLOSEDIR 9 // 关闭目录
#define OPTEE_MRF_READDIR 10 // 读目录
// 扩展操作命令
#define OPTEE_MRF_SYNC 11 // 同步数据到存储
#define OPTEE_MRF_GET_INFO 12 // 获取文件信息
#define OPTEE_MRF_SET_INFO 13 // 设置文件信息
高性能RPC消息处理架构
Copy
// RPC参数结构定义
struct optee_msg_param {
uint64_t attr; // 参数属性和类型
union {
struct {
uint64_t buf_ptr; // 缓冲区指针
uint64_t size; // 缓冲区大小
uint64_t shm_ref; // 共享内存引用
} memref;
struct {
uint64_t a; // 64位值A
uint64_t b; // 64位值B
uint64_t c; // 64位值C
} value;
} u;
};
// 高级RPC消息分发器
static const struct fs_rpc_operation {
const char *name;
TEE_Result (*handler)(size_t num_params, struct tee_ioctl_param *params);
size_t min_params;
uint32_t required_caps; // 所需的安全能力
} fs_ops[] = {
{"open", ree_fs_new_open, 3, FS_CAP_READ},
{"create", ree_fs_new_create, 3, FS_CAP_WRITE | FS_CAP_CREATE},
{"close", ree_fs_new_close, 1, FS_CAP_BASIC},
{"read", ree_fs_new_read, 2, FS_CAP_READ},
{"write", ree_fs_new_write, 2, FS_CAP_WRITE},
{"truncate", ree_fs_new_truncate, 2, FS_CAP_WRITE | FS_CAP_TRUNCATE},
{"remove", ree_fs_new_remove, 2, FS_CAP_DELETE},
{"rename", ree_fs_new_rename, 3, FS_CAP_RENAME},
{"opendir", ree_fs_new_opendir, 3, FS_CAP_READ},
{"closedir", ree_fs_new_closedir, 1, FS_CAP_BASIC},
{"readdir", ree_fs_new_readdir, 3, FS_CAP_READ},
{"sync", ree_fs_new_sync, 1, FS_CAP_SYNC},
};
// 智能RPC处理器实现
TEEC_Result tee_supp_fs_process(size_t num_params, struct tee_ioctl_param *params)
{
TEEC_Result res;
uint32_t cmdid;
struct timespec start_time, end_time;
bool timing_enabled = false;
// 1. 基本参数验证
if (num_params < 1 ||
(params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) != TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT) {
EMSG("Invalid RPC parameters");
return TEEC_ERROR_BAD_PARAMETERS;
}
cmdid = params[0].a;
// 2. 操作范围检查
if (cmdid >= ARRAY_SIZE(fs_ops)) {
EMSG("Invalid filesystem command ID: %u", cmdid);
return TEEC_ERROR_NOT_SUPPORTED;
}
const struct fs_rpc_operation *op = &fs_ops[cmdid];
// 3. 参数数量验证
if (num_params < op->min_params) {
EMSG("Insufficient parameters for %s: got %zu, need %zu",
op->name, num_params, op->min_params);
return TEEC_ERROR_BAD_PARAMETERS;
}
// 4. 安全能力检查
if (!check_fs_capabilities(op->required_caps)) {
EMSG("Insufficient capabilities for %s operation", op->name);
return TEEC_ERROR_ACCESS_DENIED;
}
// 5. 性能监控开始
if (should_monitor_performance(cmdid)) {
clock_gettime(CLOCK_MONOTONIC, &start_time);
timing_enabled = true;
}
// 6. 调用具体的处理函数
DMSG("Executing %s operation", op->name);
res = op->handler(num_params, params);
// 7. 性能统计更新
if (timing_enabled) {
clock_gettime(CLOCK_MONOTONIC, &end_time);
update_operation_stats(cmdid, &start_time, &end_time, res);
}
// 8. 错误处理和日志记录
if (res != TEEC_SUCCESS) {
EMSG("Operation %s failed with error 0x%x", op->name, res);
log_fs_error(cmdid, res, params);
} else {
DMSG("Operation %s completed successfully", op->name);
}
return res;
}
智能错误恢复和重试机制
Copy
// 错误分类和恢复策略
enum fs_error_class {
FS_ERROR_TRANSIENT, // 临时错误,可重试
FS_ERROR_RESOURCE, // 资源错误,需要等待
FS_ERROR_PERMANENT, // 永久错误,不可恢复
FS_ERROR_SECURITY, // 安全错误,记录并拒绝
};
struct fs_error_info {
enum fs_error_class class;
uint32_t max_retries;
uint32_t delay_ms;
const char *description;
};
static const struct fs_error_info error_recovery_table[] = {
{FS_ERROR_TRANSIENT, 3, 100, "Temporary I/O error"}, // EAGAIN
{FS_ERROR_RESOURCE, 5, 500, "Resource temporarily unavailable"}, // ENOMEM
{FS_ERROR_TRANSIENT, 2, 200, "Device busy"}, // EBUSY
{FS_ERROR_PERMANENT, 0, 0, "File not found"}, // ENOENT
{FS_ERROR_PERMANENT, 0, 0, "Permission denied"}, // EACCES
{FS_ERROR_SECURITY, 0, 0, "Security violation"}, // EPERM
};
// 智能重试执行器
static TEEC_Result execute_with_retry(fs_operation_func_t func,
struct fs_operation_context *ctx)
{
TEEC_Result res;
uint32_t attempt = 0;
const struct fs_error_info *error_info;
do {
res = func(ctx);
if (res == TEEC_SUCCESS)
break;
// 获取错误信息
error_info = classify_error(res);
if (!error_info || error_info->class == FS_ERROR_PERMANENT ||
error_info->class == FS_ERROR_SECURITY) {
break; // 不可恢复的错误
}
attempt++;
if (attempt >= error_info->max_retries) {
EMSG("Max retries (%u) exceeded for operation", error_info->max_retries);
break;
}
DMSG("Retry attempt %u after %u ms for error: %s",
attempt, error_info->delay_ms, error_info->description);
// 等待后重试
usleep(error_info->delay_ms * 1000);
} while (true);
// 记录最终结果
if (res != TEEC_SUCCESS && attempt > 0) {
EMSG("Operation failed after %u retries: 0x%x", attempt, res);
}
return res;
}
3. 文件系统操作实现
存储路径管理
Copy
// 存储根目录初始化
static int tee_supp_fs_init(void)
{
size_t n = 0;
mode_t mode = 0700; // 仅所有者可访问
// 设置存储根路径: ${fs_parent_path}/
n = snprintf(tee_fs_root, sizeof(tee_fs_root), "%s/",
supplicant_params.fs_parent_path);
// 创建目录结构
if (mkpath(tee_fs_root, mode) != 0)
return -1;
return 0;
}
// 生成绝对路径
static size_t tee_fs_get_absolute_filename(char *file, char *out, size_t out_size)
{
// 拼接: tee_fs_root + file
int s = snprintf(out, out_size, "%s%s", tee_fs_root, file);
if (s < 0 || (size_t)s >= out_size)
return 0;
return (size_t)s;
}
文件创建操作
Copy
static TEEC_Result ree_fs_new_create(size_t num_params,
struct tee_ioctl_param *params)
{
char abs_filename[PATH_MAX] = { 0 };
char abs_dir[PATH_MAX] = { 0 };
const int flags = O_RDWR | O_CREAT | O_TRUNC;
int fd = 0;
// 1. 参数验证
if (num_params != 3 || /* 验证参数类型 */)
return TEEC_ERROR_BAD_PARAMETERS;
// 2. 获取文件名并生成绝对路径
char *fname = tee_supp_param_to_va(params + 1);
if (!tee_fs_get_absolute_filename(fname, abs_filename, sizeof(abs_filename)))
return TEEC_ERROR_BAD_PARAMETERS;
// 3. 尝试创建文件
fd = open_wrapper(abs_filename, flags);
if (fd >= 0)
goto out;
// 4. 如果目录不存在,创建目录层次结构
if (errno == ENOENT) {
// 创建父目录
char *d = dirname(abs_dir);
if (!mkdir(d, 0700)) {
fd = open_wrapper(abs_filename, flags);
if (fd >= 0)
goto out;
}
// 处理多层目录创建...
}
out:
fs_fsync(); // 确保数据同步到磁盘
params[2].a = fd; // 返回文件描述符
return TEEC_SUCCESS;
}
文件打开操作
Copy
static TEEC_Result ree_fs_new_open(size_t num_params,
struct tee_ioctl_param *params)
{
char abs_filename[PATH_MAX] = { 0 };
int fd = 0;
// 1. 获取绝对路径
char *fname = tee_supp_param_to_va(params + 1);
if (!tee_fs_get_absolute_filename(fname, abs_filename, sizeof(abs_filename)))
return TEEC_ERROR_BAD_PARAMETERS;
// 2. 尝试以读写模式打开
fd = open_wrapper(abs_filename, O_RDWR);
if (fd < 0) {
// 3. 失败则尝试只读模式(处理只读文件系统)
fd = open_wrapper(abs_filename, O_RDONLY);
if (fd < 0)
return TEEC_ERROR_ITEM_NOT_FOUND;
}
params[2].a = fd;
return TEEC_SUCCESS;
}
文件I/O操作
Copy
// 读操作
static TEEC_Result ree_fs_new_read(size_t num_params,
struct tee_ioctl_param *params)
{
int fd = params[0].b; // 文件描述符
off_t offset = params[0].c; // 偏移量
void *buf = tee_supp_param_to_va(params + 1); // 缓冲区
size_t len = MEMREF_SIZE(params + 1); // 长度
// 定位并读取
if (lseek(fd, offset, SEEK_SET) < 0)
return errno_to_teec(errno);
ssize_t bytes = read(fd, buf, len);
if (bytes < 0)
return errno_to_teec(errno);
MEMREF_SIZE(params + 1) = bytes; // 返回实际读取字节数
return TEEC_SUCCESS;
}
// 写操作
static TEEC_Result ree_fs_new_write(size_t num_params,
struct tee_ioctl_param *params)
{
int fd = params[0].b;
off_t offset = params[0].c;
void *buf = tee_supp_param_to_va(params + 1);
size_t len = MEMREF_SIZE(params + 1);
// 定位并写入
if (lseek(fd, offset, SEEK_SET) < 0)
return errno_to_teec(errno);
ssize_t bytes = write(fd, buf, len);
if (bytes < 0)
return errno_to_teec(errno);
if ((size_t)bytes != len)
return TEEC_ERROR_STORAGE_NO_SPACE;
return TEEC_SUCCESS;
}
4. 目录操作支持
目录遍历
Copy
// 打开目录
static TEEC_Result ree_fs_new_opendir(size_t num_params,
struct tee_ioctl_param *params)
{
char abs_path[PATH_MAX] = { 0 };
DIR *dir = NULL;
int handle = 0;
// 生成绝对路径
char *path = tee_supp_param_to_va(params + 1);
if (!tee_fs_get_absolute_filename(path, abs_path, sizeof(abs_path)))
return TEEC_ERROR_BAD_PARAMETERS;
// 打开目录
dir = opendir(abs_path);
if (!dir)
return errno_to_teec(errno);
// 分配句柄
handle = handle_get(&dir_handle_db, dir);
if (handle < 0) {
closedir(dir);
return TEEC_ERROR_OUT_OF_MEMORY;
}
params[2].a = handle;
return TEEC_SUCCESS;
}
// 读目录项
static TEEC_Result ree_fs_new_readdir(size_t num_params,
struct tee_ioctl_param *params)
{
int handle = params[0].b;
DIR *dir = handle_lookup(&dir_handle_db, handle);
struct dirent *dirent = NULL;
if (!dir)
return TEEC_ERROR_BAD_PARAMETERS;
// 跳过隐藏文件(以'.'开头)
while (true) {
dirent = readdir(dir);
if (!dirent)
return TEEC_ERROR_ITEM_NOT_FOUND;
if (dirent->d_name[0] != '.')
break;
}
// 复制文件名到输出缓冲区
void *buf = tee_supp_param_to_va(params + 1);
size_t fname_len = strlen(dirent->d_name) + 1;
MEMREF_SIZE(params + 1) = fname_len;
if (fname_len > len)
return TEEC_ERROR_SHORT_BUFFER;
memcpy(buf, dirent->d_name, fname_len);
return TEEC_SUCCESS;
}
5. 错误处理和安全机制
错误码转换
Copy
static TEEC_Result errno_to_teec(int err)
{
switch (err) {
case ENOSPC:
return TEEC_ERROR_STORAGE_NO_SPACE; // 存储空间不足
case ENOENT:
return TEEC_ERROR_ITEM_NOT_FOUND; // 文件不存在
default:
return TEEC_ERROR_GENERIC; // 通用错误
}
}
安全考虑
- 路径验证: 所有文件路径都在tee_fs_root下,防止目录遍历攻击
- 权限控制: 目录权限设置为0700(仅所有者访问)
- 同步操作: 使用O_SYNC标志和fsync()确保数据持久化
- 句柄管理: 使用句柄数据库管理目录句柄,防止泄露
6. RPC调用路径
TEE到REE的调用流程
Copy
1. TEE侧文件操作 (ree_fs_ops)
↓
2. RPC调用 (OPTEE_MSG_RPC_CMD_FS)
↓
3. tee-supplicant接收RPC
↓
4. tee_supp_fs_process()分发
↓
5. 具体操作函数 (ree_fs_new_*)
↓
6. Linux文件系统调用
↓
7. 结果返回给TEE
参数传递
- 输入参数: 通过共享内存传递文件名、数据等
- 输出参数: 文件描述符、读取的数据、错误码等
- 缓冲区管理: 使用tee_supp_param_to_va()访问共享内存
7. 存储目录结构
实际文件系统布局
Copy
${fs_parent_path}/ ← 存储根目录
├── TA_UUID_1/ ← TA1的存储目录
│ ├── dirf.db ← 目录文件数据库
│ ├── dirh.db ← 目录哈希数据库
│ └── 50A7B331-D26A-...-F76C3421/ ← 具体对象目录
│ ├── O ← 对象数据文件
│ └── .info ← 对象信息文件
├── TA_UUID_2/ ← TA2的存储目录
│ └── ...
└── ...
文件命名规则
- TA目录: 以TA的UUID命名
- 对象目录: 以对象ID的十六进制表示命名
- 数据文件: ‘O’表示对象数据
- 元数据文件: ‘.info’包含对象属性和元数据
8. 配置和初始化
Supplicant启动配置
Copy
// 存储路径配置 (通常为 /data/tee/)
supplicant_params.fs_parent_path = "/data/tee/";
// 初始化时调用
if (tee_supp_fs_init() != 0) {
EMSG("Failed to initialize TEE filesystem");
return TEEC_ERROR_STORAGE_NOT_AVAILABLE;
}
运行时特性
- 延迟初始化: 第一次文件操作时才初始化存储根目录
- 目录自动创建: 根据需要自动创建TA存储目录
- 错误恢复: 创建失败时自动清理半创建的目录结构