当给定受保护内存时,如何使系统调用调用我的 SIGSEGV 处理程序?
-
21-08-2019 - |
题
我正在开发一个我们使用的内存跟踪库 mprotect
删除对大部分程序内存的访问,并使用 SIGSEGV 处理程序在程序接触各个页面时恢复对各个页面的访问。这在大多数情况下都非常有效。
我的问题是,当程序调用系统调用时(比如 read
)对于我的库已标记为无法访问的内存,系统调用仅返回 -1 并设置 errno
到 EFAULT
. 。这以奇怪的方式改变了正在测试的程序的行为。我希望能够在系统调用实际进入内核之前恢复对系统调用的每个内存页的访问。
我当前的方法是为每个涉及内存的系统调用创建一个包装器。每个包装器在将其交给真正的系统调用之前都会接触分配给它的所有内存。这似乎适用于直接从程序进行的调用,但不适用于 libc 进行的调用(例如, fread
将会通知 read
直接不使用我的包装器)。有没有更好的方法?怎么可能得到这种行为?
解决方案
您可以使用 ptrace(2)
为了达成这个。它允许您监视进程并在发生某些事件时得到通知。为了您的目的,请查看 PTRACE_SYSCALL
它允许您在系统调用进入和退出时停止进程。
然而,您将不得不更改一些内存跟踪基础设施,因为 ptrace
运行时,父进程监视子进程,并且就子进程而言,它不知道受监视事件何时发生。话虽如此,您应该能够执行以下操作:
- 设置 ptrace 父级和子级,监控(至少)
PTRACE_SYSCALL
. - 子进程执行系统调用;并通知家长。
- 父级保存请求的系统调用信息;和用途
PTRACE_GETREGS
和PTRACE_SETREGS
更改子状态,而不是调用系统调用;子进程调用“内存取消保护”例程。 - 孩子的记忆不受保护;然后加注
SIGUSR1
或类似地告诉控制父母记忆工作已完成。 - 家长抓到
SIGUSR
, ,使用PTRACE_SETREGS
恢复以前保存的系统调用信息并恢复子进程。 - 子进程恢复并执行原始系统调用。
不隶属于 StackOverflow