Linux 内核更新后 VMware vmnet 无法编译:证据、恢复与安全回退

如果 VMware Workstation 在内核更新和重启前正常、之后却提示 vmnetvmmon 无法编译,先把它视为一次由内核切换触发的兼容性事件,而不是立即修改 VMware 自带源码。相似的界面提示至少可能来自四类不同问题:产品与宿主内核不在支持组合内、正在运行的内核缺少匹配的构建树、编译器或工具链不匹配,以及模块已生成但被 Secure Boot 拒绝加载。

本文从“刚刚更新了内核”这个时间点出发,给出取证、临时恢复、受支持修复和回退路径。更完整的版本支持矩阵、发行版头文件安装方法及 MOK 流程,参见站内的 VMware 内核头文件与支持矩阵指南

安全边界: 先正常关闭所有虚拟机,并确认虚拟机文件有独立、可恢复的备份。不要开启长期 root shell,不要直接解包并改写 /usr/lib/vmware/modules/source 中的归档,不要运行来源不明的预编译模块,也不要为了加载模块而关闭 Secure Boot。远程宿主在重启或换内核前必须有带外控制台。旧内核只能作为有时限的应急回退,不能永久冻结安全更新。

1. 固定事件时间线,不要先动系统

先记录故障前后唯一发生的变化:内核包、宿主发行版、VMware 版本,还是 Secure Boot/MOK 状态。下面的命令只读;单条命令失败本身也是证据,不要用猜测的包名“补齐”结果。

date -Is
uname -r
uname -m
cat /etc/os-release
vmware --version
last -x reboot | head -n 5
journalctl --list-boots

再查发行版自己的包管理历史,确认新内核的准确包版本和安装时间。Debian/Ubuntu、Fedora/RHEL、openSUSE 的历史查询方式不同,应使用该发行版当前文档,而不是把其他发行版的安装命令直接套用。记录工作内核和故障内核的完整 uname -r,不要只写“6.x”。

2. 保存原始日志,并在分享前脱敏

Broadcom 说明 VMware 在首次启动或安装时会本地构建 vmmonvmnet,进度可出现在 /tmp/vmware-root/vmware-PID.log。先列出候选日志,不要删除或覆盖:

find /tmp/vmware-root -maxdepth 1 -type f -name 'vmware-*.log' -printf '%T@ %p\n' 2>/dev/null | sort -nr | head
journalctl -k -b --no-pager | grep -Ei 'vmmon|vmnet|module|verification|signature|lockdown|required key'

同时保存 VMware 弹窗中的第一处编译错误及其前后上下文;最后一行通常只是汇总。对外分享前,应删除用户名、主机名、内部路径、内部仓库地址、网络接口地址和任何令牌。不要上传 .vmx、磁盘文件、许可证材料、私钥或完整虚拟机清单。

3. 用失败阶段分类,而不是凭症状猜修复

证据位置 常见分类 下一步
当前 VMware/宿主/内核不在 Broadcom 支持表内 支持组合不匹配 更新到供应商支持的 VMware 版本,或短期启动已知正常且仍受发行版维护的内核
/lib/modules/<运行内核>/build 缺失或不是该内核 头文件/构建树不匹配 从当前发行版的官方仓库安装与完整 uname -r 精确匹配的开发包
日志在 C 编译前就报 gccmake 或生成工具缺失 工具链缺失 按 VMware 支持说明和发行版文档安装精确前置项
日志包含内核 API、类型或函数编译错误 源码与内核 API 不兼容 优先升级 VMware 或回退到支持内核;不要套用其他版本的补丁
编译成功,但内核日志出现签名、验证或 lockdown 错误 Secure Boot/模块签名 按当前发行版和 Broadcom 的流程签名并登记 vmmonvmnet
两个模块均已加载,但 NAT、桥接或仅网络失效 运行期网络问题 转向 VMware 服务、虚拟网络配置和宿主网络诊断,不再重复编译

Broadcom 的当前支持表会列到具体 VMware 版本、宿主发行版和部分内核上限;不能由“发行版名称相同”推断任意 HWE、OEM、自编译或主线内核都受支持。

4. 核对运行内核、构建树和工具链

外部模块必须针对正在运行的内核构建。Linux 内核文档说明,构建树需要包含对应配置和头文件;一个存在但指向另一内核的目录同样不合格。

KernelRelease="$(uname -r)"
readlink -f "/lib/modules/$KernelRelease/build"
test -r "/lib/modules/$KernelRelease/build/Makefile" && echo 'build tree present' || echo 'build tree missing'
cat /proc/version
gcc --version
make --version

不要创建假的 build 符号链接,也不要从随机镜像下载头文件。内核风格、架构、配置和开发包必须彼此匹配。编译日志若明确要求特定编译器,再与 /proc/version 的构建信息比较;轻微版本差异不等于自动失败,真正的报错才是依据。具体发行版包名见前述 站内深度指南

5. 先选择受支持、可逆的恢复路径

按风险从低到高处理:

  1. 临时启动已知正常内核。 在本地或带外控制台的引导菜单中选择先前已验证的内核;Ubuntu 的官方恢复文档说明可从 GRUB 的 “Advanced options” 选择具体内核。不要删除新内核,也不要把旧内核永久设为默认。若新内核修复了安全漏洞,应缩短回退窗口和宿主暴露面。
  2. 核对并安装供应商支持的 VMware 更新。 只使用 Broadcom 官方门户或组织批准的软件源,核验版本、签名和发布说明;先确认该版本支持目标宿主与内核。保留安装介质、配置备份和回退版本。
  3. 补齐精确匹配的发行版开发包。 仅在证据显示构建树或工具缺失时进行,且使用发行版官方仓库。不要盲目升级整个发行版作为一次模块修复。
  4. 在维护窗口运行一次官方模块重建。 确认虚拟机已关闭、支持组合成立、磁盘空间充足后,才运行这一条有权限且有日志的命令:
EvidenceDir="$PWD/vmware-kernel-evidence"
umask 077
mkdir -p "$EvidenceDir"
LogPath="$EvidenceDir/vmware-modconfig-$(date +%Y%m%d-%H%M%S).log"
test ! -e "$LogPath" || exit 1
set -o pipefail
sudo vmware-modconfig --console --install-all 2>&1 | tee "$LogPath"
BuildStatus="${PIPESTATUS[0]}"
echo "vmware-modconfig exit status: $BuildStatus"

这不是通用成功保证:命令行选项属于 VMware 版本接口,运行前应以已安装版本的帮助和 Broadcom 文档为准。不要用 root shell 包住整个会话。若第一次构建失败,保存第一处错误后停止;反复重跑不会修复不受支持的内核 API。

6. 把“编译失败”和“加载失败”分开

如果日志显示 .ko 已成功生成,而 VMware 仍报告 /dev/vmmon 不存在,应检查 Secure Boot 和签名,而不是继续改 C 代码:

command -v mokutil >/dev/null && mokutil --sb-state
modinfo -F filename vmmon
modinfo -F signer vmmon
modinfo -F filename vmnet
modinfo -F signer vmnet
journalctl -k -b --no-pager | grep -Ei 'vmmon|vmnet|verification|signature|lockdown|required key'

modinfo 找不到模块通常仍是构建/安装问题;模块有路径但 signer 为空,且内核日志拒绝签名,才指向签名路径。Broadcom 的官方说明要求同时处理 vmmonvmnet;Ubuntu 也说明自建模块在 Secure Boot 下需要可信签名和 MOK 登记。私钥必须仅由宿主管理员保管并限制权限,不能放入文章、工单、仓库或聊天。模块每次重建后都可能需要重新签名。不要以关闭 Secure Boot 代替修复。

7. vmnet 已加载但网络仍坏,是另一条故障链

先证明模块状态和 VMware 单元名称,再决定是否需要网络层改动:

lsmod | grep -E '^(vmmon|vmnet) '
ip -brief link
systemctl list-unit-files --no-pager | grep -i vmware
journalctl -k -b --no-pager | grep -Ei 'vmnet|bridge|nat|filter'

服务名和网络布局随产品、发行版及安装方式而异。不要因为 vmnet 字样就删除 /etc/vmware/networking、重建所有虚拟网络、清空防火墙,或更改生产桥接。先备份 VMware 网络配置,记录 NAT/host-only/bridge 的预期状态,再用当前版本的 Virtual Network Editor 或官方管理界面做一个有回退点的变更。桥接还可能受宿主 NetworkManager、无线网卡限制、VPN、名称空间或防火墙影响。

8. 社区模块补丁只能是受控例外

社区补丁不是“最新内核的一键修复”。仅当没有供应商支持的产品/内核组合、业务明确接受不受支持状态、且能在隔离环境验证时,才考虑以下评审门槛:

  • 补丁必须精确绑定 VMware 完整版本、内核完整版本和架构;只审查源码差异,不接受来源不明的预编译 .ko
  • 固定提交或发布标签,记录来源、许可证、哈希、评审人和补丁差异;先在一次性测试宿主编译并进行安全审查。
  • 不直接编辑安装目录中的 vmnet.tar/vmmon.tar,不盲目复制其他版本的行号替换,也不运行下载后直接进入 root shell 的脚本。
  • 保留原包和可启动的已知正常内核;产品或内核每次更新后,补丁都必须重新评审,不能静默复用。
  • 生成的模块仍须遵守 Secure Boot 签名策略。若无法说明源码、构建链和签名密钥的信任边界,应停止并升级给 Broadcom、发行版支持方或组织管理员。

生产宿主、受监管环境或承载敏感虚拟机的设备,通常应改用明确受支持的组合,而不是把社区分支当作长期维护策略。

9. 验证、回退与停止条件

重启目标内核后,再采集一次相同证据,并比较而不是只看 GUI 是否打开:

uname -r
modinfo -F filename vmmon
modinfo -F vermagic vmmon
modinfo -F signer vmmon
modinfo -F filename vmnet
modinfo -F vermagic vmnet
modinfo -F signer vmnet
lsmod | grep -E '^(vmmon|vmnet) '
journalctl -k -b --no-pager | grep -Ei 'vmmon|vmnet|verification|signature|lockdown|required key'

先启动不含敏感数据的隔离测试虚拟机,分别验证关机、再次启动以及实际使用的 NAT、host-only 或 bridge 模式;不要用生产虚拟机做第一次测试。失败时回到已记录的工作内核或已批准的 VMware 版本,并保留新旧日志。

遇到以下任一情况应停止:支持矩阵不包含该组合;首次错误是未知内核 API;需要关闭 Secure Boot、执行盲目源码替换或安装未签名二进制;只有远程连接而没有带外控制台;虚拟机没有可验证备份;宿主受组织策略管理;回退内核已不再获得安全维护。此时把 VMware 版本、完整内核版本、发行版、架构、首个脱敏错误、Secure Boot 状态和已经尝试的单次变更交给官方支持或管理员。

官方资料

历史原文存档(仅供出处核验,请勿执行)

下面完整保留 source_export 的可见正文,仅作为 2014 年问题背景与文章出处。其中的 root 操作、直接修改 VMware 内部归档、旧内核 API 替换和删除命令均不适用于当前系统,也未经本指南认可。 本存档未做删除、改写、空白规范化或隐私/安全删节;外部地址位于惰性纯文本围栏内,不是本文推荐链接。


最近将ubuntu升级到了14.04,出现了vmware无法启动的情况。具体表现为:每次启动的时候都会弹出一个VMWare Kernel Module Updater的对话框,要求根据当前内核版本重新编译一些内核模块,但是其中网络模块vmnet总是编译失败。

查找相关资料发现原因在于升级到ubuntu 14.04之后现在的Linux内核版本是3.13,这个内核版本修改了一些底层函数,而VMWare的相关源码包还没有来得及修改相关代码。由于是内核版本的问题,所以同样的问题也大量出现在Fedora等系统上。

因此同样的问题可以继续存在于3.14, 3.15等后续版本中。

解决方法为修改vmnet模块的源码包中的两处代码。

1,获取root权限,进入相关目录:

su

cd /usr/lib/vmware/modules/source


2,解压vmnet源码包(得到vmnet-only文件夹):

tar -xf vmnet.tar


3,备份原来的文件:

mv vmnet.tar vmnet.tar.bak


4,修改源文件filter.c:

4.1,修改206行的:VNetFilterHookFn(const unsigned int hooknum // IN:

为:VNetFilterHookFn(const struct nf_hook_ops *ops, // IN:

4.2,修改255行的: transmit = (hooknum == VMW_NF_INET_POST_ROUTING);

为: transmit = (ops->hooknum == VMW_NF_INET_POST_ROUTING);

5,打包修改过的文件,删除无用的文件

tar -uf vmnet.tar vmnet-only

rm -rf vmnet-only


6,重新编译内核模块,启动vmware

可以直接点击vmware workstation的图标,启动自动检测和编译过程;也可以通过命令:

vmware-modconfig –console –install-all


感谢:Bearox和Garrett Skjelstad

http://blog.csdn.net/bearox/article/details/21294609

http://ping8888.com/2013/12/13/vmware-modules-kernel-3-13/

原载于http://blog.csdn.net/yanxiangtianji

转载请注明出处

Leave a Reply