QEMU应从C走向锈蚀

2020-08-13 04:54:33

欢迎Rededers和HackerNews的朋友们!这篇帖子在QEMU社区之外引起了关注,所以我想强调两件可能不是马上就清楚的事情:我是QEMU的维护者,我不主张用Rust重写它。享受!:)。

我的KVM Forum 2018演示文稿题为《QEMU中的安全性:虚拟机如何提供隔离(Pdf)》(视频)回顾了QEMU中的安全错误,发现最常见的原因是C编程错误。这包括缓冲区溢出、释放后使用、未初始化的内存等。在这篇文章中,我将主张使用Rust作为一种更安全的语言来防止这些类型的错误。

2018年,选择一种更安全的语言还不清楚。C++提供了安全的抽象,但没有一种有效的方法来禁止不安全的语言功能。Go也提供了安全性,但担心运行时成本。生锈看起来很有前途,但很少有人对它有深刻的经验。2018年,我没有信心地争论要离开QEMU的C。

现在,在2020年,情况变得更加明朗。C编程错误仍然是QEMU中CVE的主要原因。Rust已经成熟,它的生态系统正在发展壮大,并且有一些虚拟化项目,如Crosvm、Firecracker和云管理程序,证明了Rust是编写虚拟机监视器(VMM)的有效语言。在QEMU社区,Paolo Bonzini和Sergio Lopez在Rust-VMM和vhost用户代码方面的工作启发了我更仔细地考虑从C++迁移到其他语言。

QEMU中的大多数安全错误都是C编程错误。这一点很容易通过查看CVE列表进行验证。虽然我只回顾了CVE,但似乎非安全错误也大多是C编程错误。

消除C编程错误不一定需要切换编程语言。降低软件Bug率的其他方法包括:

问题是,QEMU社区多年来一直在做这些事情,但尽管做了这些努力,仍然引入了新的bug。当然,在这些努力上花费更多的精力是可能的,但有证据表明,细菌仍在继续溜走。

这些减少错误的方法有两个问题。首先,虽然这些方法有助于找到现有的bug,但是消除bug类以便它们从一开始就不存在是一种更强有力的方法。使用C很难做到这一点,因为该语言是不安全的,这给程序员带来了安全负担。

其次,编写安全的C代码的大部分能力都来自于经验。减少bug的自定义约定、API、工具和流程是一次性贡献者或新手的障碍。它使得代码库不可访问,除非我们接受对某些贡献者较低的标准。代码质量应该尽可能少地依赖于经验,但是C是一种臭名昭著的编程语言,在您可以编写产品级质量的代码之前,它需要大量的练习。

安全语言消除了内存安全错误(以及其他类,如并发错误)。Rust在其设计中优先考虑这一点:释放后使用、双重释放、内存泄漏和其他生命周期错误在编译时由借用检查器(编译器在其中检查数据所有权)来防止。

取消空指针和严格的所有权规则可以防止指针兼容错误。

当编译时无法证明安全性时,RUST程序在运行时仍然会死机,但这不会导致C程序中看到的未定义行为。该程序简单地以回溯方式中止。在C中可能导致任意代码执行的错误在Rust中最多也就变成了拒绝服务错误。这降低了错误的严重性。

由于这种语言设计,目前困扰QEMU的大多数C编程错误要么被编译器捕获,要么变成安全的程序终止。当改用铁锈时,预期CVE的数量和严重程度都会减少,这是合理的。

同时,Rust消除了QEMU社区添加到C上的许多措施的需要,因为Rust编程语言及其编译器已经加强了安全性。这意味着新手和曾经的贡献者将不需要特定于QEMU的经验,可以更容易地编写生产质量的代码,并且可以更快地合并代码。这也意味着审查者将不得不花更少的时间指出C编程错误,或者要求做出符合QEMU做事方式的更改,这也意味着审查者将不得不花费更少的时间来指出C编程错误或要求做出符合QEMU做事方式的更改。

这就是说,由于借阅检查器,铁锈以可怕的语言而闻名。大多数程序员没有像Rust要求的那样系统和明确地考虑对象的生存期和所有权。这提高了学习这门语言的门槛,但我是这样看待它的:学习Rust在人类看来是可能的,但编写无bug的C代码则不可能。

当我签入2018年QEMU时,代码有150万行。从那时起,它就一直在增长。将大型代码库迁移到新的编程语言是极其困难的。如果人们想把QEMU转换成Rust,那就太好了,但我个人没有兴趣这么做,因为我认为集成会很混乱,会导致很多重复,而且有太多未维护的代码很难转换。

我写这篇文章的原因是,设备仿真,VMM的主要安全攻击面,可以在一个单独的程序中完成。该程序可以用任何语言编写,这就是Rust的用武之地。对于vhost设备,现在可以编写Rust设备后端,我希望这将成为写入新设备的默认方法。

对于非vhost设备,vfio-user项目正在进行进程外设备仿真。在那里也有可能在Rust中实现设备。

目前QEMU中的大多数安全错误都是C编程错误。切换到更安全的编程语言将显著减少QEMU中的安全错误。Rust现在已经足够成熟和成熟,可以用作设备仿真代码的语言。由于vhost-user和vfio-user使用Rust进行设备仿真不需要对QEMU代码进行大量转换,因此只需在一个单独的程序中即可完成。这样,攻击面就可以用铁锈写成,这样以后就不太容易受到安全错误的影响。