2010-08-09 92 views
5

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

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

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

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

谢谢!

+1

我其实已经有了代码,完全符合你想要做的事情。你的想法会起作用,但是你无法保护你的“这些页面被写入”列表所在的页面,或者你的SEGV处理程序将导致SEGV! – Borealid 2010-08-10 00:36:08

+0

@Borealid,谢谢,现在我正试图解决这个问题(我已经有了segfault处理程序,并且/ proc/self/maps解析现在可以工作)。如何避免保护包含该列表的页面?在堆栈上分配列表可行,但我没有看到任何方式将它传递给处理程序。另外,我可以将它作为全局分配,但我想使用比定长数组(比如STL容器)更出色的数据结构,并且我可能并不总是知道我写入的列表位于何处在记忆中。 – 2010-08-11 00:13:45

+0

@borealid:你说你有这样做的代码 - 你介意分享你的代码吗?我是新来的,而且我找不到直接与您联系的方式(反向频道)。我正在努力完成Linsey正在做的事情,所以任何代码示例都会非常有帮助。 – 2010-11-21 17:37:41

回答

5

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

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

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

+0

谢谢 - 我希望能有一些解决/ proc/self/maps的方法,但似乎没有(来自http://stackoverflow.com/questions/269314的讨论)/IS-有-A-更好的路超解析进程内自映射到数字输出,内存保护中)。 – 2010-08-10 14:35:54

0

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

+0

是的,对于这个问题,我们现在可以假设没有自修改代码。无论是写保护代码段还是不写代码都可以,无论哪个更容易。 – 2010-08-10 14:39:29

+0

其实我想说的是你的代码段很可能已经被写保护了。 – 2010-08-10 15:47:21

相关问题