使用金丝雀来检测bss或数据段的溢出/破坏是否有用?
使用金丝雀来检测bss或数据段的溢出/破坏是否有用?
在我们使用GCC编译的C嵌入式系统中,我们使用-ffunction-sections
和-fdata-sections
选项,使得链接器在链接最终的可执行文件时能够删除未使用的(未引用的)部分。这个方法多年来一直有效。 在同一个系统中,大多数数据结构和缓冲区都是静态分配的(通常作为文件范围的static
变量)。 当然,我们有错误,有时是令人讨厌的错误,我们希望能够快速排除缓冲区溢出的可能性。 我们想法是在每个bss节和数据节之间放置金丝雀 - 每个金丝雀只显示一个符号(由于-fdata-sections
)。就像激活Stack-Smashing和StackProtection时编译器对函数堆栈所做的一样。从主机上通过定时读取金丝雀地址来检查这些金丝雀。 修改链接脚本(手动放置部分并在其中添加金丝雀字)似乎是可行的,但这有意义吗? 有没有任何项目或文章?使用我的关键词我找不到任何东西。
admin 更改状态以发布 2023年5月20日
堆栈溢出时,堆栈保护符最有用,因为它在程序员直接控制之外进行扩展和折叠。而位于数据/ bss 上的东西不会像这样行动。它们要么是静态变量,要么是缓冲区,在这种情况下,它们应该保持固定大小,并应在算法中实施防御式编程来检查大小,而不是使用非正统的技巧。
此外,堆栈保护符专门用于基于RAM的类似PC的系统,这些系统不知道更好的方法。在嵌入式系统中,它们没有太大的意义。您可以做一些有用的事情,例如:
- 内存映射堆栈,使其增长到写入会产生硬件异常的内存区域中。例如,如果您的MCU具有将可执行内存与数据内存分离并在数据区域中执行代码或在可执行区域中写入时返回异常的能力。
- 确保程序中所有与缓冲区有关的内容都执行其错误检查,不会越界写入。静态分析工具通常可以很好地发现越界错误。甚至有些编译器也可以实现此功能。
- 添加大量防御式编程与静态断言。在编译时检查structs、buffers等的大小,代价为零。
- 运行时防御式编程。例如
if(x == good) { ... } else if(x == bad) { ... }
缺少else
。而switch(x) case A: {...}
缺少default
。"但是在理论上它不会走到那里!"。不过,在实践中,由于bug(非常可能)、flash数据保留(100%可能)或RAM上的EMI影响(相当不可能)导致运行不畅的代码时就会有这种情况。 - 等等。