rust-libteec 0.6.4

Rust implementation of TEE Client API for secure communication with Trusted Applications.
# 安全修复延后项清单(CAND_002 认证绕过 + gp vsock-manager)

状态:待修复 | 建档:2026-09-08 | 依据:libcc-teec-report.md(rust-libteec 审计)、xtee-apps-report.md(xtee-apps 审计)及当轮代码核实

## 背景

rust-libteec 的 CAND_001/003/004/005/006 已于 2026-09-08 修复(见文末"已完成修复")。
本文档记录**延后修复**的两类问题及既定设计决策,供后续会话直接实施:

1. CAND_002:CA 认证绕过(ca_auth_info 客户端自报)
2. gp vsock-manager 三个高危项(xtee-apps 报告 CAND_003/004/005 映射到 gp 代码)

## 威胁模型结论(pKVM + x-kernel TA 验签,已核实)

| 边界 | 机制 | 结论 |
|---|---|---|
| REE ↔ vTEE(VSOCK) | 设计上的公开服务接口,任意免特权 REE 进程可达(ECDH-PSK 无客户端认证) | pKVM 不改变可达性,此面上的漏洞为必修 |
| REE → vTEE 进程注入 | pKVM 硬件边界 | 被挡住 |
| 恶意 TA 二进制植入 | x-kernel exec 级验签:process/kexec/src/loader.rs:310-312 verify_ta_elf_on_load_and_cache_ta_head(feature tee_ta_sign)+ core/ksyscall/src/task/execve.rs:101-113 | 被挡住(需确认 tee_ta_sign 在生产 defconfig 启用) |
| vTEE guest 内部 | pKVM 不隔离;所有进程共享 x-kernel | CAND_004/005 的唯一现实前提 = 被攻陷的合法签名 TA |

判定:CAND_002 与 vsock-manager CAND_003 为 REE 可达(必修);CAND_004/005 为"被攻陷 TA 遏制层"(TA 隔离属性,建议做,按产品是否声明 GP 风格 TA 间隔离定优先级)。签名验证 ≠ TA 无漏洞:验签认证发布者,不认证无缺陷,OP-TEE/GP 威胁模型明确包含 malicious TA 并在签名之外做地址空间隔离。

## 延后项 1:CAND_002 CA 认证绕过(REE 可达,必修方向已定)

现状:OpenSession 请求中的 CaAuthInfo { ca_uuid, verified } 由 CA 侧自报(rust-libteec src/teec/ca_auth.rs + session.rs),gp vsock-manager 原样转发(vsock_server.rs:253/289),TA 的 acl_check(xtee-rust-sdk xtee-utee ta_manager.rs:556 → acl.rs)据其决策。

已否决方案:客户端 fail-closed(verified=false 拒绝)——ACL 决策点在 TA(OP-TEE 模型),客户端库只是传输层,且 fail-closed 挡不住绕库直连 VSOCK 的攻击者,有些 TA 合法接受未验证 CA。

既定方向:服务端(vsock-manager)权威化身份,TA 仍经 acl_check 决策:

1. 协议:teec-protocol 的 TEE_Request::OpenSession 增加 #[serde(default)] ca_attestation: Option<CaAttestationToken>(additive,旧端互不影响;注意 rust-libteec 与 gp workspace 双端协议版本对齐)。Token 含 { ca_path, verified, nonce, expiry, sig(SM2) },证书链到生产根。
2. REE 证明代理:新增 root 守护进程(或 systemd socket-activation 按需拉起),监听 unix socket(如 /run/xtee-attest/attest.sock)。流程:SO_PEERCRED 拿 pid → pidfd 防复用 → /proc/{pid}/exe → tasign 验签(生产根证书,与 ca_auth.rs:48 同源)→ 签发短时效、nonce 绑定 token。代理代码量小、单一职责,持有一把 SM2 私钥(供给流程与 CA/TA 签名证书体系对齐)。
3. vsock-manager(gp):OpenSession 分支验证 token(签名+有效期+nonce,nonce 绑定当前 TLS 连接)→ 重写 ca_auth_info(ca_uuid = path_to_uuid(token.ca_path),verified = token.verified),丢弃客户端自报值。灰度期配置可控(先透传旧值,最终收紧为无 token 即 verified=false)。加 tasign 依赖。
4. rust-libteec:新增 attest_client 模块向代理请求 token(缓存模式参照 ca_auth.rs 的 (pid, 文件标识) 缓存),session.rs OpenSession 填入 token。公开 C API 不变。
5. xtee-rust-sdk acl.rs:仅文档更新(verified 语义来源变为可信通道侧),API 不变。

## 延后项 2:vsock-manager CAND_003 会话 IDOR(REE 可达,必修,最优先)

gp 代码现状(kylin100/xtee-apps/gp/vsock-manager):
- SessionBinding(ta_runtime.rs:556-562)无连接标识;session_entry 仅按 global_session_id 查(vsock_server.rs:376/428)
- global_session_id 从 1 递增(ta_runtime.rs:572-597 next_session_id.fetch_add),枚举零成本
- ServerConfig::new(0xFFFFFFFF, ...)(vsock_server.rs:128)接受任意 CID
- 读循环退出(vsock_server.rs:190-229)无会话清理 → 孤儿会话

攻击:恶意 REE 进程 connect → ECDH/TLS → 顺序尝试 1,2,3… 对他人会话 InvokeCommand/CloseSession(CAND_003 POC)。

B1 设计(会话-连接绑定):
1. 每条 TLS 连接分配 connection_id: u64(AtomicU64,仅服务端内存不下发);handle_vsock_request/handle_packet 签名透传
2. SessionBinding 加 connection_id 字段;bind_session 记录创建者
3. Invoke/Close 改用 session_entry_for_connection(global_session_id, connection_id),归属不符返回 TEE_ERROR_ITEM_NOT_FOUND
4. 断连清理:handle_vsock_request 退出时遍历该连接会话 → best-effort 转发 CloseSession → unbind → on_session_closed(对齐 OP-TEE "context 关闭即关闭全部 session"语义,同时修复孤儿泄漏)
5. 可选纵深(非必需):global_session_id 随机化——B1 归属校验为主防线,随机化仅防未来回归。x-kernel 有 getrandom(2)(core/ksyscall/src/sys.rs:227)+ devfs random 节点 + virtio-rng;vsock-manager 进程内 ECDH/TLS 已在用 OsEntropy/CtrDrbg,复用即可,勿依赖 /dev/urandom 文件路径
6. CID 0xFFFFFFFF:调研 virga ServerConfig 是否支持限定对端 CID,不支持则记录为已知限制

## 延后项 3:vsock-manager CAND_005 注册无 pid 绑定(被攻陷 TA 遏制层)

gp 代码现状:
- ta_server.rs(78 行):/tmp/server.sock 注册入口无 SO_PEERCRED、无 UUID 校验;socket_path 直接采信注册消息自报值(:63 传入)
- mark_registered(ta_runtime.rs:377-409):不写 pid;or_insert_with 接受任意 instance_id;:406 直接覆盖 instance.socket_path
- reap_dead_instances_locked(ta_runtime.rs:490-511):child=None(外部注册)实例永不回收
- spawn 路径有 pid(:363-364),spawn_ta/resolve_ta_executable(:522-553)不验签(验签在 x-kernel exec 层,用户态无需重复)

B2 设计(注册可信建立):
1. Cargo.toml 加 libc(SO_PEERCRED)、uuid(UUID 解析)
2. ta_server.rs:注册连接上 getsockopt(SOL_SOCKET, SO_PEERCRED) 取对端 pid(内核背书);Uuid::parse_str 严格校验;注册授权两分支——A: peer == 注册表 Starting 实例 spawn pid;B: readlink /proc/{pid}/exe canonical 后位于 ta_root 且匹配 resolve_ta_executable(uuid) 结果
3. socket_path 改服务端推导 + 一致性校验:注册消息的 socket_path 必须等于 /tmp/{uuid}.{instance_id}.sock(TA 侧 ta_manager.rs:286-287 推导格式已核对一致;带 XTEE_TA_LISTENER_SOCKET_PATH 自定义路径的外部 TA 会被拒,按收紧处理)
4. mark_registered 签名加 peer_pid: u32,删除 socket_path 参数(内部推导),所有分支写入 instance.pid;instance_id 收紧为仅允许已有 Starting 槽位或该 UUID 首个实例
5. reap:child=None && pid=Some 的实例改用 pid 存活检查(kill(pid, 0) 或 /proc/{pid} 存在 + exe 复核)

## 延后项 4:vsock-manager CAND_004 套接字劫持(被攻陷 TA 遏制层)

gp 代码现状:forward_request_to_ta(vsock_server.rs:632-682)完全无身份校验,UnixStream::connect 直连注册表 socket_path(报告版本至少有 SO_PEERCRED 且 None 时跳过,gp 是校验根本不存在)。

B3 设计(转发 fail-closed):
1. forward_request_to_ta 签名加 expected_pid: Option<u32>;connect 后立即 SO_PEERCRED 核对,不匹配断开返回错误
2. expected_pid == None 一律拒绝转发(fail-closed,不留跳过分支——报告 CAND_004 修复要点)
3. 全部调用点(OpenSession/InvokeCommand/CloseSession/B1 断连清理)传 registry.instance_pid(uuid, instance_id)(ta_runtime 新增接口)
4. SO_PEERCRED 函数放公共模块,ta_server.rs 与 vsock_server.rs 复用

## 实施顺序与验证

1. B1(必修,纯 gp vsock-manager 改动,协议不变)
2. B2 + B3(共享 SO_PEERCRED 公共函数,一起做)
3. CAND_002(跨组件:协议 → 代理 → vsock-manager 验证 → libteec 取 token,需证书/部署流程配合)

验证:cargo test -p vsock-manager(现有 ta_runtime.rs:696-1144 测试底子 + 新增用例:归属拒绝、断连清理、mark_registered 写 pid、自报路径拒绝、无 pid 拒绝转发、pid-only 实例 reap);设备 make test-c-examples 全链路。

约束(用户既定):
- 公开 C API 与线上协议字节格式不变(CAND_002 协议仅 additive,serde default)
- TA 侧 xtee-utee 在 B1-B3 零改动;x-biometric 不动
- 不引入装饰性注释;随机数直接用现有 RNG 基础设施(getrandom(2)/进程内 CtrDrbg),不依赖 /dev/urandom 文件

## 已完成修复(2026-09-08,rust-libteec,供追溯)

- CAND_001/003(FinalizeContext 路径):context.rs 新增 registered_id/is_registered(纯地址校验),remove_context 拒绝未登记/ fd 篡改指针;c_api.rs TEEC_FinalizeContext 解引用前先 is_registered;shared_memory.rs release_by_context 同样加固
- CAND_004/005/006(TMPREF/Register 越界):新增 src/teec/vmem.rs(/proc/self/maps 区间校验,单 VMA + 权限检查,maps 不可读时放行告警);get_tmpref_data 读前可读校验、set_tmpref_data 写前可写校验 + 截断告警;allocate_cc register 分支拷贝前可读校验;c_api.rs 三个函数 doc 注明安全契约
- 验证:make test 139+19 用例全绿,cargo clippy --workspace --all-targets 零警告