分享
为什么问答平台  ›  专栏  ›  技术社区  ›  St.Antario

如果涉及到map_fixed,那么无限堆栈不能超过最初的132kib? - Unlimited stack cannot grow beyond the initial 132KiB if MAP_FIXED involved?

  •  0
  • St.Antario  · 技术社区  · 1 周前

    我正在用Stack进行一些实验,下面的内容让我陷入困境。

    可以看出,Linux有 [stack] 映射 132KiB 尺寸。万一 ulimit -s unlimited 如果我们调整 rsp 因此。所以我决定 ulimit-s无限制 并运行以下程序:

    PAGE_SIZE     equ 0x1000
    
    ;mmap staff
    PROT_READ     equ 0x01
    PROT_WRITE    equ 0x02
    MAP_ANONYMOUS equ 0x20
    MAP_PRIVATE   equ 0x02
    MAP_FIXED     equ 0x10
    
    ;syscall numbers
    SYS_mmap      equ 0x09
    SYS_exit      equ 0x3c
    
    section .text
    
    global _start
    
    _start:
        ; page alignment
        and rsp, -0x1000
    
        ; call mmap 0x101 pages below the rsp with fixed mapping
        mov rax, SYS_mmap
        lea rdi, [rsp - 0x101 * PAGE_SIZE]
        mov rsi, PAGE_SIZE
        mov rdx, PROT_READ | PROT_WRITE
        mov r10, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED
        mov r8, -1
        mov r9, 0
        syscall
    
        sub rsp, 0x80 * PAGE_SIZE
        mov qword [rsp], -1 ; SEGV
    
        mov rax, SYS_exit
        mov rdi, 0
        syscall
    

    即使调整了 相对标准偏差 不管怎样,它都会出错。我不太明白。我在地址手动创建了一个固定映射 rsp - 0x101 * PAGE_SIZE 101页以下 相对标准偏差 .

    我的期望是它不会干扰扩展堆栈( rsp - 0x80 在我的例子中)直到我们找到固定的地图 RSP-0x101*页面尺寸 .

    顺便说一句,如果我移除 MAP_FIXED 从映射来看,它是不执行的,并且不会发生segfault(如预期)。这是Strace输出:

    mmap(0x7ffe4e0fe000, 4096, PROT_READ|PROT_WRITE, 
         MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x1526e3f3a000
    

    但是 地图固定 工作是否:

    mmap(0x7ffd8979c000, 4096, PROT_READ|PROT_WRITE, 
         MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7ffd8979c000
    

    upd:如果 lea rdi, [rsp - 0x101 * PAGE_SIZE] 替换为 lea rdi, [rsp - 0x200 * PAGE_SIZE] .

    1 回复  |  直到 1 周前
        1
  •  4
  •   Jester    1 周前

    Linux内核在堆栈和其他映射之间强制设置间隙。如果不能保持这个间隙,那么堆栈就不会增长。

    相关源代码(mm/mmap.c),来自 line 2498

    /* enforced gap between the expanding stack and other mappings. */
    unsigned long stack_guard_gap = 256UL<<PAGE_SHIFT;
    
    static int __init cmdline_parse_stack_guard_gap(char *p)
    {
        unsigned long val;
        char *endptr;
    
        val = simple_strtoul(p, &endptr, 10);
        if (!*endptr)
            stack_guard_gap = val << PAGE_SHIFT;
    
        return 0;
    }
    __setup("stack_guard_gap=", cmdline_parse_stack_guard_gap);
    

    line 2424 以下内容:

    int expand_downwards(struct vm_area_struct *vma,
                       unsigned long address)
    {
        struct mm_struct *mm = vma->vm_mm;
        struct vm_area_struct *prev;
        int error = 0;
    
        address &= PAGE_MASK;
        if (address < mmap_min_addr)
            return -EPERM;
    
        /* Enforce stack_guard_gap */
        prev = vma->vm_prev;
        /* Check that both stack segments have the same anon_vma? */
        if (prev && !(prev->vm_flags & VM_GROWSDOWN) &&
                (prev->vm_flags & (VM_WRITE|VM_READ|VM_EXEC))) {
            if (address - prev->vm_end < stack_guard_gap)
                return -ENOMEM;
        }
    

    您可以通过内核参数看到它是可调整的,但默认值是256。因此,此间隙不适用于0x80和0x101页之间,但如果使用0x200则适用。