程序堆栈大小

程序堆栈大小

我了解到每个进程的默认堆栈大小限制为 8MB,并且 mmap_base 是根据 rlimit 中的堆栈大小和随机值计算的。下面的代码是 mmap_base 函数,它计算 x86 中的 mmap_base 地址(linux/include/uapi/asm-generic/resource.h)。

static unsigned long mmap_base(unsigned long rnd)
{
    unsigned long gap = rlimit(RLIMIT_STACK);

    if (gap < MIN_GAP)
        gap = MIN_GAP;
    else if (gap > MAX_GAP)
        gap = MAX_GAP;

    return PAGE_ALIGN(TASK_SIZE - gap - rnd);
}

我想知道如果程序堆栈大小大于 8MB+rnd 值怎么办?我的意思是如果堆栈大小增长到 mmap_base 以上怎么办?如果我分配超过 8MB 的堆栈内存,是否会因分段错误而失败?如果内核自动扩大堆栈大小,是否可以将 mmap_base 中的内容移动到其他空间?

答案1

进程主线程堆栈大小不能增长到大于设置的限制。此限制的默认值为 8 MB。超过此限制将导致分段错误,并且进程将被发送信号SIGSEGV,默认情况下将其杀死。堆栈的最大大小可以ulimit -s在启动程序之前更改。程序启动后,内核不会在内存区域(如 mmap 区域)移动,也无法这样做,因为通常有指向该区域的指针在移动后会指向错误的地址。

但是,堆栈溢出检查是在访问堆栈内存时执行的,因此仅在堆栈上执行大量分配或以其他方式更改堆栈指针的值并不一定会触发故障。

2017 年夏天,有人讨论过利用这种行为的可能性。如果某些攻击者可以欺骗程序分配大量内存,则可能会导致堆栈指针跳过保护区并指向有效但不同的区域。这为一些巧妙的技巧来控制流程提供了机会。看这篇 lwn.net 文章来讨论这个问题。

相关内容