1. 内核模块概念
a.什么是内核模块
内核模块是操作系统中动态加载到内核的代码组件,用于扩展内核功能而无需重新编译或重启系统。
1. 定义与作用
- 动态扩展:内核模块允许在运行时添加或移除功能,如设备驱动、文件系统支持或网络协议。
- 无需重启:加载模块后立即生效,避免系统停机,提升灵活性。
2. 运行环境
- 内核空间:模块在内核态运行,直接访问硬件和核心资源,与用户程序隔离(用户态通过系统调用交互)。
- 高权限操作:可执行底层操作(如中断处理、内存管理),但错误可能导致系统崩溃。
3. 可加载模块
可加载模块(Loadable Kernel Module, LKM)是操作系统内核的一种动态扩展机制,允许在不重新编译或重启系统的前提下,将代码(如设备驱动、文件系统、网络协议等)按需加载到内核中运行。
4. 总结
内核模块是增强操作系统功能的动态组件,通过灵活加载机制支持硬件扩展和系统优化。
b. 宏&微&混合 内核
1. 宏内核
核心理念:
- 高度集成:所有核心功能(进程管理、内存管理、文件系统、设备驱动等)均运行在内核空间,共享同一地址空间,通过直接函数调用交互
- 高性能:服务调用无需跨进程通信(IPC),延迟极低(纳秒级),适合实时性要求高的场景
- 模块化有限:虽然支持动态加载内核模块(LKM),但整体代码紧密耦合,扩展性较差
典型应用:Linux、早期VxWorks
2. 微内核
核心理念:
- 最小化内核:仅保留核心功能(进程调度、内存管理、IPC),其他服务(文件系统、驱动等)作为用户态进程运行
- 消息传递机制:服务间通过IPC通信,隔离性强但可能引入性能开销
- 模块化设计:服务可独立加载/卸载,提升系统灵活性和安全性
典型应用:QNX、HarmonyOS
3. 混合内核
核心理念:
- 折中设计:结合宏内核的高效性与微内核的隔离性,部分核心服务运行于内核态,非关键服务移至用户态
- 性能与安全平衡:例如将文件系统、网络协议栈保留在内核空间,而驱动或部分服务以用户态进程运行
典型应用:Windows NT、macOS
2.内核模块构成
a. 内核模块构成
1)核心
a. 头文件
内核专用头文件主要位于kernel/include/linux/*
和CPU架构相关kernel/arch/$(ARCH)/include/*
linux/module.h- 提供模块相关的API接口
linux/init.h- 初始化,清理相关接口
b. 加载/卸载宏
宏所在头文件是linux/module.h;
-
#define module_init(x) __initcall(x);- 指定模块函数入口,主要完成模块初始化工作
- 模块入口函数:
int __init func_init(void);- 功能:模块被加载动内核时,入口函数自动被内核执行,模块入口函数使用
__init声明 - 函数参数:
void - 返回值类型:
int一般返回errno,可根据perror()进行解析 - 使用:
module_init(func_init)
- 功能:模块被加载动内核时,入口函数自动被内核执行,模块入口函数使用
-
#define module_exit(x) __exitcall(x);- 指定模块卸载函数入口,主要完成模块资源释放和模块的卸载
- 模块退出函数:
void __exit func_exit(void);- 功能:模块在退出时自动调用,退出函数使用
__exit声明 - 函数参数:
void - 返回值类型:
void - 使用:
module_exit(func_exit)
- 功能:模块在退出时自动调用,退出函数使用
c. 许可声明
宏所在头文件是linux/module.h;
#define MODULE_LICENSE(_license) MODULE_FILE MODULE_INFO(license, _license)- 功能:标注模块许可类型
- 宏参数:开源许可协议类型的字符串
- 使用:
MODULE_LICENSE("GPL");
d. 最简内核结构
simplemod.c
#include <linux/module.h>
#include <linux/init.h>
static int __init simplemod_init(void) {
return 0;
}
static void __exit simplemod_exit(void) {
}
module_init(simplemod_init); // 模块初始化函数
module_exit(simplemod_exit); // 模块退出函数
MODULE_LICENSE("GPL");
Makefile
ARCH=arm64 # 架构
CROSS_COMPILE=aarch64-none-linux-gnu- # 交叉编译工具
obj-m += simplemod.o # 模块
KDIR := /project/mycode/rockchip-sdk/kernel # 内核源码路径
.PTHONY:
all clean
# 编译
all:
$(MAKE) -C $(KDIR) M=$(CURDIR) modules
# 清除
clean:
$(MAKE) -C $(KDIR) M=$(CURDIR) clean
2)模块描述信息
宏所在头文件是linux/module.h;
描述信息会通过modinfo 命令显示,帮助用户了解模块的用途。
a. 模块作者
#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author)
- 功能:声明内核模块的作者
- 宏参数类型:字符串
- 使用:
MODULE_AUTHOR("ah@email");
b. 描述信息
#define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description)
- 功能:提供模块的简要说明,方便其他开发者或用户理解模块的用途
- 宏参数类型:字符串
- 使用:
MODULE_DESCRIPTION("This is description");
c. 模块起别名
#define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias)
- 功能:为模块定义一个别名
- 宏参数类型:字符串
- 使用:
MODULE_ALIAS("zhf");
d. 模块依赖关系
#define MODULE_SOFTDEP(_softdep) MODULE_INFO(softdep, _softdep)
- 功能:告知模块依赖关系
- 宏参数类型:字符串
- 使用:
MODULE_SOFTDEP("pre: module-foo post: module-baz");
e. 模块版本号
#define MODULE_VERSION(_version) MODULE_INFO(version, _version)
- 功能:定义模块的版本
- 宏参数类型:字符串
- 使用:
MODULE_VERSION("1.0");
b. 模块相关操作
1)如何编译
a. 源码外-编译成模块
编译Linux内核模块的makefile
ARCH=arm64 # 架构
CROSS_COMPILE=aarch64-none-linux-gnu- # 交叉编译工具
obj-m += simplemod.o # 模块
KDIR := /project/mycode/rockchip-sdk/kernel # 内核源码路径
.PTHONY:
all clean
# 编译
all:
$(MAKE) -C $(KDIR) M=$(CURDIR) modules
# 清除
clean:
$(MAKE) -C $(KDIR) M=$(CURDIR) clean
核心内容介绍(编译内核模块的最小make指令):
obj-<X>:编译过程中,程序会被编译为xxx.o文件,在根据<X>可选参数将xxx.o文件构建或链接成制定的文件。obj-:指定某个文件或目录是构建过程中的一个中间目标<X>:可取值y、m、nm:栗子obj-m += xxx.o将xxx.o文件构建成模块xxx.koy:栗子obj-y += xxx.o,将xxx.o编译进内核n:栗子obj-n += xxx.o
- 另一种用法:
obj-<X> += dir/接目录
$(MAKE) -C $(KDIR) M=$(CURPWD) modules$(MAKE) -C $(KDIR) M=$(CURPWD) cleanMAKE:是一个特殊的宏变量、代表make本身;使用MAKE变量有几个好处:a.可移植性;b.递归调用;c.选项传递-C $(KDIR):-C是change director,如含义-C $(KDIR)指向make跳转到KDIR目录下,KDIR是一个变量,记录路径,该路径一般写内核源码路径M=$(CURDIR):M用于指定将编译的模块源码路径,CURDIR是makefile中的一个宏变量,不赋值则只想当前目录的绝对路径modules:编译成xxx.ko模块clean:清除由make生成的文件
b. 源码内-编译成模块
详细描述见Kconfig子系统
c. 编译进内核
详细描述见Kconfig子系统
2)操作指令
a. 加载:insmod
含义:加载模块
指令格式:insmod filename
b. 查看已加载模块:lsmod
含义:列出加载的内核模块
指令格式:lsmod
c. 查看模块信息:modinfo
含义:模块信息
指令格式:modinfo [options] filename [args]
| 参数 | 作用 | 示例 |
|---|---|---|
| 无参数 | 显示模块的所有元信息(作者、描述、许可证、依赖等) | modinfo ext4 |
-a | 显示模块作者信息(等价于 -F author) | modinfo -a my_module |
-d | 显示模块描述(等价于 -F description) | modinfo -d vboxdrv |
-l | 显示模块许可证(等价于 -F license) | modinfo -l nvidia |
-p | 显示模块支持的参数(等价于 -F parm) | modinfo -p e1000 |
-n | 显示模块的文件路径 | modinfo -n ext4 |
-0 | 使用 \0(空字符)分隔输出字段,便于脚本解析 | modinfo -0 -F version my_module |
-F <字段> | 指定要显示的字段(支持 author, description, license, vermagic 等) | modinfo -F version iwlwifi |
-k <内核版本> | 指定要查询的内核版本(需模块路径包含该版本) | modinfo -k 5.15.0-86-generic /path/to/module.ko |
--set-version <版本> | 强制指定内核版本(覆盖自动检测) | modinfo --set-version=5.15.0-86-generic my_module |
d. 卸载:rmmod
含义:卸载模块
指令格式:rmmod [options] modulename ...
| 参数 | 作用 | 示例 |
|---|---|---|
| 无参数 | 直接卸载模块 | rmmod modulename |
-f | 强制卸载模块 | rmmod -f modulename |
-w | 等待模块使用计数归零后自动卸载 | rmmod -w modulename |
-a | 移除所有未使用的模块 | rmmod -a |
-v | 显示版本 | rmmod -v |
e. modprobe
含义:智能管理内核模块的命令
指令格式:modprobe [options] MODULE [SYMBOL=VALUE]...
| 参数 | 作用 | 示例 |
|---|---|---|
-a | 加载多个模块 | modprobe -a mod1 mod2 |
-l | 列表 | modprobe -l |
-r | 卸载模块(递归移除依赖) | modprobe -r mod1 |
-v | 显示详细操作信息(调试模式) | modprobe -v |
f. 查看日志:dmesg
含义:查看内核日志
指令格式:dmesg [options]
| 参数 | 作用 | 示例 |
|---|---|---|
| 无参数 | 显示日志 | dmesg |
-c | 清空内核日志 | dmesg -c |
-n LEVEL | 设置日志等级 | dmesg -n 5 |
-s SIZE | 设置日志大小 | dmesg -s 10 |
-r | 打印内存中的日志信息 | dmesg -r |
c. 其他
1)模块传参
在内核模块开发中,传递参数允许用户在加载模块时动态配置其行为(如调整调试级别、设置硬件地址、指定缓冲区大小等)。Linux 内核提供了一套灵活的机制来定义、接收和验证参数。
a. 传参类型
| 类型 | 数据 |
|---|---|
| 基本类型 | bool,char,byte,ushort,short,uint,int,long |
| 数组类型 | array |
| 字符串类型 | string |
b. 模块宏
模块宏主要在linux/moduleparam.h目录下
-
module_param(name,type,perm);- 模块参数
- 宏函数参数:
name:要传递给代码中的变量名字type:参数类型perm:参数读写权限
-
module_param_array(name,type,nump,perm);- 模块数组参数
- 宏函数参数:
name:要传递给代码中的变量名字type:数组参数类型nump:数组长度perm:参数读写权限
-
module_param_string(name,string,len,perm);- 字符串参数
- 宏函数参数:
name:要传递给代码中的变量名字string:驱动程序中变量的名字len:字符串大小perm:参数读写权限
-
MODULE_PARM_DESC(_parm,"desc")- 模块参数添加描述信息
- 宏函数参数:
_parm:要描述的参数名desc:描述信息
c. 权限
权限主要在/sys/module/<模块>/parameters/下文件权限(如0644)。
示例:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/moduleparam.h> // 模块传参需要包含的头文件
#define MODULE_ARR_SIZE 2
#define MODULE_STR_SIZE 10
// 加载参数
static int i32ModeleArrSize = 0;
static int i32ModuleID = 0;
static int Arr[MODULE_ARR_SIZE];
static int sName[MODULE_STR_SIZE];
/* 基本数据类型 */
module_param(i32ModuleID, int, S_IRUGO);
MODULE_PARM_DESC(i32ModuleID, "e.g: ID号");
/* 数组类型 */
module_param_array(Arr, int, &i32ModeleArrSize, S_IRUGO);
MODULE_PARM_DESC(Arr, "e.g: 1,2");
/* 字符串类型 */
module_param_string(sName, (char *)sName, sizeof(sName), S_IRUGO);
MODULE_PARM_DESC(sName, "e.g: Name");
static int param_init(void)
{
printk("进入param !!!\n");
printk("ModuleID:%d Name:%s Arr:%d %d\n", i32ModuleID, (char *)sName, Arr[0], Arr[1]);
return 0;
}
static void param_exit(void)
{
printk("退出param !!!\n");
}
module_init(param_init);
module_exit(param_exit);
MODULE_LICENSE("GPL"); // 协议
MODULE_AUTHOR("zhf"); // 开发用户信息
2)Makefile编译流程*
待补充
3)内核符号表
内核符号表是一个存储内核及模块中导出符号(函数、变量)的数据结构,包含符号名称、内存地址、类型及属性等信息。
- 导出宏:
EXPORT_SYMBOL(sym):导出符号供所有模块使用EXPORT_SYMBOL_GPL(sym):仅限GPL兼容模块使用
- 编译:
KBUILD_EXTRA_SYMBOLS是 Linux 内核模块编译时的一个关键环境变量,用于解决模块间符号依赖问题。当模块 B 需要使用模块 A 导出的函数或变量(通过EXPORT_SYMBOL或EXPORT_SYMBOL_GPL导出)时,需通过该变量指定模块 A 的符号表文件路径,确保编译模块 B 时能正确解析符号引用。- 在
Makefile中加入KBUILD_EXTRA_SYMBOLS += $(PATH) export KBUILD_EXTRA_SYMBOLS
- 在
示例
导出符号表模块文件export_mod.c
#include <linux/module.h>
#include <linux/init.h>
int g_export_var = 0;
void export_var_add(void) {
g_export_var += 2;
}
void export_var_sub(void) {
g_export_var -= 2;
}
EXPORT_SYMBOL(g_export_var); /* 导出全局变量 */
EXPORT_SYMBOL(export_var_add); /* 导出操作接口 */
EXPORT_SYMBOL(export_var_sub); /* 导出操作接口 */
static int __init export_mod_init(void) {
printk("g_export_var %d\n", g_export_var);
return 0;
}
static void __exit export_mod_exit(void) {
printk("g_export_var %d\n", g_export_var);
}
module_init(export_mod_init);
module_exit(export_mod_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ah");
编译内核符号表的Makefile
ARCH=arm64
CROSS_COMPILE=aarch64-none-linux-gnu-
obj-m += export_mod.o
KDIR := /project/mycode/rockchip-sdk/kernel # 内核源码路径
.PTHONY:
all clean
# 编译
all:
$(MAKE) -C $(KDIR) M=$(CURDIR) modules
# 清除
clean:
$(MAKE) -C $(KDIR) M=$(CURDIR) clean
调用模块符合表文件use_mod.c
#include <linux/module.h>
#include <linux/init.h>
// 需要声明一下
extern int g_export_var;
extern void export_var_add(void);
extern void export_var_sub(void);
static int __init use_mod_init(void) {
export_var_add();
printk("g_export_var:%d\n", g_export_var);
return 0;
}
static void __exit use_mod_exit(void) {
export_var_sub();
printk("g_export_var:%d\n", g_export_var);
}
module_init(use_mod_init)
module_exit(use_mod_exit)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ah");
编译时需要指定符号表路径,Makefile文件如下
ARCH=arm64
CROSS_COMPILE=aarch64-none-linux-gnu-
obj-m += use_mod.o
# EXPORT_SYMBOLS_FILE_PATH-添加导出符号文件的路径(必须是绝对路径)
EXPORT_SYMBOLS_FILE_PATH = /project/mycode/my_kernal_driver/01-kernel-mod/01-export_mod/export_mod/Module.symvers
KBUILD_EXTRA_SYMBOLS = $(EXPORT_SYMBOLS_FILE_PATH)
export KBUILD_EXTRA_SYMBOLS
KDIR := /project/mycode/rockchip-sdk/kernel # 内核源码路径
.PTHONY:
all clean
# 编译
all:
$(MAKE) -C $(KDIR) M=$(CURDIR) modules
# 清除
clean:
$(MAKE) -C $(KDIR) M=$(CURDIR) clean
生成的符号表文件内容Module.symvers,在加载时,需要先加载A,在加载B,否则B无法正常加载
0x00000000 export_var_sub /project/mycode/my_kernal_driver/01-kernel-mod/01-export_mod/export_mod/export_mod EXPORT_SYMBOL
0x00000000 g_export_var /project/mycode/my_kernal_driver/01-kernel-mod/01-export_mod/export_mod/export_mod EXPORT_SYMBOL
0x00000000 export_var_add /project/mycode/my_kernal_driver/01-kernel-mod/01-export_mod/export_mod/export_mod EXPORT_SYMBOL
实验结果:
需要先加载export_mod.ko,在加载use_mod.ko,否则会出现如下错误
insmod: can't insert 'use_mod.ko': unknown symbol in module, or unknown parameter
正常情况:
[ 2682.388716] g_export_var 0
[ 2691.069925] g_export_var:2
[ 2751.738297] g_export_var:0
[ 2755.913290] g_export_var 0
注意:若模块与模块之间存在依赖,其实还可以将两个模块放到同一个目录下,使用同一个Makefile进行编译;具体看多内核模块。
4)多内核模块
同时编译多个内核模块,并且模块间可相互调用,无需指定符号表;
示例:
目录结构:
02-more_mod/
├── Makefile
├── more_mod1.c
├── more_mod2.c
└── more_mod3.c
1 directory, 4 files
模块1:more_mod1.c
#include <linux/module.h>
#include <linux/init.h>
extern void print_more_mod2(void);
extern void print_more_mod3(void);
static int __init more_mod_init(void) {
print_more_mod2();
print_more_mod3();
return 0;
}
static void __exit more_mod_exit(void) {
}
module_init(more_mod_init)
module_exit(more_mod_exit)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ah");
模块2:more_mod2.c
#include <linux/module.h>
#include <linux/init.h>
void print_more_mod2(void) {
printk("print_more_mod:%s\n", __func__);
}
EXPORT_SYMBOL(print_more_mod2);
static int __init more_mod_init(void) {
return 0;
}
static void __exit more_mod_exit(void) {
}
module_init(more_mod_init)
module_exit(more_mod_exit)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ah");
模块3:more_mod3.c
#include <linux/module.h>
#include <linux/init.h>
void print_more_mod3(void) {
printk("print_more_mod:%s\n", __func__);
}
EXPORT_SYMBOL(print_more_mod3);
static int __init more_mod_init(void) {
return 0;
}
static void __exit more_mod_exit(void) {
}
module_init(more_mod_init)
module_exit(more_mod_exit)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ah");
编译多个内核模块及相互之间调用的Makefile,会编译出多个内核模块,且模块1依赖于模块2和3,加载时需要先加载模块2和3,在加载模块1
ARCH=arm64
CROSS_COMPILE=aarch64-none-linux-gnu-
KDIR := /project/mycode/rockchip-sdk/kernel # 内核源码路径
obj-m += more_mod1.o more_mod2.o more_mod3.o
.PTHONY:
all clean
# 编译
all:
$(MAKE) -C $(KDIR) M=$(CURDIR) modules
# 清除
clean:
$(MAKE) -C $(KDIR) M=$(CURDIR) clean
将生成的more_mod1.ko、more_mod2.ko、more_mod3.ko导入开发板,按依赖顺序依次加载more_mod2.ko、more_mod3.ko,最后加载more_mod1.ko
5)多源文件&头文件构成内核模块
a. 模块目录结构
03-inc_mod/
|-- Makefile
|-- inc_mod.c
|-- inc_mod.h
`-- use_inc.c
0 directories, 4 files
包含所需要的inc_mod.c和inc_mod.h生成的库,在use_inc.c中调用,编译时需需要在Makefile中指定模块依赖的源文件。
b. 多源文件&头文件构成内核模块
<[user_name]-objs> += *.o:指定模块依赖的源文件(多个.c文件需在此列出)obj-m = [user_name].o:定义模块名称(需与生成的.ko文件一致)ccflags-y += -I$(CURDIR):指令头文件路径- 注意事项:
[user_name]必须一致;
示例:
源文件1:mod1.c
#include <linux/module.h>
#include <linux/init.h>
void print_mod1(void) {
printk("%s\n", __func__);
}
源文件1头文件:mod1.h
#ifndef __MOD1_H__
#define __MOD1_H__
#ifdef __cplusplus
extern "C" {
#endif
extern void print_mod1(void);
#ifdef __cplusplus
}
#endif
#endif /* __MOD1_H__ */
源文件2:mod2.c
#include <linux/module.h>
#include <linux/init.h>
void print_mod2(void) {
printk("%s\n", __func__);
}
源文件2头文件:mod2.h
#ifndef __MOD2_H__
#define __MOD2_H__
#ifdef __cplusplus
extern "C" {
#endif
extern void print_mod2(void);
#ifdef __cplusplus
}
#endif
#endif /* __MOD2_H__ */
源文件3:mod3.c
#include <linux/module.h>
#include <linux/init.h>
void print_mod3(void) {
printk("%s\n", __func__);
}
源文件3头文件:mod3.h
#ifndef __MOD3_H__
#define __MOD3_H__
#ifdef __cplusplus
extern "C" {
#endif
extern void print_mod3(void);
#ifdef __cplusplus
}
#endif
#endif /* __MOD3_H__ */
模块文件:prj_mod.c
#include <linux/module.h>
#include <linux/init.h>
#include "mod1.h"
#include "mod2.h"
#include "mod3.h"
static int __init prj_mod_init(void) {
print_mod1();
print_mod2();
print_mod3();
return 0;
}
static void __exit prj_mod_exit(void) {
}
module_init(prj_mod_init)
module_exit(prj_mod_exit)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ah");
构建程序:Makefile
ARCH=arm64
CROSS_COMPILE=aarch64-none-linux-gnu-
KDIR := /project/mycode/rockchip-sdk/kernel # 内核源码路径
# 定义模块名称(需与生成的.ko文件一致)
obj-m += my_mod.o
# 指定模块依赖的源文件(多个.c文件需在此列出)
my_mod-objs := prj_mod.o mod1.o mod2.o mod3.o
# 添加头文件搜索路径(当前目录及子目录)
ccflags-y += -I$(CURDIR)
.PTHONY:
all clean
test:
@echo $(SOURCES)
# 编译
all:
$(MAKE) -C $(KDIR) M=$(CURDIR) modules
# 清除
clean:
$(MAKE) -C $(KDIR) M=$(CURDIR) clean
6)模块间依赖 & 自动加载*
3. 编译&调度 流程
待补充
4. 其他
a. ELF文件介绍*
待补充
b. 内核污染
1. 内核许可声明
用于描述内核的许可权限,模块不声明许可(LICENSE),内核会有(taints kernel)警告,新版本还会导致模块无法正常编译;
2. 开源协议类型
可以在MODULE_LICENSE()的定义处查看当前定义的开源协议,头文件为include/module.h;
免费的软件模块
GPLGPL v2GPL and additional rightsDual BSD/GPLDual MIT/GPLDual MPL/GPLProprietary
闭源许可
待补充
3. 内核污染
定义:加载一些不开源跟GPL不兼容的驱动许可或错误的填写了许可时,会导致内核被污染,此时一些调试功能,输出,系统API调用会失效;
示例:
#include <linux/module.h>
#include <linux/init.h>
static int __init simplemod_init(void) {
return 0;
}
static void __exit simplemod_exit(void) {
}
module_init(simplemod_init) // 模块初始化函数
module_exit(simplemod_exit) // 模块退出函数
MODULE_LICENSE("zhf");
将该模块编译加载到内核中会出现如下打印
[ 120.773340] simplemod: module license 'zhf' taints kernel.
[ 120.773430] Disabling lock debugging due to kernel taint
很显然,当前内核模块已经被污染了
查看内核污染原因
内核污染(Kernel Tainting)是 Linux 内核通过设置 TAINT_* 标记来记录系统处于非标准或潜在风险状态的机制。污染状态通过 /proc/sys/kernel/tainted 文件的值表示(每个比特位对应一种污染原因)
| 宏 | Bit位 | 触发条件 |
|---|---|---|
TAINT_PROPRIETARY_MODULE | 0 | 加载了未声明为 GPL 兼容的模块 |
TAINT_FORCED_MODULE | 1 | 使用 --force 参数强制加载模块 |
TAINT_UNSIGNED_MODULE | 2 | 加载了未签名的模块 |
TAINT_BAD_PAGE | 4 | 内核检测到内存页错误 |
TAINT_HARDWARE_ERROR | 7 | 硬件错误 |
TAINT_LIVEPATCH | 8 | 加载了实时内核补丁 |
TAINT_CPU_OUT_OF_SPEC | 11 | 检测到 CPU 超频或超出规范运行 |
c. 模块签名机制*
待补充
d. 模块版本控制*
待补充
e. 内核模块头文件
1. 系统预装的内核头文件路径(推荐方式)
通用路径:/usr/src/linux-headers-$(uname -r)/include/
- 关键头文件示例:
- 模块相关:
linux/module.h,linux/init.h - 内核API:
linux/kernel.h,linux/fs.h,linux/device.h - 内存管理:
linux/slab.h,linux/vmalloc.h
- 模块相关:
2. 内核源代码中的头文件路径
- 根目录下的:
kernel-source/include/* - 架构相关:
kernel-source/arch/<ARCH>/include/*
3. 多文件编译时头文件包含
e. 使用模块机制分析内核*
待补充