我想知道是否有办法在Linux中对每个页面进行写保护
进程的地址空间(来自进程本身的内部,通过
mprotect()
)。通过“每一页”,我的意思是每一页
进程的地址空间可能由普通用户写入
程序在用户模式下运行 - 所以,程序文本,常量,
全局变量和堆 - 但我会很满意常量,
全局和堆。我不想写保护堆栈 - 那
好像是个坏主意。
一个问题是我不知道从哪里开始写保护
记忆。查看显示内存部分的/proc/pid/maps
在使用给定的pid时,它们似乎始终以地址开头
0x08048000
,带有程序文本。 (据我所知,在Linux中,
过程的记忆与程序文本一起列出
下面,然后是常量,然后是全局,然后是堆
一个不同大小的空白空间,取决于堆的大小或
堆栈,然后堆栈从内存顶部向下生长
虚拟地址0xffffffff
。)有一种方法可以分辨出顶部的位置
堆是(通过调用sbrk(0)
,它只返回一个指针
当前的“休息”,即堆的顶部),但不是真正的方式
告诉堆开始的位置。
如果我尝试保护所有页面从0x08048000
到休息时间,我
最终得到mprotect: Cannot allocate memory
错误。我不知道mprotect
为什么会这样
无论如何都要分配内存 - 谷歌并不是很有帮助。有什么想法吗?
顺便说一下,我想这样做的原因是因为我想创建一个 在程序运行期间写入的所有页面的列表,以及 我能想到的方法是写保护所有页面, 让任何尝试的写入都会导致写入错误,然后实现写入 错误处理程序,将页面添加到列表,然后删除写入 保护。我想我知道如何实现处理程序,如果可能的话 找出要保护的页面以及如何操作。
谢谢!
答案 0 :(得分:6)
如果您尝试在未映射的网页上调用ENOMEM
,则会从mprotect()
收到/proc/self/maps
。
您最好打开fgets()
,并使用mprotect()
一行读取一行,以查找您流程中的所有映射。对于不是堆栈的每个可写映射(在第二个字段中指示)(在最后一个字段中指示),使用正确的基址和长度调用maps
(根据第一个字段中的起始和结束地址计算) )。
请注意,此时您需要设置故障处理程序,因为读取{{1}}文件本身的行为可能会导致您的地址空间内的写入。
答案 1 :(得分:0)
开始简单。写保护几页并确保您的信号处理程序适用于这些页面。然后担心扩大保护范围。例如,您可能不需要对代码段进行写保护:操作系统可以在内存上实现写入或执行保护语义,以防止代码段被写入: