LWN: 加固 virtio!

Linux News搬运工

共 3716字,需浏览 8分钟

 ·

2021-08-27 18:55

关注了就能看到更多这么棒的文章哦~

Hardening virtio

August 9, 2021
This article was contributed by Marta Rybczyńska
DeepL assisted translation
https://lwn.net/Articles/865216/

一直以来在虚拟化环境中,host 都是受到 guest 的信任的,并且负责保护自己不能受到那些恶意 guest 的破坏。随着保密计算(confidential computing)等举措的开展,这一规则变得更进一步了,也就是:guest 不再信任 host。这种基本原则的变化,导致需要在以前没有加边界防御(boundary defence)的地方也要加上了。最近,Andi Kleen 提交了一组 patch set,希望在 virtio 中添加这些必需的保护措施。这组 patch set 所引发的讨论,再一次说明需要针对更多的使用场景来加固 virtio。

Virtio 为一些类型的设备(如网络或块设备)提供了一个标准化的接口。使用 virtio 的话,guest 可以运行一个简化的通用驱动程序,host 来处理与底层的真正设备的交互。virtio 设备(host 端)和驱动程序(guest 端)之间的通信是通过名为 virtqueues 的数据结构来进行的,这通常是一些 memory buffer,不过实际的实现方式还是取决于所使用的总线的。

The scope of the hardening

在 confidential-computing 世界里,host 不可以访问那些没有明确共享给它的 guest memory。此外,guest 的内存可以由处理器用 host 完全不知道的密钥来进行加密。Kleen 的工作是建立在英特尔即将推出的硬件功能之上,也就是名为信任域扩展(TDX,Trust Domain Extensions)的功能,其目标是希望保护云环境中的 guest。这个功能是基于一些架构扩展功能的,包括使用了 Multi-Key Total Memory Encryption(MKTME)的内存加密(在 2019 年在 LWN 提到的时候还是使用的另一套有些差异的内存加密 API),以及一种称为安全仲裁模式(SEAM, Secure-Arbitration Mode)的新增 CPU mode。在受保护的模式(protected mode)中,在 SEAM 下运行的代码只能利用指定的内存区域(也就是加密过的),而其他所有进程(还有 DMA 操作)都不能访问到该区域。Virtio 作为 guest 和 host 之间常用的接口,就必须格外小心,要避免损害 TDX 提供的安全性。

直到最近,virtio 驱动程序都认为另一边是可以信任的。因此,在处理与设备(即 host 这一侧)共享的各种元数据时(例如操作描述符、ring buffer 位置、最终结果代码等)时,有时没有进行必要的检查。因此,它们可能无法检测出坏指针,或者超出范围的 buffer index 之类的错误。因此,恶意的 host 完全可以利用 buffer overrun 来获得对 guest 内存的访问能力。其他情况下,也是需要检查 device 的元数据的,因为 virtio 不再只是在 guest 和 host 之间使用了,也有一些物理设备现在正在实现 virtio 接口。

这些 patch 可以分为三部分。第一部分是对 virtio 本身的加固,位于 virtio-ring。它还禁用了 virtio 的一些模式。第二部分是启用了 TDX 的 x86 系统的 mode restriction。最后,则是 swiotlb 的改动,swiodtlb 是用来在无法直接使用 DMA 的情况下经过 bounce buffer 来实现 DMA 功能。patch set 中包含的这些加固措施对恶意指针增加了额外检查。

Virtio modes

Virtio 定义了许多 mode ,分别具有不同的内存组织模式,这完全取决于设备和驱动程序的需求。这样依赖就导致有多种代码路径需要进行加固。显然,其中一部分 mode 修复起来更容易一些。Kleen 决定只保护 split mode,也就是每个 virtqueue 都由不同的部分组成,每个部分都可以由 driver 或 device 写入,但不可以被两者同时写入。

当前 patch set 中,当 guest 运行在 TDX 保护模式下时,不允许采用其他 mode。这样一来就无法使用 indirect descriptor 了(这是一种 split-mode extension,允许在另一个专门的内存区域分配多个描述符,通过增加 ring 的容量来改善性能)。同样被禁用的还有 packed mode,这是一种更紧凑的内存布局。这些限制引起了一些反对意见。Jason Wang 观测到,禁用 indirect descriptor 会造成很大的性能损失。Kleen 感到要保证这种模式的安全很困难,他认为这种模式太难保护了。Wang 认为这个问题可以解决,并承诺会发布一组 patch。

Andy Lutomirski 也不同意这种禁用了所有 mode 只保留一种的做法。他后来明确强调,不能让 device 在任何配置下损坏 driver,所以加固的做法需要更通用一些:

对于大多数 Linux 驱动来说,恶意的 device 如果会破坏 host memory ,那么这就是一个 bug 而不是一个 feature。如果某个 USB 设备可以破坏内核的内存,那就是一个严重的 bug。如果一个 USB-C 设备可以破坏内核 bug,这也是一个严重的 bug,尽管可悲的是,我们可能有很多这样的 bug。如果一个 Firewire device 可以破坏内核内存,11 频道的新闻都会报道了。如果一个蓝牙或 WiFi 的对端设备可以破坏内核内存,人们就会为它写十四行诗,并给它起各种特别的名字。那么为什么 virtio 就要是特别的?

根据 Lutomirski 的说法,驱动程序应该需要对所有的使用场景来说都是安全,而不仅仅是在使用 TDX 的情况。只在运行 TDX 时禁用其他 mode 并不能解决问题,因为这些 mode 中的漏洞可以被利用来攻击现有的系统。他还指出,virtio 不仅是一种软件实现,而且还有硬件设备也是采用了 virtio 兼容的接口暴露给驱动程序。在另一封邮件中,他建议将驱动程序分成现代版本和传统版本(这个传统版本可以包括所有那些并未真正使用的 mode,以及那些无法在不破坏兼容性的情况下修复的 mode),然后将现代版本完全彻底地加固起来。

Kleen 并不赞同,他说在其他情况下(可能是那些没有使用 TDX 这类机制的情况)完全没有内存保护,并且还有导致兼容性问题的风险(他并没有明确解释这一点)。边界检查是无条件启用的,但其他 virtio 模式只有在 TDX 激活时才被禁用。讨论就这样结束了,没有明确的结论。

Similar work

在讨论中,Wang 指出还有其他一些类似的加固需求,包括对 AMD 安全加密虚拟化(SEV, Secure Encryted Virtualization)的支持。另一个对 virtio 加固的需求来自于 SmartNIC 以及那些实现了 virtio 接口的设备,主要包括 vDPA (一种在 data path 上实现 virtio 的设备类型,它的 control path 上还有一个 vendor driver ) 以及 VDUSE (一种在用户空间实现的 vDPA 设备)。它们也有类似的问题,都不应该相信 device 所提供的元数据。根据 Kleen 的说法,这些其他情况只要基于他的改动之上增加一些改动应该就可以实现这个功能了。

Conclusions and next steps

对设备驱动进行加固,从而能对抗恶意设备,这是受到内核开发者欢迎的目标。讨论表明确实有多种使用场景需要这样的功能,而且不同的部分都需要这样的 fix。Kleen 的 patch set 在当前收到的评价有赞同也有反对。这里主要的问题似乎是它与 TDX 的工作关联太紧密了,而内核开发者们喜欢一个更通用的解决方案。我们可能会在未来看到这项工作的更多版本,以及 virtio 的其他加固修复工作。

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

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~



浏览 32
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报