重新映射堆栈成功,但稍后会引发 SEGV

Remapping stack succeeds, but later SEGV is raised

我 运行 一个用汇编编写的简单程序,在 strace 下仅执行 SYS_exit.

_start:
    mov rax, 0x3C
    mov rdi, 0x0
    syscall

并注意到堆栈没有 mmap 内存:

alrorp@dmspc:~$ strace ./bin 
execve("./bin", ["./bin"], 0x7ffd591eda80 /* 65 vars */) = 0
exit(0)                                 = ?
+++ exited with 0 +++

所以我试着用MAP_FIXED对堆栈页面对齐地址做mmap如下:

int main(void){
    int a = 1;
    void *ptr = &a;
    void *page_aligned_ptr = (void *)((intptr_t) ptr & -4096);
    mmap(page_aligned_ptr, 4096, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
}

问题是在调用 mmap 成功后出现段错误(即 returns 请求的地址而不是 MAP_FAILED)。

mmap(0x7ffdf50db000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7ffdf50db000
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=NULL} ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault

您能就此行为给出任何提示吗?在堆栈损坏的情况下,核心转储似乎(几乎)没用。

为堆栈创建自定义映射之类的东西是否有意义?

用零字节的新匿名页面替换包含您的 return 地址的堆栈页面显然会在 main return 秒后立即导致段错误,并弹出 0 进入 RIP。

注意si_addr=NULL,IIRC 那是错误发生的代码地址。所以 RIP=0 在 运行 a ret 之后 RSP 指向 a 0。 (ret 本身不会出错,但是来自地址 0 的 code-fetch 会出错。

或者实际上段错误将在 mmap 的 libc 包装器内部,它本身必须 ret.

使用调试器 single-step C 编译器为您创建的 asm。