11 月 3 日 12:00 UTC,Xen 项目把 XSA-523 从预披露列表里放出来。标题很短:arbitrary read/write via grant copy。
内容更短。受影响范围:4.6 及之后的所有版本。影响:恶意 guest 可以读写其他 domain 的任意内存,包括 Dom0。缓解措施:无。
XCP-ng 在同一天的更新说明里把话说得直白:“a single compromised guest can break out of its isolation and take over the whole host.”(一个被拿下的 guest 就能越出隔离,接管整台宿主机。)Vates 给这条评了 Critical。
这不是一台机器的问题。公有云上跑 Xen 的每一台宿主机、Qubes OS 的每一台笔记本、以及所有基于 4.6 到 4.19 之间版本的下游产品,都在这个范围里。
到底出了什么事
先把两张 CVE 摆清楚。它们属于同一个根因,是两个独立的判断错误:
| 编号 | 错在哪 |
|---|---|
| CVE-2026-102703 | 帧号(frame number)与 grant 引用(grant reference)在内部缓存里被弄混了 |
| CVE-2026-102704 | 按帧号拷贝本应只允许操作调用者自己的内存,这项检查放错了位置 |
两个都出在 grant copy 这条路径上。Xen 公告的原话是:“For performance reasons, Xen caches details internally to reuse already validated data. The conditions on when to re-validate the internal data were not correct in some cases.”
翻译过来:为了性能,Xen 在内部缓存了细节,好复用已经校验过的数据;而“什么时候该重新校验”的条件,在某些情况下是错的。
版本边界有点反直觉:Xen 4.5 及更早不受影响。原因不是老版本更安全,而是这套缓存优化本身是 4.6 才加进去的。一个为吞吐做的优化,八年后变成了隔离边界上的窟窿。
补丁的情况按平台分成三种:
| 平台 | 状态 | 代价 |
|---|---|---|
| Xen 4.19.x 及 unstable | 有补丁(xsa523-1/2.patch) | 重启宿主 |
| Xen 4.18.x – 4.17.x | 有补丁(xsa523-4.18-1/2.patch) | 重启宿主 |
| Xen 4.6 – 4.16 | 没有补丁 | 只能升大版本,或把不可信 guest 挪走 |
| XCP-ng 8.3 | xen-4.17.7-4.2.xcpng8.3,11 月 3 日发布 | 必须重启主机 |
| Qubes 4.3 | Xen 4.19.6-3 进 dom0 | 重启 dom0;AEM 用户要重新封装口令 |
| Debian bookworm / trixie / forky | 仍标 vulnerable | 等安全更新 |
| Debian sid | 已修 | — |
4.16 拿不到补丁有具体原因:它的安全支持在 2024 年 12 月 2 日就结束了。还跑 4.16 的机器,从那天起就已经在“自己承担风险”的状态里,这次只是把风险具体化了。
补丁之外还有一层成本,容易被低估:Xen 没有热补丁。Linux 内核有 livepatch、kpatch 这类机制,可以在不停机的情况下替换函数;hypervisor 层没有等价物,因为要替换的是正在为所有 guest 提供隔离的那段代码。所以 Xen 的安全更新,落地形式永远是“重启物理机”。
这也是为什么 Xen 系的安全公告里,“有没有补丁”和“敢不敢重启”是两个独立的问题。补丁发了不等于修好了,中间隔着一个排期。
拆解:grant copy 是什么,缓存又是怎么错的
要理解这个洞,得知道 Xen 里两台虚拟机之间怎么搬数据。
虚拟机(domain)之间不共享内存,这是 Xen 的第一条设计原则。一台机器想把一块磁盘或一张网卡给 guest 用,标准做法是:拥有设备的 domain(通常是 Dom0)把自己的页“借”出去,在 grant table 里登记一条记录。这条记录里有两个编号,一个是对外的租约号 gref(grant reference),一个是真实的物理页号 mfn(machine frame number),外加读/写权限位。
guest 想读磁盘,就给后端一个 gref。后端拿着 gref 去 hypervisor 请求 grant copy:把那个页里的 4 KB 搬到我的缓冲区里。整个过程 hypervisor 充当中间人,两边都没有对方的页表项。
关键在于 hypervisor 每次都要查表:这个 gref 对应的页在哪、有没有写权限、是不是已经过期。这一步是热点路径,虚拟机每读写一次磁盘、每发一个网络包都要走。
所以 Xen 做了一个优化:批量操作时,如果连续的几次 copy 落在同一个页上,就不重复查表,把上一次校验过的结果直接拿来用。 一次 128 KB 的块读写是 32 个 4 KB 页的连续拷贝,这个优化能省掉 31 次查表。
这个优化的收益不是小数。一台跑 20 台虚拟机的宿主机,网络和磁盘的 grant copy 每秒能到几十万次,每次查表都要拿 grant table 的锁、走一遍权限判断。省掉 31/32 的查表,等于把这条路径的开销压到原来的十分之一量级。这也是为什么它会被写进去,以及为什么八年没人愿意动它。
代价是这套缓存必须自己保证“校验结果”和“校验对象”一直对得上。一旦对不上,hypervisor 会非常自信地放行一次它没检查过的拷贝,而且不会报错。
公告说“帧号和 grant 引用被弄混了”,落到代码上就是缓存键的问题。缓存里存的是一组(编号 → 校验结果)的映射,但这组编号有两种来源:gref 来自 grant table,mfn 来自物理地址空间。两者都是整数,都在同一段范围里,缓存键如果不带类型标记,gref = 0x1a3f 和 mfn = 0x1a3f 会命中同一条缓存。攻击者只要构造一批 copy,让自己的 gref 数值等于别人页面的 mfn,就能让 hypervisor 拿“我自己的页已校验”的记录,去放行“别人的物理页”。
第二个洞更直接。按帧号拷贝(而不是按 gref)本来只允许用于调用者自己的内存,因为帧号是物理地址空间的直接索引,不做这层限制等于给了 guest 一个任意物理地址读写口。这项检查的位置不对,走到了缓存命中的快路径上就被绕过了。
用门禁打个比方。保安记不住每张脸的权限,只能记工牌号。第一次刷卡他核对了一遍,没问题,于是把“这个号可以进”记在便签上。后面来的人只要报同一个号,他就直接放行。现在的问题是,便签上写的号是门牌号,而访客报的是工号,两个编号长得一样,数字又碰巧对得上。
这不是 grant copy 第一次出事
今年 7 月 28 日,Xen 发过 XSA-500,也是 grant copy 的问题,走的是另一套补丁。XSA-523 在公告里明确写了“与 XSA-500 独立,有自己的补丁”。
同一个组件,四个月里两个洞。这不是巧合。grant copy 是 Xen 里少数几个**同时处理“来自不可信方的输入”和“直接访问物理内存”**的地方,权限判断、缓存、批量优化、兼容旧 ABI 全挤在两个文件里。这种地方出问题,往往是多个优化互相叠出来的缝,单看哪一条逻辑都是对的。
历史上这个位置出过不止一次事。2015 年的 VENOM(CVE-2015-3456)出在软驱控制器,2017 年的 XSA-216 出在 grant table,2022 年的 XSA-387 又是一批内存泄漏。虚拟化层的漏洞密度从来高于普通内核代码,因为它坐在“隔离”这个位置上,任何一点差错都会被放大成跨租户。
谁需要动,动起来有多贵
这个洞的修复成本,和“谁的机器”高度相关。
跑 XCP-ng / XenServer 的私有云和托管商。 需要重启物理主机。XCP-ng 8.3 的更新包 11 月 3 日就发了,但没有热补丁机制,重启就是重启。一台宿主机上跑 30 台虚拟机的话,这是一次计划内的全量停机。托管商要排窗口、要通知客户、要处理“能不能不重启”的扯皮。Vates 把它评成 Critical,就是为了让这件事排进本周而不是下个季度。
Qubes OS 用户。 Qubes 的整个安全模型建立在“每个 qube 是一个 Xen domain”上,Xen 的隔离就是它的全部。Qubes 4.3 把补丁推到 dom0,代价是重启 dom0,也就是关掉所有正在运行的 qube。公告里还有一条容易漏的:用 Anti Evil Maid 的人必须重新封装口令,因为新的 Xen 二进制改变了 PCR18 和 PCR19 的度量值。这一步不做,下次启动会被自己的完整性校验拦住。
公有云的多租户环境。 这是风险最高、动静最小的一类。攻击者只要在任意一台 guest 里拿到代码执行(一次 Web 漏洞、一个被投毒的依赖、一个逃出容器的进程都够),就能横向读同一台宿主机上其他租户的内存,包括 Dom0 的内存。拿到 Dom0 就意味着拿到这台物理机上所有 guest 的磁盘和网络。
顺手对照一下 KVM。 两套方案的隔离线不在同一个位置。KVM 里,设备模型跑在用户态的 QEMU 进程里,guest 与宿主的交互大部分经过 virtio 的共享环,攻击面在 QEMU 这个普通进程上;拿下它,得到的是一台宿主机上的一个用户态进程。Xen 把后端驱动放在 Dom0,隔离判断放在 hypervisor 里,好处是 Dom0 之外少一层用户态转发,坏处是 hypervisor 里的每一行代码都在隔离线上。XSA-523 打中的正是这条线。
Xen 4.6 到 4.16 的下游产品。 这些版本没有补丁可用。运维能做的只有三件事:把大版本升上去(一次真正的迁移项目)、把不可信 guest 移走(很多场景做不到)、接受风险并加密敏感数据(等于承认隔离失效)。这也是老版本最容易被忽略的地方:没有补丁的漏洞,通常不会出现在补丁管理系统的报表里。
边界:这个洞什么时候打不中
有几处我需要说清楚,因为公告里都留了空白。
第一,攻击需要 guest 内先有代码执行。 Xen 只说了“恶意 guest 可以读写”,没有说需要什么样的特权。XSA-523 里没有提到是否需要在 guest 内核里、还是普通用户态就够。这两者的门槛差一个数量级。(待核实:公告未说明所需的 guest 内权限级别。)
第二,没有已知的在野利用。 三份公告(Xen、XCP-ng、Qubes)都没提观测到攻击。没有证据不等于没有发生,虚拟化层的入侵本来就以“不留日志”著称。
第三,这个洞是 AI 找出来的,这一点值得单独看。 Xen 公告的致谢写得很清楚:“This issue was discovered by Anthropic using Claude, then validated by Stephan Lipp of Ada Logics. It was then independently reported by the CodeAnt AI Security Research Team.”发现、验证、独立复现,三个环节分别由模型、外部验证者、另一家 AI 安全团队完成。
我不想把这件事写成“AI 攻破了 hypervisor”。更准确的描述是:一个缓存键类型混淆的漏洞,人眼扫过无数遍没看出来,模型在批量读代码时看出来了,然后由人验证。这和 11 月 1 日 Google 公布的 PageBreak 是同一套分工:模型提假设,验证器给证据。区别在于这次的验证成本高得多,要在一台真机器上让一个 guest 读到另一个 guest 的内存,才能确认。
第四,还有多少同类问题没被发现,公告不会回答。 4.6 引入的这套缓存优化跑了八年,两个 CVE 是同一次审计的产物。同一批逻辑在 grant map、grant unmap、grant transfer 上有没有对应的问题,公告没说。XSA-500 的存在说明这块代码的审计一直在进行,也说明它还没审干净。
接下来两周看什么
三个可验证的信号。
一是 Debian bookworm 和 trixie 的 xen 包什么时候从 vulnerable 变成 fixed。这两个版本的机器量最大,也是国内一堆虚拟化产品的底座。
二是 XCP-ng 和 XenServer 的用户论坛里,会不会出现“计划外重启导致业务中断”的集中反馈。补丁发了但没人敢重启,是这类漏洞最常见的落地状态。
三是 Xen 会不会在四周内再发一个 grant 相关的 XSA。如果发了,说明这是同一轮审计在继续清账,那 4.6 到 4.16 那批“没有补丁”的机器就该被认真讨论一次了,而不是继续挂在资产清单里当“低优先级”。
来源
- XSA-523: arbitrary read/write via grant copy — Xen Security Advisory
- Xen Hypervisor Flaws Let One Malicious VM Read and Write Any Other VM's Memory — The Hacker News
- November 2026 security and maintenance updates for XCP-ng 8.3 LTS — XCP-ng
- QSB-121: XSA-523 — Qubes OS
- CVE-2026-102703 — Debian Security Tracker