VM guest虚拟机内的进程是否有可能使用VMX(AMD-V,VT-x)CPU指令,然后由外部VMM处理而不是直接在CPU上处理?

编辑:假定外部VM使用VMX本身来管理其虚拟来宾计算机(即,它在Ring -1中运行)。

如果有可能,是否有任何VMM的实现都支持模拟/拦截VMX调用(VMware,Parallels,KVM等)?

最佳答案

英特尔的VT-x或AMD的AMD-V都不支持硬件中的完全递归虚拟化-在CPU中,CPU以call / ret对的相同方式保留嵌套虚拟化环境的层次结构。

逻辑处理器仅支持两种操作模式:主机模式(在Intel术语中称为VMX根模式,在AMD的术语中称为管理程序)和来宾模式(在AMD手册中称为,而在Intel的手册中称为VMX非根模式)。
这意味着层次结构扁平化,CPU对每个虚拟化环境都进行了相同的处理-CPU不知道VM层次结构的深度是多少级。

尝试在访客内部使用他们自己的虚拟化指令将对监视器(VMM)产生控制。
但是最近出现了一些对加速常用虚拟指令的支持,从而使嵌套VM成为可能。

我将尝试分析实现嵌套虚拟化所要面对的问题。
我并没有处理全部问题,而是在考虑基本情况,而忽略了涉及硬件虚拟化的所有部分。本身与软件虚拟化一样有问题的部分。

注意
我不是虚拟化技术专家,也没有任何经验,欢迎进行更正。
该答案的目的是使读者从概念上相信嵌套虚拟化是可能的,并概述了要面对的问题。

VT-x

逻辑处理器通过执行vmxon进入VMX操作-进入模式后,处理器立即进入root模式。
根模式是VMM的模式,它可以启动,恢复和处理VM。

然后,VMM使用vmptrld设置当前的VMCS(VM控制结构)-VMCS包含虚拟化来宾所需的所有元数据。
VMCS的读写不是通过直接内存访问‡,而是通过vmreadvmwrite指令进行。

最后,VMM执行vmlaunch以开始执行来宾。

接受虚拟机

现在,逻辑处理器正在虚拟环境中执行。
假设guest虚拟机本身就是VMM,我们称其为非根VMM-它需要重复上述步骤。

但是,英特尔在其手册中有明确规定(手册3-第25.1.2章):

以下说明导致在VMX非root用户操作中执行时,VM退出:
[...]
对于VMX引入的说明也是如此,其中包括:
[...],VMLAUNCHVMPTRLD,[...]和VMXON

vmxon该指令导致VM退出,根VMM在其最后一个vmlaunch之后从指令恢复,可以检查VMCS退出的原因并采取适当的措施。
我不是经验丰富的VMM编写者,所以我不确定根VMM必须完全模仿该指令执行什么操作-因为在VMX根模式下执行vmxon将会失败,并且先执行vmxoff,然后执行vmxon,VM区由非根VMM似乎是一个安全漏洞(或导致它的隐患),我相信所有根VMM要做的就是记录来宾现在处于“VMX根模式”。
在这里引号是必需的:仅当根VMM将控制权交还给非根VMM时,该模式才存在于软件中,而CPU将处于非根VMX模式。

之后,非根VMM将尝试使用vmptrld设置当前VMCS。vmptrld将导致VM退出,并且根VMM再次处于控制状态-如果CPU不支持VMCS shadowing,则根VMM必须记录由非根VMM给出的指针现在是当前VMCS-如果CPU可以。支持VMCS遮盖VMM,将的VMCS链接指针字段设置为 VMCS(用于虚拟化非根VMM的指针)到非根VMM给出的VMCS。
VMM以一种或另一种方式知道哪个虚拟化VMCS是活动的。

由非根VMM执行的vmreadvmwrite将或不会导致VM退出。
如果激活了VMCS阴影,则CPU不会执行VM退出操作,而是读取活动VMCS中由VMCS链接指针指向的VMCS(称为阴影VMCS)。
这将加速嵌套虚拟机的虚拟化。
如果未激活VMCS阴影,则CPU将退出VM,并且根VMM必须模拟读取/写入。

最后,非根VMM将启动其VM-这是一个嵌套VM。vmlaunch将触发虚拟机退出。
根VMM必须做一些事情:

  • 将其VMCS保存在某处。
  • 合并当前的VMCS和非根VMM VMCS-例如,由于VMCS控制,导致VM退出的事件是合并的一个,因此在这方面必须是两者的并集。
  • 加载合并的VMCS作为CPU当前的
  • 做一个vmlaunch / vmresume

  • 梦想中

    现在,CPU正在执行嵌套VM(VVM-虚拟VM?)。
    当敏感指令或事件导致VM退出时会发生什么?

    从处理器的角度来看,虚拟化只有两个级别:根VMX模式和非根VMX模式。
    由于访客处于非root用户VMX模式下,因此控制权将转移回root VMX模式代码-即root VMM。

    现在,根VMM必须了解该事件是来自其VM还是来自其VM的VM。
    这可以通过跟踪vmlaunch / vmresume的使用并检查VMCS中的位来完成。

    如果将VM出口定向到非根VMM,则根VMM必须加载其原始VMCS,最终在其中设置非根VMM的链接,更新非根VMM VMCS状态位并执行vmresume
    如果将VM出口定向到该出口,则根VMM将像处理其他任何VM出口一样处理它。

    梦中的梦

    如果我们想在嵌套VM中创建VM怎么办?
    虚拟虚拟VM(VVVM)的种类。

    有两件事要注意:
  • 根VMM仍然是每个VM退出期间调用的VMM。
    即使VVVM有3个级别,它也不是非根非根VMM,它是用于虚拟化它的第一个和/或唯一的管理器。
    从安全角度来看,根VMM是薄弱环节。
  • 硬件实际上并不支持任意深度嵌套。
    从支持1级嵌套到n级嵌套(再次我在这里没有经验),VMM可能不需要太多的工作,但是仍然需要上面概述的特殊支持。
    这不像启动VM那样容易,CPU会照顾所有其他一切。

  • 显卡

    在AMD-v中没有root或non-root模式,CPU开始使用vmrun执行VM,该vmrun带有指向VMCB(VM控制块)的指针,该VMCB具有与Intel VMCS相同的作用。
    根据vmload,CPU处于访客模式。

    VMCB已缓存,但只能通过常规内存访问来读取。vmsave / vmrun指令显式加载要缓存的VMCB字段并从缓存中保存。

    该接口比Intel的接口更简单,但功能同样强大-即使涉及嵌套虚拟化。

    假设我们在VM内部,并且代码执行vmrun-因此我们在虚拟化VMM。

    从技术上讲,VMM可以选择VMRUN何时触发或不触发VM退出。
    然而,实际上,AMD-v当前始终要求前者:

    以下条件被视为非法状态组合:
    [...]
    * vmrun拦截位清除

    因此,根VMM(我将使用与Intel情况相同的术语)将获得控制权,并且必须模拟vmrun(因为硬件仅支持单一级别的虚拟化)。

    根VMM可以保存当前VMCB并将其与非根VMM VMCB合并,并像Intel一样继续使用vmrun

    退出后,根VMM必须确定出口是定向到该出口还是定向到非根VMM,这又可以通过跟踪VMCB中的vmrun和控制位来完成。

    再次做梦

    我们已经相对容易地在虚拟机内部设置了虚拟机-现在退出虚拟机时会发生什么?
    根VMM接收退出,并且如果定向到非根VMM,则必须还原其原始VMCB并继续运行(即,将vmsave与原始VMCB一起使用)。

    AMD-v通过考虑其地址来宾地址,从而支持vmload和ojit_code指令的快速虚拟化,因此可以进行通常的页面嵌套虚拟化。

    再次提出盗梦空间

    与Intel情况一样,只要VMM支持该功能,就可以再次嵌套虚拟化。

    针对英特尔案件提出的关键安全警告同样适用于AMD的警告。

    ‡由于其实现定义的格式,并且存储区域可以用作溢出区域,因此不能实时更新

    关于assembly - 是否可以在VM中使用VMX CPU指令?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42597774/

    10-10 09:59