“__kprobes”的使用及其工作原理?

use*_*953 3 c linux-kernel

在提到Linux内核的内存模块时,我不清楚一些功能。其中一项功能如下所示:

static inline int __kprobes notify_page_fault(struct pt_regs *regs)
{
int ret = 0;

/* kprobe_running() needs smp_processor_id() */
if (kprobes_built_in() && !user_mode_vm(regs)) {
    preempt_disable();
    if (kprobe_running() && kprobe_fault_handler(regs, 14))
        ret = 1;
    preempt_enable();
}

return ret;
} 
Run Code Online (Sandbox Code Playgroud)

我对返回类型和函数名称之间的“__kprobes”感到困惑。当我查看compiler.h中“__kprobes”的初始化时,我发现如下:

/*Ignore/forbid kprobes attach on very low level functions marked by 
this attribute:*/
#ifdef CONFIG_KPROBES
# define __kprobes  __attribute__((__section__(".kprobes.text")))
#else
# define __kprobes
#endif
Run Code Online (Sandbox Code Playgroud)

好吧,我知道在编译时 __kprobe 将被其定义的部分替换。

问题:

1.) 的意义是__attribute__((__section__(".kprobes.text")))什么?

2.) 在“function_name”之前使用它时,它在编译时和运行时做什么?

我阅读了kprobe并发现它必须对断点和回溯做一些事情。我对 kprobe 的理解是它将帮助调试器创建回溯和断点。有人可以用简单的话解释我它是如何工作的,如果我错了,请纠正我。

Ale*_*oba 6

TL; 博士

  1. __attribute__((__section__(".kprobes.text"))) 将该函数放在 kprobes 无法找到的单独部分中,从而防止出现无限断点。
  2. 您必须在“function_name”之前使用它才能将整个“function_name”符号放在单独的部分中。

真实答案

kprobes(内核探针)是用于动态跟踪的 Linux 内核机制。它允许您在几乎任何内核函数处插入断点,调用您的处理程序,然后继续执行。它通过使用所谓的内核探针/kprobe 运行时修补内核映像来工作 - 请参阅struct kprobe。此探针将允许您将控制权传递给您的处理程序,并且该处理程序通常会进行一些跟踪。

那么,引擎盖下发生了什么:

  • 您可以struct kprobe通过定义中断地址和传递引用的处理程序来创建您的。
  • 你注册你的探针 register_kprobe
  • 内核 kprobe 子系统从您的探针中查找地址
  • 然后kprobe:
    • int 3在给定地址插入断点 CPU 指令(对于 x86)
    • 添加一些包装器代码来保存上下文(寄存器等)
    • 添加更多代码以帮助您访问函数参数或返回值。
  • 现在,当内核执行命中该探测地址时:
    • 它会落入 CPU 陷阱
    • 它将保存上下文
    • 它将通过以下方式将控制权传递给您的处理程序 notifier_call_chain
    • ...
    • 毕竟它会恢复上下文

这就是它的工作原理。正如你所看到的,这是一个非常巧妙和肮脏的 hack,但是某些内核函数非常低级,以至于探索它们毫无意义。notify_page_fault是这些功能之一 - 作为notifier_call_chain它的一部分,用于将控制权传递给您的处理程序。

所以如果你试探notify_page_fault你会得到无限循环的断点,这不是你想要的。您真正想要的是保护这种功能,而 kprobes 通过将其放置在单独的部分来做到这一点.kprobes.text。这将阻止对该函数进行探测,因为 kprobe 不会在该部分查找地址。这是__attribute__((__section__(".kprobes.text"))).