【问题标题】:Is using canaries for bss or data-sections to detect overflows/smashing useful?将金丝雀用于 bss 或数据部分以检测溢出/粉碎有用吗?
【发布时间】:2020-05-14 00:44:43
【问题描述】:

在我们基于 GCC 的 C 嵌入式系统中,我们使用 -ffunction-sections-fdata-sections 选项来允许链接器在链接最终可执行文件时删除未使用(未引用)的部分。这多年来一直很好。

在同一个系统中,大多数数据结构和缓冲区都是静态分配的(通常在文件范围内作为static-variables)。

当然,我们有错误,有时是令人讨厌的错误,我们希望快速排除缓冲区溢出的可能性。

我们的一个想法是在每个 bss-section 和 data-section 之间放置金丝雀——每个都只呈现一个符号(因为-fdata-sections)。就像编译器在激活 Stack-Smashing 和 StackProtection 时对函数堆栈所做的那样。可以通过“不时”读取金丝雀地址来从主机检查这些金丝雀。

似乎修改链接器脚本(手动放置该部分并在其间添加一个金丝雀字)似乎是可行的,但这有意义吗?

在野外有项目或文章吗?使用我的关键字我找不到任何东西。

【问题讨论】:

  • 好吧,您可能知道这并不能取代安全编程和代码审计,但在某些情况下,它当然可能有助于检测缓冲区溢出并防止漏洞或行为不端的系统。当然,在短时间内检查金丝雀是必要的,并且可能会给系统(尤其是低容量的嵌入式系统)带来不必要的负载或延迟。
  • 安全的编程和代码审计以及编码标准并不能防止错误。至少不是在 C 中,这就是我们的想法。
  • 当然它们可以防止错误。它们是否能防止所有个错误取决于这些操作的执行程度以及代码的复杂程度。
  • “安全的编程和代码审计以及编码标准并不能防止错误” 那你就做错了。加强组织进行同行评审,采用像 MISRA-C 这样的合理编码标准,然后使用静态分析工具添加检查都是提高代码质量的非常有效的方法。以牺牲上市时间为代价,因为虽然它们很有效,但这些东西往往会消耗大量的时间和耐心。
  • 我应该说“不要阻止所有的错误”。

标签: c gcc linker embedded bare-metal


【解决方案1】:

Canaries 对堆栈最有用,因为它的扩展和折叠超出了程序员的直接控制。你在 data/bss 上的东西不是那样的。它们要么是静态变量,要么如果它们是缓冲区,它们应该保持在其固定大小内,这应该通过算法就地防御性编程来检查,而不是非正统的技巧。

此外,堆栈金丝雀专门用于基于 RAM 的、类似 PC 的系统中,这些系统不知道有什么更好的方法。在嵌入式系统中,它们不是很有意义。你可以做一些有用的事情:

  • 内存映射堆栈,使其增长到写入将产生硬件异常的内存区域。例如,如果您的 MCU 能够将可执行内存与数据内存分开,并且当您尝试在数据区域执行代码或写入可执行区域时会产生异常。
  • 确保程序中处理缓冲区的所有内容都执行错误检查并且不会越界写入。静态分析工具通常可以很好地发现越界错误。甚至一些编译器也能做到这一点。
  • 使用静态断言添加大量防御性编程。在编译时检查结构、缓冲区等的大小,它是免费的。
  • 运行时防御性编程。例如if(x==good) {...} else if(x == bad) {... } 缺少else。而switch(x) case A: { ... } 缺少default。 “但理论上是去不了那里的!”不,但在实践中,当您得到由错误(很可能)、闪存数据保留(100% 可能)或 EMI 对 RAM 的影响(不太可能)导致的失控代码时。
  • And so on

【讨论】:

  • 所以你对我的问题的回答是否定的,没用?
  • 在理想世界中,我们可以控制一切。在我们的世界中,我们拥有使用我们提交的(静态)缓冲区的专有代码,我们不知道发生了什么。感谢您提出的替代方案,这确实是很好的做法。
  • @PatrickB。不是特别有用,没有。就像在 RS-232 协议中折腾固定字节同步字一样,而不是解决根本问题 - 即 RS-232 不是很坚固,应该使用另一种技术。如果出现错误,则处理根本原因,而不是处理错误症状。
猜你喜欢
  • 1970-01-01
  • 2017-06-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多