Linux 内核 - 如何将 jprobe 与 kretprobe 匹配?

Linux Kernel - How to match a jprobe to kretprobe?

我正在编写一个内核模块来监视一些系统调用,如果调用成功,则希望 return 将函数参数传递给用户空间(通过 netlink 套接字)。

jprobe.kp.symbol_name = "rename";
jprobe.entry = rename_handler;

kretprobe.kp.symbol_name = "rename";
kretprobe.handler = rename_ret_handler;

static rename_obj_t _g_cur_rename = NULL;

static void _rename_handler(const char *oldpath, const char *newpath)
{
    _g_cur_rename = create_rename(oldpath, newpath);
    jprobe_return();
}

static void _rename_ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
{
    /* Send only if successful */
    if (regs_return_value(regs) == 0) {
        add_send_queue(_g_cur_rename);
    }
    return 0;
}

我担心另一个重命名系统调用可能会抢占[1] jprobe 之后的当前系统调用,我将发送不正确的 return 代码和参数。

jprobe: rename(a, b)
    jprobe rename(c, d)
    kretprobe
kretprobe

编辑:这篇文章[2]指出在 kprobe 处理程序期间中断被禁用。但这是否意味着在整个链(jprobe -> kprobe -> kretprobe)中禁用中断或仅针对单个 kprobe?

  1. https://unix.stackexchange.com/questions/186355/few-questions-about-system-calls-and-kernel-modules-kernel-services-in-parallel
  2. https://lwn.net/Articles/132196/

每个 jprobe 调用都禁用中断:不是整个序列。

在应用程序处理它们的时间内,您预计有多少次调用?有不同的方法,具体取决于您期望调用的速度有多快。最简单的方法是,如果您只期望在处理它们之前可能有几百个调用,并且您将静态内存用于此目的,则实现一个内存中 rename_obj_t 对象的静态数组,然后使用内核 asm 中的 atomic_add 指向下一个条目(mod 数组的大小)。

这样您每次都会返回一个唯一的静态引用,只要在您处理返回值之前计数器不回绕即可。 atomic_add 保证有正确的内存屏障,因此您不必担心缓存一致性等问题。