LWN:改进KVM来增强guest系统保护和安全!

点击上方蓝色“ Linux News搬运工 ”关注我们~

Enhancing KVM for guest protection and security

November 20, 2019

This article was contributed by Sergio Lopez

原文来自:https://lwn.net/Articles/805114/

KVM里面一个主要的原则,就是希望能尽量重用Linux的基础设施(指Linux现有代码中的各个子系统),并且着重关注处理器的虚拟化。在2007年的时候,这个原则也就意味着代码改动更加小,也不会过于分散在kernel的各个子系统里面,这一点在跟诸如Xen这样的其他虚拟化技术对比的时候是个明显优势。因此,KVM也比较轻松地就合入了mainline。

不过,现在大家更加关注微架构漏洞了(microarchitectural vulnerabilities),重点已经发生了变化,因此KVM对其他kernel子系统的依赖就变成了一个缺点。比如说,host (宿主机)kernel扩展了TCB(Trusted Computing Base),也就带来了更大的受攻击面。此外kernel的数据结构例如direct memory map也会允许Linux能访问到guest系统里面的memory,这其实根本没有必要,并且也违反了只赋予最小权限的原则。在KVM Forum 2019会议上,长期KVM贡献者Jun Nakajima在自己的主题演讲“改善KVM对guest系统的保护和安全”中解释了这方面的风险,以及提出了一些改进策略。

Removing the VMM from the TCB

Nakajima指出了当前KVM hypervisor设计方案里面的3大主要安全问题:过于依赖Linux子系统,user-space的virtual machine monitor (VMM)有权访问它所管理的guest系统里的数据,kernel有权访问所有的地址空间以及数据结构,包括当前host系统里运行的所有guest系统。他受到了AMD SEV等针对虚拟化的内存加密技术,他建议了一个新的安全策略,就是要以guest系统的角度来考虑,把TCB里面的元素尽量多的删除掉。

第一步就是要把user-space VMM从TCB里拿掉。可以让guest系统使用一个新的KVM机制来指定哪一块内存空间应该共享出去,剩下的内存空间就全部标记为guest私有。VMM这边发起的对guest不希望共享出去内容的访问,全部都会导致page fault采取对应的措施,例如给VMM发送一个signal。

这意味着guest系统里面运行的kernel需要做一些修改,这样才能利用这个机制,并且确保DMA操作必须是完全利用跟VMM共享的这块内存区域的(可以利用软件I/O translation buffer来做,就是基于swiotlb的弹性缓冲区)。这个策略目前已经用来支持AMD SEV了,可以让guest系统运行中拥有内存加密的能力(从而让host kernel和user-space VMM都无法访问),而Nakajima指出这个方案的目的是尽量利用现有代码。

Protecting guests from the host kernel

如果把user-space VMM从TCB拿掉,确实是会有用处的,不过这只是第一步而已。更进一步来说,我们打算把host Linux kernel也从TCB中拿掉,这就需要更多的改动,才能让hypervisor掌控(原文用的"absorb",不确定怎么翻译最合适了)这个host kernel,把它原本具有的对guest系统全部访问的权限剥夺掉。

这个功能早在2016年KVM Forum的时候就有介绍了,当时对这个功能的称呼是VBH (virtualization-based hardening),正如这个名字所说,hypervisor会利用硬件虚拟化来保护自己避免受到host kernel的攻击。在hypervisor自己初始化好之后,Linux就会进入guest mode运行(会带有一些特殊权限),hypervisor就可以用EPT/NPT(extended and nested page tables)跟IOMMU配合起来,控制Linux对物理内存的访问。

采用这种执行模式的话,KVM就能够为guest系统提供虚拟内存上下文(virtual memory context),而不需要依赖Linux的内存管理子系统。Linux内存管理子系统只会用于服务host系统中运行user-space进程,以及kernel本身。这样一来,KVM就是唯一一个能够访问地址空间映射关系(address space mapping)并且修改它们(包括mapping的protection level)的子系统了,因此,哪怕攻击者能控制kernel的某些子系统,也仍然无法攻破guest系统的内存空间。

这样改了之后,虽然还远未达到Type-1 Hypervisor的要求,不过KVM已经把Linux的底层虚拟内存功能的很大一部分绕过去了。当然,这也就意味着hypervisor自己需要能提供诸如swapping page等机制,也要定义一些新的接口提供对真正后端内存 (RAM,software-defined,NVDIMM等) 的访问。

KVM Forum 2019里面Liran Alon和Alexandre Chartre在他们的主题演讲“KVM ASI (Address Space Isolation)”中提到的内容也跟这个有点类似。他们建议针对每个guest系统创建一个虚拟地址空间专门用于映射每个虚拟机自己的数据,KVM,以及需要用到的内核子系统。这个方式没有那么极端,因为它还是会使用Linux内存管理机制,因此预计会比较容易被接受合入upstream,不过它的缺点就是仍然保持了比较大的TCB。

总而言之,大家似乎已经公认需要重新思考KVM管理guest系统内存的方式,以及重新思考KVM和Linux其他子系统的关系。

Going further: removing KVM from the TCB

目前已经介绍的策略可以把VMM和host kernel从TCB中移除。最后异步就是要把KVM本身从TCB中移除。为了能达到这个目标,KVM必须要从它的地址空间中把guest memory整个移除,也包括要从 Linux direct map中移除映射。只有guest特意共享出来的区域可以被KVM访问。这样做会有一些麻烦,因为现在VM-exit的时候所做的一些操作一直假设KVM是能够访问全部guest memory的。VM(虚拟机)在把控制权还给host kernel的时候,会通过调用VM-exit来完成一些VM本身无法完成的工作。

为了克服这个问题,Nakajima提出了两个选项。一个是修改适配guest里面运行的kernel,把那些可能会触发VM-exit从而导致KVM访问guest memory的操作都替换成显式的hypercall。另一个选项,为了避免修改驱动程序,可以把这类操作表现为一个virtualization exception (#VE) 处理函数(handler)。这个处理函数可以模拟进行各类内存映射I/O操作(MMIO, memory-mapped I/O)并转化为hypercall。

这两种策略可以选一个,用来确保guest memory和hypervisor隔离开。总之都可以帮助避免不小心泄露数据,也能阻止side-channel attach,不过如果攻击者获得了KVM完全控制权的话,还是能修改内存映射(mapping),因此也可能访问到每一个guest系统的私有区域的。如果连这个风险也要解除的话,就需要硬件机制的帮助了,例如AMD SEV及其后续的SEV-ES(Encrypted State)和SEV-SNP(Secure Nested Paging)。这样就能让guest memory可以被透明地加密掉,这样哪怕是hypervisor也不能访问明文数据。

Proof of concept and performance

最后,Nakajima展示了一个原型系统,实现的功能包括把guest mapping从VMM和host kernel里面都摘除出去,然后给出了初步的性能数据。针对virtio设备上的磁盘读取操作,在一个guest系统里面,他测得CPU耗时增加了1.2%,如果使用超过10个guest,就有1.3%的增加。针对写操作来说影响要小一些,单个guest是1.1%的增长,超过10个guest的情况时1.2%。针对网络发送操作,也是在一个virtio设备上,单guest系统的CPU耗时增加2.6%,超过10个guest系统增加3.8%。

Nakajima介绍他的下一步工作是完成这个概念证明系统,就把patch发送给upstream社区。也许这会引起mailing list上的不少热烈讨论,关于KVM可以使用的其他一些地址空间隔离技巧来保护guest的memory不受控制了host的攻击者破坏,并且不受side-channel泄露影响。

全文完

LWN文章遵循CC BY-SA 4.0许可协议。

极度欢迎将文章分享到朋友圈 

长按下面二维码关注:Linux News搬运工,希望每周的深度文章以及开源社区的各种新近言论,能够让大家满意~

我来评几句
登录后评论

已发表评论数()

相关站点

热门文章