Rust成为C的接班人 或将开发Linux驱动

Rust 是由 Mozilla 主导开发的专注于安全、速度和并发的系统级编程语言,目前已经逐渐走向成熟。最近,英特尔首席工程师 Josh Triplett 在 2019 年开源技术峰会(OSTS)上发表了主题为“英特尔和 Rust:系统编程的未来”的演讲。他就开发人员是否可以用Rust开发驱动程序这一问题询问了Linux内核稳定版维护者 Greg Kroah-Hartman。

Kroah-Hartman 表示愿意接受用 Rust 开发Linux内核的驱动程序,但有两个条件。其一,以可选的方式存在,而不是默认启用,这样其他开发者就不需要使用Rust去构建内核;其二,Rust 驱动需要展现出比 C 驱动更具优势的特性,比如针对内核API的安全封装器。看样子,大家未来有很大的机会使用Rust编写Linux驱动。

在很长一段时间里,Linux内核和驱动程序开发,基本上都是用C语言编写的。

然而,C写driver的主要缺陷在于C赋予程序员的自由度过大,所谓能力越大责任越大,程序员需要小心处理各种细节以保证driver的安全。在一些情况下,程序员容易因为疏忽大意写出不安全的代码。例如申请的内存忘记释放(内存泄漏),使用了已经被释放的指针(use-after-free),数组越界访问(buffer overflow)等等。这些错误大多归因为C是一门不安全的语言。

前段时间,随着微软计划用Rust取代C和C++新闻的曝出,Rust被认为是C/C++的接班人。由Mozilla开发的Rust被认为具有较强的安全性。同时,由于特殊的类型系统,Rust不需要垃圾收集,也被认为是高效的。Rust程序运行速度极快,可防止段错误并保证线程安全。这些属性使该语言极大地吸引了专注于应用程序安全性的开发人员。香港中文大学系统安全系博士李卓华指出,Rust主要通过严格的语法和安全检查来限制程序员,“逼迫”程序员写出更安全的代码。例如Rust的ownership特性保证任何时刻,一个对象最多只有一个可变引用,且在其生命期结束后编译器会自动将其内存释放,从而避免了内存泄漏和use-after-free的问题。

《Rust编程之道》作者张汉东表示,Rust的优势在于内存安全和并发安全,以及现代化的类型系统,更能保证程序的正确性。并且拥有现代化的工具链,比如对SIMD、WASM等的支持。现在已经有人用Rust写了WASM的虚拟机(Wasmer),允许在 Linux 内核中实现安全的 WebAssembly 运行环境,这样可以避免如系统调用(上下文切换)、用户态/内核态数据复制等性能损耗(当前评测情况是提升10%)。看得出来,使用Rust扩展Linux内核,会带来更多的可能性。

北美华人安全论坛BASec创始人韦韬认为,Rust有着出色的性能表现,不过对于普通业务而言,性能不是关键,稳定性才是。这个恰恰是Rust的最强项。就稳定性而言,Rust碾压大部分语言,包括C,C++,Go,Python,PHP等等。但是没有免费的午餐,Rust的稳定性来自于Borrow Checker的"严苛",Ownership机制对于Rust入门者有一定的门槛。但大部分情况下,配合上基本的编程规范(严格限制unsafe/unwrap/…等),只要Rust编译器点头,程序运行起来就没什么问题。需要注意的是,Rust保障的内存安全不包括防止内存泄露。因为内存泄露的语义和具体应用逻辑强相关,所以还需要做额外的内存泄露检查,但这方面的工具比较现成,一般不是大问题。但即使如此,Rust写驱动也不太乐观,主要是两个原因。一是需要把底层的unsafe仔细封装,因为在驱动场景下,很多操作不满足Rust safe的要求,一旦代码里混杂了很多unsafe,那么因常规安全检验工具的缺乏,Rust反而会不如C。二是硬件厂家的工程师从C改为Rust更漫长,广泛的硬件驱动支持才是Linux生态繁荣昌盛的根基,这个生态挑战比单纯的技术挑战更大。

就Rust目前开发Linux驱动的落地难点问题,李卓华列出以下几点:

  1. Linux内核中定义的函数,结构体众多,想要在Rust中使用需要将它们重新改写成对应的Rust版本,这一点人工完成的话工作量极大,自动完成的话(用bindgen将C翻译成Rust)代码丑陋杂乱,且缺乏安全抽象。
  2. Linux内核使用的很多C的特性没有对应的Rust实现,例如C结构体的bitfield。
  3. Driver主要是底层的代码,有时需要Rust的unsafe特性,无法保证安全性。
  4. 编写Driver主要是提供一组回调函数(callback function),由内核负责在合适的时候调用。这就需要回调函数必须用FFI(Foreign Function Interface)编写(因为Linux内核只提供C的函数原型),且必须是全局的(因为要让Linux内核可以找到它们),这就限制了开发者封装和组织风格良好的代码。
  5. 调用内核函数也是unsafe的,除非为其提供一层安全抽象。
  6. Linux不保证API和ABI的稳定性,因此难以封装内核函数和数据结构。

在此前InfoQ发表的文章中,有些读者评论Rust的生态尚未建立,可能会成为落地的阻碍。对此,韦韬表示,Crate虽然还不够丰富,但现在逐渐在改善;其实更大的问题是低质量的Crate混杂其中,会破坏Rust应用的稳定性和安全性。但相比较而言,Rust的crate包管理比C/C++强太多,已经有很多落地实践表明是完全可行的。

关于人们关心的如何为Linux的内核函数提供一层安全的抽象的问题。专家认为,这里存在不少挑战,但是是一个正确的方向,这个方向如果成功,会极大的提升Linux内核的安全性和稳定性。

感兴趣的Rust开发人员不必从头开始。目前至少有一个Github项目已经存在,它适用于内核模块的框架,有关该项目的背景信息可以在2019年Linux北美安全峰会的演示文稿中获取。

相关链接:
Rust 未来可用于开发 Linux 驱动
Rust-Module im Linux-Kernel vorstellbar

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章