堆栈红色区域的实际大小是多少?

What is the actual size of stack red zone?

x86-64 System V ABI中指定$rsp - 128后面的space是所谓的红色区域,不被任何信号处理程序触及。在我的机器上

$ ulimit -s
8192

我预计堆栈中只有 2 页。所以我写了下面的程序来测试红色区域可以扩展到多大:

PAGE_SIZE equ 0x1000
SYS_exit equ 0x3C

section .text
global _start 

_start:
    lea rcx, [rsp - 0x1f * PAGE_SIZE]
    mov rax, rsp
loop:
    sub rax, PAGE_SIZE
    mov qword [rax], -1
    cmp rax, rcx
    jne loop

    mov rax, SYS_exit
    mov rdi, 0x20

所以我预计程序总是失败。但该程序有时会失败 SEGV 有时会正常完成

行为与 MAP_GROWSDOWN 文档完全相同:

This flag is used for stacks. It indicates to the kernel virtual memory system that the mapping should extend downward in memory. The return address is one page lower than the memory area that is actually created in the process's virtual address space. Touching an address in the "guard" page below the mapping will cause the mapping to grow by a page. This growth can be repeated until the mapping grows to within a page of the high end of the next lower mapping, at which point touching the "guard" page will result in a SIGSEGV signal.

正如所讨论的 使用 MAP_GROWSDOWNPROT_GROWSDOWN 创建的映射不会那样增长:

volatile char *mapped_ptr = mmap(NULL, 4096,
                        PROT_READ | PROT_WRITE | PROT_GROWSDOWN,
                        MAP_GROWSDOWN | MAP_ANONYMOUS | MAP_PRIVATE,
                        -1, 0); 

mapped_ptr[4095] = 'a';  //OK!
mapped_ptr[0]    = 'b';  //OK!
mapped_ptr[-1]   = 'c';  //SEGV

问题: 结合上面的推理,唯一使用 MAP_GROWSDOWN 的映射是主线程的 [stack] 映射 ?

你混淆了2个不同的概念,只是它们都涉及到堆栈,红色区域和堆栈内存区域的扩展是无关的。如果调用信号处理程序并且未指定替代信号处理程序堆栈,则红色区域下方但在堆栈内的内存位置将被更改。

我怀疑 mmap 分配的 MAP_GROWSDOWN 区域增长失败是因为另一个区域在下面不久,mmap 通常会连续向下分配虚拟地址。

None 这与 red-zone 有任何关系,因为您没有移动 RSP。内存保护适用于页面粒度,但 red-zone 始终仅比 RSP 低 128 字节,这对 read/write 以及 和异步破坏都是安全的。


不,除非您手动使用 MAP_GROWSDOWN,否则什么都不用 。主线程的堆栈使用 non-broken 机制,不会让其他 mmap 调用随机窃取其增长 space。在 Analyzing memory mapping of a process with pmap. [stack]

上查看我的回答

您的 asm 代码的 sometimes-success 与 - 您正在接触比 RSP 低 124 KiB 的内存,因此有时 132 KiB 的初始分配恰好足够,具体取决于 ASLR 以及 space args + env 在堆栈中的占用量。

是有趣的部分:MAP_GROWSDOWN 可能不适用于单页映射。但同样,这与堆栈 没有任何关系。手册页说“此标志用于堆栈”。是 100% 错误的。这是添加功能时的意图,但设计实际上并不可用,因此即使与文档相比,实现也可能存在错误。