---
url: >-
  https://cubesandbox.com/zh/guide/troubleshooting/pvm-host-boot-unsigned-modules.md
---

# module.sig\_enforce=1 导致 PVM 宿主内核启动掉进 initramfs

## 问题现象

按照 PVM 部署文档安装 `kernel-release-*` 发布的 PVM 宿主内核并执行
`deploy/pvm/grub/host_grub_config.sh` 后，重启系统直接掉进 initramfs 救援
shell：

```text
Gave up waiting for root file system device.  Common problems:
 - Boot args (cat /proc/cmdline)
   - Check rootdelay= (did the system wait long enough?)
 - Missing modules (cat /proc/modules; ls /dev)
ALERT!  /dev/mapper/openstack--dev--vg-root does not exist.  Dropping to a shell

BusyBox v1.37.0 (Debian 1:1.37.0-6+b9) built-in shell (ash)
(initramfs)
```

通过 GRUB「Advanced options」子菜单仍可正常启动发行版自带内核。

## 环境信息

* Cube Sandbox 版本：v0.7.x（撰写时的部署脚本）
* 部署模式：PVM（无 `/dev/kvm`，由 PVM 宿主内核提供 KVM 能力）
* 宿主机 OS / 内核：VMware 上的 Debian 13 (trixie) —— 见下方实测案例；
  ESXi 上也有一致症状
  （[#1949](https://github.com/TencentCloud/CubeSandbox/issues/1949)）
* 相关组件：`deploy/pvm/grub/host_grub_config.sh`

## 根因分析

两个事实叠加导致故障：

1. 社区发布内核的**模块没有签名**。pvm\_host 内核配置里
   `CONFIG_MODULE_SIG=y`，但 `CONFIG_MODULE_SIG_ALL` 未启用、
   `CONFIG_SYSTEM_TRUSTED_KEYS=""`，构建产物中的 `.ko` 文件全部没有签名
   （`modinfo -F signer` 对 `dm-mod.ko`、`kvm.ko`、`scsi_mod.ko`、
   `mptspi.ko`、`vmw_pvscsi.ko` 等均返回空）。
2. `host_grub_config.sh` 按设计在内核启动参数中启用
   `module.sig_enforce=1`。签名强制开启后，内核拒绝加载**所有**未签名
   模块，存储驱动（如 VMware 上的 `mptspi`、LVM 的 `dm-mod`）无法加载，
   根分区设备自然找不到。

## 实测案例：VMware 上的 Debian 13 (trixie)

宿主机：Debian 13 (trixie) VMware 虚拟机，未开启嵌套虚拟化，磁盘挂载在
LSI 53c1030 Fusion-MPT 控制器（`mptspi`）上，根分区位于 LVM
（`/dev/mapper/openstack--dev--vg-root`）。

| 内核 | 来源 | 模块签名情况 |
| --- | --- | --- |
| `6.12.113+deb13-amd64`（发行版） | Debian | 已签名 —— `signer='Build time autogenerated kernel key'`，压缩格式 `.ko.xz` |
| `6.6.117-opencloudos9.cubesandbox.pvm.host-gbc75224fca7e` | `kernel-release-261012-1` deb | **未签名** —— 所有模块 `modinfo -F signer` 为空 |

发布 PVM 内核的相关配置（取自 `/boot/config-<kver>` 与
`/proc/config.gz`）：

```text
CONFIG_MODULE_SIG=y
# CONFIG_MODULE_SIG_FORCE is not set
# CONFIG_MODULE_SIG_ALL is not set
CONFIG_MODULE_SIG_KEY="certs/signing_key.pem"
CONFIG_MODULE_SIG_HASH="sha512"
CONFIG_SYSTEM_TRUSTED_KEYRING=y
CONFIG_SYSTEM_TRUSTED_KEYS=""
```

安装 deb 后的模块签名检查：

```console
$ modinfo -F signer /lib/modules/6.6.117-...pvm.host/kernel/drivers/md/dm-mod.ko
（空）
$ modinfo -F signer /lib/modules/6.12.113+deb13-amd64/kernel/drivers/md/dm-mod.ko.xz
Build time autogenerated kernel key
```

恢复过程（实际执行的步骤）：

1. 重启 → GRUB → `Advanced options for Debian GNU/Linux` → 启动
   `6.12.113+deb13-amd64`。

2. 去掉该参数并重新生成 grub 配置：

   ```bash
   sed -i 's/ module\.sig_enforce=1//' /etc/default/grub
   update-grub
   reboot
   ```

3. 重启进入 PVM 内核后：`kvm_pvm` 正常加载、`/dev/kvm` 出现，Cube Sandbox
   安装和运行一切正常。

> 提示：该平台上磁盘顺序（sda/sdb）在重启之间可能变化。除 LVM 根分区外，
> `/etc/fstab` 中的挂载项建议使用 `UUID=`。

## 实测案例：VMware 上的 openEuler 24.03 LTS-SP4

宿主机：openEuler 24.03 LTS-SP4 VMware 虚拟机，未开启嵌套虚拟化，100 GiB
空白数据盘用于 `/data/cubelet`，根分区为 LVM（ext4）。

| 内核 | 来源 | 模块签名情况 |
| --- | --- | --- |
| `6.6.0-159.4.3.154.oe2403sp4.x86_64`（发行版） | openEuler | 已签名 —— `signer='openEuler kernel ICA 1'`，压缩格式 `.ko.xz` |
| `6.6.117-opencloudos9.cubesandbox.pvm.host-gbc75224fca7e` | `kernel-release-261012-1` rpm | **未签名** —— 与 Debian 案例是同一份构建产物 |

openEuler 自带内核把自家证书内置进了内核，这正是 PVM 内核构建需要效仿的
模式：

```text
# openEuler 自带内核
CONFIG_MODULE_SIG=y
# CONFIG_MODULE_SIG_FORCE is not set
CONFIG_MODULE_SIG_KEY=""
CONFIG_SYSTEM_TRUSTED_KEYS="certs/openeuler-cert.pem"

# PVM 发布内核
CONFIG_MODULE_SIG=y
# CONFIG_MODULE_SIG_ALL is not set
CONFIG_MODULE_SIG_KEY="certs/signing_key.pem"
CONFIG_SYSTEM_TRUSTED_KEYS=""
```

模块签名检查：

```console
$ modinfo -F signer /lib/modules/6.6.0-159.../kernel/drivers/md/dm-mod.ko.xz
openEuler kernel ICA 1
$ modinfo -F signer /lib/modules/6.6.117-...pvm.host/kernel/drivers/md/dm-mod.ko
（空）
```

结论：PVM 内核构建产物与宿主发行版无关——未签名模块和
`module.sig_enforce=1` 的风险在 RPM 系发行版（openEuler、CentOS 等）上完全
相同，恢复和规避方法也一样。

## 解决方案

### 1. 恢复主机

参照上方实测案例中的恢复步骤：从 GRUB 启动发行版旧内核，然后从
`/etc/default/grub` 中移除 `module.sig_enforce=1` 并重新生成 grub 配置。

### 2. 在内核构建侧修复，grub 脚本保持启用

[PR #2053](https://github.com/TencentCloud/CubeSandbox/pull/2053) 不会弱化
`host_grub_config.sh`：它继续无条件追加 `module.sig_enforce=1`。根因改为在
内核构建侧修复——在 `deploy/pvm/configs/pvm_host` 中开启模块签名：

```text
CONFIG_MODULE_SIG=y
CONFIG_MODULE_SIG_ALL=y                        # modules_install 时为所有内核内置模块签名
CONFIG_MODULE_SIG_KEY="certs/signing_key.pem"  # 私钥 + 匹配的 X.509 证书
CONFIG_SYSTEM_TRUSTED_KEYS=""                  # 签名密钥的公钥证书会自动嵌入内核
```

启用 `CONFIG_MODULE_SIG_ALL=y` 后，`make modules_install` 会用
`CONFIG_MODULE_SIG_KEY` 为所有内核内置模块签名；构建过程还会提取匹配的
公钥证书（`certs/signing_key.x509`）并嵌入内核的 trusted keyring，因此
内核只信任它自己发布的模块——这正是让无条件的
`module.sig_enforce=1` 变得安全的原因。

用该配置重新构建并发布 `kernel-release-*` 产物。仍在运行旧（未签名）发布
内核的主机，必须先安装重新构建的签名内核，再重新执行
`host_grub_config.sh`，否则强制签名仍会拒绝其模块。该方向已用自建内核
验证：用更新后配置构建的 Debian 13 `deb` 与 openEuler 24.03 `rpm` 均可在
`module.sig_enforce=1` 下启动，`kvm_pvm`/`/dev/kvm` 正常，未签名模块被拒、
用构建密钥签名的模块可加载。

上线时还有两个注意点：

* 安装新内核后，移除旧的未签名 PVM 内核包（或至少不要选择其 GRUB 入口）。
  `module.sig_enforce=1` 是全局生效的，选中旧入口仍会掉进 initramfs。
* 用新的 `kernel-release-*` tag 发布重建后的产物，并提升包版本。该配置
  改动不会改变内核 release 字符串，所以相同版本的 RPM 不会被自动升级；
  给 `LOCALVERSION` 加后缀或显式提升包版本，才能让签名内核成为真正的升级。

### 3. 任意主机上的快速风险检查

要检查**所有已安装的 PVM 内核**，而不只是当前运行的内核：恢复路径会启动
发行版内核，此时 `uname -r` 不一定就是 grub 脚本要配置的内核。

```bash
for kdir in /lib/modules/*pvm.host*; do
  [ -d "$kdir" ] || continue
  kver=$(basename "$kdir")
  echo "== $kver"
  grep -qw "module.sig_enforce=1" /proc/cmdline && echo "  enforcement: ON"
  grep -E "^CONFIG_MODULE_SIG_FORCE=" "/boot/config-$kver" 2>/dev/null \
    || zgrep -E "^CONFIG_MODULE_SIG_FORCE=" /proc/config.gz 2>/dev/null
  # 遇到第一个没有签名的模块就停止：签名强制会拒绝加载它。
  find "$kdir" \( -type f -o -type l \) -name '*.ko*' 2>/dev/null |
  while IFS= read -r m; do
    [ -n "$(modinfo -F signer "$m" 2>/dev/null)" ] || { echo "  unsigned: $m"; break; }
  done
done
```

高危状态 = 强制签名已开启（cmdline、grub 配置或
`CONFIG_MODULE_SIG_FORCE=y`），而任一已安装 PVM 内核中**任意**模块的
signer 为空或 `modinfo` 无法读取。此时下一次启动就会再次掉进 initramfs。
注意 `modinfo -F signer` 只能证明存在签名字段，不能证明内核信任该签名
密钥：用内核不信任的密钥签名的模块在强制模式下同样会被拒绝，而这种情况
无法在启动前从用户态检出。

### 4. 树外与 DKMS 模块

主机上必须加载的任何树外/DKMS 模块，必须用内核信任的同一密钥签名
（`scripts/sign-file`），否则会被强制模式拒绝。无法用发布签名密钥签名的
模块，应改为编译进内核。

> 注意：本次修改之前发布的 `kernel-release-*` 产物模块仍未签名。必须先
> 用更新后的 `deploy/pvm/configs/pvm_host` 重新构建，才能在运行这些旧内核
> 的主机上安全使用无条件的 `module.sig_enforce=1`。

## 参考

* 相关 PR：[#2053](https://github.com/TencentCloud/CubeSandbox/pull/2053)
* 可能相关的 issue：[#1949](https://github.com/TencentCloud/CubeSandbox/issues/1949)
* 内核文档：[Module Signing](https://docs.kernel.org/admin-guide/module-signing.html)
