打印
[综合信息]

程序运行时堆栈溢出检测及失效安全策略

[复制链接]
919|45
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tifmill|  楼主 | 2024-6-26 10:03 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

本文主要介绍如何在程序运行时进行堆栈溢出检测及检测到堆栈溢出之后的失效安全策略。

程序运行时堆栈溢出检测主要通过检查对应的堆栈指针(SP)是否超出指定的堆栈范围来实现,一般可以分为硬件检测和软件检测。

硬件堆栈溢出检测

硬件堆栈溢出检测的原理:设置对应的硬件单元,如果在程序运行过程中,SP超出指定的堆栈范围,会触发对应的硬件错误。目前主要有如下两种方式:

  • 使用堆栈限制寄存器(Stack Limit registers)
  • 使用内存保护单元(MPU:Memory Protection Unit)
使用堆栈限制寄存器(Stack Limit registers)

ARMv8-M架构中包含了堆栈限制寄存器(Stack Limit registers),当SP的值小于(ARMv8-M架构中堆栈是向下生长的)对应Stack Limit registers的值时,会触发UsageFault或者HardFault:

使用内存保护单元(MPU:Memory Protection Unit)

为了提高系统的安全性,越来越多的MCU集成了内存保护单元(MPU:Memory Protection Unit),可以通过设置MPU的属性,当SP访问超出指定的堆栈范围时,产生MemManageFault或者HardFault:


软件堆栈溢出检测

软件堆栈溢出检测的原理:在程序开始之前,往堆栈防护区域填充特定的值(比如0xCD),然后在程序运行时去检查堆栈防护区域中之前填充的值是否被篡改:如果被篡改了,说明堆栈溢出。


RTOS任务堆栈溢出检测

通常情况下,RTOS会提供任务堆栈溢出检测功能,只需要使能对应的宏定义,打开堆栈溢出检测功能。当检测到堆栈溢出时,RTOS会调用相应的堆栈溢出钩子函数(hook)。

注意:RTOS一般会计算各个任务堆栈的使用情况,所以在新建任务时,RTOS会把任务堆栈所有区域都填充特定的值,然后在运行过程中去检测和计算对应的堆栈使用情况。



在RTOS里面进行任务堆栈溢出检测一般需要如下操作(下面以Azure RTOS为例):

  • 定义对应的宏使能堆栈检测功能


  • /* Determine whether or not stack checking is enabled.





  • By default, ThreadX stack checking is disabled.





  • When the following is defined, ThreadX thread stack checking is enabled.





  • If stack checking is enabled (TX_ENABLE_STACK_CHECKING is defined),





  • the TX_DISABLE_STACK_FILLING define is negated,





  • thereby forcing the stack fill which is necessary for the





  • stack checking logic. */








  • #define TX_ENABLE_STACK_CHECKING


  • 定义并注册堆栈溢出钩子函数(hook)


  • void my_stack_error_handler(TX_THREAD *thread_ptr);








  • /* Register the "my_stack_error_handler" function with ThreadX





  • so that thread stack errors can be handled by the application. */





  • status = tx_thread_stack_error_notify(my_stack_error_handler);


系统堆栈溢出检测

系统堆栈溢出检查需要开发人员手动添加对应的代码:在程序开始之前,往堆栈防护区域填充特定的值(比如0xCDCDCDCD),然后在程序运行时去检查堆栈防护区域中之前填充的值是否被篡改。



  • #define STACK_FILL_PATTERN 0xCDCDCDCD





  • /* Linker generated symbols */


  • extern uint32_t CSTACK$$Base;





  • /* Fill the stack base with dedicated pattern */


  • *((uint32_t *) &CSTACK$$Base) = STACK_FILL_PATTERN;








  • /* Check system stack overflow */


  • /* If the filled pattern is changed, there is stack overflow */


  • if(STACK_FILL_PATTERN != *((uint32_t *) &CSTACK$$Base))


  • {





  • }

注意:软件堆栈溢出检查由于是通过软件代码进行检测,可能没有那么及时,也有可能在堆栈溢出的地方已经造成了其它的硬件错误(比如从堆栈POP出的PC指向了不可执行的地址)。

堆栈溢出之后的措施

前面介绍了程序运行时进行堆栈溢出检测的方法。那么当检测到堆栈溢出之后程序应该怎么处理呢?

由于堆栈溢出可能会造成程序运行需要的重要数据的破坏,而这种破坏是未知的。所以当发生堆栈溢出时,程序通常是很难继续正常运行的,往往需要通过系统复位来重新回到正常的状态。但是需要注意的是,在系统复位之前,需要确保系统进入安全状态,避免造成更严重的损害。下面是发生堆栈溢出之后一般的处理策略:

  • 确保系统进入安全状态(比如关掉对应的执行器)
  • 如果条件允许,Log堆栈溢出事件到非易失性存储器(Data Flash或者EEPROM),以便后续分析
  • 系统复位

使用特权

评论回复
沙发
LEDyyds| | 2024-6-27 16:21 | 只看该作者
处理措施可以

使用特权

评论回复
板凳
埃娃| | 2024-6-28 17:41 | 只看该作者
栈溢出后是下面的数据消失还是顶上的消失啊?

使用特权

评论回复
地板
突然下起雨| | 2024-8-28 12:32 | 只看该作者
在 ARMv8-M 架构中,堆栈限制寄存器用于检测堆栈溢出。

使用特权

评论回复
5
好几遍vh| | 2024-9-30 15:18 | 只看该作者
硬件堆栈溢出检测的原理:设置对应的硬件单元,如果在程序运行过程中

使用特权

评论回复
6
qiufengsd| | 2024-10-3 08:39 | 只看该作者
在堆栈的顶部预留一小块内存区域作为监视哨兵。当程序正常运行时,这块区域不应该被访问。如果检测到该区域被修改,说明堆栈已经溢出。

使用特权

评论回复
7
pentruman| | 2024-10-3 10:29 | 只看该作者
当检测到堆栈溢出时,实施失效安全策略,如进入安全模式、保存关键数据、关闭非关键功能、复位系统或请求外部干预。

使用特权

评论回复
8
updownq| | 2024-10-3 11:57 | 只看该作者
检查程序中的代码,寻找可能导致堆栈溢出的原因。例如,递归函数调用过深、局部变量过多或大型数据结构的使用等都可能消耗大量的堆栈空间。

使用特权

评论回复
9
loutin| | 2024-10-3 14:15 | 只看该作者
可以在程序中设置一个全局的错误标志,当堆栈溢出时设置该标志,并在主循环中检查该标志,以便及时采取相应的措施。

使用特权

评论回复
10
robincotton| | 2024-10-3 15:50 | 只看该作者
在程序开发阶段,使用工具进行动态堆栈分析,以确定实际需要的堆栈大小,并据此调整堆栈大小设置。

使用特权

评论回复
11
febgxu| | 2024-10-3 17:49 | 只看该作者
配置看门狗定时器,确保在堆栈溢出导致程序无法正常工作时,能够自动重启单片机。

使用特权

评论回复
12
cemaj| | 2024-10-3 19:39 | 只看该作者
设计一个安全模式,当系统检测到堆栈溢出或其他严重错误时,进入安全模式。在安全模式下,可以采取一些限制功能的措施,以确保系统的基本运行。

使用特权

评论回复
13
pl202| | 2024-10-4 14:04 | 只看该作者
一些单片机开发环境提供了堆栈余量指示器的功能。这个指示器可以显示当前堆栈的使用情况,帮助开发人员确定是否存在堆栈溢出的风险。

使用特权

评论回复
14
timfordlare| | 2024-10-4 15:48 | 只看该作者
将关键任务和非关键任务的堆栈分开,确保即使非关键任务的堆栈溢出也不会影响关键任务的执行。

使用特权

评论回复
15
sheflynn| | 2024-10-4 17:38 | 只看该作者
在程序中,可以通过软件模拟的方式来检测堆栈的使用情况。例如,可以在关键位置插入代码,记录堆栈的使用量,并与预设的堆栈大小进行比较。

使用特权

评论回复
16
pixhw| | 2024-10-4 19:25 | 只看该作者
在堆栈溢出发生后,首先需要确保系统进入一个安全状态,避免造成更严重的损害。这可能包括关掉某些执行器或者禁用某些功能。

使用特权

评论回复
17
youtome| | 2024-10-4 21:07 | 只看该作者
在程序设计和开发阶段,应根据程序的复杂度和运行需求合理分配堆栈大小,以避免因堆栈过小而导致的溢出风险。

使用特权

评论回复
18
i1mcu| | 2024-10-4 22:42 | 只看该作者
通过定义宏来启用实时操作系统(RTOS)的任务堆栈溢出检测功能。

使用特权

评论回复
19
modesty3jonah| | 2024-10-5 09:41 | 只看该作者
可以使用堆栈限制寄存器来检测堆栈溢出。当堆栈指针(SP)的值小于堆栈限制寄存器的值时,会触发UsageFault或HardFault。

使用特权

评论回复
20
timfordlare| | 2024-10-5 11:16 | 只看该作者
在设计阶段就考虑堆栈溢出的可能性,并制定相应的预防措施。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

44

主题

1339

帖子

0

粉丝