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
相关产品推荐
相关产品推荐

