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

Linux内核模块信号量down正常但up触发空指针解引用

问题根因

这个错误和file_operations缺少回调没有任何关系,未实现的文件操作回调会由VFS层做默认处理,不会触发内核崩溃。问题100%出在你的信号量初始化逻辑错误,引发了**释放后使用(UAF)**和信号量内部数据结构损坏。


错误原因拆解

  • 信号量初始化的错误写法
    你当前的信号量初始化代码做了完全无意义的动态分配+浅拷贝:

    struct semaphore *sema;
    sema = kmalloc(sizeof(struct semaphore), GFP_KERNEL);
    sema_init(sema, 1);
    my_device->sem = *sema;
    // 大概率你在这之后调用了kfree(sema),这是直接诱因
    

    内核中struct semaphore内部不是纯值类型,它包含一个自旋锁、一个计数器、一个等待队列链表头wait_list。sema_init初始化你kmalloc出的信号量时,会把wait_list的next/prev指针设置为指向这个kmalloc出来的信号量自身的wait_list成员。
    你通过结构体赋值把信号量浅拷贝到my_device->sem时,只会拷贝结构体内容,不会修正wait_list的指针——也就是说my_device->sem.wait_list的两个指针仍然指向你之前kmalloc的临时内存地址,而不是my_device里嵌入的信号量自己的wait_list。

  • 为什么down操作正常、up操作崩溃

    • 第一次调用down/down_interruptible时,信号量计数器初始值为1,操作只需要把计数器减为0就直接返回,完全不会触碰等待队列链表,所以即使wait_list指针是错的,也不会触发异常。
    • 如果你在拷贝完信号量后调用了kfree(sema),那块临时kmalloc的内存会被内核回收,可能被其他数据覆写,导致wait_list的链表指针变成垃圾值。当你调用up时,内核需要检查等待队列上是否有需要唤醒的睡眠进程,会访问这个已经被破坏的wait_list链表:遍历被污染的链表时会拿到非法的等待项结构,从中读出的task_struct指针为NULL,之后调用wake_up_process(NULL)时,需要访问task_struct里偏移为0x7a4的锁成员,正好触发你看到的NULL pointer dereference at virtual address 00000000000007a4报错,和你提供的调用栈完全吻合。

修复方法

删掉所有无意义的信号量动态分配逻辑,直接初始化嵌入在MyDev结构体里的信号量即可:

// 删掉原来的kmalloc、指针赋值相关代码,直接写这一句
sema_init(&my_device->sem, 1);

这种写法会让sema_init直接正确初始化设备结构体内嵌信号量的所有成员,wait_list的指针会指向自身,不存在浅拷贝、内存泄漏、野指针问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 06:27:25