Linux 进程堆栈被局部变量溢出(堆栈保护)

2024-11-04 08:43:00
admin
原创
31
摘要:问题描述:来自_chkstk() 函数的用途是什么?:在堆栈的末尾,有一个保护页被映射为不可访问的内存 - 如果程序访问它(因为它试图使用比当前映射的更多的堆栈),则会发生访问冲突。_chkstk()是一个特殊的编译器辅助函数,确保局部变量有足够的空间即它正在进行一些堆栈探测(这里是LLVM 示例)。 这种...

问题描述:

来自_chkstk() 函数的用途是什么?:

在堆栈的末尾,有一个保护页被映射为不可访问的内存 - 如果程序访问它(因为它试图使用比当前映射的更多的堆栈),则会发生访问冲突。

_chkstk()是一个特殊的编译器辅助函数,

确保局部变量有足够的空间

即它正在进行一些堆栈探测(这里是LLVM 示例)。

这种情况是 Windows 特有的。因此 Windows 对该问题有一些解决方案。

让我们考虑一下 Linux(或其他类 Unix 系统)下的类似情况:我们有很多函数的局部变量。第一个堆栈变量访问位于堆栈段后面(例如mov eax, [esp-LARGE_NUMBER],这里 esp-LARGE_NUMBER 是堆栈段后面的东西)。Linux(也许是其他类 Unix 系统)或开发工具中是否有任何功能可以防止可能的页面错误或其他问题,例如海湾合作委员会,铛等等?-fstack-check(GCC 堆栈检查)能以某种方式解决这个问题吗?这个答案指出它与非常相似_chkstk()

PS 这些帖子1、2没有太大帮助。

PPS 总的来说,问题在于操作系统(主要是Linux与 Windows)实现方法之间的差异,这些方法处理大量堆栈变量,这些变量位于堆栈段后面。添加了 C++ 和 C 标签,因为它与 Linux 本机二进制生成有关,但汇编代码与编译器有关。


解决方案 1:

_chkstk进行堆栈探测以确保在(可能)较大的分配(例如 alloca)之后按顺序触及每个页面。因为 Windows 每次只会将堆栈增大一页,直到达到堆栈大小限制。

触碰该“保护页”会触发堆栈增长。它无法防止堆栈溢出;我认为您误解了“保护页”在此用法中的含义。

函数名称也可能具有误导性。 _chkstk文档只是说:当函数中有多个局部变量页面时,编译器会调用该函数。 它实际上并没有检查任何内容,只是确保在使用内存之前已经触及中间页面esprsp也就是说,唯一可能的效果是:没有任何效果(可能包括有效的软页面错误)或堆栈溢出时的无效页面错误(试图触及 Windows 拒绝增加堆栈以包含的页面)。它确保通过无条件写入来分配堆栈页面。

我想你可以把这看作是检查堆栈冲突,方法是确保在堆栈溢出的情况下继续之前触摸不可映射的页面。


ulimit -s如果触摸旧堆栈页面下方的内存(如果它高于当前堆栈指针),Linux 将使主线程堆栈1增加任意数量的页面(最多为设置的堆栈大小限制;默认为 8MiB) 。

如果您触碰超出增长限制的内存,或者不先移动堆栈指针,则会导致段错误。 因此,Linux 不需要堆栈探测,只需将堆栈指针移动您想要保留的字节数即可。编译器知道这一点并相应地发出代码。

另请参阅使用“push”或“sub”x86 指令时如何分配堆栈内存?以了解有关 Linux 内核的功能以及 Linux 上的 glibc pthreads 的功能的更多底层详细信息。

Linux 上足够大的内存alloca可以将堆栈一直移动到堆栈增长区域底部,超出其下方的保护页,并进入另一个映射;这是堆栈冲突。https ://blog.qualys.com/securitylabs/2017/06/19/the-stack-clash 当然,它要求程序使用可能非常大的大小进行分配,具体取决于用户输入。CVE -2017-1000364 的缓解措施是留下 1MiB 保护区域,需要比正常情况大得多的分配才能越过保护页。

这个 1MiB 保护区域低于ulimit -s(8MiB)增长限制,而不是低于当前堆栈指针。它与 Linux 的正常堆栈增长机制是分开的。


gcc -fstack-check

的效果gcc -fstack-check本质上与 Windows 上始终需要的效果相同(MSVC 通过调用 来实现_chkstk):在移动较大或运行时变量量时,触摸前一个堆栈指针和新堆栈指针之间的堆栈页。

但是这些探测器的目的/好处在 Linux 上有所不同;在 GNU/Linux 上,无错误的程序永远不需要它来保证正确性。它“仅”防御堆栈冲突错误/漏洞。

在 x86-64 GNU/Linux 上,gcc -fstack-check将(对于具有 VLA 或大型固定大小数组的函数)添加一个循环,该or qword ptr [rsp], 0循环使用 和 进行堆栈探测sub rsp,4096。对于已知的固定数组大小,它可以只是一个探测器。代码生成看起来效率不高;它通常不会在这个目标上使用。(Godbolt编译器资源管理器示例将堆栈数组传递给非内联函数。)

https://gcc.gnu.org/onlinedocs/gccint/Stack-Checking.html描述了一些控制执行操作的 GCC 内部参数-fstack-check

如果您想要绝对安全以抵御堆栈冲突攻击,那么这个应该可以做到。不过,正常操作不需要它,1MiB 保护页面对大多数人来说就足够了。


请注意,这-fstack-protector-strong完全不同,它可防止本地数组上的缓冲区溢出覆盖返回地址。 与堆栈冲突无关,攻击针对的是小型本地数组上方堆栈上已有的内容,而不是通过大量移动堆栈来针对其他内存区域。


脚注 1:Linux 上的线程堆栈(用于初始线程以外的线程)必须预先完全分配,因为魔法增长功能不起作用。只有进程的初始线程(即主线程)才能拥有它。

(有一个mmap(MAP_GROWSDOWN)功能,但它并不安全,因为没有限制,并且没有什么可以阻止其他动态分配随机选择当前堆栈下方的页面,从而将未来的增长限制在堆栈冲突之前的微小大小。此外,由于只有触摸保护页面时它才会增长,因此需要堆栈探测。由于这些令人震惊的原因,MAP_GROWSDOWN不用于线程堆栈。主堆栈的内部机制依赖于内核中的不同魔法,这确实可以防止其他分配窃取空间。)

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用