在我的程序中,我创建了一个简单的pthread来探索它在内存中的样子,以及将调用什么系统调用:
void *foo() {
printf("test");
}
int main() {
pthread_t a;
pthread_create(&a, NULL, foo, NULL);
pthread_join(a, NULL);
while(true);
}
使用strace,我看到它在没有任何权限的情况下在堆栈前几乎没有留下空间:
mmap(NULL, 8392704, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7fc67e53e000
mprotect(0x7fc67e53f000, 8388608, PROT_READ|PROT_WRITE) = 0
clone(child_stack=0x7fc67ed3dfb0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7fc67ed3e9d0, tls=0x7fc67ed3e700, child_tidptr=0x7fc67ed3e9d0) = 9020
在/proc/[pid]/maps中,它看起来是这样的:
7fc67e53e000-7fc67e53f000 ---p 00000000 00:00 0
7fc67e53f000-7fc67ed3f000 rw-p 00000000 00:00 0
我的问题是使用这个---p
段的目的是什么?
这被称为保护页,将其放在堆栈下面的目的是,在堆栈溢出的情况下,您会得到一个错误,该错误将捕获并终止进程(或者可能被拦截以做可疑的事情(,而不是让堆栈指针在相邻的任何内存中继续增长。不过,只有当堆栈一次最多以一页为增量前进而没有中间的内存访问时,这才有效。自90年代以来,安全社区就理解了这一点,但直到2017年,编译器工程师才知道这一点。2017年,它因"堆栈冲突"而臭名昭著,并让GCC添加了-fstack-clash-protection
选项,在任何强化环境中,默认情况下都应启用该选项。