STM32 Crash 上下文信息采集

1. 背景介绍

在 STM32 设备 Crash 的时候,触发硬件错误中断,在中断向量表的头部有如下几个中断:

  • HardFault_Handler
  • MemManage_Handler
  • BusFault_Handler
  • UsageFault_Handler

关于每个 Fault_Handler 的具体说明请参考文末相关资料;一些 RTOS 都会定义好一些 FaultHandler,以便在设备崩溃的时候,能够打印出一些进程上下文信息,随后 reset 设备。
另外, 除了 HardFault_Handler 默认启用外,其他几个 Handler 需要用户手动打开; HardFault 触发逻辑有以下几个,根据 SCB->HFSR 寄存器的值分为:

  • FORCED:MemManage Fault、 Bus Fault、Usage Fault 未启用,则这几个错误会由 HardFault_Handler 处理; 或者前面几个 Handler 内再次出现异常,则触发 HardFault

  • DEBUG_VT: debug 子系统未启用时发生调试行为(如中断等)

  • VECTTBL: 异常处理的时候,从中断向量表中读到错误的地址

图1. HFSR 寄存器的 bit 定义

而在发生可配置的错误中断时,具体错误的详细信息保存在 SCB->CFSR 寄存器中,其定义如下:

图2. CFSR 寄存器及其内部三个寄存器值(UFSR, BFSR, MFSR)的 bit 定义

在异常处理逻辑中,我们可以得到设备在异常发生时的上下文,包括默认压入栈的 r0, r1, r2, r3, r12, lr, pc, psr这 8 个寄存器,还可手动保存 r4~r11 这8个寄存器,最后还有部分错误状态寄存器;
一般情况下设备在异常处理之后需要 reset 重置来恢复运行,但是我们可以做一些有趣的事情:

  • “可恢复”的错误:在多线程/任务的 RTOS 系统环境下,如果是某个用户线程触发了“可恢复”的错误,我们可以保存进程上下文,然后调用 RTOS 的一些函数,清理掉这个线程,并适时重启该线程;

  • “不可恢复”的错误:如果是 RTOS 内核或者其他原因导致的不可恢复错误,我们可以将关键的寄存器信息保存在 Backup Registers/SRAM 中(STM32 Backup Registers/SRAM 读写);
    就算设备未通过电池连接 VBAT 脚,但是设备 reset 过程并不会断电,因此 RTC 和备份域中的资源可以在reset过程中得以保存。

借此,我们可以提供以下一些能力:

  • 研发同学可以获取设备异常发生时的上下文,直接定位到函数位置,不再需要物理连接设备复现异常,对于远程设备故障的排查十分方便

  • 在攻击者尝试一些攻击行为时,比如失败的缓冲区溢出,大概率会导致设备出现异常崩溃; 我们可以第一时间发现并解决安全隐患,甚至在攻击者成功利用之前完成漏洞的修复
    (配合严格的MPU策略更佳)

  • 发生可恢复的错误时,通知 RTOS 内核重启部分进程/任务,而不影响设备其他功能的运行,减少宕机时间
    (尤其在一些关键任务的执行过程中)


2. 方案实现

模仿 RTT 代码中 HardFault_Handler 的汇编实现,为三个可配置的异常处理编写处理函数,将关键寄存器信息保存在 Backup Registers 中;
在 Handler 函数中尽量不破坏原进程上下文,最后跳转 RTT 默认的 HardFault_Handler 以保留其崩溃信息 dump 的基本功能;

  • LL 库 + GCC

    • sec.h(stm32f4xx)

  • RT-Thread + HAL 库 + GCC ( RT-Studio 环境 )

    • sec.h(stm32f4xx)

  • RT-Thread + LL 库 + ARM CC (Keil uVision 5 环境)
    由于 ARM CC 5 对内联汇编支持有限,多种语法都导致编译错误,因此未使用汇编重写 Handler, 而选择直接修改 cpuport.c 的 rt_hw_hard_fault_exception() 函数,以保存上下文信息

    • sec.h(stm32f1xx)

    • cpuport.c(stm32f1xx)


3. 注意事项

  • 不同 RTOS 对于 msp、psp 的使用方式可能不一致(正常情况下 msp 为 Handler 线程和内核线程的栈帧, psp 为业务线程的栈帧)

  • 以上方案只保存了 MemManage Fault、BusFault、UsageFault 三类可配置异常的上下文,未对 HardFault 进行处理(以最大程度保持对RTOS自身 crash 处理逻辑的兼容)


4. 参考资料

发表评论

您的电子邮箱地址不会被公开。