1.内核模块概念

201 阅读10分钟

1. 内核模块概念

a.什么是内核模块

内核模块是操作系统中动态加载到内核的代码组件,用于扩展内核功能而无需重新编译或重启系统。

1. 定义与作用

  • 动态扩展内核模块允许在运行时添加或移除功能,如设备驱动、文件系统支持或网络协议。
  • 无需重启:加载模块后立即生效,避免系统停机,提升灵活性。

2. 运行环境

  • 内核空间:模块在内核态运行,直接访问硬件和核心资源,与用户程序隔离(用户态通过系统调用交互)。
  • 高权限操作:可执行底层操作(如中断处理、内存管理),但错误可能导致系统崩溃。

3. 可加载模块

可加载模块(Loadable Kernel Module, LKM)是操作系统内核的一种动态扩展机制,允许在不重新编译重启系统的前提下,将代码(如设备驱动、文件系统、网络协议等)按需加载到内核中运行。

4. 总结

内核模块是增强操作系统功能的动态组件,通过灵活加载机制支持硬件扩展和系统优化。

b. 宏&微&混合 内核

宏&微&混合内核.png

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、n
      • m:栗子obj-m += xxx.oxxx.o文件构建成模块xxx.ko
      • y:栗子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) clean
    • MAKE:是一个特殊的宏变量、代表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 authormodinfo -a my_module
-d显示模块描述(等价于 -F descriptionmodinfo -d vboxdrv
-l显示模块许可证(等价于 -F licensemodinfo -l nvidia
-p显示模块支持的参数(等价于 -F parmmodinfo -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_SYMBOLEXPORT_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

模块1more_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");

模块2more_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");

模块3more_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.cinc_mod.h生成的库,在use_inc.c中调用,编译时需需要在Makefile中指定模块依赖的源文件。

b. 多源文件&头文件构成内核模块
  • <[user_name]-objs> += *.o:指定模块依赖的源文件(多个.c文件需在此列出)
  • obj-m = [user_name].o:定义模块名称(需与生成的.ko文件一致)
  • ccflags-y += -I$(CURDIR):指令头文件路径
  • 注意事项[user_name]必须一致;

示例

源文件1mod1.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__ */

源文件2mod2.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__ */

源文件3mod3.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

免费的软件模块

  • GPL
  • GPL v2
  • GPL and additional rights
  • Dual BSD/GPL
  • Dual MIT/GPL
  • Dual MPL/GPL
  • Proprietary

闭源许可

待补充

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_MODULE0加载了未声明为 GPL 兼容的模块
TAINT_FORCED_MODULE1使用 --force 参数强制加载模块
TAINT_UNSIGNED_MODULE2加载了未签名的模块
TAINT_BAD_PAGE4内核检测到内存页错误
TAINT_HARDWARE_ERROR7硬件错误
TAINT_LIVEPATCH8加载了实时内核补丁
TAINT_CPU_OUT_OF_SPEC11检测到 CPU 超频或超出规范运行

c. 模块签名机制*

待补充

d. 模块版本控制*

待补充

e. 内核模块头文件

1. 系统预装的内核头文件路径(推荐方式)

通用路径:/usr/src/linux-headers-$(uname -r)/include/

  • 关键头文件示例
    • 模块相关linux/module.h, linux/init.h
    • 内核APIlinux/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. 使用模块机制分析内核*

待补充