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

时间:2010-08-09 20:48:58

标签: linux sigsegv signal-handling mprotect

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

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

如果我尝试保护所有页面从0x08048000到休息时间,我 最终得到mprotect: Cannot allocate memory错误。我不知道mprotect为什么会这样 无论如何都要分配内存 - 谷歌并不是很有帮助。有什么想法吗?

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

谢谢!

2 个答案:

答案 0 :(得分:6)

如果您尝试在未映射的网页上调用ENOMEM,则会从mprotect()收到/proc/self/maps

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

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

答案 1 :(得分:0)

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