如何在给定受保护的内存时使系统调用调用我的SIGSEGV处理程序?

问题描述:

我正在研究一个内存跟踪库,我们使用mprotect来删除对大部分程序内存的访问以及一个SIGSEGV处理程序,以便在程序触及时恢复对单个页面的访问。这在大多数情况下都很有效。如何在给定受保护的内存时使系统调用调用我的SIGSEGV处理程序?

我的问题是,程序调用系统调用(比如read)与我的图书馆没有标明存取存储器时,系统调用只是返回-1,并将errnoEFAULT。这以奇怪的方式改变了正在测试的程序的行为。我希望在实际进入内核之前能够恢复对系统调用的每个内存页面的访问。

我目前的做法是为每个接触内存的系统调用创建一个包装。每个包装器在将其交给真正的系统调用之前都会触及给予它的所有内存。看起来这样可以直接从程序中调用,但不适用于由libc创建的调用(例如,fread将直接调用read而不使用我的包装)。有没有更好的方法?怎么可能得到这种行为?

+0

那真是愚蠢。当系统调用无效内存时,谁期望EFAULT而不是段错误? :P看起来像系统调用和用户空间函数之间的随机不一致...... – 2012-03-07 16:08:51

您可以使用ptrace(2)来实现此目的。它允许您监视进程并在发生特定事件时得到通知。出于您的目的,请查看PTRACE_SYSCALL,它允许您在系统调用进入和退出时停止进程。

但是,您必须更改一些内存跟踪基础结构,因为ptrace的操作使得父进程监视子进程,并且就儿童而言,它无法识别受监视事件的时间发生。话虽如此,你应该可以做一些事情:

  • 安装ptrace父母和孩子,监视(至少)PTRACE_SYSCALL
  • 子进程执行系统调用;并通知家长。
  • Parent保存请求的系统调用信息;并使用PTRACE_GETREGSPTRACE_SETREGS来更改子状态,而不是调用系统调用;子进程调用'内存解除保护'例程。
  • 孩子不保护它的记忆;然后提出SIGUSR1或类似的告诉控制父母内存工作已完成。
  • 父级渔获SIGUSR,使用PTRACE_SETREGS恢复以前保存的系统调用信息并恢复孩子。
  • 孩子恢复并执行原始系统调用。
+0

http://lkml.org/lkml/2008/8/25/40有一些实验允许你自己使用ptrace来捕捉你自己的系统调用。 ..但是,这个多进程舞蹈通常是必要的。 – ephemient 2009-07-02 00:21:12