ref: CSE,IPADS,SE,SJTU
尽管虚拟化技术确保了VM之间的相互隔离,然而VMM的重要性变得更高了。如果能够破解VMM,那么通过VM就能影响到VMM上运行的所有VM。而随着虚拟化技术的发展,VMM的代码量大小越来越大,其中的bug也越来越多。(用VMM代替hypervisor,因为字数少)
然而,VMM的bug是不可避免的,我们无法防止VMM被破解,只能想办法减少VMM被破解后的代价。最重要的部分就是内存隔离。
Xen Bugs
Software - 嵌套虚拟化
方法1:降低VMM优先级(从而无法随意访问VM的内存)
VMM不再运行在root mode中,而是和VM的kernel一样,运行在non-root mode的ring 0
root mode下运行cloudvisor,充当一个中间人,VM对VMM的访问都通过虚拟机接口,由cloudvisor转交给VMM。
cloudvisor对于页标记所有权,如果VMM想要访问VM的页,那么就会被拒绝。因为cloudvisor本身的代码量相对很少,bug也会更少,更容易验证。
方法2:拆分VMM(从而每个VMM slice只能访问自己的内存)
VMM拆分成多个slice(代码相同,不同实例),无法拆分的则作为shared service。
无需将VMM放进non-root mode,而只是先在root mode下运行security monitor。为了防止VM能破解VMM来攻击其他的VM,我们只需要把VMM slice之间隔离即可。每个slice除了一开始可见的页表之外
- 禁止修改CR3(source code)
- 禁止修改页表(readonly)
Hardware - Enclave & TEE
TEE是相对于REE而言的,其中运行独立的操作系统,独立的加密机制,独立的硬件,以确保绝对的安全性。当然后文依然有很多TEE的漏洞
Counter-mode encryption
保护内存的最好办法就是加密,这里每个内存块都有独一无二的Pad(最后和数据做异或),通过seed和秘钥共同生成。在我们的内存中存储的是密文,每次读写都需要通过pad进行解密或者加密
AISE [Rogers, Micro'07]
seed如果使用地址,会有很多缺陷,
如果是物理地址,一旦发生页表的交换,就会导致seed改变
如果是虚拟地址,在pad重用方面也会有很大问题(比如多程序访问同一块)
而使用计数器,则只需要增加一块存储区域。
每个chunk的种子通过counter 逻辑页表ID chunk的PPO chunk ID组成,因此和地址是独立的。(因为Page Offset是不参与页表映射的)
加密
Merkle-tree based integrity check
每一个block的MAC包含counter、address等信息,通过对MAC分层计算hash,最终得到1个值,一旦内存被恶意篡改了,显然上层的hash值就错误了。
Enclave
Enclave的作用就是,提供一个严格的加密内存,这个内存只有持有秘钥的应用能访问,里面存放代码或者数据,而OS/VMM即使拥有更高的权限,依然被阻挡在外。其唯一的操作便是内存的读写。最新的Enclave都有着各种分区隔离机制,有的是用chunk实现,还有的使用Page Table实现,这里略。
Attack Example
TEE并非万能
Boomerang
TEE比REE更高优先级,一旦在TEE中执行某些程序(例如把当前时间写到指定地址),那么地址是不会被检查的,
[NDSS'17] BOOMERANG: Exploiting the Semantic Gap in Trusted Execution Environments
Rowhammer
DRAM在频繁访问的情况下,周边的bit可能会发生丢失(因为DRAM是用电刷新的)。那么问题在于,如何既频繁访问,又不会命中缓存。下面的代码就是一段rowhammer的攻击
由于dram本身不存在良好的纠错机制,会造成极大的破坏。
Meltdown
这个问题出在CPU的乱序执行上,因为权限控制可能阻挡了僭越指令的执行,但是在CPU的流水线时期,产生的内存访问的影响却不会消失。即使指令回滚,黑客仍然有办法通过cache的hit/miss来判断。例如下面的代码,通过buf数组中到底谁被hit,就能判断出key的值。
代码语言:javascript复制Load key, %rax
Load buf[%rax], %rbx
因此隔离kernel和user很重要。目前已经存在的方式是为kernel态和user态提供不同的页表,从源头上杜绝访问,而不是单纯的权限控制,进程切换时增加额外的开销。
Side channel
尽管数据本身是加密的,问题在于数据访问的模式是无法掩盖的。如果我们知道一个图像的处理算法,通过算法本身的内存访问(如page fault)就能近似反推出算法的输入。这类攻击目前基本没有抵御手段。