背景
工作中经常遇到驱动相关问题,之前对驱动开发也是现学现买。准备系统接触linux驱动驱动和kernel,刚开始主要熟悉linxu驱动框架,不涉及相关硬件(后续可能会学习ARM或RISC-V)。打算在自己的主机上编译kernel模块,直接调试加载。
环境
- ununtu 24.04
- kernel版本
$ uname -r
6.8.0-31-generic
源码和分析
第一个简单的驱动以hello.c命令,代码中只有module init和module exit.
#include <linux/module.h>
#include <linux/cdev.h>
int hello_init(void)
{
printk("hello world! init.\n");
return 0;
}
void hello_exit(void)
{
printk("hello world! exit.\n");
return;
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
下面是一个简单的Makefile文件,kernel模块编译需要用到linux的头文件.
obj-m := hello.o
KERNELDIR := /usr/src/linux-headers-6.8.0-31-generic
all default:modules
install:modules_install
modules modules_install help clean:
$(MAKE) -C $(KERNELDIR) M=$(shell pwd) $@
make后生成hello.ko,使用insmod导入,出现错误。
$ sudo insmod hello.ko
insmod: ERROR: could not insert module hello.ko: Key was rejected by service
dmesg日志,可以通过另一个终端打开dmesg,命令:dmesg -wH
[Apr30 15:22] Loading of unsigned module is rejected
以上,insmod失败是由于hello.ko没有签名,被拒绝加载。
生成密钥
创建一个 X.509 密钥对(公钥和相应的密钥)以用作 MOK。
- 创建一个OpenSSL 配置文件,例如
~/x509.genkey
[ req ]
default_bits = 4096
distinguished_name = req_distinguished_name
prompt = no
x509_extensions = mode_exts
[ req_distinguished_name ]
CN = kernel module test
emailAddress = linxuew@gmail.com
[ mode_exts ]
basicConstraints=critical,CA:FALSE
keyUsage=digitalSignature
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid
该CN =
行定义了 MOK 主要可识别的名称,因此请在其中输入想要的任何内容。
- 创建密钥对
openssl req -x509 -new -nodes -utf8 -sha256 -days 36500 \
-batch -config x509.genkey -outform DER \
-out signing_key.x509 \
-keyout signing_key.priv
现在你应该有两个文件:
signing_key.x509
是公钥,将其注册为 MOK(机器所有者密钥)signing_key.priv
相应的私钥,用于签署自己构建的模块。
- 确保已经安装
mokutil
,然后运行下面命令注册。
sudo mokutil --import signing_key.x509
输入以上命令完成MOK注册的第一阶段。要完成MOK注册,需要重启电脑(重启后进入蓝屏,此时蓝屏很正常)。选择 Enroll MOK
,在提示时输入之前与此请求关联的密码,并确认注册。
此时该公钥永久添加到MOK,后续可以使用该密钥签名kernel模块在ubuntu主机上调试。
hello.ko签名并运行
- 签名
/usr/src/linux-headers-6.8.0-31-generic/scripts/sign-file sha256 \
../keys/signing_key.priv ../keys/signing_key.x509 hello.ko
- 使用insmod和rmmod加载、卸载模块,在dmesg中看到相应打印。
[Apr30 16:15] hello world! init.
[ +3.253135] hello world! exit.
参考
https://docs.kernel.org/admin-guide/module-signing.html