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

如何在内核模块中获取Linux发行版或操作系统名称

在Linux内核模块中获取发行版名称的两种方案

方案1:读取内核原生的linux_proc_banner变量(对应/proc/version)

/proc/version的内容直接来自内核全局变量linux_proc_banner,该变量已通过EXPORT_SYMBOL_GPL导出,可在GPL兼容的内核模块中直接访问,无需手动解析proc文件系统。

示例代码

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>

// 声明内核导出的版本横幅变量
extern const char linux_proc_banner[];

static int __init distro_init(void) {
    printk(KERN_INFO "=== /proc/version 内容 ===\n");
    printk(KERN_INFO "%s", linux_proc_banner);

    // 自定义解析逻辑:提取发行版关键词
    const char *ubuntu_str = strstr(linux_proc_banner, "Ubuntu");
    const char *rhel_str = strstr(linux_proc_banner, "Red Hat");
    if (ubuntu_str)
        printk(KERN_INFO "检测到发行版:Ubuntu\n");
    else if (rhel_str)
        printk(KERN_INFO "检测到发行版:Red Hat Enterprise Linux\n");
    else
        printk(KERN_INFO "无法识别发行版\n");

    return 0;
}

static void __exit distro_exit(void) {
    printk(KERN_INFO "发行版检测模块已卸载\n");
}

module_init(distro_init);
module_exit(distro_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("通过linux_proc_banner检测发行版");

注意事项

  • 模块必须声明MODULE_LICENSE("GPL"),否则无法访问GPL导出的变量。
  • 不同发行版的linux_proc_banner包含的关键词不同,需根据需求调整字符串匹配逻辑。

方案2:通过call_usermodehelper执行用户态命令

如果需要更精准的发行版信息(比如从/etc/os-release或lsb_release获取),可以用call_usermodehelper触发用户态进程执行命令,再读取输出结果。

示例代码(读取/etc/os-release)

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/uaccess.h>
#include <linux/err.h>
#include <linux/umh.h>
#include <linux/string.h>

#define TMP_OUTPUT "/tmp/distro_tmp.out"

static int __init distro_init(void) {
    int ret;
    struct subprocess_info *sub_info;
    struct file *fp;
    loff_t pos = 0;
    char buf[512];
    ssize_t read_bytes;

    // 构造命令:将/etc/os-release输出写入临时文件
    char *argv[] = {
        "/bin/sh",
        "-c",
        "cat /etc/os-release > " TMP_OUTPUT,
        NULL
    };
    char *envp[] = {
        "HOME=/",
        "PATH=/sbin:/bin:/usr/sbin:/usr/bin",
        NULL
    };

    // 初始化并执行用户态命令,等待执行完成
    sub_info = call_usermodehelper_setup(argv[0], argv, envp, GFP_KERNEL, NULL, NULL, NULL);
    if (!sub_info) {
        printk(KERN_ERR "初始化用户态助手失败\n");
        return -ENOMEM;
    }
    ret = call_usermodehelper_exec(sub_info, UMH_WAIT_PROC);
    if (ret != 0) {
        printk(KERN_ERR "执行用户态命令失败,返回值:%d\n", ret);
        return ret;
    }

    // 读取临时文件内容
    fp = filp_open(TMP_OUTPUT, O_RDONLY, 0);
    if (IS_ERR(fp)) {
        printk(KERN_ERR "打开临时文件失败,错误码:%ld\n", PTR_ERR(fp));
        return PTR_ERR(fp);
    }

    printk(KERN_INFO "=== /etc/os-release 内容 ===\n");
    while ((read_bytes = kernel_read(fp, buf, sizeof(buf)-1, &pos)) > 0) {
        buf[read_bytes] = '\0';
        printk(KERN_INFO "%s", buf);

        // 解析PRETTY_NAME字段
        char *pretty_name = strstr(buf, "PRETTY_NAME=\"");
        if (pretty_name) {
            pretty_name += strlen("PRETTY_NAME=\"");
            char *end = strchr(pretty_name, '\"');
            if (end) *end = '\0';
            printk(KERN_INFO "识别到发行版:%s\n", pretty_name);
        }
    }

    // 清理资源
    filp_close(fp, NULL);
    // 删除临时文件
    argv[2] = "rm -f " TMP_OUTPUT;
    sub_info = call_usermodehelper_setup(argv[0], argv, envp, GFP_KERNEL, NULL, NULL, NULL);
    if (sub_info) {
        call_usermodehelper_exec(sub_info, UMH_WAIT_PROC);
    }

    return 0;
}

static void __exit distro_exit(void) {
    printk(KERN_INFO "发行版检测模块已卸载\n");
}

module_init(distro_init);
module_exit(distro_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("通过用户态助手检测发行版");

注意事项

  • 使用UMH_WAIT_PROC确保内核等待用户态进程执行完毕,避免读取空文件。
  • 临时文件需选择内核有权限访问的路径,执行后建议删除避免残留。
  • 若目标系统没有/etc/os-release,可替换命令为lsb_release -d或cat /etc/redhat-release等。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 06:20:53