Linux 6.8下statx系统调用劫持修改返回值时遇空指针解引用
解决Linux 6.8下kretprobe劫持statx系统调用的空指针解引用问题
问题根源
空指针解引用的核心原因是对kretprobe的寄存器上下文理解错误:
- kretprobe的
m_statx处理器函数中,传入的struct pt_regs *regs已经是statx系统调用的用户态寄存器上下文,不需要再从regs->di去获取额外的struct pt_regs指针。 - 错误地将
regs->di强制转换为struct pt_regs *user_regs,导致后续访问user_regs->si时访问非法内存,触发空指针异常。
x86_64架构下statx系统调用的参数传递遵循标准ABI:
rdi:文件描述符fdrsi:用户态路径字符串指针pathnamerdx:标志位flagsr10:掩码maskr8:用户态struct statx缓冲区指针statxbufr9:时间戳类型at
修正后的完整代码
#include <linux/init.h> #include <linux/module.h> #include <linux/kprobes.h> #include <linux/uaccess.h> #include <linux/stat.h> MODULE_VERSION("v.0"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Flavien <flav> ASTRAUD <flav@epita.fr>"); MODULE_DESCRIPTION("ex. pour interception d'un syscall"); static int m_statx(struct kretprobe_instance *ri, struct pt_regs *regs) { long r = 0; char path[128] = {0}; // 初始化避免垃圾值输出 struct statx statxbuf; // 直接从regs读取用户态路径参数 r = strncpy_from_user(path, (char __user *)regs->si, sizeof(path)-1); if (r < 0) { pr_err("Failed to copy path from user space\n"); return 0; } // 读取用户态的statx缓冲区数据 r = copy_from_user(&statxbuf, (struct statx __user *)regs->r8, sizeof(struct statx)); if (r != 0) { pr_err("Failed to copy statxbuf from user space\n"); return 0; } pr_info("STATX_V3 %s size=%lld\n", path, statxbuf.stx_size); // 修改返回的文件大小字段 statxbuf.stx_size = 42; // 将修改后的数据写回用户态缓冲区 r = copy_to_user((struct statx __user *)regs->r8, &statxbuf, sizeof(statxbuf)); if (r != 0) { pr_err("Failed to copy modified statxbuf to user space\n"); } return 0; } static struct kretprobe kret = { .handler = m_statx, }; static int override_statx(void) { kret.kp.symbol_name = "__x64_sys_statx"; if (register_kretprobe(&kret) < 0) { pr_err("Failed to register kretprobe for statx\n"); return -1; } pr_info("kretprobe registered successfully\n"); return 0; } static void pullback_syscall(void) { unregister_kretprobe(&kret); } static int __init kstatx_init(void) { pr_info("kstatx INIT\n=============\n"); return override_statx(); } static void __exit kstatx_exit(void) { pr_info("kstatx END\n=============\n"); pullback_syscall(); } module_init(kstatx_init); module_exit(kstatx_exit);
关键修改说明
- 移除错误的
struct pt_regs *user_regs转换逻辑,直接使用传入的regs获取系统调用参数。 - 增加参数拷贝的错误检查,避免后续操作基于非法数据执行。
- 初始化
path数组,防止打印垃圾字符。 - 修正
override_statx的返回值逻辑,注册失败时返回错误码便于调试。 - 补充必要头文件,消除编译警告。
额外注意事项
- kretprobe在系统调用返回前执行处理器函数,此时系统调用已完成核心逻辑,你修改的是最终返回给用户的结果。
strncpy_from_user返回值:成功时返回拷贝的字节数(不含终止符),失败时返回负数错误码。- 开发时建议通过
dmesg -w实时查看内核日志,快速定位问题。
内容的提问来源于stack exchange,提问作者flav
相关产品推荐
相关产品推荐

