多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

BIOS显示Secure Boot已启用,Linux却报disabled?一文讲透UEFI安全启动状态错位

BIOS显示Secure Boot已启用,Linux却报disabled?一文讲透UEFI安全启动状态错位 1. 先搞清楚这两个Secure Boot 状态到底是谁在说话很多人第一次碰到这个现象的时候反应都差不多明明进 BIOS 看到 Secure Boot 那一栏写着 Enabled进系统敲一条命令返回的却是SecureBoot disabled。于是开始怀疑是不是主板骗人、是不是系统装歪了、是不是固件有 bug。我当年第一次遇到也折腾了大半天后来才明白这俩状态压根不是同一个东西它们分别由两个不同的角色、在不同的时机、用不同的口径在汇报。先把结论摆前面BIOS 里显示的是固件层面的开关状态Linux 里读到的是内核实际生效的安全启动状态。这两者绝大多数情况下是一致的但只要有任何一个中间环节掉了链子就会出现上面说开、下面说关的错位。你要做的不是纠结谁对谁错而是顺着这条链路一层层往下查找到那个断点。这篇文章我打算把这条链路完整拆开讲从固件里的开关到 UEFI 变量到内核怎么读、怎么判定再到常见的几种错位场景和排查手法。适合两类人看——一类是刚接触 UEFI 安全启动、被这个现象搞懵的新手另一类是已经知道大概原理但想搞清楚到底哪一步断了的运维和系统玩家。看完你应该能自己定位问题而不是靠重启碰运气。在展开之前先统一几个概念不然后面容易绕晕。Secure Boot安全启动是 UEFI 规范里的一套机制核心目的是确保开机时加载的引导程序和内核镜像是被信任签名的防止有人往引导链里塞东西。它依赖一组叫UEFI 变量的东西来记录状态其中最关键的两个是SecureBoot和SetupMode。而 Linux 这边内核启动后会去读这些变量把结果通过/sys/firmware/efi/efivars/暴露出来同时mokutil、bootctl、dmesg这些工具会给你一个人话版的结论。错位就发生在固件写的和内核读到的之间。2. 固件里的已启用到底意味着什么2.1 BIOS 界面上的开关只是意图声明你在 BIOS/UEFI 设置界面里看到的那个 Secure Boot 选项本质上是固件给你看的一个配置意图。它告诉你固件当前被设置成我希望启用安全启动。但注意这只是意图不是结果。固件要真正让安全启动生效还需要满足一堆前置条件比如平台密钥PK、密钥交换密钥KEK、签名数据库db这些变量都得正确写入而且不能处于 Setup Mode。换句话说BIOS 里那个 Enabled 更像是你在一张申请表上勾了我要办这个业务但业务到底办没办成得看后台有没有真正受理。很多主板厂商的界面做得比较乐观只要你没手动关掉它就显示 Enabled哪怕底下的密钥其实没配全、或者被清空了它照样显示 Enabled。这就是错位的第一大来源。2.2 固件状态其实分好几种不止开/关真正懂 UEFI 的人不会只用开/关来描述安全启动因为固件内部至少有这几种状态固件内部状态含义BIOS 界面常见显示Setup Mode密钥未写入或已被清除处于可配置状态有时仍显示 Enabled有时显示 SetupUser Mode SecureBoot 开密钥齐全安全启动真正生效EnabledUser Mode SecureBoot 关密钥齐全但开关被关掉Disabled密钥被清空PK/KEK/db 被删退回 Setup Mode视厂商而定可能仍显示 Enabled看到没密钥被清空这一行就是重灾区。很多主板在你执行恢复默认设置或者刷完 BIOS 之后会把密钥清掉退回 Setup Mode但界面上的 Secure Boot 那一栏还是显示 Enabled。这时候你进 Linux 一查内核读到SetupMode1自然就判定安全启动没生效返回 disabled。两边都没说谎只是说的不是一回事。2.3 为什么厂商界面不把真实状态显示清楚这个问题我被问过很多次。原因其实很现实BIOS 界面是给配置用的不是给诊断用的。厂商假设你进来就是要改设置所以它显示的是当前设置值而不是运行时实际状态。而且不同厂商对 Setup Mode 的界面呈现策略不一样有的会明确标出来有的干脆不显示导致用户根本不知道密钥已经没了。提示如果你怀疑是密钥问题别在 BIOS 界面里瞎找直接进 Linux 用命令读 UEFI 变量那个才是真相。3. Linux 里的 disabled 是怎么算出来的3.1 内核读的是 UEFI 变量不是 BIOS 界面Linux 判断安全启动状态靠的是读 UEFI 运行时变量。最直接的两个文件在/sys/firmware/efi/efivars/SecureBoot-GUID /sys/firmware/efi/efivars/SetupMode-GUID这两个文件的内容是一个字节准确说是 4 字节属性 1 字节数据最后那个字节如果是1就代表真0就代表假。内核在启动早期会读这两个变量然后决定SecureBoot这个全局标志是开还是关。你后面用的所有工具本质上都是在读这个内核标志或者重新去读这两个变量。所以链路是这样的BIOS 设置界面意图 ↓ 固件写入 UEFI 变量 SecureBoot / SetupMode事实 ↓ 内核启动时读取 内核全局标志判定 ↓ 工具查询 mokutil / bootctl / dmesg呈现任何一层出问题最终呈现就会和 BIOS 界面不一致。下面我逐个拆。3.2 用命令直接看原始变量别只看结论很多人上来就敲mokutil --sb-state看到SecureBoot disabled就慌了。其实你应该先看原始变量那才是第一手证据# 看 SecureBoot 变量最后一位是数据 od -An -t u1 /sys/firmware/efi/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c # 看 SetupMode 变量 od -An -t u1 /sys/firmware/efi/efivars/SetupMode-8be4df61-93ca-11d2-aa0d-00e098032b8c如果SecureBoot最后一位是0说明固件层面就没开如果SetupMode是1说明密钥没配全安全启动不可能生效。这两个一读基本就能定位是固件侧的问题还是系统侧的问题。3.3 内核日志里其实早就写了原因还有一个被严重低估的信息源dmesg。内核在启动时如果发现安全启动相关的东西有问题会往日志里写。你可以这样过滤dmesg | grep -i -E secure|efi|setup常见的有这么几类输出含义完全不同Secure boot enabled内核确认安全启动生效和 BIOS 一致。Secure boot disabled内核读到 SecureBoot0固件层面就是关的。Secure boot disabled (Setup Mode)密钥没配全退回 Setup Mode。完全没有相关行可能是内核没走 EFI 启动或者变量读取失败。最后那种完全没有最坑因为它意味着你可能压根不是 UEFI 启动而是 Legacy/CSM 模式启动的。这种情况下/sys/firmware/efi目录可能都不存在安全启动自然无从谈起。4. 六种典型错位场景对号入座我把这些年遇到过的BIOS 说开、Linux 说关的情况归了归类基本逃不出下面六种。你可以拿着自己的现象对号入座能省不少时间。4.1 场景一密钥被清空退回 Setup Mode这是最常见的一种。典型触发动作是恢复 BIOS 默认设置、刷固件、换主板电池、手动执行过清除安全启动密钥。现象是 BIOS 界面 Secure Boot 仍显示 Enabled但 Linux 里SetupMode1mokutil报 disabled。判断方法就是读SetupMode变量是1就实锤了。解决办法是进 BIOS 重新执行恢复出厂密钥或者安装默认密钥把 PK/KEK/db 写回去退出 Setup Mode。有些主板这个选项藏得很深可能在 Security 或者 Boot 子菜单里名字叫Restore Factory Keys、Install Default Secure Boot Keys之类。4.2 场景二系统其实是 Legacy/CSM 启动的这个也很常见尤其是老机器或者装系统时没注意。BIOS 里 Secure Boot 开着但你的系统是用 Legacy BIOS 或者 CSM 兼容模式引导的。这种情况下内核根本没走 UEFI 路径读不到 UEFI 变量自然报 disabled。判断方法很简单ls /sys/firmware/efi如果这个目录不存在或者efibootmgr命令报错说没有 EFI 支持那你就是 Legacy 启动。解决办法是进 BIOS 关掉 CSM确保从 UEFI 分区引导必要时用efibootmgr重建引导项。4.3 场景三引导链中间有未签名的环节安全启动是整条链都要验签的固件验引导程序引导程序验内核内核验模块。如果中间任何一个环节没签名或者签名不被信任安全启动会在那一环失败。但这里有个微妙的地方失败的方式不同呈现也不同。如果是引导程序没签名固件直接拒绝加载你根本进不了系统会看到安全启动违规的报错。但如果是内核模块没签名系统能起来只是那个模块加载失败而mokutil可能仍然报 enabled。真正会导致BIOS 开、系统报 disabled的通常是引导程序这一环被跳过或者用了 shim 之类的中间层导致内核读到的状态和固件不一致。4.4 场景四虚拟机或容器环境的特殊性如果你是在虚拟机里跑 Linux那 BIOS 界面和 Linux 里的状态不一致就更正常了。虚拟机的固件是宿主模拟出来的安全启动支持参差不齐。有的虚拟化平台默认不开安全启动但它的设置界面可能显示得模棱两可有的开了但没配密钥内核读到的就是 Setup Mode。判断方法还是那套读变量、看 dmesg。虚拟化环境下别指望界面一切以变量为准。4.5 场景五内核版本或配置差异极少数情况下是内核本身的问题。比如某些定制内核编译时没开 EFI 相关选项或者启动参数里加了efidisable_early_pci_dma之类影响 EFI 初始化的东西导致内核读不到变量。这种比较少见但排查时可以用uname -r确认内核版本用cat /proc/cmdline看启动参数有没有异常。4.6 场景六双系统引导器劫持了引导链装了双系统的机器上如果引导器比如某个第三方引导管理程序不是被安全启动信任的它可能会用各种方式绕过验签。绕过之后内核虽然起来了但它读到的安全启动状态可能是被降级过的。这种场景排查起来最绕建议直接看dmesg里 EFI 相关的完整输出顺着引导链一段段确认。5. 一套可复现的排查流程光讲场景不够我给你一套我自己常用的排查顺序照着走基本能定位。整个过程不需要重启太多次大部分信息在系统里就能拿到。5.1 第一步确认是不是 UEFI 启动# 方法一看目录 ls -d /sys/firmware/efi 2/dev/null echo UEFI || echo Legacy # 方法二看 efibootmgr efibootmgr 2/dev/null | head -5如果这一步就判定是 Legacy那后面都不用查了问题根源就是启动模式不对。进 BIOS 关 CSM改成纯 UEFI 引导。5.2 第二步读原始 UEFI 变量SB_GUID8be4df61-93ca-11d2-aa0d-00e098032b8c echo -n SecureBoot: ; od -An -t u1 /sys/firmware/efi/efivars/SecureBoot-$SB_GUID | awk {print $NF} echo -n SetupMode: ; od -An -t u1 /sys/firmware/efi/efivars/SetupMode-$SB_GUID | awk {print $NF}对照结果SecureBootSetupMode结论10安全启动真正生效和 BIOS 一致00固件层面就是关的去 BIOS 开01密钥没配全退回 Setup Mode11矛盾状态固件可能有 bug考虑刷固件5.3 第三步交叉验证工具输出mokutil --sb-state bootctl status 2/dev/null | grep -i secure dmesg | grep -i -E secure boot|setup mode三个工具的输出如果一致那结论就稳了。如果不一致以原始变量为准工具可能有缓存或者版本差异。5.4 第四步根据结论决定动作如果是 Setup Mode进 BIOS 恢复密钥。如果是 Legacy 启动改 UEFI 引导。如果是固件矛盾状态考虑更新固件。如果一切正常但工具报错检查工具版本和内核配置。注意改 BIOS 设置前先记下当前引导项顺序免得改完进不去系统。我踩过这个坑改完 CSM 之后引导项全乱了折腾了半小时才恢复。6. 密钥管理这块新手最容易栽的坑6.1 PK、KEK、db 到底谁管谁安全启动的密钥体系是分层的很多人搞不清这三个的关系。简单说PKPlatform Key最顶层一个平台只有一把代表平台所有者。KEKKey Exchange Key用来签名 db 和 dbx 的更新可以有多把。dbSignature Database真正用来验签引导程序和内核的白名单。dbxForbidden Database黑名单被吊销的签名放这里。链路是 PK 授权 KEKKEK 授权 db/dbx 的更新。所以如果你把 PK 清了整个体系就塌了直接退回 Setup Mode。这也是为什么清除密钥操作要慎之又慎。6.2 自己签名内核模块的正确姿势如果你需要加载自己编译的内核模块又不想关安全启动那就得自己签名然后把公钥注册进 MOKMachine Owner Key。流程大致是# 生成密钥 openssl req -new -x509 -newkey rsa:2048 -keyout MOK.priv -outform DER -out MOK.der -nodes -days 36500 -subj /CNMy Key/ # 签名模块 /usr/src/linux-headers-$(uname -r)/scripts/sign-file sha256 MOK.priv MOK.der your_module.ko # 注册公钥会要求重启进 MOK 管理界面确认 mokutil --import MOK.der重启后会进一个蓝色的 MOK 管理界面需要你手动确认导入。这一步很多人以为敲完命令就完事了结果重启没注意公钥没导进去模块还是加载不了。6.3 别轻易关安全启动来图省事我见过太多人一遇到模块加载失败第一反应就是进 BIOS 把安全启动关了。短期确实省事但长期看是把整个引导链的防护都拆了。正确做法是签名 注册 MOK一次配置好后面就顺了。而且现在主流发行版对第三方模块的签名支持都挺成熟没必要因噎废食。7. 常见问题速查表把高频问题整理成表方便你直接查。现象最可能原因快速验证解决方向BIOS 显示 Enabledmokutil 报 disabled密钥被清空Setup Mode读 SetupMode 变量BIOS 恢复出厂密钥同上但 SetupMode0固件层面 SecureBoot0读 SecureBoot 变量BIOS 里重新开启/sys/firmware/efi 不存在Legacy/CSM 启动ls 该目录改纯 UEFI 引导dmesg 无 secure 相关行内核没走 EFI 路径看 /proc/cmdline检查引导模式模块加载失败但系统能起模块未签名dmesg 看模块报错签名 注册 MOK双系统下状态飘忽引导器绕过验签看完整 EFI 日志统一引导链8. 我个人的几条实操心得折腾安全启动这些年有几个体会是文档里不会写的分享给你。第一永远以 UEFI 变量为准别信界面。BIOS 界面是给人配置用的不是给人诊断用的。养成进系统先读变量的习惯能省掉大量重启进 BIOS 看一眼的无用功。第二改 BIOS 前先备份引导项。efibootmgr -v的输出截个图存着改完设置如果引导乱了照着恢复。这个习惯帮我救过好几次场。第三Setup Mode 不等于故障。它只是一个状态说明密钥没配。很多新手看到 Setup Mode 就以为主板坏了其实进 BIOS 点一下恢复密钥就好了。理解状态机的意义比记住具体操作更重要。第四虚拟化环境别套用物理机的经验。虚拟机的固件行为差异很大安全启动支持也参差不齐。在虚拟机里排查先确认虚拟化平台本身对安全启动的支持程度再往下查。第五签名这件事一次配好长期受益。自己签模块、注册 MOK前期花半小时后面所有自编译模块都能顺畅加载不用反复关安全启动。这笔账怎么算都划算。最后再补一句关于排查心态的这个BIOS 说开、系统说关的现象本质上是信息源不一致不是谁坏了。你要做的是找到那个断点而不是急着下结论说主板有问题或者系统有问题。顺着固件到变量到内核这条链路走一遍答案自然就出来了。
返回列表