【问题标题】:Can I write-protect every page in the address space of a Linux process?我可以写保护 Linux 进程地址空间中的每个页面吗?
【发布时间】:2011-03-27 12:31:13
【问题描述】:

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

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

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

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

谢谢!

【问题讨论】:

  • 我实际上已经有代码可以完全按照您的要求进行操作。您的想法可行,但您无法保护您的“这些页面已编写”列表所在的页面,否则您的 SEGV 处理程序将导致 SEGV!
  • @Borealid,谢谢,这就是我现在要解决的问题(我现在已经有了 segfault 处理程序和 /proc/self/maps 解析工作)。如何避免保护包含该列表的页面?在堆栈上分配列表会起作用,但是我看不到任何将它传递给处理程序的方法。或者,我可以将其分配为全局,但我想使用比固定长度数组(如 STL 容器)更高级的数据结构,而且我可能并不总是知道要写入的列表的位置在记忆中。
  • @borealid:你说你有代码可以做到这一点——你介意分享你的代码吗?我是新来的,我找不到直接联系你的方法(反向渠道)。我正在努力做 Linsey 正在做的事情,所以任何代码示例都会非常有帮助。

标签: linux segmentation-fault signal-handling mprotect


【解决方案1】:

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

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

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

【讨论】:

【解决方案2】:

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

【讨论】:

  • 是的,对于这个问题,我们现在可以假设没有自修改代码。我可以对代码部分进行写保护,无论哪个更容易。
  • 其实我想说的是你的代码段很可能已经写保护了。
猜你喜欢
  • 1970-01-01
  • 2018-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-14
  • 2015-04-01
相关资源
最近更新 更多