本系列文章是为了解释x86虚拟化内部是怎样工作的。我发现大部分信息都是在学术工作和研究论文中发布的,这对初学者来说是很难理解的,我会尝试从头开始并建立所需的知识。这对于理解虚拟化如何工作或编写你的虚拟机管理程序或其他场景(如攻击虚拟机管理程序安全性)是有用的。
在哲学中,虚拟意味着一些不真实的东西 。在计算机中,虚拟化是指创建一个虚拟(而不是真实)版本的东西,包括硬件平台,存储设备和网络资源。
虚拟化是一个广泛的概念,我们可以在不同的领域应用虚拟化,例如:
这项技术的应用带来了很多好处,我们用真实的例子说明这一点,通常一家公司会用到多种工具:
如果没有虚拟化,你可能需要多台服务器来托管所有这些服务,因为其中一些需要Windows作为主机,而其他可能需要Linux作为基本的操作系统。通过虚拟化,你可以使用一台服务器同时托管多个虚拟机,每台虚拟机运行不同的操作系统(如OSX,Linux和Windows),这种设计允许将服务器合并到一台物理机中。
除此之外,如果其中一个出现故障,它不会影响其他服务器,因此,这种方法帮助企业轻松维护和节约成本。最重要的是,分离那些服务在不同的服务器中被认为是一项安全功能,因为它支持强隔离,这意味着如果攻击者获取了其中一台服务器的权限,他无法访问其它的东西。
另一个优势是,通过虚拟化,你可以轻松调整你需要的硬件资源。例如,如果你在虚拟机中托管了一个Web应用,某天的某个时间段你的站点有大量的请求,应用难以处理负载,在这种情况下,你不需要打开服务器并手工插入更多的RAM或CPU,你可以通过虚拟机配置并分配更多的资源来调整它,甚至,你可以生成新的虚拟机来均衡负载,假如你的网站在晚间流量较少,我们只需较少资源来让服务器上的其他虚拟机使用。这种方法可以有效地管理资源,而不是拥有如此多内核和内存(RAM)的物理服务器,但这些资源大多被闲置,可闲置的服务器也要消耗电力和资源。
虚拟化在软件测试上也有很大帮助,它使一个程序员在部署到生产环境前轻松地确保他的软件完美地运行。当一个程序员提交一些新代码时,一个虚拟机在运行中被创建,同时,运行一系列的测试用例,代码仅在所有测试通过后被发布。
最后,但同样重要的是,虚拟机可以被迁移,这意味着可以轻松迁移整个机器从一台服务器到另一台服务器,即使使用不同的硬件。这有助于当硬件开始出现故障或者需要进行一些维护等情况。只需点击一下鼠标即可移动所有的堆栈和配置到另一台服务器而无须停机。
考虑到这一点,虚拟化为公司带来了巨大的空间/功率/成本节省。
你可能会惊讶于,随着CP/40 的发展,虚拟化的概念始于20世纪60年代早期的IBM大型机。IBM售卖支持并大量使用虚拟化的计算机。在计算机(历史)的早期阶段,虚拟化软件允许多用户共享昂贵的主机硬件,每个用户运行他们自己的单用户操作系统实例。
随着多用户操作系统复杂性的提高,硬件成本的迅速下降,以及计算机的普及,虚拟机不再流行。到20世纪80年代,业界对虚拟化失去兴趣,而在20世纪80年代和90年代开发的新的架构不必包含支持虚拟化的架构。
真正的革命开始与1990年,VMware为x86引进它第一个虚拟化解决方案。其他产品紧随其后:Xen ,KVM ,VirtualBox ,Hyper-V ,Parallels 等等。近年来,对虚拟化的兴趣暴增并且现在它已成为云计算的基础部分,由于虚拟化,云服务如Windows Azure,Amazon Web Services和Google Cloud平台成为了数十亿美元的市场行业。
在深入细节之前,我们定义一些术语:
要创建一个管理程序,我们需要确保向真机一样引导虚拟机,并且在虚拟机上安装任意操作系统,就像在真实硬件上可做的一样。管理程序的任务就是提供这种错觉(译者注:和真实硬件上一样的错觉)并高效地完成。在写入虚拟机管理程序时,需要考虑系统的3个方面:1.CPU和内存虚拟化(特权指令、页表)。2.平台虚拟化(中断、时钟,...)。3.IO设备虚拟化(网络、磁盘、bios,...)。
实际上,两位计算机科学家Gerald Popek 和 Robert Goldberg发表了一篇影响深远的论文《虚拟化第三代体系结构的正式要求》 ,它准确定义了为了有效的支持虚拟化所需满足的条件,那些条件被分为三部分:
让我们分析这三个特性:对于等价性 ,VMM上的软件(通常是操作系统和它的所有应用)应该和它在真实硬件上执行相同(模定时效应)。所以如果你下载一个Linux Debian的ISO,你应该能引导它,并使用所有的程序如同在真实硬件上使用。
为了提高性能 ,大多数在客户机上执行的指令应该在没有VMM的介入下,直接在底层物理硬件上运行。模拟器(如Bochs)模拟所有的底层物理硬件如CPU和内存,所有的硬件使用程序中的数据结构表示,指令的执行涉及调度循环,它会为每条指令更新那些数据结构,模拟器的好处是你可以模拟代码即使它是基于不同CPU的,坏处是它非常慢。因此,如果你准备模拟所有的指令集,你不会获得良好的性能。换句话说,只有特权指令需要VMM的干预。
最后,对于安全性 ,保护每个虚拟环境的数据和资源免受共享物理资源的任何威胁或性能干扰非常重要。例如,如果你为虚拟机分配了1GB的RAM,客户机就不能够使用之外的更多内存。另外,VMM不能允许客户机为整个机器禁用中断或修改页表映射,否则,可能会破坏管理程序的完整性,并且,这可能导致任意代码在主机执行,或者其他客户机运行在同一台服务器,使整台服务器容易受到攻击。
早期的虚拟化技术被称为陷阱和模拟 ,它被广泛地认为是虚拟化的唯一方法。陷阱基本上是一个本地的异常/错误,会在客户机操作系统没有需要的权限运行特定的指令时发生。陷阱和模拟 方法仅仅意味着VMM会捕获任何 特权指令并模拟它的行为。
尽管Popek和Goldberg没有排除其他技术的可能性,但多年来由于将虚拟化非正式的等同于使用陷阱-模拟的能力导致了一些混淆。为了避免这种混淆,我们应该使用术语经典可虚拟化来描述单纯的使用陷阱-和-模拟的可被虚拟化架构。从这种意义说,x86并不是经典的可虚拟化,我们会看到为什么,但是,通过Popek和Goldberg的标准,使用后面描述的技术,它是可虚拟化的。
在本节,我们将讨论为什么x86不是经典可虚拟化(使用陷阱-和-模拟)的一些关键点,然而,在我们这样做之前,我想介绍一些关于处理器的低级的概念,理解x86的问题需要这些概念。
简而言之,x86架构支持4种特权级别,或环(rings),ring 0 是最高级,ring 3最低。操作系统内核和它的驱动运行在ring 0,用户程序运行在ring 3,ring 1 和2 通常不使用。
Popek和Goldberg定义了特权指令和敏感指令。敏感指令包括控制硬件资源分配的指令,如改变MMU设置的指令。在x86中,敏感指令的例子是:
敏感指令(也被称为IOPL-senstive)可仅仅当CPL(Current Privilege Level,当前权限级别)<=IOPL(I/O Privilege Level,I/O权限级别)时被执行。当CPL > IOPL时尝试执行敏感指令会生成GP(general protection,通用保护)异常。
特权指令如果在用户模式下执行会造成陷阱。在x86中,特权指令例子如下:
特权指令仅可在当前权限级别为0(CPL = 0)时被执行。当CPL !=0 时尝试执行特权指令会生成#GP 异常。
当谈到x86处理器的内存保护时,这是一个非常重要的方面。在保护模式 (CPU的本地模式),x86架构支持分段 和分页 机制的非典型组合,每种机制通过存储在内存中的数据结构编程到硬件中。分段 提供了隔离代码、数据、和栈的机制,以便多个程序可以在同一个处理器上运行而互不干扰。分页 提供了实现常规页面调度,虚拟内存系统的机制,在虚拟内存系统中,程序节的执行环境按需被映射到物理内存。分页也被用来隔离多任务。记住,传统模式和兼容模式有分段,x86-64模式分段被限制。我们在下一章介绍这一点。
Popek 和 Goldberg证明,基于陷阱和模拟的简单VMM只能在所有虚拟化-敏感(virtaulization-senstive)指令有所有的特权指令的架构中被建立。对于符合标准的架构,VMM仅在非特权模式(例如,从不在最高特权级)运行虚拟机指令,并处理由执行特权指令导致的陷阱。下表列出了不幸违反Popek 和 Goldberg规则的x86架构指令,因此导致x86不可虚拟化。 第一组指令当执行在特权模式下(%cpl ≤ %eflags.iopl )操作中断标志%eflags.iopl ,除非该标志保持不变。不幸的是,操作系统(客户机内核)使用那些指令修改中断状态,并且默默忽略中断标志将组织VMM使用陷阱和模拟方式正确地跟踪虚拟机中的中断状态。
第二组指令提供对在GDT/LDT中段描述符的可见性。出于非特权和保护的原因,VMM需要控制实际的硬件段描述符表。当在虚拟机中直接运行时,那些指令会访问VMM的表(而不是那些被客户机操作系统管理的表),从而混淆软件。
第三组指令操作段寄存器。这是有问题的,因为处理器的权限级别在代码段寄存器中是可见的。例如 push %cs 拷贝%cpl作为一个字的低2位压到栈中。如果push %cs被直接发送到CPU,被期待运行在%cpl=0的虚拟机(客户机内核)中的软件可能发生不被期待的行为。该问题被称为特权级别名(ring aliasing,译者注:特权级别名是指 Guest OS 在虚拟机中运行的级别并不是它所期望的。)。
第四组指令提供对特权状态的只读访问。例如,GDTR,IDTR,LDTR和TR包含指向控制CPU操作的数据结构的指针。软件可以在特权级0执行从这些寄存器读取或存储的指令(LGDT, LIDT, LLDT, 和 LTR)。然而,软件可以在任何级别执行读取或存储那些寄存器的指令(SGDT, SIDT, SLDT, 和 STR)。如果直接执行,这些指令将返回VMM结构的地址,而不是虚拟机操作系统指定的地址。如果VMM以不被期望的值维持寄存器,客户机操作系统可能判定他没有完全控制CPU。
当非特权客户操作系统进行特权级压缩 时,出现另一个问题。为了在虚拟机之间隔离,VMM运行在ring 0虚拟机运行在ring 1(0/1/3型)或ring 3(0/3/3型)。尽管0/1/3模型更简单,但它在支持x86架构(AMD 64和EM64T)的64位扩展的CPU上以64位模式运行时不可被使用。为了隔离客户机操作系统和VMM,可以使用分页 或分段限制 。然而,64位模式下不支持分段限制并且x86上的分页不区分ring 0,1和2。这会导致特权级压缩,客户机操作系统必须运行在ring 3,不受用户程序保护。
操作系统希望能够访问处理器的全部虚拟地址空间,在IA-32中称为线性地址空间(linear-address)。VMM 必须在客户机操作系统的地址空间中保留一部分供其使用,这允许VMM轻松访问客户机数据,尽管VMM的指令和数据结构会占用大量的客户机虚拟地址空间。或者,VMM可以运行在独立的地址空间,但是,即使这样,VMM也必须使用少量的客户机地址空间用来容纳管理客户机软件和VMM之间交换的控制结构(对于IA-32,这些结构包括驻留在线性地址空间中的IDT和GDT)。VMM必须阻止客户机访问那些VMM正在使用的那部分客户机虚拟地址空间。否则,如果客户机能够写入那些部分,客户机检测到它正在虚拟机中运行(如果可以读取那些部分),VMM的完整性会收到影响。客户机尝试访问地址空间中的那些部分必须生成到VMM的转换,VMM可以模拟或支持他们。术语地址空间压缩指的是来自保护那部分虚拟地址空间和支持客户机访问那些部分的挑战。
总之,如果你想构建一个VMM并使用陷阱和模拟来虚拟化客户机,x86会与你相抗衡。 译者注:在该站点虚拟化技术漫谈 可以找到以上概念更详细的介绍。
正如我们之前所见,由于个人工作站的兴起和大型计算机的衰落,虚拟机被认为只不过是计算史上的一个脚注。正因如此,x86的设计没有考虑虚拟化。因此,x86不符合Popek 和 Goldberg的经典虚拟化标准就不足为奇了。然而,技术被开发用来避开x86虚拟化的欠缺。我们将简要介绍不同的技术,因此我们预留了将要详细解释各自工作原理的章节。
它提供了无须修改客户机操作系统的虚拟化。它依赖如二进制翻译 (binary translation,BT)的技术来陷阱和虚拟化某些敏感和非虚拟化的指令的执行。通过这种方法,可以发现(静态或运行时动态)关键指令并用陷阱替代到软件中要被模拟的VMM中。
VMware 在1998年首次实现了可以虚拟任何x86操作系统的技术。简而言之,VMWare利用二进制转译和直接执行,涉及用虚拟硬件上具有预期效果的新指令序列翻译内核代码替代非虚拟化指令。同时,用户级代码直接在处理器上执行以实现高性能虚拟化。
在这种技术下,客户机内核被修改用来运行在VMM上。换句话说,客户机内核知道它已经被虚拟化。通过和VMM通讯的,称为超级调用(hypercalls)的调用(calls)替换掉应该运行在ring 0的特权指令。超级调用调用VMM来代表客户机内核执行任务。由于客户机内核有通过超级调用直接和VMM通讯的能力,因此相对于全虚拟化,该技术有更高的性能。然而,这需要特定的客户机内核, 它了解超虚拟化技术并附带所需要的软件支持,初此之外,PV将仅工作在客户机操作系统实际被修改的情况,显然,这并非总是如此(专有操作系统)。因此,超虚拟化可能会导致差的兼容性和对传统操作系统的支持。一个领先的超虚拟化系统是Xen
尽管全虚拟化和超虚拟化设法解决了x86非经典虚拟化的问题,但由于性能开销,兼容性和设计和维护中的复杂性,如VMMs,这些技术就像工作区。出于该原因,Intel和AMD必须设计一个高效的虚拟化平台来解决根本问题,并防止x86成为典型的虚拟化技术。2005年,两家领先的芯片厂商都为其处理器推出了硬件虚拟化支持。Intel称之为虚拟化技术(Virtualization Technology,VT),AMD称之为安全虚拟机(Secure Virtual Machine,SVM)。这些背后的思想是用新的指令扩展x86 ISA,并创建一个VMM将获得更多权限的新模式,你可以认为ring 0前的ring -1,允许操作系统停留在预期位置,并捕获硬件的直接尝试访问。在实施过程中,更多的权限级别(ring)被添加,但最重要的事情是,有一个额外的特权模式,其中管理程序可以捕获和模拟之前默默失败的操作。目前,所有的现代管理程序(Xen,KVM,HyperV,...)主要使用HVM。
考虑到现在混合虚拟化非常普遍,例如,替代使用HVM进行CPU虚拟化和模拟IO设备(使用Qemu),使用超虚拟化进行IO虚拟化被认为是更性能优良的,因为它使用设备的轻量级接口,而不是依靠模拟硬件。我们会在之后的章节中讨论这个问题。
我们将管理程序分为三类:
管理程序主要基于驻留在系统中的位置进行分类,或者换句话说,根据操作系统是否在当前系统中进行分类。但是对于第一种类型和第二种类型管理程序没有明确或标准的定义。第一种类型管理程序直接运行在硬件上,因此被称为裸机管理程序。操作系统不是必要的,因为它直接运行在物理机上。在第二种类型中,有时称为托管虚拟机管理程序,管理程序/VMM在操作系统中存在,利用设备驱动和操作系统(Windows,Linux或OS X)提供的系统支持实现内存管理,处理器调度,资源分配,非常类似于常规进程。当首次启动时,它就像一个新引导的计算机并希望在驱动器中找到包含操作系统的DVD/CD-ROM或USB设备。然而,这次的驱动可能会是虚拟设备。例如,可能是以ISO文件形式存储在主机硬盘上的镜像,并让管理程序假装它正在从正常的DVD驱动器中读取数据。之后,它通过运行在DVD中找到的安装程序将操作系统安装到虚拟硬盘(同样只是一个Windows,Linux或OS X文件)上。一旦客户机操作系统被安装在虚拟硬盘上,就可以被引导和运行。
实际上,第一种类型的管理程序和第二种类型的管理程序之间的区别并没有多大意义,因为第一种类型的管理程序也需要某种类型的操作系统,通常是小型Linux(如Xen和ESX)。我只想展示这些不同,因为你会在任何虚拟化课程中遇到。 最后一类管理程序于运行其他操作系统的(管理程序的)目的不同,相反,他们被用来存在于运行的操作系统中作为额外的保护层。这种虚拟化通常在反病毒,沙箱,甚至rootkits中遇到。
在本节,你已经了解了虚拟化是关于什么的一般概念,它的优势,和不同类型的管理程序。我们也讨论了是x86非经典可虚拟化的问题,并讨论了虚拟机管理程序和为解决它采取的一些解决方案。在下一章,我们会深入虚拟化的不同方法以及流行的管理程序如何实现它们。
x86软件和硬件技术对比 A Comparison of Software and Hardware Techniques for x86.
现代操作系统(第四版) Modern Operating Systems (4th edition).
虚拟机监控程序的进化 The Evolution of an x86 Virtual Machine Monitor.
理解全虚拟化,超虚拟化和硬件辅助虚拟化 Understanding Full Virtualization, Paravirtualization and Hardware Assisted Virtualization.
精通KVM虚拟化 Mastering KVM Virtualization.
Xen管理程序权威指南 The Definitive Guide to the Xen Hypervisor.
原文链接:Virtualization Internals Part 1 - Intro to Virtualization
编译:看雪翻译小组 sudozhange 校对:看雪翻译小组 fyb波
[注意]APP应用上架合规检测服务,协助应用顺利上架!
最后于 2018-7-3 20:48
被sudozhange编辑
,原因: