内核补丁在我方宿主机环境已测试通过,现开源修补模块。如遇不可用问题请及时发起 issue. https://github.com/Aoripus-LTD/Januscape-Hotfix
README(原文见Github):
Januscape 热修复 — CVE-2026-53359
针对 CVE-2026-53359(Januscape) 的零停机实时补丁——KVM/x86 shadow MMU
中的虚拟机逃逸漏洞。
无需重启、无需迁移虚拟机,直接修补运行中的内核。
- 概述
- 本热修复做了什么
- 如何检查你的内核是否存在漏洞
- 部署
- 方案 A:一键热修复
- 方案 B:手动内核补丁
- 架构
- 系统要求
- 宿主机内核
- 编译环境
- 虚拟机(攻击面)
- QEMU 版本与 PoC 的可利用性
- Go 安装器参考
- 验证
- 故障排查
- 常见问题
- 项目结构
- 许可证
- 参考资料
概述
Januscape 是 kvm_mmu_get_child_sp() 中的一个 UAF(释放后使用) 漏洞,
允许 KVM 虚拟机:
- 拒绝服务(DoS):引发宿主机内核 panic,导致同一物理机上所有租户 VM 全部瘫痪
- 虚拟机逃逸:在宿主机上执行任意代码(完整逃逸利用代码已存在但尚未公开)
该漏洞潜伏了 16 年(2010 年至 2026 年 6 月),同时影响 Intel(VMX/EPT)
和 AMD(SVM/NPT)——是首个已确认的跨架构 KVM 逃逸漏洞。
| 详情 | |
|---|---|
| CVE 编号 | CVE-2026-53359 |
| 原始 PoC | github.com/V4bel/Januscape |
| 上游修复 | commit 81ccda30b4e8(2026-06-16 并入主线) |
| 影响范围 | Linux ≥ 2.6.35(2010-08-01)至未包含 81ccda30b4e8 的内核 |
| 已修复版本 | 主线 ≥ 2026-06-16;执行 grep 'role.word' /proc/kallsyms 确认 |
| 触发条件 | 嵌套虚拟化(L1 使用裸 VMX/SVM 运行 L2) |
| 所需权限 | 虚拟机 root 权限(公有云实例通用条件) |
| 影响架构 | Intel VMX/EPT + AMD SVM/NPT(仅 x86,arm64 不受影响) |
本热修复做了什么
修复在 shadow page 复用检查中新增一个条件:
// 修复前(存在漏洞):仅比较 gfn 就复用
if (... && spte_to_child_sp(*sptep)->gfn == gfn)
// 修复后(安全):同时要求 role 匹配
if (... && spte_to_child_sp(*sptep)->gfn == gfn
&& spte_to_child_sp(*sptep)->role.word == role.word)
这阻止了直接拆分页(direct split page)被错误复用于间接影子遍历(indirect
shadow walk),从而避免反向映射(reverse map)损坏和 UAF。
如何检查你的内核是否存在漏洞
# 如果返回空,说明内核未包含上游补丁,需要安装本热修复
grep 'role.word' /proc/kallsyms
部署
方案 A:一键热修复(推荐,零停机)
这是热补丁方案——在不重启、不迁移虚拟机的情况下将修复应用于运行中的内核。
预构建模块(相同内核版本)
# 加载热修复(零停机,不影响任何虚拟机)
insmod hotfix-$(uname -r)-x86_64.ko
# 验证
dmesg | grep "PATCH ACTIVE"
# 回滚(恢复原始函数)
rmmod hotfix
在目标主机上从源码编译
# RHEL / CentOS
yum install -y kernel-devel-$(uname -r) make gcc
# Debian / Ubuntu
apt install -y linux-headers-$(uname -r) build-essential
# 编译并加载
cd kmod && make && insmod hotfix.ko
Go 安装器(推荐用于集群部署)
cd installer
go build -o januscape-hotfix .
# 仅检查前置条件
./januscape-hotfix check
# 部署(自动检测偏移量、编译、加载、验证)
./januscape-hotfix deploy --force
# 回滚
./januscape-hotfix rollback
架构
┌─────────────────────────────────────────────────────┐
│ Go 安装器 │
│ 检测偏移量 → 编译 kmod → insmod → 验证 │
│ (BTF → DWARF → 数据库 → 默认值) │
└────────────────────┬────────────────────────────────┘
│ gfn_off=0x38 role_off=0x28
▼
┌─────────────────────────────────────────────────────┐
│ 内核模块 (hotfix.ko) │
│ │
│ 通过 ftrace Hook kvm_mmu_get_child_sp(): │
│ 优先级 1:register_ftrace_direct() [5.11+] │
│ 优先级 2:ftrace IPMODIFY + SAVE_REGS [4.0+] │
│ │
│ 运行时解析 KVM 内部符号: │
│ kallsyms_lookup_name(直接调用或 kprobe 降级) │
└─────────────────────────────────────────────────────┘
Hook 机制选择
| 内核版本 | 方法 | 可靠性 |
|---|---|---|
| ≥ 5.14 | register_ftrace_direct(ops, addr) |
最佳 — 直接调用跳板 |
| 5.11–5.13 | register_ftrace_direct(ip, addr) |
良好 — 直接调用跳板(旧 API) |
| 4.0–5.10 | ftrace IPMODIFY + SAVE_REGS | 良好 — 通过 ftrace 处理程序重定向 IP |
| < 4.0 | 不支持 | 需要 CONFIG_DYNAMIC_FTRACE_WITH_REGS |
kallsyms_lookup_name 解析方式
| 内核版本 | 方法 |
|---|---|
| < 5.7 | __symbol_get("kallsyms_lookup_name") — 已导出 |
| ≥ 5.7 | 对 kallsyms_lookup_name 使用 kprobe — 未导出,偷取地址 |
系统要求
宿主机内核
- Linux ≥ 4.0(需要
FTRACE_OPS_FL_IPMODIFY) CONFIG_DYNAMIC_FTRACE=y(所有发行版内核默认开启)CONFIG_KALLSYMS_ALL=y(RHEL/CentOS/Debian/Ubuntu 默认开启)CONFIG_DYNAMIC_FTRACE_WITH_REGS=y(< 5.11 内核需要)
编译环境
- 与目标内核版本匹配的
kernel-devel/linux-headers gcc、makebpftool(可选 — 用于自动偏移量检测)
虚拟机(攻击面)
- 向虚拟机暴露了嵌套虚拟化(
kvm_intel.nested=1或kvm_amd.nested=1) - 虚拟机拥有 root 权限(公有云实例通用条件)
QEMU 版本与 PoC 的可利用性
测试中发现的意外现象:即使漏洞信号始终能到达内核,QEMU 版本会影响 PoC
能否完全触发宿主机 panic。
| QEMU 版本 | PoC 行为 | 详情 |
|---|---|---|
| ≥ 7.0 | 完全暴露 — PoC 触发宿主机 panic | 嵌套 VMX/SVM 透传成熟;L1 的 vmxon/vmrun 到达存在漏洞的 KVM shadow MMU 路径并赢得竞争。 |
| 6.x | 部分暴露 — 虚拟机崩溃,宿主机存活 | PoC 的嵌套 VMX 操作确实到达了 L0 KVM(dmesg 中可见 nested_vmx_load_cr3 / vmx_handle_exit),证明了逃逸信号越过了边界。但 QEMU 6.x 不完整的嵌套 VMX 模拟在 L0 上赢得竞争之前就将 L1 VM abort 了。 |
| ≤ 5.x | 不太可能到达漏洞路径 | 嵌套 VMX 出现之前的 QEMU 时代;L1 根本无法执行 vmxon。 |
实测证据 — 测试环境:QEMU 6.2.0(EL8),L0 内核 6.19.2-elrepo,L1
内核 6.8.0-55-generic(Ubuntu 24.04):
# ── L1(测试虚拟机)──
$ dmidecode -s system-product-name
KVM # ← 确认:这是一台虚拟机
$ grep -E 'vmx|vmcs|shadow' /proc/cpuinfo | head -3
vmx flags: vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad
ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid
unrestricted_guest vapic_reg vid shadow_vmcs pml tsc_scaling
# ← 嵌套 VMX 特性已就绪
$ sudo rmmod kvm_intel && sudo modprobe kvm_intel nested=1
$ lsmod | grep kvm
kvm_intel 487424 0 # ← 虚拟机内嵌套 KVM 正常工作
kvm 1404928 1 kvm_intel
$ cd Januscape-main && make && sudo rmmod kvm_intel && sudo insmod poc.ko
[*] poc step 1/4: backend=VMX/EPT ready
[*] poc step 2/4: nested page tables + L3 guest image built
[*] poc step 3/4: launching 8 kthreads (1 writer + 7 faulters)
[*] poc step 4/4: race live -- host DoS triggering
# ← 虚拟机随即崩溃
# SSH 连接中断
# ── L0(宿主机)──
$ qemu-system-x86_64 --version
QEMU emulator version 6.2.0 # ← QEMU 6.x
$ dmesg | grep 'nested_vmx\|vmx_handle_exit' | tail -5
? vmx_get_segment+0xc5/0x130 [kvm_intel]
? nested_vmx_load_cr3+0xab/0x160 [kvm_intel] # ← 逃逸信号已到达
vmx_handle_exit+0xe/0x40 [kvm_intel] # L0 KVM!
? nested_vmx_load_cr3+0xab/0x160 [kvm_intel]
vmx_handle_exit+0xe/0x40 [kvm_intel]
$ uptime # ← 宿主机存活,未 panic
18:23:41 up 7 days, 3:14, 1 user
关键结论:逃逸信号(
nested_vmx_load_cr3→vmx_handle_exit)可
证实地到达了 L0 KVM。QEMU 6.x 在越过边界之后才 abort 了 L1 VM,
但 KVM 中存在的漏洞代码路径已经在执行。
重要:QEMU 6.x abort 虚拟机不是安全保障——漏洞信号已证实到达
宿主机 KVM。更精巧的利用方式(或其他嵌套 VMX 触发序列)仍可能在 7.x
之前的 QEMU 上赢得竞争。请勿将 QEMU 版本视为缓解措施。
Go 安装器参考
januscape-hotfix <命令> [参数]
命令:
deploy 检测、编译并安装热修复
check 仅试运行:验证前置条件
rollback 卸载热修复(rmmod)
status 显示当前热修复状态
build 仅编译内核模块(不部署)
参数:
--force, -f 跳过确认提示
--all 为所有已安装的 kernel-devel 包编译
偏移量检测优先级
BTF (bpftool) → DWARF (vmlinux 调试信息) → 偏移量数据库 → 默认值
struct kvm_mmu_page 需要以下结构体字段偏移量:
| 字段 | 典型偏移值 | 含义 |
|---|---|---|
gfn |
0x38(6.x)/ 0x30(4.x) |
虚拟机物理帧号 |
role.word |
0x28(6.x)/ 0x20(4.x) |
shadow page 角色 |
在目标内核上验证:
pahole -C kvm_mmu_page /usr/lib/debug/lib/modules/$(uname -r)/vmlinux \
| grep -E 'gfn|role'
Shell 脚本(简易替代方案)
# 无需 Go 环境的快速部署
./apply.sh # 交互式部署
./apply.sh --force # 非交互模式
./apply.sh --rollback # 卸载热修复
./apply.sh --status # 检查状态
./apply.sh --check # 仅检查前置条件
方案 B:手动内核补丁(编译新内核)
如果不使用热补丁模块,希望将修复永久内建于内核,则可直接将上游补丁应用到
内核源码树:
# 1. 下载并应用上游修复
cd /path/to/linux-source
curl -L 'https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/patch/?id=81ccda30b4e8' | patch -p1
# 2. 验证变更(仅一个文件,6 行添加,4 行删除)
git diff arch/x86/kvm/mmu/mmu.c
# 3. 按发行版流程重新编译并安装内核
# (RHEL/CentOS:make rpm-pkg;Debian/Ubuntu:make bindeb-pkg)
完整修复仅有 10 行 diff:
--- a/arch/x86/kvm/mmu/mmu.c
+++ b/arch/x86/kvm/mmu/mmu.c
- union kvm_mmu_page_role role;
+ union kvm_mmu_page_role role = kvm_mmu_child_role(sptep, direct, access);
- if (is_shadow_present_pte(*sptep) && !is_large_pte(*sptep) &&
- spte_to_child_sp(*sptep) && spte_to_child_sp(*sptep)->gfn == gfn)
+ if (is_shadow_present_pte(*sptep) &&
+ !is_large_pte(*sptep) &&
+ spte_to_child_sp(*sptep) &&
+ spte_to_child_sp(*sptep)->gfn == gfn &&
+ spte_to_child_sp(*sptep)->role.word == role.word)
return ERR_PTR(-EEXIST);
- role = kvm_mmu_child_role(sptep, direct, access);
return kvm_mmu_get_shadow_page(vcpu, gfn, role);
注意:Go 安装器和
apply.sh是按现状提供、不作任何保证的便利
工具。它们已在常见的 RHEL/CentOS/Debian/Ubuntu 内核配置(开启
CONFIG_DYNAMIC_FTRACE=y和CONFIG_KALLSYMS_ALL=y)上经过测试。在
生产环境部署前,请先在自有测试环境中验证。对于关键业务系统,推荐使用
手动内核重编译方案(方案 B)。
验证
# 1. 模块已加载
lsmod | grep hotfix
# 2. dmesg 中确认热补丁已生效
dmesg | grep "PATCH ACTIVE"
# 3. Sysfs 热补丁状态
cat /sys/kernel/livepatch/hotfix/enabled
# 4. kallsyms 中能看到已修补的符号
grep januscape /proc/kallsyms
故障排查
| 症状 | 可能原因 | 解决方法 |
|---|---|---|
kvm_mmu_get_child_sp not in kallsyms |
未设置 CONFIG_KALLSYMS_ALL |
检查内核配置 |
register_ftrace_direct: -22 |
函数未找到或已修补 | 验证 grep kvm_mmu_get_child_sp /proc/kallsyms |
insmod: Unknown symbol |
KVM 模块未加载 | 先执行 modprobe kvm |
加载后 dmesg 出现 gfn mismatch |
结构体偏移量错误 | 手动指定:insmod hotfix.ko gfn_off=0x?? role_off=0x?? |
| 模块加载但热补丁未生效 | KVM 在热补丁之后加载 | 卸载热补丁,加载 KVM,再重新加载热补丁 |
找不到 kernel-devel |
缺少内核头文件 | 安装对应版本的 kernel-devel-$(uname -r) |
常见问题
需要重启吗?
不需要。 这是实时补丁。通过 insmod 加载,通过 rmmod 移除。不
影响任何正在运行的虚拟机。
会影响正在运行的虚拟机吗?
不会。 该修复只改变未来 shadow MMU 遍历的 shadow page 复用
逻辑。现有的 shadow pages 不受影响。
低于 4.0 的内核怎么办?
不支持。4.0 之前的内核缺少 FTRACE_OPS_FL_IPMODIFY。如果仍在运行
RHEL 7(3.10),需要基于 text_poke 的方案(独立项目)或升级内核。
arm64 受影响吗?
不受。 Januscape(CVE-2026-53359)仅影响 x86。但 arm64 KVM 宿主机
应关注另一个独立漏洞 ITScape (CVE-2026-46316)。
如果我的内核已经包含上游修复怎么办?
安装器会检测到:
grep 'role.word' /proc/kallsyms && echo "已修补"
可以编译一次部署到多台机器吗?
可以。在安装了匹配 kernel-devel 的主机上编译:
cd kmod && make KDIR=/path/to/target-kernel-headers
# 将 hotfix.ko 分发到相同内核版本的主机
或使用 make all-kernels 为所有已安装的内核版本编译。
QEMU 6.x 部分屏蔽了 PoC——我安全吗?
不。 PoC 的嵌套 VMX 信号即使在 QEMU 6.x 上也会到达宿主机 KVM
(dmesg 中 nested_vmx_load_cr3 的调用栈轨迹已证实)。虚拟机崩溃
是因为 QEMU 6.x 的嵌套 VMX 模拟不完全,但逃逸信号已经越过了边界,
进入了存在漏洞的 KVM 路径。更精巧的触发序列可能无视 QEMU 版本赢得
竞争。请升级 QEMU 并修补 KVM——不要将任何一方视为另一方的替代品。
项目结构
.
├── kmod/
│ ├── hotfix.c # 通用内核模块(4.x–6.x)
│ ├── offsets_db.h # 结构体偏移量数据库(降级方案)
│ └── Makefile # 内核模块编译系统
├── installer/
│ ├── main.go # Go 安装器(deploy/check/rollback/status)
│ └── go.mod # Go 模块定义
├── apply.sh # Shell 部署脚本(替代方案)
├── .gitignore
├── README.md # 英文文档
└── README.zh-CN.md # 中文文档(本文件)
许可证
GPL v2,详见 Linux 内核源码树中的 COPYING 文件。
版权所有 (c) 2026 AORIPUS (BEIJING) TECHNOLOGY CO., LTD. & GEELINX LTD.
联系方式:master@aoripus.com
参考资料
- 原始 PoC — V4bel/Januscape
- 上游修复 — commit 81ccda30b4e8
- lore.kernel.org 补丁讨论
- oss-security 公告
- Google kvmCTF
公告原文
影响范围:KVM 实例(须启用嵌套虚拟化)
尊敬的 Geelinx 用户:
近日,安全社区披露了名为 Januscape (CVE-2026-53359) 的高危 KVM 逃逸漏洞。该漏洞潜伏于 Linux 内核的 KVM 影子页表 (Shadow MMU) 机制中,允许拥有虚拟机 root 权限的用户通过特定操作,导致其所在的物理宿主机内核崩溃(DoS),甚至存在进一步获取宿主机权限的风险。
鉴于 Geelinx 全面采用 KVM 架构,且我们的 Compute VPS 产品原生支持嵌套虚拟化,此漏洞属于最高风险级别。Geelinx 在获悉情报后已第一时间介入,现将我们的应对方案与修复计划公告如下:
响应与修复措施
我们深知业务连续性对您的重要性。为了最大程度保障用户的正常业务不中断,Geelinx 暂不会执行全局关闭嵌套虚拟化或强制重启所有物理机的应急方案。
目前,我们的正在执行为底层宿主机网络下发内核热补丁。该技术将在系统运行状态下直接修复内存中的漏洞逻辑,整个过程对您的实例完全透明,无需重启实例,不影响嵌套虚拟化功能。在热补丁全面覆盖完毕前,我们已在物理宿主机层面启用了高优先级的 eBPF 探针监控。
热修补补丁测试完成后,我们将开源该补丁供 IDC 商家作为修补方案
对您的影响
正常业务用户:您无需采取任何操作,您的业务、网络、以及运行中的虚拟机/容器环境均不会受到此次修复影响。
安全警告(零容忍政策): 我们已将 Januscape 漏洞特征加入系统监控。任何尝试在 Geelinx 实例内运行相关 PoC、恶意构造影子页表异常、或企图攻击宿主机的行为,将会被记录日志,对于蓄意破坏底层节点稳定性的账号,我们将直接封禁并清退。
维护物理节点的稳定是保障所有租户权益的底线。我们将密切关注上游内核社区的最新动态。
感谢您对 Geelinx 的理解与支持。如有任何疑问,请随时通过工单系统联系技术支持团队。
Geelinx LTD
2026.7.7
