【问题标题】:When and how to use GCC's stack protection feature?何时以及如何使用 GCC 的堆栈保护功能?
【发布时间】:2015-01-16 10:51:33
【问题描述】:

在编译我正在处理的项目(商业多平台 C++ 游戏引擎,在 Mac OS X 10.6 和 GCC 4.2 上编译)时,我已启用 -Wstack-protector 警告。 即使启用了-fstack-protector,此标志也会警告无法防止堆栈粉碎的函数。 GCC 在构建项目时会发出一些警告:

没有保护功能:没有至少 8 个字节长的缓冲区
不保护局部变量:可变长度缓冲区

对于第一个警告,我发现可以调整缓冲区在函数中使用时必须具有的最小大小,以保护该函数免受堆栈粉碎:可以使用--param ssp-buffer-size=X,其中 X 为 8默认情况下,可以低至 1。

对于第二个警告,除非我停止使用 -Wstack-protector,否则我无法抑制它的出现。

  1. 什么时候应该使用-fstack-protector? (例如,在开发期间的所有时间,或者只是在跟踪错误时?)
  2. 什么时候应该使用-fstack-protector-all
  3. -Wstack-protector 告诉我什么?是否建议我减小缓冲区最小大小?
  4. 如果是这样,将大小设置为 1 有什么缺点吗?
  5. 看来-Wstack-protector 不是那种你想在任何时候都启用的标志,如果你想要一个无警告的构建。对吗?

【问题讨论】:

  • 这些选项试图防止基于缓冲区溢出/堆栈损坏的攻击。这些文章应该会有所帮助: - What's the stack smashing protector - SSP
  • 你需要使用C99的变长数组(VLA)特性吗?如果你不使用它,你就不会得到警告——你会得到保护。您真的确定您从使用 VLA 中获得了足够的收益,以至于失去保护是可以接受的吗?
  • VLA 已被删除,警告在这种情况下很有用。
  • 感谢您的链接。不过,我仍然没有看到大局。堆栈保护对商业游戏真的有用吗?如果启用 -fstack-protector,游戏是否会受到任何性能影响?最小缓冲区大小设置为 1?或者是否启用了 -fstack-protector-all?
  • 您希望人们尝试破解您的代码吗?如果是这样,这可能是个好主意。至于性能,你必须计算。这是一个起点:trl.ibm.com/projects/security/ssp/…

标签: c++ gcc stack protection


【解决方案1】:

堆栈保护是一种强化策略,而不是调试策略。如果您的游戏具有网络感知功能或其他数据来自不受控制的来源,请将其打开。如果它没有来自不受控制的地方的数据,请不要打开它。

结果如下:如果您有错误并根据攻击者可以控制的内容更改缓冲区,则攻击者可以覆盖返回地址或堆栈的类似部分,以使其执行其代码而不是您的代码。代码。如果堆栈保护检测到这种情况发生,它将中止您的程序。您的用户不会高兴,但他们也不会被黑客入侵。这不是关于在游戏中作弊的黑客行为,而是关于某人利用您代码中的漏洞来创建可能感染您的用户的漏洞的黑客行为。

对于面向调试的解决方案,请查看诸如 mudflap 之类的东西。

关于您的具体问题:

  1. 如果您从不受控制的来源获取数据,请使用堆栈保护程序。这个问题的答案很可能是肯定的。所以使用它。即使您没有来自不受控制的来源的数据,您也可能最终或已经拥有但没有意识到。
  2. 如果您想要额外的保护来换取一些性能损失,可以使用所有缓冲区的堆栈保护。来自gcc4.4.2 manual

    -fstack-protector

    发出额外的代码来检查缓冲区溢出,例如堆栈粉碎攻击。这是通过将保护变量添加到具有易受攻击对象的函数来完成的。这包括调用 alloca 的函数,以及缓冲区大于 8 字节的函数。进入函数时初始化守卫,然后在函数退出时检查。如果保护检查失败,则会打印一条错误消息并退出程序。

    -fstack-protector-all

    与 -fstack-protector 类似,只是所有函数都受到保护。

  3. 警告告诉您堆栈保护无法保护的缓冲区。

  4. 不一定建议您减小最小缓冲区大小,在大小为 0/1 时,它与 stack-protector-all 相同。如果您决定重新设计代码以保护缓冲区,它只是向您指出,以便您可以这样做。
  5. 不,这些警告并不代表问题,它们只是向您指出信息。不要经常使用它们。

【讨论】:

  • -fstack-protector 是否只检查缓冲区大于“8 字节”的函数?为什么不是 4 字节或 1 字节?
  • @wenchiching,原因是性能和溢出的可能性。发现 8 字节是溢出可能性值得保护性能成本的阈值。
  • 堆栈保护的调试策略是可能的并且有时很有用:(1) 执行使用堆栈保护编译的二进制文件并在调试器中禁用 ASLR(地址空间布局随机化)。 (2) 等待一个核心。 (3) 核心将指示被破坏的堆栈金丝雀的地址。 (4) 在调试器中重新运行你的二进制文件,并在被破坏的堆栈金丝雀的地址上设置一个硬件观察点。 (5) 当位于罪魁祸首地址的内存被修改时,调试器将停止。
【解决方案2】:

您确实不应该关心正常构建的警告。这实际上更像是一条信息性消息。我希望很明显,您确实对堆栈上的可变大小缓冲区存在固有的安全问题;尺寸计算错误,你会打开一个大洞。

【讨论】:

  • 来自:osdir.com/ml/cocoa-dev/2009-06/msg01658.html 使用以下命令禁用所有堆栈粉碎警告:-Wno-stack-protector 目前还没有编译指示仅禁用此警告。 (这经常发生在 GCC 中。通常在没有警告或警告太少之间存在紧张关系。一种解决方案是为有问题的文件制作特殊的 make 目标并为其设置特殊的编译标志。)
  • 您能否详细说明为什么可变大小的缓冲区与固定大小的缓冲区在风险方面存在显着差异?我可以理解为什么很难将它们放在一个函数中,就像堆栈保护器对固定大小的缓冲区所做的那样。
  • 双重攻击向量:攻击者可以提供比您分配给缓冲区更多的输入字节,或者他可以尝试在您的缓冲区大小分配中找到错误
猜你喜欢
  • 2019-08-11
  • 2010-11-23
  • 1970-01-01
  • 2014-04-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多