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

SIGKILL信号下内核驱动模块资源销毁及泄漏问题解决

内核态驱动资源在进程被kill -9终止时的泄漏问题与修复

问题描述

已知进程被kill -9(即SIGKILL信号)终止时,用户态资源(如fd/socket)会被内核自动销毁,但内核态驱动资源的销毁方式存在疑惑,举例如下:

1. 驱动代码实现

static void *mm;
static long my_ioctl(unsigned int cmd, unsigned long arg, void *priv)
{
    switch (cmd) {
    case IOC_CREATE_RESOURCE:
        mm = kmalloc();
        break;
    case IOC_DESTROY_RESOURCE:
        kfree(mm);
        break;
    }

    // ...
}

static struct file_operations myfops = { 
    .owner = THIS_MODULE,
    .open = my_open,
    .unlocked_ioctl = my_ioctl,
};

2. 用户进程执行流程

fd = open();
ioctl(fd, IOC_CREATE_RESOURCE);
// 对资源进行操作
ioctl(fd, IOC_DESTROY_RESOURCE);
close(fd);

3. 异常场景

进程在执行第二个ioctl(销毁资源)前被kill -9终止,导致销毁资源的ioctl无法执行。

核心疑问:

  • 这种情况是否会导致第一个ioctl创建的内核态资源泄漏?
  • 该如何修复?(注:原理解为驱动无法感知kill -9操作)

问题解答

1. 资源泄漏结论

是的,当前驱动实现会导致内核态资源泄漏。原因如下:

  • 用全局变量mm存储分配的资源,仅通过主动调用IOC_DESTROY_RESOURCE才会释放;
  • 进程被kill -9终止时,内核只会自动关闭进程持有的文件描述符,但当前驱动的file_operations中没有绑定资源清理逻辑,分配的kmalloc内存不会被自动释放,最终造成泄漏。

2. 修复方案

核心思路是将资源与文件描述符(struct file)绑定,利用内核在进程退出时会调用文件对象release回调的机制,自动清理资源。具体实现步骤:

步骤1:为每个文件实例分配私有数据结构

放弃全局变量mm,在open回调中为每个struct file创建私有数据,用于存储资源指针:

// 定义私有数据结构
struct my_priv_data {
    void *mm;
};

static int my_open(struct inode *inode, struct file *file)
{
    struct my_priv_data *priv = kmalloc(sizeof(struct my_priv_data), GFP_KERNEL);
    if (!priv)
        return -ENOMEM;
    priv->mm = NULL;
    file->private_data = priv; // 将私有数据绑定到file对象
    return 0;
}

步骤2:修改ioctl逻辑,操作私有数据中的资源

static long my_ioctl(unsigned int cmd, unsigned long arg, void *priv)
{
    struct my_priv_data *my_priv = (struct my_priv_data *)priv;
    switch (cmd) {
    case IOC_CREATE_RESOURCE:
        if (!my_priv->mm) {
            my_priv->mm = kmalloc(...); // 按需分配资源
            if (!my_priv->mm)
                return -ENOMEM;
        }
        break;
    case IOC_DESTROY_RESOURCE:
        if (my_priv->mm) {
            kfree(my_priv->mm);
            my_priv->mm = NULL;
        }
        break;
    }
    // ...
    return 0;
}

步骤3:实现release回调,自动清理资源

在file_operations中添加release函数,当文件描述符被关闭(包括进程被kill -9导致的隐式关闭)时,自动释放绑定的资源:

static int my_release(struct inode *inode, struct file *file)
{
    struct my_priv_data *my_priv = (struct my_priv_data *)file->private_data;
    if (my_priv->mm) {
        kfree(my_priv->mm); // 释放未手动销毁的资源
    }
    kfree(my_priv); // 释放私有数据结构本身
    return 0;
}

static struct file_operations myfops = { 
    .owner = THIS_MODULE,
    .open = my_open,
    .unlocked_ioctl = my_ioctl,
    .release = my_release, // 添加release回调
};

补充说明

  • 进程被kill -9终止时,内核会触发进程退出流程,其中会关闭所有打开的文件描述符,对应调用每个文件对象的release回调;
  • 驱动不需要感知kill -9信号,只需利用内核的文件生命周期管理机制,就能保证资源在文件关闭时被自动清理;
  • 避免使用全局变量存储进程专属资源,否则会引发多进程访问的竞争问题,同时无法实现资源的进程级隔离清理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 22:50:33