Andi Kleen's blog

专注于挑战难题和其他探索

退出 Intel x86 hypervisor

包含一条评论

这是一个比较冷门的话题,可能对实现 Intel hypervisor 的人有帮助。它假设你了解 Intel 虚拟化架构的基础知识,可以参考 Hypervisor from scratch 这篇教程。完整的 VT 架构描述可以在 Intel SDM 的 Volume 3 中找到。

假设我们编写了一个 x86 hypervisor,它在 UEFI 环境中启动,并虚拟化 OS 的初始化阶段。但 hypervisor 最终希望退出,以避免在 OS 运行时产生额外的开销。

hypervisor 的工作方式是,它在自己的内存中运行,并使用自己的页表,这些页表在每次 VM exit 时由 VT-x 实现自动切换。这样,它就与主 OS 隔离开来。

在某个 exit 发生时,hypervisor 在自己的上下文中运行,并判断不再需要自己,并希望退出。要禁用 VT 支持,可以使用 VMXOFF 指令。但我们真正需要的是一个原子操作:VMXOFF + 切换到原始 OS 页表 + 跳转,并且所有这些操作都不能使用任何寄存器,因为这些寄存器需要已经恢复到 OS 的原始状态。

一个技巧是使用 MOV to CR3 指令,该指令会重新加载页表,并充当跳转。一旦页表重新加载,CPU 将使用新加载的页表中的转换来获取下一条指令,因此我们可以将执行权转移到 guest 上下文。但是,要做到这一点,MOV CR3 需要正好位于目标指令的页偏移量之前。这可以通过将 trampoline 复制到正确的页面偏移量来实现(可能与前一个页面重叠)。trampoline 位于一个特殊的传输页表映射中,该映射将可写代码页放置在与目标映射重叠的位置。

但也有一些复杂情况。hypervisor 还需要加载 guest 的分段状态(如 GDT/LDT)。理论上,只需将这些 guest 页面映射到传输映射中,并在传输之前加载它们即可。但是,如果 GDT/LDT 与目标地址位于同一页面上会发生什么情况(这在真实的 OS 汇编启动代码中很常见,因为汇编启动代码是一个小型汇编文件,代码和数据之间没有任何页面分隔)?一种选择是将它们也复制到传输页面并从那里加载,或者 hypervisor 首先将它们复制到临时缓冲区并从那里加载。在第二种选择中,这些结构的基础地址将不正确,但在实践中,您通常可以依赖于它们最终会被重新加载。

另一个问题是目标的寄存器状态。MOV to CR3 需要一个寄存器作为重新加载的源,并且它需要是 trampoline 的最后一条指令。因此,无法恢复它使用的寄存器。但请记住,hypervisor 是在 exit 的结果下执行此操作的。如果我们选择一个已经破坏寄存器的条件的 exit,我们可以使用同一个寄存器进行重新加载,并且在原始 guest 中执行的下一条指令(并且最初导致 exit 的指令)将再次覆盖它。

一个非常方便的指令是 CPUID。它在 OS 启动中多次执行,并破坏多个寄存器。事实上,VMX 总是拦截 CPUID,因此它无论如何都必须处理这些 exit。因此,退出 hypervisor 的技巧是等待下一个 CPUID exit,然后使用 CPUID 破坏的寄存器之一进行最终的 CR3 重新加载。这将导致目标中的一条指令的寄存器状态不一致,但除非原始 OS 当前正在运行调试器,否则它永远不会注意到。原则上,任何由于破坏寄存器的指令而导致的 exit 都可以用于此目的。

如果 OS 的目标地址与 hypervisor 在进入传输映射之前运行的位置冲突,则可能会出现另一个潜在的复杂情况。这可以通过在跳转到传输 trampoline 之前使用第三个辅助映射来解决。实际上,这似乎不是问题,因为 x86 OS 通常在启动时以 1:1 映射运行,并且这不会与 UEFI 程序(我们的 hypervisor)使用的 1:1 映射冲突。

祝 hypervisor hacking 愉快! 作者:therapsid 2025 年 3 月 18 日晚上 9:34 发布在 curiosities,kernel

« The browser circle closes again

对 'Quitting an Intel x86 hypervisor' 的一条回复

订阅评论 RSS

  1. 9zybbf We send a transfer from user. Confirm =>> https://telegra.ph/Binance-Support-02-18?hs=6dc5fe145591a5bd6997b09abe9717df& 23 Mar 25 at 03:05

发表评论

姓名 邮箱 (不会被公开) 网站 Δ

页面

搜索

搜索站点存档

友情链接

存档

分类

Meta

The Journalist 模板由 Lucian E. Marin 提供 — 专为 WordPress 构建