0

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_GROWSDOWN并且PROT_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]映射?

4

2 回答 2

5

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

我怀疑mmap分配MAP_GROWSDOWN区域无法增长是因为另一个区域就在下方,mmap通常会连续向下分配虚拟地址。

于 2019-07-06T17:22:37.597 回答
3

这些都与红色区域无关,因为您没有移动 RSP。内存保护适用于页面粒度,但红色区域始终仅比 RSP 低 128 个字节,这对于读/写安全的,并且对异步破坏是安全的。


不,MAP_GROWSDOWN除非您手动使用它,否则没有任何用处。主线程的栈使用了一个不中断的机制,不会让其他mmap调用随机窃取它的增长空间。请参阅我关于使用 pmap 分析进程的内存映射的答案。[堆]

您的 asm 代码的有时成功与 为什么此代码在地址随机化开启时崩溃?- 你在 RSP 下触及最多 124 KiB 的内存,所以 132 KiB 的初始分配有时恰好足够,这取决于 ASLR 和 args + env 在堆栈上占用的空间。

为什么 MAP_GROWSDOWN 映射不增长?有趣的是:MAP_GROWSDOWN 可能不适用于 1 页映射。但同样,这与堆栈无关。手册页显示“此标志用于堆栈”。是 100% 错误的。这是添加功能时的意图,但设计实际上并不可用,因此即使与文档相比,实现也可能存在错误。

于 2019-07-07T09:25:53.360 回答