如何在内核模块中获取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
相关产品推荐
相关产品推荐

