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

Linux内核模块调用strstr检测指定路径打开文件夹时系统崩溃求助

问题排查与解决方案

1 崩溃原因说明

首先明确:Linux内核原生提供strstr()函数(定义在<linux/string.h>),本身可以在内核模块中正常使用,你的崩溃是代码其他逻辑错误导致的,核心问题如下:

  • kmalloc参数顺序写反
    内核kmalloc的函数原型为void *kmalloc(size_t size, gfp_t flags),你当前传入的kmalloc(GFP_KERNEL,100*sizeof(char))完全颠倒了参数顺序,实际是请求分配数值等于GFP_KERNEL(通常为0xCC0)大小的内存,分配标志用错误的100,大概率返回NULL或者非法地址,后续d_path写入buf时直接访问非法内存触发崩溃。
  • 访问cwd前未做错误指针校验
    d_path执行失败时返回的是ERR_PTR类型的错误指针(比如路径长度超过buf长度时返回ERR_PTR(-ENAMETOOLONG)),这类指针的值不是NULL,你的if(cwd)判断完全无效,把错误指针传给strstr就会触发非法地址访问。
  • 遍历fdtable时越界访问
    你直接用while(fdt->fd[i] != NULL)遍历fd数组,没有判断i < fdt->max_fds,很容易超出fd数组的实际长度访问野指针,触发崩溃。
  • 遍历内核动态结构未加锁
    for_each_process遍历进程列表、访问进程的files结构体和fdtable时,必须持有对应的锁(比如RCU读锁),否则遍历过程中数据结构被其他CPU修改/释放,就会触发野指针访问。
  • 没有检查buf分配结果
    你没有判断kmalloc的返回值是否为NULL,分配失败时后续写入直接崩溃。

2 修复后的实现方案

2.1 基础修复代码

#include <linux/module.h>
#include <linux/sched.h>
#include <linux/fdtable.h>
#include <linux/dcache.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/rcupdate.h>

static int __init path_check_init(void)
{
    struct task_struct *task_list;
    struct fdtable *fdt = NULL;
    struct path files_path;
    char *cwd;
    const char *myPath = "/home/anh/src/";
    size_t myPath_len = strlen(myPath);
    char *buf;
    char *ret;

    // 修正kmalloc参数顺序,分配PAGE_SIZE大小的buf避免路径过长
    buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
    if (!buf) {
        printk(KERN_ERR "buf alloc failed\n");
        return -ENOMEM;
    }

    // 遍历进程前加RCU读锁
    rcu_read_lock();
    for_each_process(task_list) {
        struct files_struct *files = get_files_struct(task_list);
        if (!files)
            continue;
        
        spin_lock(&files->file_lock);
        fdt = files_fdtable(files);
        // 遍历fd带上限判断避免越界
        for (unsigned int i = 0; i < fdt->max_fds; i++) {
            if (!fdt->fd[i])
                continue;
            files_path = fdt->fd[i]->f_path;
            cwd = d_path(&files_path, buf, PAGE_SIZE);
            // 校验cwd是合法指针再操作
            if (!IS_ERR(cwd)) {
                // 你的需求是路径前缀匹配,用strncmp比strstr更高效,也不会匹配到路径中间的字段
                if (strncmp(cwd, myPath, myPath_len) == 0) {
                    printk(KERN_INFO "Open file with fd %d  path: %s", i, cwd);
                }
                // 如果一定要用strstr也可以,确认引入<linux/string.h>即可
                // ret = strstr(cwd, myPath);
                // if (ret) {
                //     printk(KERN_INFO "Open file with fd %d  path: %s", i, cwd);
                // }
            }
        }
        spin_unlock(&files->file_lock);
        put_files_struct(files);
    }
    rcu_read_unlock();

    kfree(buf);
    return 0;
}

static void __exit path_check_exit(void)
{
    printk(KERN_INFO "module exit\n");
}

module_init(path_check_init);
module_exit(path_check_exit);
MODULE_LICENSE("GPL");

2.2 字符串包含校验的替代方案

如果确实需要判断字符串包含关系,除了直接用内核原生的strstr(),也可以根据场景选择更适配的函数:

  • 前缀匹配:用strncmp(),如上面示例代码,性能更高,不会出现误匹配
  • 后缀匹配:用strends()(部分内核版本支持)或者自行实现后向比较逻辑
  • 任意位置匹配:直接用内核原生strstr(),确保引入<linux/string.h>头文件即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 15:36:06