linux - 为什么 kprobes 禁用抢占以及何时可以安全地重新启用它?

标签 linux kernel preemption kprobe

根据docs , kprobes 禁用抢占:

Probe handlers are run with preemption disabled. Depending on the architecture and optimization state, handlers may also run with interrupts disabled (e.g., kretprobe handlers and optimized kprobe handlers run without interrupt disabled on x86/x86-64).

来自 commit 9a09f261a我们可以清楚地看到优化的 kprobes 曾经在启用抢占的情况下运行。

为什么会这样?我将 kprobes 理解为一种在内核中的特定地址注入(inject)一些代码的方法,并且理解任何代码都应该没问题。

  • 是什么让 kprobes 如此特殊以至于必须禁用抢占?
  • 在什么情况下我可以重新启用抢占?

最佳答案

至少在 x86 上,Kprobes 的实现依赖于在 Kprobe 处理程序运行时禁用抢占这一事实。

当您将一个普通的(不是基于 Ftrace 的)Kprobe 放在一条指令上时,该指令的第一个字节将被 0xcc(int3,“软件断点”)覆盖。如果内核尝试执行该指令,则会发生陷阱并调用 kprobe_int3_handler()(请参阅 do_int3() 的实现)。

为了调用您的 Kprobe 处理程序,kprobe_int3_handler() 找到哪个 Kprobe 命中,将其保存为 percpu 变量 current_kprobe 并调用您的预处理程序。之后,它准备一切以单步执行原始指令。单步执行后,将调用您的后处理程序,然后执行一些清理工作。 current_kprobe 和其他一些 per-cpu 数据用于执行所有这些操作。仅在此之后启用抢占。

现在,假设预处理器启用了抢占,立即被抢占并在不同的 CPU 上恢复。如果 Kprobes 的实现试图访问 current_kprobe 或其他 per-cpu 数据,内核可能会崩溃(如果此时该 CPU 上没有 current_kprobe,则 NULL 指针 deref)或更糟。

或者,被抢占的处理程序可以在同一个 CPU 上恢复,但另一个 Kprobe 可能会在它休眠时命中那里 - current_kprobe 等将被覆盖,并且很可能发生灾难。

在 Kprobe 处理程序中重新启用抢占可能会导致难以调试的内核崩溃和其他问题。

所以,简而言之,这是因为 Kprobes 是这样设计的,至少在 x86 上是这样。关于它们在其他架构上的实现,我不能说太多。


根据您要完成的目标,其他内核工具可能会有所帮助。

例如,如果您只需要在某些函数的开头运行代码,请查看 Ftrace 。然后,您的代码将在与您 Hook 的函数相同的条件下运行。


综上所述,我的一个项目实际上需要使用 Kprobes,以便处理程序在与 w.r.t. 相同的条件下运行。抢占作为探测指令。您可以找到实现 here 。然而,它必须克服重重困难才能在不破坏任何东西的情况下实现这一目标。到目前为止它一直工作正常,但它比我想要的更复杂,也有可移植性问题。

关于linux - 为什么 kprobes 禁用抢占以及何时可以安全地重新启用它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48585919/

相关文章:

xml - 无法使用 wget 检索完整文件

linux - linux中的音频流采样率

linux - 新的 linux 内核,没有使用 lkms 的 lsm,没有内核 Hook 现在怎么办?

c++ - 如何避免在用户模式下抢占我的线程

linux - 获取当前用户的名字

linux - 我可以在 ubuntu 上终止 console-kit-dae 进程吗?

c - 如何测试旧的linux内核?

c - 如何在linux内核模块中添加RTC定时器

python - 如何阻止 Pepper 机器人抢占其平板电脑?

c - 如何限制 C/POSIX 中函数的执行时间?