【问题标题】:Is this is a good way to intercept system calls?这是拦截系统调用的好方法吗?
【发布时间】:2012-05-28 03:46:54
【问题描述】:

我正在编写一个工具。该工具的一部分将是它能够记录系统调用的参数。好吧,我可以为此使用ptrace,但ptrace 非常慢。我想到的一个更快的方法是修改 glibc。但这变得越来越困难,因为 gcc 神奇地插入了自己的内置函数作为系统调用包装器,而不是使用 glibc 中定义的代码。使用-fno-builtin 也无济于事。

所以我想到了编写一个共享库的想法,其中包括每个系统调用包装器,例如mmap,然后在调用实际的系统调用包装器函数之前执行日志记录。例如,我的mmap 的伪代码如下所示。

int mmap(...)
{
 log_parameters(...);
 call_original_mmap(...);
 ...
}

然后我可以使用 LD_PRELOAD 先加载这个库。你认为这个想法会奏效吗,还是我错过了什么?

【问题讨论】:

  • 它可能不适用于静态链接的可执行文件。而且它不适用于执行系统调用而不通过 libc 的可执行文件。
  • 您想在每次执行实际的系统调用时(在每个int 0x80),还是在每次调用库处理函数时进行拦截?
  • 我认为它可能会很慢。这基本上正是 valgrind 对其仪器所做的事情,尽管它是一个非常知名和开发的工具,但它仍然会影响性能。我认为如果有更快的方法,它就会在那里使用。我的猜测是你低估了日志记录功能的成本,而且没有办法解决这个问题。
  • 看看fakeroot,它使用了一个共享库,里面有一堆libc函数包装器,里面加载了LD_PRELOAD
  • @jthill,正是我的观点。我经常为此目的使用strace。我刚刚检查了在使用opendir()fstatat() 时最终调用了哪些系统调用libc6-2.15,以及使用了哪些参数。

标签: c linux gcc x86-64 glibc


【解决方案1】:

您在用户空间中想出的任何方法都无法与任何应用程序无缝协作。对您来说幸运的是,已经支持在内核中执行您想要执行的操作。 Kprobes 和 Kretprobes 允许您检查机器在系统调用之前和之后的状态。

此处的文档:https://www.kernel.org/doc/Documentation/kprobes.txt

【讨论】:

    【解决方案2】:

    如果您正在开发的代码与流程相关,有时您可以在不破坏现有代码的情况下开发替代实现。如果您正在重写一个重要的系统调用并且想要一个功能齐全的系统来调试它,这将很有帮助。

    对于您的情况,您正在重写 mmap() 算法以利用令人兴奋的新功能(或使用新功能进行增强)。除非您在第一次尝试时一切都正确,否则调试系统并不容易:无功能的 mmap() 系统调用肯定会导致系统无功能。一如既往,有希望。

    通常,保留剩余算法并在旁边构建替代算法是安全的。您可以通过使用用户 ID (UID) 作为决定使用哪种算法的条件来实现这一点:

    if (current->uid != 7777) {
    /* old algorithm .. */
    } else {
    /* new algorithm .. */
    }
    

    除 UID 7777 之外的所有用户都将使用旧算法。您可以使用 UID 7777 创建一个特殊用户来测试新算法。这使得测试与流程相关的关键代码变得更加容易。

    【讨论】:

      【解决方案3】:

      正如其他人所提到的,如果二进制文件是静态链接的,动态链接器将跳过任何使用 libdl 拦截函数的尝试。相反,您应该考虑自己启动该过程并绕道您希望拦截的函数的入口点。

      这意味着你自己启动进程,拦截它的执行,并重写它的内存,在内存中函数定义的开头放置一条跳转指令到你控制的新函数。

      如果你想拦截实际的系统调用而不能使用ptrace,你要么必须找到每个系统调用的执行位置并重写它,要么你可能需要覆盖内存中的系统调用表并过滤掉除您要控制的进程之外的所有内容。

      【讨论】:

        【解决方案4】:

        所有来自用户空间的系统调用都通过一个中断处理程序来切换到内核模式,如果你找到了这个处理程序,你可能可以在那里添加一些东西。

        编辑我找到了这个http://cateee.net/lkddb/web-lkddb/AUDITSYSCALL.html。 Linux 内核:2.6.6–2.6.39、3.0–3.4 支持系统调用审计。这是一个必须启用的内核模块。如果不至于混淆,也许您可​​以查看此模块的源代码。

        【讨论】:

        • LSM 也可用于控制系统调用。 en.wikipedia.org/wiki/Linux_Security_Modules
        • 这不是普遍正确的——在某些操作系统的某些版本上,x86 可能是正确的,但是有许多平台和/或操作系统不使用中断作为用户模式到内核的转换机制。
        猜你喜欢
        • 2022-07-07
        • 2015-10-04
        • 2012-02-27
        • 2021-07-06
        • 2010-09-05
        • 2014-10-11
        • 2010-09-09
        • 2012-09-09
        相关资源
        最近更新 更多