内核模块(.ko) 开发入门

发布时间 2023-12-20 11:30:42作者: _hong

内核模块时指的是在操作系统内核中动态加载的一段代码,它可以扩展和增强操作系统的功能。内核模块通常用于为操作系统添加新的设备驱动程序、文件系统、网络协议栈等功能。

内核模块是以二进制形式存在的(*.ko),它们被编译为对象文件,并在运行时被加载到操作系统内核中。内核模块与操作系统内核紧密耦合,可以访问内核的数据结构、函数和服务,并与操作系统的其他部分进行交互。

如何开发一个可在运行时动态加载的内核模块?下面是一个 hello world.ko 的完整实例。

1 程序实例

#include <linux/module.h>

static int hello_init(void) {
    printk(KERN_INFO "Hello, World!\n");
    return 0;
}

static void hello_exit(void) {
    printk(KERN_INFO "Goodbye, World!\n");
}

module_init(hello_init);
module_exit(hello_exit);

// 内核模块信息。以下为可选内容,不止这些,仅供参考
MODULE_AUTHOR("Hong");
MODULE_DESCRIPTION("A simple hello world module");
MODULE_VERSION("0.1");
MODULE_LICENSE("GPL");

解释:

1)必须包含的头文件:linux/module.h

2)规定初始化函数 module_init() 和退出函数 module_exit()

2 内核模块编译

使用 make 进行编译,需要提前编写好 Makefile,指定编译为一个可加载的内核模块:

# hello_kernle.ko Makefile
obj-m := hello_kernel.o

编译指令为:

make -C /usr/src/kernels/4.19.91-26.6.19.kos5.x86_64/ M=/root/makefile_test/ko_module/ modules

通常直接将编译指令编写到 Makefile 中,重写 Makefile

obj-m := hello_kernel.o

all:
    make -C /usr/src/kernels/$(shell uname -r)/ M=$(shell pwd) modules

clean:
    rm -f *.o *.ko *.mod* *.order *.symvers

执行 make,将触发 make -C /usr/src/kernels/$(shell uname -r)/ M=$(shell pwd) modules

执行 make clean,将触发 rm -f *.o *.ko *.mod* *.order *.symvers

3 加载验证内核模块

使用以下指令,操作内核模块:

# 加载内核模块
insmod hello_kernel.ko

# 列出并检索内核模块
lsmod | grep hello_kernel

# 查看内核模块信息
modinfo hello_kernel.ko

# 移除内核模块
rmmod hello_kernel

验证输出:

tail -f /var/log/message

image

4 常见问题

签名校验失败
[51418.816072] hello_kernel: loading out-of-tree module taints kernel.
[51418.816100] hello_kernel: module verification failed: signature and/or required key missing - tainting kernel

image

此问题的成因是,选择编译的内核配置项开启了内核模块签名校验功能。

解决方案:

a)手动给编写的内核模块签名(本文不采用);
b)直接关掉内核模块签名校验的配置项。

进入编译内核源码根目录下,进入配置菜单:

注意本示例的内核版本为 4.19

cd /usr/src/kernels/$(uname -r)/
make menuconfig

进入 Enable loadable module support, 关闭 Module signature verification 选项,右下角保存退出。

image

image

view .config 查看配置是否生效。

重新编译内核模块,问题解决。