有没有办法先发制人地避免段错误?

时间:2010-11-28 18:29:22

标签: c pointers segmentation-fault dereference

情况如下:

我正在使用挂钩ioctl()系统调用的LD_PRELOADed模块分析程序与驱动程序的交互。我正在使用的系统(嵌入式Linux 2.6.18内核)幸运地将数据的长度编码到'request'参数中,因此我可以愉快地转储具有正确长度的ioctl数据。

然而,相当多的这些数据都有指向其他结构的指针,我不知道它们的长度(毕竟这是我正在研究的)。所以我正在扫描数据以获取指针,并将数据转储到该位置。我担心如果指针接近段边界,这可能会使我的代码对段错误开放(我的早期测试似乎表明情况就是如此)。

所以我想知道在尝试取消引用之前,我可以做些什么来先发制人地检查当前进程是否拥有特定的偏移量?这甚至可能吗?

编辑:只是一个更新,因为我忘了提到一些非常重要的东西,目标系统是基于MIPS的,虽然我也在我的x86机器上测试我的模块。

4 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:1)

如果你的嵌入式linux安装了/ proc / filesystem,你可以解析/ proc / self / maps文件并验证指针/偏移量。 maps文件包含进程的内存映射,请参阅here

答案 2 :(得分:0)

我知道没有这种可能性。但是你可能能够实现类似的东西。如man 7 signal所述,SIGSEGV可以被捕获。因此,我认为你可以

  1. 首先取消引用已知为指针的字节序列
  2. 一个接一个字节,有时会触发SIGSEGV
  3. SIGSEGV的处理程序中,标记在步骤2的循环中检查的变量
  4. 退出循环,此页面已完成。
  5. 有几个问题。

    • 由于多个缓冲区可能位于同一页面中,因此您可能会输出您认为的缓冲区,实际上是几个缓冲区。您可能能够通过LD_PRELOAD电围栏帮助解决这个问题,AFAIK会使应用程序为每个动态分配的缓冲区分配整个页面。所以你不会输出几个缓冲区,认为它只有一个,但是你仍然不知道缓冲区的结束位置,最后会输出很多垃圾。此外,此方法无法帮助基于堆栈的缓冲区。
    • 您不知道缓冲区的结束位置。

    未测试。

答案 3 :(得分:0)

你不能只检查段边界吗? (我猜是通过分段边界来表示页面边界?)

如果是这样,页面边界被很好地划分(4K或8K),因此地址的简单屏蔽应该处理它。