我可以写保护Linux进程的地址空间中的每个页面吗?

Lin*_*per 5 linux mprotect signal-handling segmentation-fault

我想知道是否有办法在Linux进程的地址空间中写入保护每个页面(从进程本身的内部,通过 mprotect()).通过"每一页",我的意思是进程的地址空间的每个页面都可以由用户模式下运行的普通程序写入 - 所以,程序文本,常量,全局变量和堆 - 但是我会对常量,全局变量和堆很满意.我不想写保护堆栈 - 这似乎是一个坏主意.

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

如果我尝试保护所有页面0x08048000直到休息,我最终会收到mprotect: Cannot allocate memory错误.我不知道为什么mprotect要分配内存 - 而Google并不是很有帮助.有任何想法吗?

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

谢谢!

caf*_*caf 6

您收到ENOMEM来自mprotect()如果你试图调用它没有被映射的页面.

你最好的选择是打开/proc/self/maps,一次读一行,fgets()找到你的过程中的所有映射.对于不是堆栈的每个可写映射(在第二个字段中指示)(在最后一个字段中指示),mprotect()使用正确的基址和长度调用(根据第一个字段中的起始和结束地址计算).

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