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

内核模块访问task->mm->pgd致系统无响应的原因及解决方法

问题原因与解决方法

问题原因

  1. 缺少进程链表并发保护:内核的task_struct进程链表是全局共享资源,进程创建、退出、调度等操作会在多CPU环境下并发修改链表。直接通过for_each_process遍历而不持有tasklist_lock自旋锁,会导致遍历过程中链表结构被破坏,触发非法内存访问或死锁,最终系统失去响应。
  2. mm结构访问存在竞态:即使判断了p->mm != NULL,在多核心场景下,目标进程可能正处于退出销毁流程,mm结构随时可能被释放,此时访问p->mm->pgd会触发野指针访问,引发系统崩溃。

解决方法

1. 增加进程链表锁保护

遍历进程链表时必须持有tasklist_lock自旋锁,保证遍历过程中链表结构不会被并发修改:

  • 进程上下文(如模块函数调用):使用read_lock/read_unlock(遍历属于读操作,无需写锁)
  • 中断上下文:使用read_lock_irqsave/read_unlock_irqrestore,关闭本地中断并保存状态

2. 安全访问mm结构

通过引用计数或读写锁保证mm结构的稳定性:

  • 调用get_task_struct(p)增加进程引用计数,防止进程在访问期间被销毁,访问完成后用put_task_struct(p)释放引用
  • 对于用户态进程(p->mm != NULL),持有mm->mmap_sem读锁,避免mm结构被并发修改

修改后的代码示例

#include <linux/sched/signal.h>
#include <linux/sched.h>
#include <linux/mm.h>

void testFunc(void)
{
    struct task_struct *p;

    printk(KERN_INFO "testFunc\n");

    pid_t pid = current->pid;
    // 安全访问当前进程的pgd
    if (current->mm && current->mm->pgd) {
        down_read(&current->mm->mmap_sem);
        printk(KERN_INFO "current PID - %d, pgd %px\n", pid, current->mm->pgd);
        up_read(&current->mm->mmap_sem);
    }

    // 持有进程链表读锁,保护遍历流程
    read_lock(&tasklist_lock);
    for_each_process(p)
    {
        get_task_struct(p); // 增加进程引用,防止遍历中进程被销毁
        printk(KERN_INFO "pid - %d\tpname - %s\n", p->pid, p->comm);
        
        if (p->mm && p->mm->pgd) {
            // 持有mmap_sem读锁,保护mm结构不被并发修改
            down_read(&p->mm->mmap_sem);
            printk(KERN_INFO "pgd: %px\n", p->mm->pgd);
            up_read(&p->mm->mmap_sem);
        }

        put_task_struct(p); // 释放进程引用
    }
    read_unlock(&tasklist_lock);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 23:50:33