3、安全启动的启动流程:从固件到OS的完整验证链
安全启动,说白了就是一条信任链。从你按下电源键那一刻起,系统就开始了一场「接力验证」——每一级组件都要检查下一级的签名,直到操作系统完全跑起来。任何一个环节出问题,启动就会中断。
我调试过不少启动失败的机器,大部分问题都出在这条链的某个节点上。今天我们就把它拆开来看。
3.1 信任链的起点:固件验证阶段
按下电源键后,CPU 首先执行的是 UEFI 固件(也就是 BIOS 的现代版本)。固件里内置了一组出厂时烧录的证书,叫做 KEK(Key Exchange Key) 和 db(允许数据库)。
固件会做三件事:
- 验证自己的代码完整性(自检)
- 读取启动设备上的 BootLoader(比如 shim.efi 或 grubx64.efi)
- 用 db 里的公钥验证 BootLoader 的签名
如果签名验证失败,固件直接拒绝加载。屏幕上可能显示 Secure Boot Violation,或者直接黑屏重启。
关键点: 固件只信任它数据库里的证书。你装了一个没签名的 BootLoader,或者证书过期了,启动就会卡在这一步。
3.2 BootLoader 的签名验证
BootLoader 是信任链的第二个环节。它被固件验证通过后,会接管控制权。但它的任务还没完——它要去验证操作系统的内核。
以 Linux 为例,常见的 BootLoader 是 shim + GRUB 的组合:
- shim.efi:一个很小的、由微软签名的程序。它负责加载 GRUB,并验证 GRUB 的签名。
- GRUB:真正的引导管理器。它加载内核、initramfs,并验证它们的签名。
我遇到过一种情况:shim 版本太旧,不认识新内核的签名算法。结果 GRUB 能起来,但加载内核时报 Verification failed: (0x1A) Security Violation。升级 shim 就解决了。
避坑指南: 如果你自己编译内核,记得给内核加上签名。否则 GRUB 会拒绝加载。签名工具是 sbsign,命令类似:
sbsign --key my.key --cert my.crt --output vmlinuz-signed vmlinuz
3.3 内核模块的签名要求
内核启动后,安全启动的验证还没结束。内核会检查所有加载的模块(.ko 文件)是否有有效签名。这是为了防止恶意内核模块被注入系统。
内核模块的签名验证策略由 CONFIG_MODULE_SIG 内核选项控制。常见模式有:
| 策略 | 行为 | 适用场景 |
|---|---|---|
| 强制验证 | 未签名模块直接拒绝加载 | 生产环境、安全要求高的系统 |
| 允许未签名 | 只警告,不阻止加载 | 开发调试环境 |
| 仅验证 | 签名有效则加载,无效则拒绝 | 大多数发行版默认 |
你可以在 /proc/sys/kernel/modules_disabled 查看当前策略。如果值是 1,那所有未签名模块都别想加载。
注意: 有些第三方驱动(比如 NVIDIA 显卡驱动)需要自己签名。我曾经帮一个同事排查过:他装完驱动重启后黑屏,日志里全是 Required key not available。最后发现是驱动模块没签名,内核直接拒载了。
3.4 完整验证链流程图
下面这张图展示了从固件到操作系统的完整验证流程。你可以对照着看,哪个环节出问题,就重点查哪个环节的日志。
3.5 常见故障点与排查思路
根据我的经验,安全启动失败的原因通常集中在以下几个地方:
- 固件数据库问题:db 或 KEK 被清空、证书过期、或者误删了微软证书。可以用
mokutil --list-enrolled查看当前已注册的证书。 - BootLoader 签名不匹配:shim 和 GRUB 版本不兼容,或者 GRUB 被修改过。重新安装
shim-signed和grub-efi-amd64-signed通常能解决。 - 内核模块签名缺失:自己编译的模块没签名,或者签名用的密钥不在 MOK(Machine Owner Key)列表里。用
mokutil --import导入你的公钥。
一个小技巧: 如果你不确定问题出在哪,可以先在固件设置里暂时关闭 Secure Boot,看看能不能正常启动。如果能,那问题肯定出在签名验证上;如果不能,那就是其他硬件或配置问题了。
嗯,安全启动的验证链其实不复杂,但每个环节都环环相扣。你只要记住:每一级只信任上一级签过名的东西。排查时顺着链往下走,看日志里报的是哪个组件的签名失败,就能快速定位。