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

时间:2019-07-06 15:31:25

标签: assembly x86-64 mmap callstack red-zone

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

$ 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文档中的行为完全相同:

  

此标志用于堆栈。它向内核指示虚拟   映射应在内存中向下扩展的内存系统。的   返回地址比实际的存储区低一页   在进程的虚拟地址空间中创建。触摸中的地址   映射下方的“防护”页面将导致映射增长   页面。可以重复这种增长,直到映射增长到   在下一个较低的映射的高端页面中,   点触摸“后卫”页面将产生SIGSEGV信号。

如前所述,使用MAP_GROWSDOWNPROT_GROWSDOWN创建的in this question映射不会以这种方式增长:

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 个答案:

答案 0 :(得分:5)

您会混淆2个不同的概念,除了它们都涉及堆栈之外,红色区域和堆栈存储区的扩展无关。如果调用信号处理程序且未指定其他信号处理程序堆栈,则将更改红色区域下方但堆栈内的内存位置。

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

答案 1 :(得分:2)

与红色区域无关,因为您没有移动RSP。内存保护使用页面粒度进行工作,但是红色区域始终仅比RSP低128个字节,因此可以安全地读取和写入 ,并且可以避免异步破坏。


否,MAP_GROWSDOWN除非您手动使用,否则什么也不会使用。主线程的堆栈使用一种不中断的机制,该机制不允许其他mmap调用随机窃取其增长空间。在Analyzing memory mapping of a process with pmap. [stack]

上查看我的答案

有时您的asm代码成功与完全相同 Why does this code crash with address randomization on?-您的内存要比RSP低124 kb,所以最初分配132 kiB有时就足够了,具体取决于ASLR和args + env在堆栈上需要多少空间。

Why is MAP_GROWSDOWN mapping does not grow?是有趣的部分:MAP_GROWSDOWN可能不适用于1页映射。但是同样,这与堆栈没有任何关系。手册页上写着“此标志用于堆栈”。是100%错误的。这是添加功能时的意图,但是设计实际上并不可用,因此即使与文档相比,实现也可能有问题。