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

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:文件描述符fd
  • rsi:用户态路径字符串指针pathname
  • rdx:标志位flags
  • r10:掩码mask
  • r8:用户态struct statx缓冲区指针statxbuf
  • r9:时间戳类型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的返回值逻辑,注册失败时返回错误码便于调试。
  • 补充必要头文件,消除编译警告。

额外注意事项

  1. kretprobe在系统调用返回前执行处理器函数,此时系统调用已完成核心逻辑,你修改的是最终返回给用户的结果。
  2. strncpy_from_user返回值:成功时返回拷贝的字节数(不含终止符),失败时返回负数错误码。
  3. 开发时建议通过dmesg -w实时查看内核日志,快速定位问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 14:07:19