Linux 进程堆栈被局部变量溢出(堆栈保护)
- 2024-11-04 08:43:00
- admin 原创
- 30
问题描述:
来自_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
文档只是说:当函数中有多个局部变量页面时,编译器会调用该函数。 它实际上并没有检查任何内容,只是确保在使用内存之前已经触及中间页面esp
。rsp
也就是说,唯一可能的效果是:没有任何效果(可能包括有效的软页面错误)或堆栈溢出时的无效页面错误(试图触及 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
不用于线程堆栈。主堆栈的内部机制依赖于内核中的不同魔法,这确实可以防止其他分配窃取空间。)
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件