← 文章 / 芯片硬件
Hacker News 3小时前 · 2026-09-19 04:20:09 · 3 阅读

光发射引导激光故障注入:攻破 RP2350 安全调试

光发射显微镜技术使我们定位到了树莓派微控制器中负责启用调试功能的寄存器。

随后,在相邻的两个位置发射激光脉冲,即使在调试功能已被永久禁用的情况下,也恢复了芯片 Secure 世界的调试器访问权限。

利用救援复位后获取的该访问权限,我们从一次性可编程(OTP)存储中恢复了一个机密信息。由于复位操作在固件应用运行时锁之前中断了芯片,因此该存储页保持 Secure 可读状态。

执行此攻击需要物理访问权限、破坏性准备步骤以及大约 $250,000 的实验室设备。

RP2350 的安全模型

RP2350 是树莓派的双核微控制器:每个处理器插槽在启动时可以选择 Arm Cortex-M33 或 RISC-V Hazard3 核心。其硬件安全功能包括:

  • 安全启动:基于 OTP 中预置的公钥指纹对签名固件进行认证
  • Armv8-M TrustZone:隔离 Secure 和 Non-secure 执行状态
  • 永久禁用调试的设置
  • 故障检测器:旨在检测由时钟或电源操纵引起的时序干扰

树莓派通过其 RP2350 黑客挑战赛主动邀请研究人员评估这些保护措施。首届挑战赛于 2024 年 8 月至 12 月针对原始芯片进行。在解决多项发现的问题后,树莓派发布了 A4 修订版——这也是我们测试的版本。

永久安全配置和启动公钥指纹存储于一次性可编程(OTP)存储器中:每个位只能从 0 翻转为 1 一次且不可逆转,因此写入的内容将贯穿芯片整个生命周期。

OTP 被组织成 128 字节的页面,并由两个持久的锁定行保护:对于第 n 页,PAGEn_LOCK0 配置可选的读写密钥以及未输入密钥时的行为,而 PAGEn_LOCK1 包含硬件强制执行的 LOCK_SLOCK_NS 权限。这些状态只能从读写变为只读或不可访问,但不能变得更宽松。

OTP 子系统对安全相关字段采用冗余编码:根据 RP2350 数据手册,关键标志采用“八条连续 OTP 行中的三票制”编码,而 OTP 锁定位则采用“多数表决的三重冗余”。

在 OTP 复位时,持久化的 LOCK_SLOCK_NS 值会初始化每页的 运行时锁(也称软锁)。固件可以在下一次 OTP 复位前收紧此锁,但无法放宽;该运行时更改无法在复位后保留。

外部调试器通过 Arm 的 串行线调试(SWD) 接口与 RP2350 通信。请求首先到达串行线调试端口(SW-DP),然后被路由到访问端口。在本文使用的 Cortex-M33 配置中,每个核心都有一个连接至其系统总线的内存访问端口(Mem-AP);启用 Mem-AP 后,调试器可读写允许的内存和外设。另有一个常开访问端口 RP-AP,提供少量复位和恢复控制功能。

安全调试指具有安全属性的 Mem-AP 访问。调试器随后可与访问控制逻辑允许的安全内存映射资源进行交互,并可暂停或检查处于安全状态运行的核心。

永久标志 CRIT1.DEBUG_DISABLE 旨在关闭此路径。当该标志被设置时,两个核心的 Mem-AP 使能信号均被置零,从而“完全禁止 AP 执行任何总线访问”,同时禁用工厂测试用的 JTAG 接口和 RISC-V 调试模块的访问端口。SW-DP 和 RP-AP 仍会响应,但两个核心的 Mem-AP 均无法访问系统总线。

但存在一个覆盖机制:内存映射寄存器 DEBUGEN 允许安全软件重新启用每个核心的 Mem-AP,并独立开启经由它的安全访问。数据手册指出,DEBUG_DISABLE “可通过设置该寄存器的所有位来完全覆盖”。

执行链中的这一关键覆盖机制正是我们将调试接口作为目标的原因。在 Mem-AP 上获得安全调试访问权限,是一种通用的原语,可用于读写安全内存、暂停并单步执行核心,以及检查其寄存器。该寄存器能否通过故障注入被设置,正是本文其余部分回答的问题。

实验设置

目标配置

Raspberry Pi 的 RP2350 Hacking Challenge 要求参赛者提取存储在 OTP1 中的 128 位密钥。启动时,经过签名的挑战固件会先确认 page 48 具有预期的持久锁,然后施加运行时锁,在下次 OTP 复位之前拒绝 Secure 和 Non-secure 访问该密钥。

我们在自己的 A4 版本设备上复现了厂商定义的这套配置:

  • 将公钥的 SHA-256 指纹写入 BOOTKEY0
  • BOOT_FLAGS1.KEY_VALID 设为 0x1BOOT_FLAGS1.KEY_INVALID 设为 0xe
  • 启用安全启动(CRIT1.SECURE_BOOT_ENABLE = 1
  • 永久禁用调试(CRIT1.DEBUG_DISABLE = 1
  • 以最高灵敏度启用毛刺检测器(CRIT1.GLITCH_DETECTOR_ENABLE = 1CRIT1.GLITCH_DETECTOR_SENS = 3
  • 按照挑战配置为 page 1 和 page 2 设置持久锁
  • 把 page 48 的持久锁设为 PAGE48_LOCK1 = 0x3c3c3c,即拒绝 Non-secure 访问(LOCK_NS = INACCESSIBLE),同时保留 Secure 读写权限(LOCK_S = READ_WRITE

启用安全启动后只有 Cortex-M33 核能运行,因此两个处理器插槽在这些实验中均使用 Arm 核。

样品制备与实验台

我们对该设备进行了背面开盖,让红外光穿透硅衬底直接照射晶体管,而不会被正面的金属层阻挡。随后把芯片焊回子板,并连接到 Scaffold——Ledger Donjon 开源的设备驱动与监控平台。由于拆除芯片背面的引线框架会切断其 GND 连接,需要用一根铜线将其恢复2

背面开盖封装的 RP2350 安装在分析子板上
背面开盖封装的 RP2350 安装在分析子板上
用于攻击实验的实验台
用于攻击实验的实验台

DEBUGEN:覆盖永久禁用调试

DEBUGEN 包含五个功能位:

名称作用
0PROC0启用核心 0 的内存访问端口
1PROC0_SECURE允许通过核心 0 的内存访问端口进行 Secure 访问
2PROC1启用核心 1 的内存访问端口
3PROC1_SECURE允许通过核心 1 的内存访问端口进行 Secure 访问
8MISC启用其他调试组件,包括交叉触发接口和 RISC-V 调试访问端口

核心的 Secure 调试需要同时设置这两个位:启用 Mem-AP 的位,以及允许通过该端口进行 Secure 访问的位。

与 OTP 安全字段使用的冗余编码不同,数据手册未记载 DEBUGEN 具备任何位冗余、奇偶校验或多数表决机制。

因此,我们测试了激光脉冲能否在上述安全设备中置位 DEBUGEN 位。

光子发射引导的定位

进行这项测试的前提是知道瞄准位置。置位单个 DEBUGEN 位意味着命中单个寄存器位的存储单元,无异于大海捞针。这比激光故障注入中常见的指令跳过故障更难瞄准:后者中,核心流水线中任意一个触发器的扰动都可能引发同样的跳过,其敏感区域足够宽泛,允许通过随机扫描找到。对单个 DEBUGEN 位进行盲扫是行不通的。

晶体管在开关切换时会发出微弱、与开关活动相关的近红外光子,因此通过收集重复执行时的光子发射,可以揭示选定控制信号在哪里发生状态变化。这使得光子发射显微镜(PEM)非常适合《DEBUGEN》:作为一个内存映射寄存器,安全软件可以在循环中精确地切换特定比特位,驱动测量所需的重复状态变化。我们将 PEM 用作第一个定位阶段,所得到的地图将后续的激光扫描限制在几微米大小的区域内。

我们比较了不同比特掩码的循环,这些循环反复切换选定的《DEBUGEN》比特位,仅目标比特不同。寄存器相对于相机自身噪声的光子发射很微弱,对温度等缓慢漂移的环境条件敏感,因此单帧图像没有意义。通过平均每个循环的许多帧,随机传感器噪声被抑制了;减两个平均值叠加后,循环共享的所有内容都被抵消了:静态背景、传感器偏移、热发射以及与选定比特无关的开关。在采集期间交错这两个值,使得缓慢的漂移不会偏置减法。剩下的就是跟踪选定比特的发射。

DEBUGEN 掩码 0x3 和 0xc 的全视图光子发射捕获的 200 次平均叠加及其带符号差分。
所有 200 次掩码 0x3 和 0xc 采集的平均叠加,随后是它们的带符号差分。红色表示正值,表示 0x3 的发射更大;蓝色表示负值,表示 0xc 的发射更大。下方的定位图额外平衡了采集顺序,然后才组合匹配差分。

在不同比特掩码之间的重复比较,揭示了相机视野中三个区域内的紧凑位点,与《DEBUGEN》的 0–3 比特相关。

Infrared overview of the die with three marked regions, plus zooms of those regions overlaid with coloured DEBUGEN bit sites.
相机视野的红外全景图,标注了三个区域。彩色像素标记了与 `DEBUGEN` 位 0-3 相关的位置。

这些区域显示了与各个 DEBUGEN 位相关的开关活动,但并不能直接定位存储单元。每个位观测到的多个热点,可能来自存储单元本身,也可能来自相关逻辑电路。由于缺少版图数据,我们无法区分这两种情况。不过,这些区域仍然大幅缩小了搜索范围。

发现 1 —— 对 DEBUGEN 进行故障注入可获得 Secure 调试权限

激光故障注入(LFI)方面,我们使用 980 nm 脉冲激光,最大光功率 2.97 W,实际工作在约 40% 功率(约 1.2 W),脉宽 100 ns,搭配 50 倍物镜。每次发射脉冲后,我们都通过 SWD 探测调试访问端口。

在 PEM 找到的区域内,我们进行了 LFI 扫描,并利用 SWD 反馈校准出相距几微米的两个敏感位置。在其中一个位置,脉冲使核心 1 的 Mem-AP 开放了总线访问,说明 PROC1 被置位;在另一个位置,Mem-AP 的 Control/Status Word 报告 SDeviceEn = 1,这一状态信号表明 PROC1_SECURE 很可能已被置位。每次发射脉冲后,我们都会检查这两个指标。

左侧为 PEM 位点位的红外视图,右侧为 LFI 故障点位的红外视图。
左:与 `DEBUGEN` 位相关的 PEM 位点。右:LFI 红外视图上的激光故障点。

设置某一位的脉冲可能会导致另一位被清零,因此同时设置两位需要迭代序列。我们的脚本向 PROC1 位置发送脉冲,直到总线可访问;随后向 PROC1_SECURE 位置发送脉冲,直到 SDeviceEn = 1;若总线访问丢失,则返回至第一个位置。一旦位点和脉冲参数完成校准,该序列即可在数秒内启用 Secure 调试。值得注意的是,使用 20x 物镜无法复现此序列。由于两个位置仅相距几微米,较宽的光斑很可能同时命中设置位的区域和清零位的区域,导致无法获得正确的位值。

两位均设置完成后,无需额外脉冲或软件写入,位状态将保持置位。通过核 1 的 Mem-AP 读取 Secure 专用的 DEBUGEN 寄存器,返回值为 0xc;由于 DEBUGEN 仅限 Secure 访问,此次成功读取确认该事务具有 Secure 属性。

通过核 1 的 Mem-AP 启用 Secure 访问,使调试器能够读写满足以下条件的内存映射资源:ACCESSCTRL 权限将调试器视为总线管理器,且目标特定控制允许 Secure AHB 事务。独立于这些直接读取,调试器仍可暂停和单步执行核心,并检查或修改其寄存器,从而通过 Secure 核心介导的提取方式破坏 TrustZone 运行时隔离。这并不意味着启动 ROM 会接受未经认证的固件:当固件正常启动时,安全启动仍会对其认证,但无法保护在验证后仍对调试器可访问的运行时状态。

在 Hacking Challenge 配置中的应用

上文提到的具有 Secure 属性的 Mem-AP 访问能够暴露 Secure 运行时状态,但挑战文档第 48 页所述的运行时锁仍在固件运行后阻止对密钥的访问。该页的持久锁 `PAGE48_LOCK1 = 0x3c3c3c` 拒绝 Non-secure 读取,但将 `LOCK_S` 保持在 `READ_WRITE` 状态,因此在运行时锁收紧之前,仍可通过具有 Secure 属性的访问进行读取。

每次启动时,固件都会向运行时锁 `otp_hw->sw_lock[48]` 写入最具限制性的二进制值 `0b1111`。此后,该寄存器会使该页面对 Secure 和 Non-secure 访问(包括 Secure 调试)均不可访问,从而阻止来自 Mem-AP 的 Secure 事务读取密钥。

正如文档所述,软件锁“在复位时从 OTP 锁页初始化”,且写入操作的状态变更仅维持“至下次复位为止”。复位 OTP 块会丢弃 `0b1111`,并恢复由 `PAGE48_LOCK1` 派生的值,此时 `LOCK_S = READ_WRITE`。

剩下的问题是:如何在允许固件重新应用运行时锁之前,重置已加锁的芯片。RP-AP“始终可访问,即使外部调试被禁用”。设置 `CTRL.RESCUE_RESTART` 会触发救援复位:这是一种完整的系统复位,同时会标记启动 ROM 在任何用户软件运行前暂停。

boot ROM 在看门狗、Flash 或 USB 启动之前检查 `POWMAN_CHIP_RESET.RESCUE_FLAG`,清除该标志后,将核心 0 保持在中断禁用的等待循环中,并将核心 1 保持在等待向量路径中3。数据手册未记载对 `CTRL.RESCUE_RESTART` 有任何限制。

我们按以下顺序操作:

  1. 救援复位。 通过 RP-AP 将 `CTRL.RESCUE_RESTART` 设置为 `1`,然后清除为 `0`。芯片复位后停留在 boot ROM 的等待路径中。由于签名固件从未运行,`sw_lock[48]` 未被收紧,仍保持由 `PAGE48_LOCK1` 派生的宽松值 —— `LOCK_S = READ_WRITE`。
  2. DEBUGEN 故障注入为 0xc在两个内核都处于 boot-ROM 等待路径时,按上述方法设置 PROC1PROC1_SECURE,这两个置位组合起来正是 0xc
  3. 挂起 core 1:通过其调试挂起控制与状态寄存器(DHCSR),经由已变为 Secure 的 Mem-AP 操作。
  4. 读取机密:通过受保护的读取接口,从 OTP 行 0xc080xc0f 读取。

我们在受测设备上执行了这套流程,成功恢复出完整的挑战机密。

DEBUGEN_LOCK 无法阻止激光引起的位翻转

DEBUGEN_LOCK 用于阻止软件写入对应的 DEBUGEN 位:每个锁定位的描述是"写入 1 即锁定 […] 位,一旦置位便无法清除"。数据手册将其定位为"避免意外写入"的手段。

在目标 DEBUGEN 位为 0、其锁定位为 1 的实验中,脉冲依然能把 DEBUGEN 置位,而锁定位仍保持 1。脉冲也能置位锁定位,无论对应的 DEBUGEN 是否变化。在成功的攻击序列中,当 PROC1PROC1_SECURE 都被置位时,五个功能锁定位已全部为 1。我们从未观察到锁定位从 1 变回 0,也就是说,一旦故障注入置位了对应的锁,后续写入 DEBUGEN = 0 也无法恢复原有的禁用状态。

软件层防护的局限

一旦通过 Mem-AP 的 Secure 访问被启用,仅凭 Secure 属性已无法把调试器与 Secure 固件隔离开。这种访问不会越过硬性 OTP 锁或外设专属的控制。ACCESSCTRL 可以阻止调试器总线管理器对特定目标的直接事务,但它本身无法阻止一个控制着 Secure 内核的调试器发起内核侧的访问,或通过内核寄存器提取已加载的值。救援复位之后,ACCESSCTRL 会在固件有机会重新配置之前,先恢复到全开放的复位默认值。因此,ACCESSCTRL 只能减少直接的 Mem-AP 暴露面,并不能构成一道独立的机密性边界。

固件仍可通过在 ACCESSCTRL 中拒绝调试器访问敏感目标,并随后设置 ACCESSCTRL.LOCK 中的调试器位,从而降低启动后的暴露风险,确保调试事务无法重新开放这些权限。安全固件还可以定期检查 DEBUGEN,若检测到异常值,则触发使处理器冷复位域清零的安全失效复位。这些措施属于尽力而为的运行时缓解方案:已启用的调试器可能在下次检查前暂停核心,而救援复位会在固件配置 ACCESSCTRL 或运行监视程序之前停止。因此,它们无法阻止本文演示的固件加载前密钥读取。

RP2350 文档中描述的加密启动流程,在两种不同的机器状态下,分别阐明了运行时锁在固件加载前的局限性,以及调试器管理器过滤在启动后的局限性。救援复位后,引导 ROM 在解密前暂停:此时尚无明文负载,但如果 OTP 页的持久权限允许 Secure 访问,且没有其他目标控制块阻止该事务,解密密钥可能可直接读取。正常加密启动后,明文已存在于 SRAM 中:直接通过 Mem-AP 读取依赖于 ACCESSCTRL 中调试器管理器的权限,而 Secure 核心控制可能允许核心介导的提取,即便直接读取被拒绝。这是架构分析,并非针对加密启动的实测结果;加密启动仍然保护外部闪存免受离线检查。

影响与攻击条件

已演示的攻击序列可获得 Secure 归属的内存访问权限、Secure 世界执行控制权,以及在复位其运行时页锁后访问挑战密钥的能力。执行此攻击需具备以下资源:

  • 破坏性物理接触。 背面解封装会永久改变封装并使芯片裸片暴露。
  • 专用实验室设备。 上文所述完整装置的成本约为 25 万美元
  • 硬件安全专业知识。 该流程涉及样品制备、裸片导航、激光参数选择,以及激光控制、平台定位和 SWD 测量的协同操作。

结论

RP2350 在 OTP 中通过冗余投票机制编码关键的调试禁用标志,但 DEBUGEN 可以覆盖这些标志的效果,且数据手册未记载其具备等效保护机制。实验中,尽管 DEBUGEN_LOCK 处于锁定状态,激光脉冲仍改变了 DEBUGEN 的值,甚至设置了阻止固件恢复禁用值的锁定位。此外,RP-AP 救援复位将挑战赛的运行时页锁恢复至其持久化值,同时阻止了用户固件的执行。软件可见机制各自完成了其文档所述功能,但它们与激光故障的交互开启了 Secure 调试,并恢复出挑战赛的秘密信息。差分 PEM 首先隔离了依赖于位的 DEBUGEN 活动,指导下的 LFI 则利用这一空间线索实现了持久的 Secure 调试。这一系统级教训表明,安全分析必须覆盖完整的执行路径,涵盖从持久化 OTP 配置到可变控制寄存器及复位行为的整个过程,因为系统安全取决于这条完整路径,而非孤立的单个机制。

披露与致谢

我们于 2026 年 7 月 28 日向 Raspberry Pi 披露了此故障。感谢 Raspberry Pi 团队在披露讨论中的积极响应,以及在安全研究方面采取的透明态度。


Antoine Plin,Ledger Donjon 硬件安全实习生

脚注

  1. https://github.com/raspberrypi/rp2350_hacking_challenge RP2350 挑战赛仓库,包含我们复刻的参考锁定配置和固件。

  2. Courk,低成本激光故障注入:RP2350 版

  3. 救援检查是 src/main/arm/varm_boot_path.c 中 core 0 启动路径的第一步;在 src/main/arm/arm8_bootrom_rt0.S 中,varm_wait_rescue 进入禁中断的 varm_dead_quiet WFI 循环,而 core 1 保持在启动 ROM 的等待向量路径中。

原始来源: Hacker News

评论 (0)