了解 C 中的堆栈溢出处理
Posted
技术标签:
【中文标题】了解 C 中的堆栈溢出处理【英文标题】:Understanding stack overflow handling in C 【发布时间】:2021-04-28 03:28:59 【问题描述】:我很好奇如何在 C 中捕获堆栈溢出并偶然发现 GNU libsigseg library。
这个库可以在很多平台上捕获堆栈溢出并提供implementation example。 为了使用该库安装堆栈溢出侦听器,必须首先为备用堆栈保留一些空间。 据我了解,这个备用堆栈用于运行侦听器,因为真正的堆栈不可用。
备用堆栈保留在altstack.h(第 40 行)中,如下所示:
[][ ][ ][ ]
| | | |
| | | crumple_zone (8 KiB)
| | usable_space (16 KiB)
| crumple_zone (8 KiB)
offset (31 B)
可用空间是实际使用的空间,此处的压缩区域是为了防止备用堆栈上的溢出:如果溢出,它会进入分配的空间,防止出现段错误,并且可能有时间检测到它。
但是,
-
我不明白为什么在堆栈之前和之后会有一个折叠区;堆栈只向一个方向增长。是不是因为某些平台的堆栈朝一个方向增长,而其他平台的堆栈朝另一个方向增长?
我不明白为什么会有偏移量。
以下是作者给出的解释:
glibc 说:用户应该使用 SIGSTKSZ 作为用户提供的缓冲区的大小。 我们希望以一种比崩溃更好的方式检测备用堆栈的堆栈溢出,因此与我们处理 libsigsegv 相比,我们过度分配。 此外,我们有意交出一个未对齐的指针,以确保备用堆栈最终仍然对齐。
最后一条语句让我有点不知所措:“......我们故意交出一个未对齐的指针,以确保备用堆栈仍然对齐”。 如果我们让堆栈不对齐,怎么会最终对齐?
【问题讨论】:
阅读-fsanitize=address
。 can catch stack overflows on a lot of platform
我看到库捕获了“页面错误”。不仅仅是***。
@KamilCuk 该库可用于仅捕获堆栈溢出,-fsanitize=address
也具有不可忽略的减速。来源:github.com/google/sanitizers/wiki/…
【参考方案1】:
我不明白为什么在堆栈之前和之后会有一个折叠区;
堆栈被声明为全局char mystack_storage[...]
。
假设堆栈向下增长,您需要存储低端的折叠区域来检测备用堆栈本身的溢出。
问题:mystack_storage[]
数组之后是什么?
答:你不知道。
如果紧随其后有另一个数组怎么办,如果 那个 数组被写入越界(例如,other_array[-20] = 'a';
之类的东西)怎么办?
要检测这种下溢,您还需要另一端的折叠区。
如果我们让堆栈不对齐,如何最终对齐?
mystack
指针故意错位。如果直接将其用作备用堆栈,则会违反许多平台上的堆栈对齐要求,并且很可能会导致崩溃。
为了防止这种情况,库不能直接使用mystack
,而是对齐它在别处。
您指向的代码旨在测试 其他代码是否正常工作。
更新:
我仍然不明白偏移量。为什么 mystack 指针如果不使用偏移量会违反堆栈对齐要求?
没有偏移,mystack
的对齐方式是未知的。它可能发生在 16 字节、8 字节甚至 1 字节边界上对齐。
使用偏移量,保证不对齐(对齐在 1 字节边界上)。
为什么不是相反:通过添加偏移量,它会故意错位并违反堆栈对齐要求。
是的,指针是故意错位的。
重点是:实际使用 mystack
的代码(该代码在别处,我没有找到),已经准备好处理未对齐的mystack
,通过适当对齐它(让我们称之为“对齐代码”)。您指向的代码旨在行使其他“对齐代码”。
现在,哪里那个“对齐代码”?
我以为它在图书馆的其他地方,但我错了。未对齐的mystack
指针直接使用here。
那么谁在做所需的对齐呢?内核可以!
来自man sigaltstack
:
ss.ss_sp
This field specifies the starting address of the stack. When a signal
handler is invoked on the alternate stack, the kernel automatically
aligns the address given in ss.ss_sp to a suitable address boundary
for the underlying hardware architecture.
所以mystack
的错位打算执行的“其他代码”不在库中,而是在内核中。
【讨论】:
而且我一直认为折叠区是耐撞性问题。 感谢您的回答,但我仍然不明白偏移量。为什么mystack
指针在不使用偏移的情况下会违反堆栈对齐要求?为什么不是相反:通过添加偏移量,它会故意错位并违反堆栈对齐要求。
感谢您抽出宝贵时间!我现在明白了。以上是关于了解 C 中的堆栈溢出处理的主要内容,如果未能解决你的问题,请参考以下文章
Visual Studio C/C++ 数组大小未处理的异常堆栈溢出 [重复]