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

我想知道是否有办法在Linux进程的地址空间(从进程内部通过mprotect() )保护每一页。 通过“每一页”,我真的指的是进程的地址空间的每一页,可以通过用户模式运行的普通程序来写 – 即程序文本,常量,全局variables和堆 – 但是我对于常量,全局variables和堆将会很满意。 我不想写保护堆栈 – 这似乎是一个坏主意。

一个问题是,我不知道从哪里开始写保护内存。 看看/proc/pid/maps ,它显示了给定pid使用的内存段,它们似乎始于地址0x08048000和程序文本。 (在Linux中,据我所知,一个进程的内存是用底部的程序文本进行布局的,然后是常量,然后是全局variables,然后是堆,然后是根据大小变化的空的空间堆栈或堆栈,然后从虚拟地址0xffffffff的内存顶部向下生长的堆栈)。有一种方法可以告诉堆栈的顶部是哪里(通过调用sbrk(0) ,它只是返回一个指向目前的“rest”,即堆的顶部),但不是一个真正的方法来告诉堆开始的地方。

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

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

谢谢!

如果您尝试在未映射的页面上调用它,您将从mprotect()接收ENOMEM

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

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

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