问题背景:为何驱动加载会被拦截?
在现代Linux发行版(如Ubuntu 22.04/24.04, RHEL 9, Fedora 38+)中,默认启用了UEFI安全启动(Secure Boot)。这一机制旨在防止未授权的代码在内核态执行。当第三方硬件驱动(如某些专用显卡、网卡或加密狗驱动)以内核模块(.ko文件)形式存在时,内核会强制校验其数字签名。
如果模块未签名、签名过期或由不受信任的密钥签发,内核将拒绝加载该模块,并抛出类似 "Module verification failed: signature and/or required key missing - tainting kernel" 的错误信息。对于IT运维人员而言,这通常表现为硬件功能异常或服务启动失败。
技术原理:MODULE_SIGNATURE 与 MOK
Linux内核通过 MODULE_SIG 配置项启用模块签名检查。该机制依赖于公钥基础设施(PKI):
- 签名过程:开发者使用私钥对模块的二进制数据进行签名,并将签名附在模块文件中。
- 验证过程:内核启动时,加载内置的公钥数据库。若模块签名能被其中的公钥解密且匹配,则允许加载;否则拒绝。
- MOK (Machine Owner Key):为了允许用户自行添加驱动, shim 引导程序引入了 MOK 管理机制。用户可以在启动阶段注册自己的公钥,这些公钥存储在 NVRAM 的非易失性存储中,供内核读取。
排查与修复方案
第一步:确认当前内核状态与模块签名情况
首先,检查正在运行的内核是否启用了签名强制验证,以及具体是哪个模块加载失败。
1. 查看内核模块签名策略:
cat /sys/module/module/parameters/enforce_signature
# 输出 1 表示强制验证,0 表示不强制
2. 查看 dmesg 日志寻找签名错误:
dmesg | grep -i "signature\|verification\|module"
3. 手动检查特定模块的签名:
modinfo /path/to/driver.ko | grep signing
第二步:方案一——为驱动模块生成并签署证书(推荐用于生产环境)
这是最规范的做法。需要生成一对 RSA 私钥和 X.509 公钥,并对模块进行重新签名。
1. 生成密钥对
# 生成RSA私钥
openssl genrsa -out driver.key 2048
# 生成自签名证书(CN可任意,但建议具有描述性)
openssl req -new -x509 -newkey rsa:2048 -keyout driver.key \
-out driver.crt -days 3650 \
-subj "/CN=Custom Driver Signing Key"
2. 签署内核模块
使用 scripts/sign-file 工具(位于Linux源码目录或 /usr/src/linux-headers-$(uname -r)/scripts/):
sudo scripts/sign-file sha256 ./driver.key ./driver.crt /lib/modules/$(uname -r)/extra/driver.ko
3. 注册公钥到 MOK
由于是自签名证书,必须将其导入 MOK 列表:
sudo mokutil --import driver.crt
系统将提示设置一个密码。重启计算机,进入蓝色背景的 MOK Management 界面,选择 Enroll MOK,输入刚才设置的密码,并确认重启。重启后,新注册的公钥将写入 NVRAM,内核即可信任该签名。
第三步:方案二——临时禁用签名检查(仅用于测试或应急)
如果无法立即获取证书或进行复杂操作,可以暂时降低安全性以加载驱动。请注意,这会降低系统安全性。
1. 修改 GRUB 配置
编辑 /etc/default/grub:
GRUB_CMDLINE_LINUX="module.sig_enforce=0"
然后更新 grub:
sudo update-grub
2. 或者,在启动时按 'e' 编辑启动项
在 linux 行末尾添加 module.sig_enforce=0,按 F10 启动。这种方式不会永久生效,适合临时调试。
第四步:方案三——使用已签名内核自带的密钥(针对开源通用驱动)
部分主流驱动(如Broadcom WiFi, NVIDIA闭源驱动的部分组件)可能已经使用了发行版厂商提供的密钥进行签名,但未被系统默认信任。此时需要导出该驱动使用的密钥并注册。
某些发行版提供了 sign-file 脚本配合系统预设密钥(如 /var/lib/shim-signed/mok/MOK.der,路径因发行版而异)。此方法较为复杂,建议优先采用方案一。
常见陷阱与注意事项
- 密钥有效期:生成的证书若过期,驱动将无法加载。建议在生成证书时使用较长的有效期(如10年),或在到期前重新签署并更新MOK。
- 架构匹配:确保
sign-file工具与当前内核版本完全匹配。不同内核版本的签名算法或头部结构可能有细微差异。 - BIOS/UEFI 设置:如果主板 BIOS 中禁用了 Secure Boot,则无需签名即可加载模块。但在企业合规环境中,通常要求开启 Secure Boot,因此签名是必经之路。
- NVIDIA 专有驱动:NVIDIA 官方 Runfile 安装的驱动通常自带签名机制,但有时会与 DKMS 冲突。建议使用发行版包管理器(apt/yum)安装驱动,或遵循 NVIDIA 官方文档进行自定义证书签名。
总结
Linux 内核模块签名机制是保障系统安全的重要防线。虽然它增加了第三方驱动部署的复杂度,但通过建立正确的 PKI 流程和 MOK 管理机制,IT 人员可以轻松实现安全与兼容性的平衡。对于频繁更换硬件驱动的环境,建议编写自动化脚本,一键完成密钥生成、模块签署和 MOK 注册,以提高运维效率。