背景

工作中经常遇到驱动相关问题,之前对驱动开发也是现学现买。准备系统接触linux驱动驱动和kernel,刚开始主要熟悉linxu驱动框架,不涉及相关硬件(后续可能回学习ARM或RISC-V)。打算在自己的主机上编译kernel模块,直接调试加载。

环境

  • ununtu 24.04
  • kernel版本
1
2
$ uname -r
6.8.0-31-generic

源码和分析

第一个简单的驱动以hello.c命令,代码中只有module init和module exit.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#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的头文件.

1
2
3
4
5
6
7
8
9
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导入,出现错误。

1
2
$ sudo insmod hello.ko
insmod: ERROR: could not insert module hello.ko: Key was rejected by service

dmesg日志,可以通过另一个终端打开dmesg,命令:**dmesg -wH**

1
[Apr30 15:22] Loading of unsigned module is rejected

以上,insmod失败是由于hello.ko没有签名,被拒绝加载。

生成密钥

创建一个 X.509 密钥对(公钥和相应的密钥)以用作 MOK。

  1. 创建一个OpenSSL 配置文件,例如~/x509.genkey
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[ 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 主要可识别的名称,因此请在其中输入想要的任何内容。

  1. 创建密钥对
1
2
3
4
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相应的私钥,用于签署自己构建的模块。
  1. 确保已经安装mokutil,然后运行下面命令注册。
1
sudo mokutil --import signing_key.x509

输入以上命令完成MOK注册的第一阶段。要完成MOK注册,需要重启电脑(重启后进入蓝屏,此时蓝屏很正常)。选择 Enroll MOK,在提示时输入之前与此请求关联的密码,并确认注册。

此时该公钥永久添加到MOK,后续可以使用该密钥签名kernel模块在ubuntu主机上调试。

hello.ko签名并运行

  1. 签名
1
2
/usr/src/linux-headers-6.8.0-31-generic/scripts/sign-file sha256 \
../keys/signing_key.priv ../keys/signing_key.x509 hello.ko
  1. 使用insmod和rmmod加载、卸载模块,在dmesg中看到相应打印。
1
2
[Apr30 16:15] hello world! init.
[ +3.253135] hello world! exit.

参考

openssl 配置

https://docs.kernel.org/admin-guide/module-signing.html