我一直试图先使用mprotect反对阅读,然后写作.
这是我的代码
#include <sys/types.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
int pagesize = sysconf(_SC_PAGE_SIZE);
int *a;
if (posix_memalign((void**)&a, pagesize, sizeof(int)) != 0)
perror("memalign");
*a = 42;
if (mprotect(a, pagesize, PROT_WRITE) == -1) /* Resp. PROT_READ */
perror("mprotect");
printf("a = %d\n", *a);
*a = 24;
printf("a = %d\n", *a);
free (a);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在Linux下这里是结果:
以下是输出PROT_WRITE:
$ ./main
a = 42
a = 24
Run Code Online (Sandbox Code Playgroud)
并为 PROT_READ
$ ./main
a = 42
Segmentation fault
Run Code Online (Sandbox Code Playgroud)
在Mac OS X 10.7下:
以下是输出PROT_WRITE:
$ ./main
a = 42
a = 24
Run Code Online (Sandbox Code Playgroud)
并为 PROT_READ
$ ./main
[1] 2878 bus error ./main
Run Code Online (Sandbox Code Playgroud)
到目前为止,我知道OSX/Linux的行为可能有所不同,但我不明白为什么PROT_WRITE在读取值时不会使程序崩溃printf.
有人可以解释一下吗?
Ser*_* L. 11
您正在观察两件事:
mprotect不适合与堆页面一起使用.Linux和OS X对堆的处理略有不同(请记住OS X使用Mach VM).OS X不喜欢它的堆页面被篡改.
如果您通过分配页面,则可以在两个操作系统上获得相同的行为 mmap
a = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
if (a == MAP_FAILED)
perror("mmap");
Run Code Online (Sandbox Code Playgroud)这是MMU的限制(在我的情况下是x86).x86中的MMU不支持可写但不可读的页面.这样设定
mprotect(a, pagesize, PROT_WRITE)
Run Code Online (Sandbox Code Playgroud)
什么也没做.而
mprotect(a, pagesize, PROT_READ)
Run Code Online (Sandbox Code Playgroud)
删除了写入priveledges并按预期获得SIGSEGV.
此外,虽然它似乎并不成为一个问题在这里,您应该编译代码-O0或设置a,以volatile int *避免任何编译器的优化.