CVE-2026-53359(Januscape):潜伏16年的 KVM/x86 客户机逃逸漏洞分析与修复

披露时间:2026-07-04(CVE 分配)/ 2026-07-06(公开)
危害等级:🔴 Critical(严重)
漏洞类型:Use-After-Free(CWE-416)→ Guest-to-Host Escape
影响组件:Linux KVM x86 Shadow MMU(arch/x86/kvm/mmu/mmu.c
潜伏时间:约 16 年(自 2010 年 commit 2032a93d66fa 起)
架构范围:Intel VMX + AMD SVM(双架构)
发现者:Hyunwoo Kim(@v4bel)

图 1:Januscape 攻击模型总览


一、漏洞概述

2026 年 7 月,安全研究员 Hyunwoo Kim(@v4bel) 在 oss-security 与 Januscape 项目 中公开了 CVE-2026-53359,并将其命名为 Januscape——一枚可在 KVM/x86 上实现 Guest-to-Host Escape 的 Use-After-Free 漏洞。

据目前公开资料,这是首个可同时在 Intel 与 AMD 上触发的 guest-to-host 逃逸研究案例(不依赖单一厂商扩展指令路径)。漏洞位于内核 KVM 的 Shadow MMU 仿真逻辑中:客户机侧操作即可破坏宿主机 shadow page 状态,进而威胁接受不可信客户机、并暴露嵌套虚拟化(nested virtualization) 的多租户 x86 公有云(如 GCP、AWS 等)。

该漏洞曾作为 0-dayGoogle kvmCTF 中成功利用。

属性详情
CVE 编号CVE-2026-53359
别名Januscape
漏洞类型Use-After-Free / 数据损坏 → DoS / Host Escape
触发面嵌套虚拟化下的 Shadow MMU(非 QEMU 用户态模拟)
权限要求客户机内 root(云实例通常满足)
arm64不受影响(x86 专用)

二、背景:为什么 Shadow MMU 会成为攻击面?

x86 KVM 将客户机虚拟地址翻译到宿主机物理地址,主要有两条路径:

  1. 硬件二级页表(TDP)
    Intel EPT / AMD NPT 由硬件完成 GPA→HPA 二级翻译。现代主机默认启用(kvm-intel.ept=1tdp_mmu=Y),走 TDP MMU

  2. Shadow Paging(影子页表)
    KVM 在软件中“镜像”客户机页表,维护 struct kvm_mmu_page(其后端是 4KB 的 sp->spt)。

嵌套虚拟化是关键开关:当 L1 客户机本身充当 Hypervisor、再用 EPT/NPT 运行 L2 时,硬件只有一级“二级页表”,因此 L0(宿主机)必须用软件 Shadow 掉 L1 为 L2 构建的嵌套页表。这条路径走的是 legacy Shadow MMU,而非 TDP MMU——Januscape 正发生在这里

更重要的是:这一切发生在 in-kernel KVM 中,不经过 QEMU 等用户态 VMM。因此它不是“常见 QEMU 逃逸”,而是纯内核 KVM 缺陷,对自研虚拟化栈的公有云同样危险。

KVM 还为每个 memslot 维护 rmap(reverse map):按 gfn 反向追踪 leaf SPTE。安装 leaf 时把 SPTE 指针加入该 gfn 的 rmap,拆除时再按同一 gfn 键移除。
install 与 teardown 看到的 gfn 键必须一致——Januscape 正是打破了这一不变量。


三、根因:kvm_mmu_get_child_sp() 只比 gfn、不比 role

补丁前的关键函数(arch/x86/kvm/mmu/mmu.c):

static struct kvm_mmu_page *kvm_mmu_get_child_sp(struct kvm_vcpu *vcpu,
						 u64 *sptep, gfn_t gfn,
						 bool direct, unsigned int access)
{
	union kvm_mmu_page_role role;

	if (is_shadow_present_pte(*sptep) && !is_large_pte(*sptep) &&
	    spte_to_child_sp(*sptep) && spte_to_child_sp(*sptep)->gfn == gfn)
		return ERR_PTR(-EEXIST);   /* 仅比较 gfn,忽略 role */

	role = kvm_mmu_child_role(sptep, direct, access);
	return kvm_mmu_get_shadow_page(vcpu, gfn, role);
}

复用判定只看子 shadow page 的 gfn,不看 role
role.direct 区分两类页面:

role.direct含义
0(indirect)真正 shadow 了 guest 页表
1(direct)大页无法按原样映射时,KVM 拆成 4KB 的 direct split 页

fetch 路径中,同一 gfn 既可能走 indirect 创建,也可能走 direct split——仅比 gfn 就会在 role 不匹配时错误返回 -EEXIST,复用错误角色的旧页。这就是 Januscape 的根因。

图 2:Role 混淆触发链

Use-After-Free 路径

错误复用会打乱 shadow page 的生命周期与 parent 指针记账,最终出现:某 shadow page 已释放,仍有父页持有指向它的指针(orphaned parent pointer)。清理时:

__kvm_mmu_prepare_zap_page()
  → kvm_mmu_unlink_parents()
    → drop_parent_pte()
      → mmu_spte_clear_no_track()
        → WRITE_ONCE(*sptep, SHADOW_NONPRESENT_VALUE)  // x86-64: BIT_ULL(63)

内核以为在“清空 shadow page 的一个槽位”,若该页已释放并被其他内核对象占用,这次写入就变成 UAF write。客户机可控制写入的 offset(槽位),写入值固定。

DoS 路径(公开 PoC)

公开 PoC 走更简单的完整性崩溃路径:

  • 被复用的 direct 页没有 shadowed_translation,leaf 的 gfn 按 sp->gfn + index 计算;
  • 安装时 rmap 记在真实 guest gfn 下,拆除时却按计算 gfn 查找;
  • pte_list_remove() 发现 rmap 不一致,触发 KVM_BUG_ON_DATA_CORRUPTION
  • CONFIG_BUG_ON_DATA_CORRUPTION=y(如 RHEL 默认)且 panic_on_oops 场景下,宿主机直接 panic

典型 panic 日志片段:

gfn mismatch under direct page 8a00 (expected 8b00, got 256e4)
WARNING: ... kvm_mmu_page_set_translation ...
kernel BUG at arch/x86/kvm/mmu/mmu.c:1091!
RIP: 0010:pte_list_remove ...
Comm: qemu-kvm

四、触发条件与影响范围

触发前提

条件说明
x86 宿主机Intel 或 AMD,运行 KVM
嵌套虚拟化实例暴露 nested virt(L1 可再开 L2)
未打补丁内核见下方版本表
客户机权限通常需 guest root(加载模块 / 直接操控 VMX/SVM)

在默认 ept=1tdp_mmu=Y 的主机上,普通 GPA 翻译走 TDP,不经过 kvm_mmu_get_child_sp;但一旦 L1 运行嵌套客户机,L0 必须 shadow L1 的 nested EPT/NPT,仍会落入该路径。

受影响版本

漏洞存在区间(git):2032a93d66fa(2010-08-01)→ 81ccda30b4e8(2026-06,修复)。

语义版本上,自 Linux 2.6.36 起受影响,直至下列安全版本(含后续):

分支安全版本(≥)
6.16.1.177
6.66.6.144
6.126.12.95
6.186.18.38
7.17.1.3
mainline7.2-rc1 及含补丁的后续版本

危害场景

  1. KVM Escape
    仅租一台公有云实例,即可 panic 同物理机上所有租户(DoS),或在完整利用链下以 host root 接管宿主机及全部客户机(RCE/Escape)。

  2. 本地提权(次要)
    部分发行版(如 RHEL)/dev/kvm0666,无特权用户也可能把该洞当作可靠 LPE。

  3. 与 QEMU 无关
    缺陷在内核 KVM,对不用 QEMU 的云厂商栈同样适用。


五、利用思路(高层,防御视角)

公开 PoC 是客户机内内核模块:在 L1 内用 raw VMX(Intel)或 SVM(AMD)自建 L2,迫使 L0 对 L1 nested 页表做 shadow,并在 race 窗口触发 role 复用。

核心几何:同一物理页既充当大页 leaf,又充当页表页,使 gfn 相同、role 不同

  1. Writer vCPU 在 huge PDE 与 table PDE 之间来回切换;
  2. Faulter vCPU 反复跑 L2 以制造经过该 PDE 的 fault;
  3. L0 模拟 PDE 写入时,commit 新值与 zap 旧 shadow 链路之间存在非原子窗口;
  4. 窗口内 get_child_sp 仍链着旧 role 子页,却按新 role 请求 → 仅 gfn 匹配即复用。

完整逃逸原语更刁钻:UAF 写值固定(SHADOW_NONPRESENT_VALUE),攻击者只控 offset,需跨 cache 选准 victim 对象;Intel/AMD 利用路径不同。完整 escape exploit 作者暂未公开。

⚠️ 请勿在未授权环境加载任何 PoC 模块。 本文仅作防御与原理说明。


六、修复方案

图 3:官方补丁与安全版本

方案一:升级内核(强烈推荐 ⭐)

主线补丁 commit:81ccda30b4e8
核心改动:复用条件增加 role.word 比较

-	if (is_shadow_present_pte(*sptep) && !is_large_pte(*sptep) &&
-	    spte_to_child_sp(*sptep) && spte_to_child_sp(*sptep)->gfn == gfn)
+	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 &&
+	    spte_to_child_sp(*sptep)->role.word == role.word)
 		return ERR_PTR(-EEXIST);

role 不同时不再复用,改为创建正确角色的新 shadow page,rmap 损坏与 UAF 路径随之消失。

发行版升级建议:

# 确认当前内核
uname -r

# Debian / Ubuntu(示例:关注 security 通道)
sudo apt update && sudo apt full-upgrade

# RHEL / Alma / Rocky
sudo dnf update kernel

# 重启进新内核
sudo reboot

云厂商请优先应用 host 侧 内核补丁(客户机升级无法修复宿主机 KVM)。

方案二:临时缓解(无法立即升级时)

措施说明代价
关闭嵌套虚拟化对不可信租户禁用 nested virt无法在 VM 内再开 VM
限制 /dev/kvm收紧权限,避免本地 LPE不影响远程租户逃逸主路径
租户隔离关键工作负载独占物理机 / 使用机密计算成本上升
监控关注 qemu-kvm 异常、pte_list_remove / gfn mismatch 日志检测滞后

临时缓解不能替代补丁:只要暴露 nested virt 且内核未修,恶意租户仍可攻击 host。

方案三:确认补丁是否已合入

# 在内核源码树中
git log --oneline --grep='unexpected role' arch/x86/kvm/mmu/mmu.c
# 或检查是否包含 81ccda30b4e8 及其 stable 回移植

# 运行中的系统可对照厂商 changelog / CVE 公告
rpm -q --changelog kernel | grep -i 53359   # RPM 系示例

七、披露时间线

时间事件
2026-06-12security@kernel.org 提交漏洞细节与利用
2026-06-13与 KVM 维护者 Paolo / Sean 讨论补丁方案
2026-06-17Paolo 将补丁发至 lore 测试
2026-06-19补丁 81ccda30b4e8 合入 mainline
2026-07-01提交 linux-distros,约 5 天 embargo
2026-07-04分配 CVE-2026-53359
2026-07-06embargo 结束,oss-security 与 Januscape 文档公开

八、总结与行动清单

Januscape 再次说明:虚拟化隔离边界上的“小不变量”(gfn + role)一旦被打破,后果可以是整机失陷。它潜伏约 16 年,跨 Intel/AMD,且不依赖 QEMU——对公有云与自建 KVM 集群都是高优先级补丁。

立即行动清单

  • 1. 资产盘点:列出所有 x86 KVM 宿主机(含 OpenStack、Proxmox、自建云、裸金属 KVM)。
  • 2. 版本核对:对照 6.1.177 / 6.6.144 / 6.12.95 / 6.18.38 / 7.1.3 等安全版本。
  • 3. 优先补 host 内核:客户机升级不能替代宿主机修复。
  • 4. 评估 nested virt:对不可信租户默认关闭嵌套虚拟化。
  • 5. 收紧 /dev/kvm:避免 0666 带来的本地提权面。
  • 6. 日志监控:关注 gfn mismatch under direct pagepte_list_remove、突发 qemu-kvm panic。
  • 7. 关联加固:同步检查 arm64 上的 ITScape (CVE-2026-46316) 等兄弟漏洞是否已修。

参考资源


⚠️ 免责声明:本文仅供安全研究与防御参考。请勿在未授权系统上测试或利用该漏洞。请尽快为 KVM 宿主机应用官方内核补丁,保护多租户隔离与生产环境安全。

CVE-2026-53359(Januscape):潜伏16年的 KVM/x86 客户机逃逸漏洞分析与修复

作者

Cryolite 冰晶石

发布日期

2026 - 07 - 13

Cryolite 冰晶石

撃っていいのは撃たれる覚悟のあるヤツだけだ。