了解 C 中的堆栈溢出处理

Understanding stack overflow handling in C

我很好奇如何在 C 中捕获堆栈溢出并偶然发现 GNU libsigseg library

这个库可以捕获许多平台上的堆栈溢出并提供 implementation example
为了使用此库安装堆栈溢出侦听器,必须首先为备用堆栈保留一些 space。 据我了解,这个备用堆栈用于 运行 侦听器,因为真正的堆栈不可用。

备用堆栈保留在altstack.h(第 40 行)中,如下所示:

[][      ][             ][      ]
|    |           |          |
|    |           |          crumple_zone (8 KiB)
|    |           usable_space (16 KiB)
|    crumple_zone (8 KiB)
offset (31 B)

可用的 space 是实际使用的,这里的褶皱区是为了防止备用堆栈溢出:如果它溢出,它会进入分配的 space,防止段错误,也许有人有时间检测它。

但是,

  1. 我不明白为什么在堆叠之前和之后会有一个褶皱区;堆栈仅在一个方向上增长。是不是因为有的平台的栈是朝一个方向增长的,有的平台是反方向的?
  2. 不明白为什么会有偏移

这里是作者给出的解释:

glibc says: Users should use SIGSTKSZ as the size of user-supplied buffers. We want to detect stack overflow of the alternate stack in a nicer manner than just crashing, so we overallocate in comparison to what we hand libsigsegv. Also, we intentionally hand an unaligned pointer, to ensure the alternate stack still ends up aligned.

最后一句话让我有点迷茫:“......我们故意传递一个未对齐的指针,以确保备用堆栈最终仍然对齐”。 如果我们不对齐,堆栈如何最终对齐?

I don't understand why there is a crumple zone before AND after the stack;

堆栈被声明为全局char mystack_storage[...]
假设堆栈向下增长,您需要存储低端的褶皱区来检测备用堆栈本身的溢出。

问题:后面 mystack_storage[] 数组是什么?
答:你不知道。

如果后面紧跟着另一个数组怎么办,如果那个数组写得越界怎么办(例如other_array[-20] = 'a';)?

要检测此类下溢,您还需要在另一端设置褶皱区。

How can the stack ends up aligned if we make so it's unaligned?

mystack 指针有意错位。如果直接用作备用堆栈,会违反许多平台上的堆栈对齐要求,并且极有可能导致崩溃。

为防止这种情况,库不能直接使用 mystack,而是在其他地方对齐

您指向的代码旨在测试 other 代码是否正常工作。

更新:

I still don't understand the offset. Why the mystack pointer would violate stack alignment requirement if used without offset?

没有偏移量,mystack 的对齐方式未知。它可能发生 在 16 字节、8 字节甚至 1 字节边界上对齐。

有了偏移量,保证不对齐(在 1 字节边界上对齐)。

Why it isn't the other way around: by adding the offset it's intentionally misaligned and violate stack alignment requirement.

是的,指针故意未对齐。

重点是:实际上使用 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的错位要执行的“其他代码”不在库中,而是在内核中。