第2章 TEE架构解析:ARM TrustZone 与硬件隔离
聊 TEE,绕不开 ARM TrustZone。这东西我最早接触是在做一款金融支付终端的时候,当时客户要求「即使系统被攻破,密钥也不能丢」。嗯,TrustZone 就是干这个的。
说白了,TrustZone 不是一套软件方案,而是 ARM 处理器在硬件层面做的安全扩展。它把一颗物理 CPU 虚拟成了两个「世界」——安全世界和普通世界。你想想看,同一个芯片,跑两套系统,互不干扰,这才是真正的隔离。
硬件隔离原理:不只是「分两个区」
很多人以为 TrustZone 就是给内存画个红线,普通程序不能越界。其实远不止这么简单。
TrustZone 的隔离是系统级的,覆盖了这几个维度:
- CPU 核心隔离:处理器新增了一个安全状态位(NS bit),每条指令、每个内存访问都会检查这个位。安全世界访问普通世界可以,反过来不行。
- 内存隔离:通过 TZASC(TrustZone Address Space Controller)把物理内存分成安全区域和非安全区域。普通世界的 DMA 设备也碰不到安全内存。
- 外设隔离:安全世界可以独占某些外设,比如指纹传感器、安全键盘。普通世界的驱动根本看不到这些设备。
- 中断隔离:安全世界有自己的中断向量表,普通世界的中断不会打断安全世界的执行。
核心要点:TrustZone 的隔离不是「软件约定」,而是「硬件强制」。普通世界想访问安全内存,总线层面就直接返回错误,连异常都不会触发——因为根本到不了那一步。
安全世界与普通世界的切换
这两个世界怎么切换?靠的是 Monitor 模式。我画个图帮你理解:
切换流程其实很清晰:
- 普通世界想调用安全服务(比如解密一段数据),执行 SMC(Secure Monitor Call)指令。
- CPU 陷入 Monitor 模式,保存普通世界的上下文(寄存器、状态)。
- Monitor 把 NS bit 清零,加载安全世界的上下文,然后切换到安全世界。
- 安全世界处理完请求,再通过 SMC 或异常返回 Monitor。
- Monitor 恢复普通世界上下文,NS bit 置 1,继续执行。
我个人的习惯:调试切换流程时,先确认 SMC 调用是否真的触发了 Monitor。我遇到过几次「假切换」——普通世界直接调了安全内存地址,总线报错,系统直接挂掉。嗯,那不是切换,那是崩溃。
Monitor 模式:两个世界的守门人
Monitor 模式是 TrustZone 里最特殊的一个模式。它既不属于普通世界,也不属于安全世界,而是独立于两者之外。我把它比作「海关」——所有进出两个世界的数据,都得经过它检查。
Monitor 模式负责这几件事:
| 职责 | 说明 | 我踩过的坑 |
|---|---|---|
| 上下文保存/恢复 | 切换时保存普通世界寄存器,加载安全世界寄存器 | 寄存器没保存全,回来时普通世界直接崩 |
| 中断路由 | 决定中断交给哪个世界处理 | 安全世界的中断被普通世界抢了,密钥操作被打断 |
| 安全检查 | 验证 SMC 调用是否合法 | 没做参数校验,普通世界传了个非法地址进来 |
| 电源管理 | 处理两个世界的休眠/唤醒 | 安全世界还在跑,普通世界把 CPU 休眠了 |
注意:Monitor 模式的代码必须放在安全且不可篡改的 ROM 里。我曾经见过一个方案,把 Monitor 代码放在 Flash 里,结果攻击者通过物理手段改了 Flash 内容,直接绕过了安全检查。嗯,那项目后来重做了。
实际项目中的避坑指南
做了几个 TrustZone 项目后,我总结了几条经验:
- 别在安全世界里做复杂计算:安全世界的内存和 CPU 资源有限,我见过有人把 AI 推理放进去,结果切换开销比计算本身还大。
- SMC 调用要加超时:普通世界调用安全服务,如果安全世界卡住了,普通世界不能一直等。我习惯设 5 秒超时,超时后复位安全世界。
- 安全世界的日志要慎用:我曾经为了调试方便,在安全世界开了串口日志,结果攻击者通过侧信道分析日志内容,推断出了密钥操作的时间模式。
- 中断优先级要规划好:安全世界的中断优先级必须高于普通世界,否则普通世界的中断会打断密钥生成操作。
一句话总结:TrustZone 的硬件隔离是 TEE 的基石。理解 Monitor 模式的切换机制,你就能明白为什么 TEE 能保护密钥不被普通世界的恶意程序窃取。下一层,我们开始动手配置实际的 TEE 环境。