打印
[华山论剑]

如何利用现代嵌入式开发工具中的堆栈保护功能

[复制链接]
1900|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
在开发以MCU为核心的嵌入式系统时,当软件程序向预设的数据结构(通常是一个固定长度的缓冲区)之外的程序调用堆栈的内存地址范围写入数据时,就会发生堆栈缓冲区溢出。这几乎必然会损坏附近的数据,甚至会改变返回函数。如果是有意为之,则这就是我们熟知的堆栈粉碎。防范堆栈缓冲区溢出的一种方法是使用堆栈canary,因其类似于在煤矿中使用金丝雀侦测毒气而得名。目前,在以IAR Embedded Workbench为代表的领先开发工具的所有最新版本中,均已支持堆栈保护功能。

堆栈保护功能已经成为最新嵌入式开发工具中必要的功能,但要在诸如IAR Embedded Workbench for Arm这样的行业标杆工具中实现堆栈保护,就要使用一种启发式算法来确认一个函数是否需要堆栈保护。如果任何函数内定义的局部变量为数组类型或包含数组类型成员的结构类型,则该函数就需要堆栈保护。此外,如果任何局部变量的地址被传播到函数之外,则该函数也需要堆栈保护。

如果一个函数需要堆栈保护,那么该函数的局部变量将被按序排放,将数组类型的变量在函数堆栈中被放置在尽可能高的地址。在这些变量之后,会放置一个canary元素。在函数入口处,canary被初始化。初始化值取自全局变量 __stack_chk_guard。在函数退出时,代码会验证canary元素是否仍然包含初始化值。如果该数值被改变,函数 __stack_chk_fail就会被调用。

使用特权

评论回复
沙发
laocuo1142|  楼主 | 2022-9-9 10:39 | 只看该作者
以被广泛使用的IAR Embedded Workbench for Arm嵌入式开发工具为例,使用Project>Options>C/C++ Compiler>Code>Stack protection选项,即可针对被认定为需要保护的函数启用堆栈保护。



或者,您也可以使用Project>Options>C/C++ Compiler>Extra Options页面,指定 --stack_protection命令行来启用堆栈保护功能。

实际应用实现堆栈保护

要使用堆栈保护,开发人员必须在应用中定义以下对象:
  • extern uint32_t __stack_chk_guard
全局变量 __stack_chk_guard在第一次使用前必须被初始化。如果初始化值是随机的,则安全性会更高。
  • __interwork __nounwind __noreturn void __stack_chk_fail(void)
__stack_chk_fail函数的作用是通知发生了错误,然后终止应用。请注意,这个函数的返回地址将指向失效函数。

arm\src\lib\runtime目录下的文件stack_protection.c提供了 __stack_chk_guard和 __stack_chk_fail函数的参考模板。

总结

由于今天全球半导体供应链紧张状况尚未得到缓解,因此许多MCU等嵌入式应用需要利用开发工具来保持核心技术和器件供应上的灵活性,并最大限度地在不同硬件平台上重用已完成的软件。在这种情况下,无论是MCU芯片开发商还是嵌入式系统工程师,都需要利用那些已被业界最广泛使用的开发工具,如IAR Embedded Workbench for Arm。由于这些工具也是其开发商和行业领先的MCU供应商多年合作的成果,可以针对不同的硬件资源体系和应用环境给出相应的帮助,如IAR Embedded Workbench中的堆栈保护功能,因此可以以更短的研发周期,来实现嵌入式开发人员的研发目标。

使用特权

评论回复
板凳
LLGTR| | 2022-10-6 21:48 | 只看该作者
感谢分享,以前一直就使用栈,没有对栈有这么深入的研究。

使用特权

评论回复
地板
tpgf| | 2022-10-9 13:44 | 只看该作者
在gcc中,通过编译选项可以添加 函数栈的保护机制,通过重新对局部变量进行布局来实现,达到监测函数栈是否非破坏的目的。

使用特权

评论回复
5
heimaojingzhang| | 2022-10-9 13:53 | 只看该作者
以堆栈溢出为代表的缓冲区溢出已成为最为普遍的安全漏洞,由此引发的安全问题比比皆是

使用特权

评论回复
6
keaibukelian| | 2022-10-9 14:07 | 只看该作者
堆栈金丝雀(Stack Canaries), 因其类似于在煤矿中使用金丝雀来感测瓦斯等气体而得名,它可以用于在函数返回之前检测堆栈缓存溢出来实现堆栈保护(Stack Protection),从而提高代码的安全性

使用特权

评论回复
7
labasi| | 2022-10-9 14:22 | 只看该作者
堆栈保存的是保证程序正常运行的临时数据,堆栈缓存溢出会覆盖堆栈缓存临近的堆栈数据,这些数据可能包含函数的返回地址,如果发生时一般会造成程序运行异常。攻击者经常利用这一点来进行堆栈粉碎攻击

使用特权

评论回复
8
paotangsan| | 2022-10-9 14:33 | 只看该作者
以前用的时候都没有注意过还有这个选项可以勾选 幸亏是默认选上的了

使用特权

评论回复
9
renzheshengui| | 2022-10-9 14:43 | 只看该作者
添加堆栈保护功能需要增加额外的机器指令,这些也会稍稍对性能产生影响,代价就是需要额外多执行一部分机器指令。

使用特权

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

本版积分规则

1172

主题

5129

帖子

12

粉丝