使用 kprobe 挂钩系统调用时空指针取消引用

Null pointer dereference when hooking system call with kprobe

提问人:GeoMldr 提问时间:11/2/2023 最后编辑:GeoMldr 更新时间:11/3/2023 访问量:83

问:

我一直在尝试在 Debian(内核版本 5.10.0-20-amd64)上挂钩 connect() 系统调用。尽管 kprobe 本身成功了,但我无法从 pt_regs 结构中检索 sockaddr。

我的代码如下所示:

static struct kprobe kp = {
    .symbol_name = "__x64_sys_connect",
};

static int handler_pre(struct kprobe *p, struct pt_regs *regs) {
    struct sockaddr *addr = (struct sockaddr * )(regs->si);
    if (addr->sa_family == AF_INET) {
        printk("Hurray!");
    }
   return 0;
}

static int __init my_hook_init(void) {
    kp.pre_handler = handler_pre;
    int ret = register_kprobe(&kp);
    if(ret<0) {
        printk(KERN_INFO "Kprobe failed %d\n", ret);
        return ret;
     }
     printk(KERN_INFO "Kprobe at %p\n", kp.addr);
     return 0;
}

static void __exit my_hook_exit(void) {
    unregister_kprobe(&kp);
    printk(KERN_INFO "kprobe at %p unregistered\n", kp.addr);
}

module_init(my_hook_init);
module_exit(my_hook_exit);

我得到的错误是这样的:

错误:内核空指针取消引用,地址:0000000000000002a

我做错了什么?系统调用的第二个参数不是应该存储在 64 位架构的 rsi 上吗?

c linux 内核 系统调用

评论

0赞 Gerhardh 11/2/2023
我不喜欢这些系统调用,但是盲目地取消引用任何指针而不检查似乎不是一个好主意。您不进行验证,在访问内存之前也不进行验证NULLregsaddr
0赞 GeoMldr 11/2/2023
即使在检查 regs 和 regs->si 后,错误仍然存在。我什至根据 C90 标准在两行中声明并分配了一个值给 *addr,但仍然

答:

0赞 GeoMldr 11/3/2023 #1

用 __sys_connect 替换 __x64_sys_connect 并在成功注册后启用 kprobe 后,问题就解决了(至少在系统不再崩溃的意义上)。 像这样的东西:

    static struct kprobe kp = {
    .symbol_name = "__sys_connect",
    .flags = KPROBE_FLAG_DISABLED
};

static int handler_pre(struct kprobe *p, struct pt_regs *regs) {
    struct sockaddr *addr = (struct sockaddr * )(regs->si);
    if (addr->sa_family == AF_INET) {
        printk("Hurray!");
    }
   return 0;
}

static int __init my_hook_init(void) {
    kp.pre_handler = handler_pre;
    int ret = register_kprobe(&kp);
    if(ret<0) {
        printk(KERN_INFO "Kprobe failed %d\n", ret);
        return ret;
     }
     printk(KERN_INFO "Kprobe at %p\n", kp.addr);
     enable_kprobe(&kp);
     return 0;
}

static void __exit my_hook_exit(void) {
    unregister_kprobe(&kp);
    printk(KERN_INFO "kprobe at %p unregistered\n", kp.addr);
}

module_init(my_hook_init);
module_exit(my_hook_exit);