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

Linux 在给定受保护内存时,如何使系统调用调用我的SIGSEGV处理程序?,linux,memory,system-calls,segmentation-fault,Linux,Memory,System Calls,Segmentation Fault,我正在开发一个内存跟踪库,在这个库中,我们使用mprotect删除对程序大部分内存的访问,并使用SIGSEGV处理程序在程序接触单个页面时恢复对它们的访问。这在大多数情况下都很有效 我的问题是,当程序调用一个系统调用(比如说read),而我的库中的内存被标记为no access时,系统调用只返回-1并将errno设置为EFAULT。这会以奇怪的方式改变正在测试的程序的行为。我希望能够在系统调用真正进入内核之前,恢复对它的访问 我目前的方法是为每个涉及内存的系统调用创建一个包装器。每个包装器在将其

我正在开发一个内存跟踪库,在这个库中,我们使用
mprotect
删除对程序大部分内存的访问,并使用SIGSEGV处理程序在程序接触单个页面时恢复对它们的访问。这在大多数情况下都很有效

我的问题是,当程序调用一个系统调用(比如说
read
),而我的库中的内存被标记为no access时,系统调用只返回-1并将
errno
设置为
EFAULT
。这会以奇怪的方式改变正在测试的程序的行为。我希望能够在系统调用真正进入内核之前,恢复对它的访问

我目前的方法是为每个涉及内存的系统调用创建一个包装器。每个包装器在将其传递给真正的系统调用之前,都会接触到提供给它的所有内存。这似乎适用于直接从程序发出的调用,但不适用于libc发出的调用(例如,
fread
将在不使用我的包装器的情况下直接调用
read
)。有没有更好的办法?如何实现这种行为?

您可以使用来实现这一点。它允许您监视流程,并在发生某些事件时得到通知。出于您的目的,请查看
PTRACE_SYSCALL
,它允许您在进入和退出SYSCALL时停止进程

但是,您必须更改一些内存跟踪基础结构,因为
ptrace
的运行方式是父进程监视子进程,而就子进程而言,它不知道监视的事件何时发生。话虽如此,您应该能够按照以下思路做一些事情:

  • 设置ptrace父级和子级,监视(至少)
    ptrace\u系统调用
  • 子进程执行系统调用;并通知家长
  • 父级保存请求的系统调用信息;并使用
    PTRACE_GETREGS
    PTRACE_SETREGS
    来更改子状态,从而代替调用系统调用;子进程调用“内存取消保护”例程
  • 孩子不保护自己的记忆;然后引发
    SIGUSR1
    或类似事件,告知控制父级内存工作已完成
  • 父级捕获
    SIGUSR
    ,使用
    PTRACE\u SETREGS
    恢复先前保存的系统调用信息并恢复子级
  • 子系统恢复并执行原始系统调用

有一些实验允许您自己进行ptrace,以捕获您自己的系统调用。。。但是,是的,这种多进程的舞蹈通常是必要的。我认为这是正确的解决方案,但它不会按规定工作。当我在系统调用时停止子级时,eip的值位于系统调用返回点(在_kernel_vsyscall中弹出堆栈外的寄存器),而不是syscenter指令。因此,当父系统捕捉到系统调用时,系统调用已经开始(并且注定要失败)。不过,当它返回时,我可能会捕捉到它,调用不受保护的例程,然后重新启动调用。@Jay:有没有可能发布(最低版本的)代码?你应该能够在孩子真正执行系统调用之前捕捉到它…@Dave Rigby,我在之前发布了一些示例代码。我正在使用GDB检查user_info结构的内容。我相信当程序第一次用SIGTRAP停止时,它就进入了写调用。然后,我将反汇编命令与user_info.regs.eip中的值一起使用。指令是“pop%ebp”,地址是u kernel_vsyscall+16(返回点)。谢谢你的持续帮助。@Jay:我运行了你链接的测试代码,它似乎对我有用-我看到第一个信号陷阱出现在SYS_write的开头。这太傻了。在给系统调用无效内存时,谁期望EFAULT而不是segfaultP看起来像是系统调用和用户空间函数之间的随机不一致。。。