良许Linux教程网 干货合集 详解Linux 内核驱动的签名

详解Linux 内核驱动的签名

为什么需要签名

现在很多 OS 都是通过 UEFI 引导的(区别一个 Linux 操作系统是通过 UEFI 还是 BIOS 引导的方法是查看是否存在*”/sys/firmware/efi”* 目录),而如果 UEFI 里使能了 secure boot,那么需要 Signed kernel image 才能加载,对应的 kernel module 也需要是签过名的。

即便 UEFI 里没有使能 secure boot,但如果内核是按照 CONFIG_MODULE_SIG_FORCE 配置的(也可通过内核启动参数*”module.sig_enforce=1″* 打开),那么也只有签过名的驱动能加载。

如果内核只是设置了 CONFIG_MODULE_SIG,那么未签名的驱动虽可被加载,但会被标记为 taint。

image-20221126211656558
image-20221126211656558

对于内核 mainline 中自带的 in-tree 驱动,如果 CONFIG_MODULE_SIG_ALL 配置项打开,则在执行 “modules_install” 时会被同步签名,因此存在签名问题的主要是 out-of-tree 驱动(在 “/proc/modues” 中被标记为 “OE”,其中 ‘O’ 表示 Out-of-tree,’E’ 表示 Unsigned module)。

又由于主流发行版中 “sig_force” 通常默认关闭,所以我们需主要关注开启了 secure boot 的场景。

image-20221126211704749
image-20221126211704749

如何签名

1. 生成 Key

签名需要一组 keypair,而产生 keypair 最通用的方式是借助 openssl,例如:

# openssl req -new -x509 -nodes -days 36500 -subj "/CN=DKMS module signing key" \
-newkey rsa:2048 -keyout $private_key \
-outform DER -out $public_key

它表示证书使用 X.509 标准,有效期是 36500 天(10 年),而 “DER” 是 RSA 公钥的一种二进制格式。

对于 Ubuntu 系统,在安装了 “shim-signed” 软件包后,还可直接使用

# update-secureboot-policy --new-key

生成 keypair,结果位于 “/var/lib/shim-signed/mok” 目录,其中 “MOK.priv” 为私钥,”MOK.der” 为公钥。

其实 “/usr/sbin/update-secureboot-policy” 就是个 shell 脚本,它的核心依然是调用 openssl,只是通过进一步的封装让使用变得更简便。

2. 执行签名

内核既然能给 in-tree 的驱动签名,那么它肯定是有一套签名工具的,这个工具在安装内核头文件后就可获取,具体路径为:

/lib/modules//build/scripts/sign-file

对于 Ubuntu 系统,在安装了 “sbsigntool” 软件包后,也可使用 “kmodsign” 作为签名工具。

根据上一步得到的 keypair,执行如下的签名指令:

# kmodsign/sign-file sha512 "$private_key" "$public_key" 

之后使用 “modinfo ” 查看,可以发现增加了 signature 的部分:

signat:         PKCS#7
signer:
sig_key:
sig_hashalgo:   md4

3. 注册 key

secure boot 的设计目的是为了防止不受信任的软件被恶意加载,那按照上述的方法,似乎谁都可以给驱动签名,那怎样的签名才是被认可的呢?

从 UEFI 到 OS,再从 OS 到 driver,这是一条信任链,只有被已经在 UEFI 里注册过的 key 签名的驱动,才是可信的。除了 UEFI 出厂时由 vendor 设置的 key,我们还可以在后续的使用过程中自行添加(称为 “enroll”),其依据的原理大致是:既然都能够操作 UEFI 了,那该用户添加的 key 应该是可被信赖的。

添加的方法是利用 mokutil工具导入 keypair 中的公钥,并随之设置一个密码(Ubuntu 系统还可以使用 “update-secureboot-policy –enroll-key”,究其实现,本质也是对 mokutil 的一层封装):

# mokutil --import $public_key

之后通过*”mokutil –list-new”* 可以看到这个状态为 “to be enrolled” 的 key。

系统重启进入 UEFI 界面后,选择 “Enroll MOK”,输入 mokutil 导入公钥时设置的密码,以确认 enrollment 操作。这样 key 就被注册成功了,启动后可通过*”mokutil –list-enrolled”* 命令查看。

番外 – Secure Boot 验证

对于没有物理机,或者不能在物理机启动阶段直接操作的情况,可考虑使用 qemu 创建的虚拟机来验证。为此,需要安装 OVMF,一个基于 EDK II 代码,专为虚拟机设计的 UEFI 组件。

具体的安装命令根据 OS 的不同而有所差别, 笔者试验用的主机是 Ubuntu 的 bionic (18.04) 版本,安装得到的 OVMF 不带 secure boot 功能(路径为 “/usr/share/OVMF”),所以从另一台 CentOS-8 的 “/usr/share/edk2/ovmf/” 拷贝了 “secboot” 版本来用。后经查询,Ubuntu 的 focal (20.04) 版本 的 “ms” 应该是使能了 secure boot 的。

qemu 配合 OVMF 使用的参数设置和各项含义,可参考 OvmfPkg 源码的 README(https://github.com/tianocore/edk2/tree/master/OvmfPkg),以及 debian wiki(https://wiki.debian.org/SecureBoot/VirtualMachine):

# qemu-system-x86_64        
        -machine q35,smm=on \
        -drive if=pflash,format=raw,unit=0,file="${OVMF_CODE}",readonly=on \
        -drive if=pflash,format=raw,unit=1,file="${OVMF_VARS}" \
        -boot menu=on

进入启动的虚机后,执行 “mokutil –sb-state” 命令,将显示 “enabled”,同时系统日志有如下打印:

# dmesg |grep -i secure
secureboot: Secure Boot enabled
kernel is locked down from EFI secure boot

这时如果加载一个未经签名的驱动,将被拒绝:

insmod error could not insert module ... operation not permitted

以上就是良许教程网为各位朋友分享的Linu系统相关内容。想要了解更多Linux相关知识记得关注公众号“良许Linux”,或扫描下方二维码进行关注,更多干货等着你 !

137e00002230ad9f26e78-265x300
本文由 良许Linux教程网 发布,可自由转载、引用,但需署名作者且注明文章出处。如转载至微信公众号,请在文末添加作者公众号二维码。
良许

作者: 良许

良许,世界500强企业Linux开发工程师,公众号【良许Linux】的作者,全网拥有超30W粉丝。个人标签:创业者,CSDN学院讲师,副业达人,流量玩家,摄影爱好者。
上一篇
下一篇

发表评论

联系我们

联系我们

公众号:良许Linux

在线咨询: QQ交谈

邮箱: yychuyu@163.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

关注微博
返回顶部