云原生架构:从技术演进到最佳实践
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.2 虚拟化指令集

虚拟化指令集指的是将某个硬件平台的二进制代码转换为另一个平台的二进制代码,从而实现不同硬件指令集之间的兼容。这种技术也被形象地称为“二进制翻译”。本节将重点介绍敏感指令集和虚拟化指令集的工作模式。

2.2.1 敏感指令集

原本的指令集设计是在传统场景下实现的,但在虚拟化场景下,在GuestOS的内核中有一部分非特权指令,它们不一定会改变或者损害整个系统,但是会影响基于虚拟化的整个系统的安全,因此人们定义了敏感指令(Sensitive Instruction)。敏感指令是操作特权资源的指令,包括修改虚拟机的运行模式,改变宿主机的状态,读/写时钟、中断等寄存器,访问存储保护系统、地址重定位系统及所有的I/O指令。例如,GuestOS的内核指令可以读取宿主机CPU的寄存器内容,从而看到整个系统的状态,这样一台虚拟机就可以看到另一台虚拟机的内部信息了。在虚拟化场景下,所有会危害到系统安全的指令集被称为“敏感指令集”。

2.2.2 虚拟化指令集的工作模式

若想了解虚拟化指令集的工作模式,必须了解Popek&Goldberg 原理。Popek&Goldberg 原理定义了如何设计一个有效的虚拟机监视器。

等价性:任何一个程序,在被管理程序控制时,除时序和资源可用性之外,应该与没有被管理程序控制时是一样的,而且预置的特权指令可以自由执行。

资源控制:一个程序发出的任何调用系统资源的动作在被执行时,都应先调用控制程序。

效率性:一个程序产生的所有无害指令都应该由硬件直接执行,控制程序不应该在任何地方产生中断。

这就是说,虚拟机GuestOS中的所有非敏感指令都会“穿透”虚拟机监视器,直接运行在CPU上。

虚拟机GuestOS中的敏感指令,理想的状态是通过陷阱机制被虚拟机监视器所捕获,然后虚拟机监视器通过不同的模拟或虚拟化技术实现在虚拟机上的模拟。具体的整个处理过程,以及虚拟机监视器对敏感指令的详细处理过程,如图2-3所示。(Popek&Goldberg原理的前提是,敏感指令必须都是特权指令,只有特权指令才能以图 2-3 所示的方式处理;若敏感指令不是特权指令,则会进行说明。)

图 2-3

在Popek&Goldberg原理中,如果敏感指令都是特权指令,当在虚拟机中执行内核态的特权指令时,则会通过陷阱机制被下层的虚拟机监视器捕获。虚拟机监视器可以对捕获的特权指令进行替换操作,从而完整地模拟出某个虚拟机监视器下的特权操作。“陷阱+模拟”机制从本质上保证了可影响虚拟机监视器正常运行的指令由虚拟机监视器模拟执行,而大部分非敏感指令还是照常运行在物理CPU上。

虚拟机监视器用到了优先级压缩技术,使得虚拟机中的应用运行在Ring 3层,GuestOS运行在Ring 1层(有时也可运行在Ring 3层),虚拟机监视器运行在Ring 0层。

将GuestOS内核的特权级别从Ring 0改为Ring 1,即可“消除”GuestOS内核的特权。但这会给GuestOS的内核指令带来一定的麻烦,原本GuestOS的内核指令是被设计在Ring 0层下执行的,通过优先级压缩后会造成部分指令在虚拟机中的Ring 1层或Ring 3层下无法执行。

针对这一问题,理论上采取的解决方法是让虚拟机监视器捕获特权指令。当GuestOS的特权指令无法直接下达到CPU执行时,可以通过虚拟机监视器的“陷阱+模拟”机制执行。

具体来说,当虚拟机中的应用需要操作重要资源时,会触发特权指令,通过陷阱机制被虚拟机监视器捕获,然后交由对应的GuestOS执行。因为虚拟化之后GuestOS运行在Ring 1层,它没有权限执行一些特权指令,需要通过其他方式保证这些特权指令的执行。

例如,当虚拟机中的应用使用系统调用时,其跳转到的GustOS内核中断处理程序(routine)运行于Ring1层。但是在内核中断处理程序中有部分指令是必须在Ring 0层才能执行的,此时会再通过陷阱机制将这些指令自动转入虚拟机监视器后执行。用户程序运行特权指令时会有两次特权下降,其中一次是进入 Ring 1 层的 GuestOS;另一次是通过特权指令的陷阱机制进入Ring 0层的虚拟机监视器。

但Popek&Coldberg原理的前提是,敏感指令必须都是特权指令,即敏感指令集是特权指令集的子集,如图 2-4 所示。只有这样,虚拟机监视器才能通过选用特权指令集的陷阱捕获方式进行虚拟化。

图 2-4

在虚拟化场景下,敏感指令必须通过陷阱机制被虚拟机监视器捕获并完成模拟执行。对于一般精简指令集(RISC)处理器,如 MIPS、PowerPC、SPARC,敏感指令肯定是特权指令,即敏感指令集属于特权指令集的子集。

但是在x86处理器中,只能保证绝大多数的敏感指令是特权指令,还有约17个敏感指令不是特权指令,也就是说,敏感指令的范围更大。然而,当特权指令集是敏感指令集的真子集时,有一部分敏感指令无法被虚拟机监视器捕获,从而无法完全被替换,这一现象被称为“虚拟化漏洞”,如图2-5所示。

图 2-5