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

发布于 2024-07-26 11:59:27 字数 468 浏览 3 评论 0原文

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

我的问题是,当程序使用我的库标记为不可访问的内存调用系统调用(例如 read)时,系统调用仅返回 -1 并将 errno 设置为EFAULT。 这以奇怪的方式改变了正在测试的程序的行为。 我希望能够在系统调用实际进入内核之前恢复对系统调用的每个内存页的访问。

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

I'm working on a memory tracking library where we use mprotect to remove access to most of a program's memory and a SIGSEGV handler to restore access to individual pages as the program touches them. This works great most of the time.

My problem is that when the program invokes a system call (say read) with memory that my library has marked no access, the system call just returns -1 and sets errno to EFAULT. This changes behavior of the programs being tested in strange ways. I would like to be able to restore access to each page of memory given to a system call before it actually goes to the kernel.

My current approach is to create a wrapper for each system call that touches memory. Each wrapper would touch all the memory given to it before handing it off to the real system call. It seems like this will work for calls made directly from the program, but not for those made by libc (for instance, fread will call read directly without using my wrapper). Is there any better approach? How is it possible to get this behavior?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

骄兵必败 2024-08-02 11:59:27

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

但是,您必须更改一些内存跟踪基础设施,因为 ptrace 的运行方式是让父进程监视子进程,并且就子进程而言,它无法了解何时发生发生受监视的事件。 话虽如此,您应该能够执行以下操作:

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

You can use ptrace(2) to achieve this. It allows you to monitor a process and get told whenever certain events occur. For your purposes, look at PTRACE_SYSCALL which allows you to stop the process upon syscall entry and exit.

You will have to change some of your memory tracking infrastructure, however, as ptrace operates such that a parent process monitors a child process, and as far as the child is concerned it doesn't have visibility of when a monitored event occurs. Having said that, you should be able to do something along the lines of:

  • Setup ptrace parent and child, monitoring (at least) PTRACE_SYSCALL.
  • Child process does a syscall; and parent is notified.
  • Parent saves the requested syscall info; and uses PTRACE_GETREGS and PTRACE_SETREGS to change child state so instead of calling the syscall; the child process calls the 'memory unprotect' routine.
  • Child unprotect's it's memory; then raises SIGUSR1 or similar to tell controlling parent that the memory work is complete.
  • Parent catches SIGUSR, uses PTRACE_SETREGS to restore the previouly-saved syscall info and resumes the child.
  • Child resumes and executes the orignal syscall.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文