有没有一种方法可以预防segfault?

3
这是情况:
我正在使用一个装载了LD_PRELOAD模块的程序来分析与驱动程序的交互。幸运的是,我正在处理的系统(嵌入式Linux 2.6.18内核)将数据长度编码到“请求”参数中,因此我可以愉快地使用正确的长度转储ioctl数据。
然而,这些数据中有很多指向其他结构体的指针,我不知道它们的长度(这正是我正在调查的)。因此,我正在扫描指针数据,并在该位置转储数据。但我担心,如果指针靠近段边界,我的代码可能会导致段错误(我的早期测试似乎证明了这一点)。
因此,我想知道是否可以预先检查当前进程是否拥有特定偏移量,然后再尝试进行解引用?这种做法是否可行?
编辑:忘记提到一些非常重要的事情,目标系统是基于MIPS的,尽管我也在我的x86机器上测试我的模块。

4个回答

3
打开一个文件描述符到/dev/null,并尝试write(null_fd, ptr, size)。如果返回值为-1且errno设置为EFAULT,则内存无效。如果返回size,则该内存可以安全读取。可能有一种更优雅的方式使用某些POSIX发明来查询内存有效性/权限,但这是经典的简单方法。

1
如果您的嵌入式Linux已经挂载了/proc/文件系统,那么您可以解析/proc/self/maps文件并根据其中的指针/偏移量进行验证。maps文件包含进程的内存映射信息,请参见这里

谢谢您的建议,起初看起来非常完美,但是在考虑如何实现时,我意识到由于每次调用 ioctl 都必须解析它,因此可能会相当慢。 - PeterBelm

0

我不知道有这样的可能性。但是你可能能够实现类似的功能。正如 man 7 signal 所提到的,可以捕获 SIGSEGV。因此,我认为你可以:

  1. 从已知是指针的字节序列开始解引用
  2. 访问一个接一个的字节,在某个时候触发 SIGSEGV
  3. SIGSEGV 的处理程序中,标记一个在步骤2的循环中检查的变量
  4. 退出循环,页面完成。

这里有几个问题。

  • 由于几个缓冲区可能存在于同一页中,你可能会输出你认为是一个缓冲区,但实际上是几个缓冲区。你可以通过 LD_PRELOAD 电子围栏来帮助解决这个问题,这将导致应用程序为每个动态分配的缓冲区分配整个页面。因此,你不会输出多个缓冲区,认为它只是一个缓冲区,但你仍然不知道缓冲区的结束位置,并且会在结尾输出大量垃圾。此外,基于堆栈的缓冲区无法通过此方法解决。
  • 你不知道缓冲区的结束位置。

未经测试。


1
如果进程已经有一个SIGSEGV的信号处理程序,那么该如何实现呢?我不确定它是否有,但这是一个明显的可能性。信号处理程序可以分层吗?不知道缓冲区结束位置并不是一个大问题,对于有趣的缓冲区,我会找出它的长度,我只需要一个“捕获所有”方法来转储数据。 - PeterBelm
signal(2) 返回指向先前安装的处理程序的指针。在解引用调用它之前,应检查常量 SIG_IGNSIG_DFL。如果要在非Linux Unix上使用它,最好使用 sigaction(2)。它还允许查询先前安装的 sigaction - dennycrane

0

你不能直接检查段边界吗?(我猜你指的是页面边界?)

如果是的话,页面边界已经很好地划分了(4K或8K),所以简单的地址掩码处理就可以解决它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接