7.2 KiB
7.2 KiB
认证 RTOS 的隔离特性:SAFERTOS ESM / CMSIS-RTX5 安全特性
这一族 RTOS 在"功能核 + 认证"之上,额外加了**访问控制与诊断特性**,会产生两类误判:同一 VA:Task A 能访问、Task B 不能
→ 可能只是 per-task 区域/保护域策略
某 API 调用失败 / 某线程不运行
→ 可能只是调用方安全等级不够
先在"谁能访问什么"这一层解释,再去怀疑对象损坏或逻辑错误。 </CORE RULE>
一、SAFERTOS + Enhanced Security Module(ESM)
基础 SAFERTOS 的空间隔离目标是非故意的内存访问(损坏/编程错误);ESM 把它加固到抵御"蓄意的"越权访问。
| 机制 | 作用 |
|---|---|
| 访问控制策略(ACP) | 限制每个任务可访问的 API 数量(例如禁止某任务改自己的特权级、改访问权限、创建新资源);任务越受限,被攻陷后的攻击面越小 |
| 对象访问控制策略(OACP) | 限制每个任务可访问的 RTOS 对象(队列、信号量、事件组等),把任务约束在初始化时分配给它的对象上 |
| 间接对象 ID | 把传统句柄(本质是 C 指针)换成经交叉引用表解析的 Object ID,使任务无法从句柄推出对象/TCB 的内存位置 |
| per-task MPU/MMU 区域 | 每任务 3 或 5 个可配置区域(随处理器变体);每次上下文切换都会重新编程;默认非特权任务只能访问自己的栈 |
- 区域要求:大小必须是 32 字节的倍数,基址必须 32 字节对齐
- 可定义对所有任务可见的全局区域;绝不应把另一个任务的栈分配给某任务
- 区域在任务创建时配置(可读/可写/可执行、用户或特权),运行期可以重新配置
- ESM 还包括:数据混淆、安全的用户/内核空间分离层、任务上下文数据隔离(上下文存在 TCB 而不是栈上)、渗透检测监控
RE 判据:
句柄不是内存指针(间接对象 ID)
→ 别把句柄当 TCB/对象地址,也别指望从它推出结构布局
二、CMSIS-RTX5 的安全特性
在 OS_SAFETY_FEATURES 等开关下提供:
| 特性 | 含义 |
|---|---|
| Safety Classes | 低安全等级的线程不能修改高等级线程;提供线程类的查询/挂起/恢复等接口。动机:RTOS 对象是经"以数字 ID 为参数、在 handler 模式执行"的系统调用访问的,单靠 MPU 保护可以被"用别的对象 ID 调 API"绕过——安全等级给对象访问加了访问控制 |
| MPU Protected Zones | 空间隔离:一个 zone 是一组带访问权限的内存区/外设,分配给一个或多个线程;zone ID 就是 MPU 表的行号,上下文切换时内核比较 zone ID 并调用回调(用户实现,通常是把对应行载入 MPU);内存违规触发 MemManage 异常。注意:中断处理程序绕过 MPU 保护,因此必须以最高完整性等级验证 |
| Thread Watchdog | 时间隔离:安全等级线程声明期望的周期/响应时间并"喂狗",未达标时由监督线程升级处理(重启线程/重启应用/受控关停/硬件复位) |
| 对象指针检查 | 检查对象指针的对齐与内存区域 |
| SVC 函数指针检查 | 检查 SVC 函数指针的对齐与内存区域;要求链接器划出专门的执行区容纳 SVC veneer 输入段 |
ISR FIFO 队列(延迟处理):
- 在 ISR 中调用部分 RTX API 不会立即完成——请求先进入 ISR FIFO 队列,等 ISR 结束后由调度器处理
- 所以:
IRQ 中调用 osXxx()
→ 对象的实际状态在 IRQ 退出之后才变化
→ 完全正常
- 队列太小会产生 ISR 队列溢出错误(专门的错误码),此时系统状态已经不一致;对策是增大引起溢出的对象尺寸,而不是怀疑队列对象损坏
- 另有"无效 SVC 函数"错误码(对象 ID 位置放的是函数)
三、权限模型与"拒绝"的语义
- SAFERTOS 的任务模型包含:自己的栈、被许可的 MPU/MMU 区域、特权状态、可访问的 RTOS 对象;上下文切换时重新编程任务的存储区域
- 因此三类现象都应先在权限层解释:
| 现象 | 优先解释 |
|---|---|
| 同一地址 Task A 能读、Task B fault | per-task 区域配置,不是内存损坏 |
| 普通任务不能访问某地址、ISR 却能 | 用户任务与特权内核/ISR 上下文的权限本就不同 |
| API 调用附近出现特权转换 | 正常的 RTOS API 网关,别当 ROP/trap 异常 |
ESM 下"拒绝"的来源:
- Task A 用某个句柄成功、Task B 用同一个句柄被拒 → 可能是对象访问策略拒绝,不是句柄损坏
- 句柄看起来完全不像指针 → ESM 用间接/混淆的对象 ID 取代直接指向控制块的句柄;应恢复 ID → 查表 → 对象 的路径,而不是硬套
句柄 = 内核指针 - 合法 API 返回拒绝 → 也可能是访问控制策略:当前任务根本没有调用该 API 的权限,而不是 API 实现坏了
决策树
拿到 SAFERTOS / RTX5 一类认证 RTOS 目标
├─ 同一地址的访问权限不一致
│ ├─ 查 per-task 区域配置(SAFERTOS)或 MPU zone 归属(RTX5)
│ └─ 区域可能被运行期重新配置
├─ 句柄看起来不像指针 / 指向奇怪的地方
│ └─ SAFERTOS ESM 用的是间接对象 ID + 交叉引用表
├─ 某 API 调用被拒
│ ├─ 查调用方的访问控制策略(能否调这个 API)与对象访问策略(能否用这个对象)
│ └─ RTX5 下查调用线程的安全等级
├─ ISR 里调用的 API 没立即生效
│ ├─ 请求进了 ISR FIFO,ISR 退出后才处理
│ └─ 出现队列溢出错误 → 增大对象尺寸,且此时系统已不一致
└─ 出现内存管理异常
├─ RTX5:MPU zone 违规
└─ 注意中断处理程序绕过 MPU 保护
工具与验证
- 访问控制:ACP/OACP 配置与运行期检查点(SAFERTOS);安全等级与对象属性(RTX5)
- 空间:per-task 区域/zone 表、区域对齐与大小约束、运行期重配置调用
- 延迟处理:ISR FIFO 队列的容量与溢出错误码
- 验证:能同时说清「这次访问受哪条策略约束 + 区域/等级当前是什么 + 失败是策略拒绝还是真的坏了」
该平台的坑(汇总)
- 把 per-task 区域导致的访问失败当内存损坏:权限差异可能完全合法
- 假设区域在任务生命周期内不变:运行期可以重新配置
- 把 SAFERTOS 的句柄当内存指针:ESM 下是经交叉引用表解析的间接对象 ID
- 忘了区域的大小/对齐约束:必须 32 字节倍数且基址 32 字节对齐
- 以为 MPU 保护覆盖中断处理程序:中断绕过保护,必须单独验证
- 只在 MPU 层找越权防线:RTX5 明确说单靠 MPU 可被"用别的对象 ID 调 API"绕过,需要安全等级
- 把 ISR 中调用的 API 未立即生效当 bug:请求进 ISR FIFO,退出后才处理
- 把 ISR 队列溢出当队列对象损坏:是容量不足,且此时系统状态已不一致
- 忽略 SVC 函数指针检查对链接布局的要求:需要专门的执行区容纳 veneer