5

我想知道是否有一种方法可以写保护 Linux 进程地址空间中的每个页面(从进程本身内部,通过 mprotect())。“每一页”是指进程地址空间的每一页,它们可能被在用户模式下运行的普通程序写入——所以,程序文本、常量、全局变量和堆——但我只对常量、全局变量和堆感到满意。我不想写保护堆栈——这似乎是个坏主意。

一个问题是我不知道从哪里开始写保护内存。查看/proc/pid/maps,它显示了给定 pid 正在使用的内存部分,它们似乎总是以 address 开头 0x08048000,以程序文本开头。(在 Linux 中,据我所知,进程的内存布局是底部的程序文本,然后是上面的常量,然后是全局变量,然后是堆,然后是大小不同的空空间,具体取决于大小堆或堆栈,然后堆栈从虚拟地址的内存顶部向下增长0xffffffff。)有一种方法可以判断堆的顶部在哪里(通过调用sbrk(0),它只是返回一个指向当前“中断”的指针,即,堆的顶部),但并不是真正判断堆从哪里开始的方法。

如果我试图保护所有页面0x08048000不被中断,我最终会得到一个mprotect: Cannot allocate memory错误。我不知道为什么mprotect要分配内存——谷歌也不是很有帮助。有任何想法吗?

顺便说一句,我想这样做的原因是因为我想创建一个在程序运行期间写入的所有页面的列表,我能想到的方法是写保护所有页面,让任何尝试的写入导致写入错误,然后实现一个写入错误处理程序,将页面添加到列表中,然后删除写保护。我想我知道如何实现处理程序,只要我能弄清楚要保护哪些页面以及如何去做。

谢谢!

4

2 回答 2

6

如果您尝试在未映射的页面上调用它,您会收到ENOMEMmprotect()

最好的办法是打开/proc/self/maps,并一次读取一行fgets()以查找您的流程中的所有映射。对于不是堆栈(在最后一个字段中表示)的每个可写映射(在第二个字段中表示),mprotect()使用正确的基地址和长度(从第一个字段中的开始和结束地址计算)调用。

请注意,此时您需要已设置故障处理程序,因为读取maps文件本身的行为可能会导致在您的地址空间内写入。

于 2010-08-10T00:14:03.817 回答
0

从简单开始。写保护几个页面并确保您的信号处理程序适用于这些页面。然后担心扩大保护范围。例如,您可能不需要对代码段进行写保护:操作系统可以在内存上实现写或执行保护语义,这将阻止代码段被写入:

于 2010-08-09T21:08:16.597 回答