4、内核启动安全:内核模块签名验证、内核启动参数安全、initramfs安全

内核启动阶段,是整个安全启动链条里最容易出纰漏的一环。为什么?因为这时候系统还没完全跑起来,很多安全机制还没生效。我见过不少团队,UEFI Secure Boot 配得严严实实,结果在内核模块加载这步被人钻了空子。

说白了,内核启动安全就三个核心点:谁在加载、怎么加载、加载了什么。咱们一个一个拆开讲。

4.1 内核模块签名验证

Linux 内核从 3.7 开始支持模块签名验证。这个机制的核心逻辑很简单:只允许加载经过签名的内核模块。没签名的?直接拒掉。

我个人习惯在生产环境强制开启 CONFIG_MODULE_SIG_FORCE。这个选项一旦打开,所有模块都必须有有效签名才能加载。我记得有一次帮客户排查问题,他们服务器莫名其妙被植入了一个 rootkit,就是通过加载未签名的恶意模块实现的。从那以后,我对模块签名验证的态度就是:要么不开,开了就别留后门。

签名验证流程

内核加载模块时,会走这么几步:

  1. 提取模块文件中的签名信息(PKCS#7 格式)
  2. 用内嵌的公钥验证签名
  3. 验证模块的哈希值是否匹配
  4. 全部通过才允许加载

关键点:签名验证依赖内核内置的公钥环。这些公钥在编译内核时就被嵌入,或者通过 UEFI Secure Boot 的 db/dbx 变量传递。如果公钥被篡改,整个验证体系就形同虚设。

配置建议

配置项 推荐值 说明
CONFIG_MODULE_SIG y 启用模块签名支持
CONFIG_MODULE_SIG_FORCE y 强制验证签名
CONFIG_MODULE_SIG_ALL y 编译时自动签名所有模块
CONFIG_MODULE_SIG_HASH sha512 使用 SHA-512 哈希算法
CONFIG_MODULE_SIG_KEY 自定义密钥路径 指定签名用的私钥

注意:私钥必须妥善保管。我曾经遇到一个案例,开发团队把签名私钥直接放在了 Git 仓库里,结果被攻击者拿到,签了一堆恶意模块。私钥泄露,签名验证就彻底废了。

4.2 内核启动参数安全

内核启动参数(kernel command line)是个容易被忽视的攻击面。你想想看,如果攻击者能在启动参数里加个 init=/bin/sh,那系统启动后直接就拿到 root shell 了。

常见的危险启动参数包括:

  • init= — 指定 init 进程,可被替换为任意可执行文件
  • rdinit= — 指定 initramfs 中的 init 进程
  • single 或 1 — 进入单用户模式,可能绕过认证
  • nosmp — 禁用 SMP,可能影响安全模块
  • module.sig_enforce=0 — 禁用模块签名强制验证
  • lsm= — 禁用或替换 Linux Security Module

防护措施

我建议从这几个方面入手:

  1. 锁定 BootLoader 配置:GRUB 的配置文件要设置密码保护,防止未授权修改
  2. 启用 UEFI Secure Boot:确保 BootLoader 本身是签名的,防止被替换
  3. 使用内核 lockdown 模式:这个模式会限制某些危险操作,包括修改启动参数
  4. 验证启动参数完整性:在 initramfs 中检查启动参数是否被篡改

小技巧:可以用 dm-verity 配合 systemd-veritysetup 来验证根文件系统的完整性。这样即使启动参数被改,也能检测到文件系统被篡改。

4.3 initramfs 安全

initramfs(初始 RAM 文件系统)是内核启动早期加载的一个微型文件系统。它的作用是在真正的根文件系统挂载之前,完成必要的硬件初始化、驱动加载、文件系统检查等工作。

问题在于,initramfs 里包含了大量敏感信息:磁盘加密密钥、网络配置、甚至有时会有明文密码。我见过最离谱的一次,某厂商的 initramfs 里直接硬编码了 LUKS 密码,而且用的是同一个密码部署了上千台设备。

initramfs 的常见风险

风险类型 具体表现 影响
敏感信息泄露 密钥、密码硬编码在脚本中 攻击者可解密磁盘
未签名 initramfs 可被替换为恶意版本 完全控制系统启动流程
调试接口未关闭 残留 shell 或调试工具 攻击者可交互式操作
依赖未验证的二进制 使用来自不可信源的工具 供应链攻击

安全加固建议

嗯,这里要注意几个关键点:

  1. 签名 initramfs:和内核模块一样,initramfs 也应该被签名。UEFI Secure Boot 可以验证 initramfs 的完整性。
  2. 最小化内容:只包含必要的工具和驱动。多余的二进制文件只会增加攻击面。
  3. 加密敏感信息:如果必须包含密钥,使用 TPM 或远程密钥服务器获取,不要硬编码。
  4. 移除调试接口:生产环境的 initramfs 不应该包含 shell、调试工具或交互式界面。
  5. 验证完整性:在 initramfs 启动过程中,对关键文件进行哈希校验。

避坑指南:我曾经遇到过一个问题,某发行版的 initramfs 生成工具默认包含了 dropbear(SSH 服务器)用于远程解锁加密磁盘。结果部署时忘了关闭这个功能,导致生产环境的 initramfs 里跑着一个 SSH 服务,而且用的是默认密码。这个漏洞直到安全审计才被发现。

4.4 整体架构与排查思路

下面这张图展示了内核启动安全的核心流程和各个检查点:

内核启动安全架构图 BootLoader 加载 内核启动参数解析 initramfs 加载 内核模块加载 根文件系统挂载 检查点 1 启动参数完整性 检查点 2 initramfs 签名验证 检查点 3 模块签名验证 排查要点: 1. 检查 BootLoader 配置是否被锁定(GRUB 密码、UEFI Secure Boot) 2. 验证 initramfs 是否签名,内容是否最小化 3. 确认内核模块签名强制验证已开启,私钥安全存储

4.5 常见排查命令

最后,分享几个我常用的排查命令:

# 检查内核模块签名强制验证是否开启
cat /sys/module/module/parameters/sig_enforce

# 查看已加载模块的签名信息
modinfo -F signature <模块名>

# 检查内核启动参数
cat /proc/cmdline

# 查看 initramfs 内容(需要先解压)
lsinitramfs /boot/initrd.img-$(uname -r)

# 检查内核公钥环
keyctl show %keyring:.builtin_trusted_keys

# 验证内核 lockdown 模式
cat /sys/kernel/security/lockdown

个人经验:我习惯在系统部署脚本里加一段自动化检查,遍历所有内核模块,确认它们都有有效签名。如果发现未签名的模块,直接报警。这个习惯帮我抓到了好几次开发环境遗留的测试模块被带到生产环境的问题。