3、安全启动的启动流程:从固件到OS的完整验证链

安全启动,说白了就是一条信任链。从你按下电源键那一刻起,系统就开始了一场「接力验证」——每一级组件都要检查下一级的签名,直到操作系统完全跑起来。任何一个环节出问题,启动就会中断。

我调试过不少启动失败的机器,大部分问题都出在这条链的某个节点上。今天我们就把它拆开来看。

3.1 信任链的起点:固件验证阶段

按下电源键后,CPU 首先执行的是 UEFI 固件(也就是 BIOS 的现代版本)。固件里内置了一组出厂时烧录的证书,叫做 KEK(Key Exchange Key) 和 db(允许数据库)。

固件会做三件事:

  1. 验证自己的代码完整性(自检)
  2. 读取启动设备上的 BootLoader(比如 shim.efi 或 grubx64.efi)
  3. 用 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 完整验证链流程图

下面这张图展示了从固件到操作系统的完整验证流程。你可以对照着看,哪个环节出问题,就重点查哪个环节的日志。

安全启动完整验证链流程图 安全启动完整验证链 UEFI 固件 验证 BootLoader 签名 (shim.efi / grubx64.efi) GRUB 引导管理器 验证内核签名 (vmlinuz + initramfs) Linux 内核 验证内核模块签名 (.ko 文件) 验证失败时 • 固件: 黑屏/重启 • GRUB: Security Violation • 内核: Required key not available 常见日志位置 • dmesg | grep -i secure • journalctl -k | grep -i sig • mokutil --sb-state

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,看看能不能正常启动。如果能,那问题肯定出在签名验证上;如果不能,那就是其他硬件或配置问题了。

嗯,安全启动的验证链其实不复杂,但每个环节都环环相扣。你只要记住:每一级只信任上一级签过名的东西。排查时顺着链往下走,看日志里报的是哪个组件的签名失败,就能快速定位。