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

标签 linux segmentation-fault signal-handling mprotect

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

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

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

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

谢谢!

最佳答案

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

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

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

关于linux - 我可以写保护 Linux 进程地址空间中的每一页吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3444052/

相关文章:

c - 运行任何英特尔 AVX 函数后,数学函数需要更多周期

c - 在 C 中使用 pthread_join 时出现段错误

c++ - 写入堆栈变量时出现 SEGFAULT

c++ - 为什么这段代码有段错误?

c - 服务器只能接受n个客户端

c++ - 对 vector (vector::operator[] 和 vector::size())的只读访问是异步安全的吗?

c - 无法递归访问子文件夹

c - 我的字符设备打不开

java - 如果内核不支持 AIO,java AsynchronousFileChannel 如何工作

c - Kill 对信号来说是不安全的尊重 - 还有其他选择吗?