You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

BPF函数的"钩子"定义位置及kfunc挂载实现原理问询

问题:kfunc/kretfunc探测内核函数的底层原理

我们可以通过bpftrace脚本探测内核函数vfs_read,示例代码如下:

kfunc:vfs_read { printf("Entered vfs_read.\n"); }
kretfunc:vfs_read { printf("Exited vfs_read.\n"); }

但查看vfs_read的源码后发现,函数首尾并没有预设的钩子点。我想了解当将探测程序挂载到kfunc的开头/结尾时,实际发生了什么。

我曾猜测是编译Linux内核时,通过预处理器指令在每个kfunc的首尾注入代码,于是编译6.6.22版本内核时,在Makefile中添加了KBUILD_CFLAGS += -save-temps=obj来保存预处理后的*.i文件,但并未找到预期的注入代码,因此产生疑问。


解答

kfunc/kretfunc这类BPF探测机制不需要内核源码预设钩子,也不是靠编译时注入代码实现的,核心依赖内核的运行时动态指令修改能力:

  • kfunc(函数入口探测):内核会动态修改目标函数开头的机器指令(比如x86架构下用int3断点指令替换原指令),让函数执行流先跳转到挂载的BPF程序。等BPF程序执行完毕后,再恢复原指令并继续执行函数的正常逻辑。
  • kretfunc(函数返回探测):内核会在函数入口处动态插入代码,把函数的返回地址替换为一个专门的跳板(trampoline)函数地址。当原函数执行到return指令时,会先跳转到这个跳板函数,触发对应的BPF程序执行,之后再跳回原本的返回地址完成函数返回。

整个过程都是运行时动态完成的,完全不需要编译内核时做预处理注入,所以你查看预处理后的*.i文件自然找不到相关代码。内核会维护探测点的管理结构,确保探测卸载时能恢复被修改的指令,不会影响内核的正常运行。

内容的提问来源于stack exchange,提问作者Rohit D

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 11:02:18