Linux Livepatch中调用原函数的相关问题及解决方案咨询
Linux Livepatch 参数修改相关问题解答
核心问题与解答
1. 直接调用原函数是否会触发无限递归?如何避免?
会触发无限递归。因为Livepatch完成替换后,func_old的符号会被重定向到func_new,此时在func_new中直接调用func_old,本质是调用自身,最终导致调用栈溢出。
避免方案:
- 借助Livepatch框架提供的机制,通过函数指针调用原函数的真实地址,而非直接使用原函数名。
- 在
klp_func结构体中,内核会自动维护原函数的指针,模块初始化时将该指针赋值给自定义的函数指针,后续通过该指针完成原函数调用。
2. 原函数在补丁中不可见导致的「implicit declaration of function」错误如何解决?
内核中并非所有函数都会导出符号,直接引用未导出的函数必然触发隐式声明错误,解决方式如下:
- 提前定义与原函数签名完全匹配的函数指针。
- 利用
klp_func结构体的old_func成员:补丁加载后,内核会自动将该成员填充为原函数的真实地址,只需在模块初始化时将其赋值给自定义的函数指针即可,无需手动声明原函数。
3. 自定义Livepatch模块执行cat /proc/cmdline后系统挂起的原因及修复
你的代码存在两个致命问题:
- 函数指针赋值时机错误:先调用
klp_enable_patch启用补丁,再给real_cmdline_proc_show赋值。此时补丁已生效,fh_cmdline_proc_show被调用时,全局指针仍为空,触发空指针调用导致内核崩溃挂起。 - 局部变量遮蔽全局变量:
livepatch_init中定义了同名局部变量,覆盖了全局函数指针,导致全局指针始终未被正确赋值。
修复后的代码:
#include <linux/seq_file.h> static int (*real_cmdline_proc_show)(struct seq_file *m, void *v); static int fh_cmdline_proc_show(struct seq_file *m, void *v) { int ret; seq_printf(m, "%s\n", "this has been ftrace hooked"); ret = real_cmdline_proc_show(m, v); pr_debug("cmdline_proc_show() returns: %d\n", ret); return ret; } static struct klp_func funcs[] = { { .old_name = "cmdline_proc_show", .new_func = fh_cmdline_proc_show, }, { } }; static struct klp_object objs[] = { { /* name being NULL means vmlinux */ .funcs = funcs, }, { } }; static struct klp_patch patch = { .mod = THIS_MODULE, .objs = objs, }; static int livepatch_init(void) { int result; // 先获取原函数指针,再启用补丁 real_cmdline_proc_show = (void *)funcs[0].old_func; if (!real_cmdline_proc_show) return -EINVAL; result = klp_enable_patch(&patch); return result; } static void livepatch_exit(void) { } module_init(livepatch_init); module_exit(livepatch_exit); MODULE_LICENSE("GPL"); MODULE_INFO(livepatch, "Y");
修复说明:
- 调整执行顺序:先从
funcs[0].old_func获取原函数地址并赋值给全局指针,再启用补丁,确保新函数调用时指针有效。 - 移除局部变量,使用全局函数指针避免遮蔽问题。
- 增加空指针检查,提前拦截获取原函数失败的情况。
内容的提问来源于stack exchange,提问作者Frontier_Setter
相关产品推荐
相关产品推荐

