谷歌最近使用 Rust 编程语言重写了 Android 虚拟化框架中受到保护的虚拟机固件,并且建议涉及固件处理项目的开发者也同样积极拥抱这种内存安全语言。
1、Rust 在 Linux 上遇阻,但在 Android 上受宠
在谷歌发布的博客中,Android 工程师 Ivan Lozano 和 Dominik Maier 深入研究了使用 Rust 替换旧版 C 和 C++ 代码的技术细节。
Lozano 和 Maier 介绍称,“大家可以看到,使用 Rust 代码来提高安全性其实相当简单易行,我们甚至会演示 Rust 工具链如何应对特殊的裸机目标。”
对于 Rust 这样一门以学习难度高而闻名的编程语言来说,“简单易行”的说法似乎有点超出普遍认知。
另外,让 C 和 C++ 开发人员尝试用 Rust 的视角观察世界同样困难重重。就在上周,Rust for Linux 项目的一位维护者刚刚选择辞职(此项目旨在将 Rust 代码纳入基于 C 的 Linux 内核),理由就是 Linux 内核开发人员对 Rust 的强烈抵制。
在今年早些时候,一位 Linux 内核贡献者在某场技术会议的热烈讨论中明确表示,“不会吧,你们不会强迫我们所有人都学习 Rust 吧。”
尽管受众态度并不积极,但谷歌还是对潜在支持者拿出了足够的耐心和鼓励。Lozano 和 Maier 指出,以往的固件通常使用内存不安全语言(例如 C 和 C++)编写而成,因此缺乏高级安全机制。而 Rust 提供了一种避免内存安全漏洞(包括缓冲区溢出和释放后使用)的方法,成功阻遏了这些在大规模代码库中占据多数的重大漏洞来源。
他们强调称,“Rust 提供了一种内存安全的 C 和 C++ 替代方案,有着足以与之媲美的性能表现和代码体量。”此外,Rust 还支持与 C 代码的互操作性,且不会带来任何额外开销。
就连美国政府最近也一直在强调这个议题,并在各领先科技企业及非营利项目的支持下,尝试用 Rust 语言重写关键开源项目及组件。去年,网络安全与基础设施安全局(CISA)就建议软件供应商“将有关法律并最终消除其产品线中的内存安全漏洞,作为公司的最高目标之一。”
谷歌已经接受了这一观点,今年 3 月,谷歌得出结论称,其 Rust 开发人员的生产力已经达到 C++ 工程师的两倍。
谷歌 Android 编程语言工程总监兼 Rust 基金会董事会主席 Lars Bergstrom 也表态说,“我们意识到 Rust 在构建技术栈各个层面的安全可靠软件方面,正在发挥极其关键的作用。”
“在谷歌,我们正推动在 Android、Chromium 等平台上使用 Rust 语言,借此减少内存安全漏洞。我们还致力于同 Rust 生态系统开展合作、推动语言落地,并为开发人员提供顺利迁移所必需的资源和培训支持。这波将 Rust 引入嵌入式及固件开发的尝试,解决了技术栈中又一关键安全难题。”
有网友指出,Rust 在 Android 上进展顺利的关键就在于 Lars Bergstrom 的态度:
“我们来看一下这位的头衔:谷歌 Android 编程语言工程总监,同时也是 Rust 基金会董事会主席。我认为,将 Android 系统全面采用 Rust 语言的进程可能会比 Linux 内核更顺利推进,因为他是负责人,有权解雇那些不按要求进行 Rust 改造的人。”
而在 Linux 圈子里,Alex Gaynor 和 Geoffrey Thomas 在 2019 年 Linux 安全峰会上表示,大约三分之二的 Linux 内核漏洞源于内存安全问题。而 Rust 理论上可以通过其本质上更安全的应用程序接口(API)完全避免这些问题。
Torvalds 对这一切怎么看?早几年的时候,他属于“观望派”——“我对这个项目感兴趣,但我认为它是由对 Rust 非常热衷的人推动的,我想看看它在实际中会如何运作。”
Torvalds 还表示:“个人而言,我并不在‘推动’Rust 的行列中,但考虑到它所承诺的优势和避免一些安全隐患的可能性,我对它持开放态度,不过我也清楚有时承诺未必能兑现。”
去年底,在 Linux 基金会的日本开源峰会上,Linus Torvalds 和 Dirk Hohndel(Verizon 开源部门负责人)讨论了 Rust 语言在 Linux 内核中的使用,Torvalds 表示,“Rust 的使用在不断增长,但目前我们还没有任何内核部分真正依赖 Rust。对我来说,Rust 是一个在技术上合理的东西,但对我个人而言,更重要的是,我们作为内核和开发者,不能停滞不前。”
这个表达有人解读为“Linus 个人对 Rust 不是那么赞赏,但 Linux 总需要尝试一些新的东西”。
另一方面也有人反驳说,“如果 Linus 没有从根本上相信 Rust 是一种应该在内核中占有一席之地的语言,那么 Rust 也不会获得内核支持。”
在今年的 KubeCon 上,Linus Torvalds 和 Dirk Hohndel 再次谈到了如何将 Rust 语言引入 Linux。Torvalds 对 Rust 的应用速度未能如预期般加快感到失望,“我原本指望着更新速度会更多,但问题在于不少老一代内核开发人员更习惯于使用 C 语言,而不太熟悉 Rust。他们不太愿意学习一种在某些方面与老办法截然不同的新语言。因此,Rust 的普及受到了一些阻力。”
除此之外,Torvalds 还评论道,“另一个原因在于,Rust 自身的基础也并不是十分牢靠。”可以说,相比 Lars Bergstrom,实际上 Torvalds 对 Rust 的态度一直很审慎。
2、作为 Android 的新默认语言,Rust 的推进一直很顺利
2021 年,谷歌宣布将 Rust 选定为 Android 开源项目(AOSP)代码新贡献的默认语言。
谷歌在 Android 项目中使用的其他内存安全语言还包括 Java 以及与 Java 兼容的 Kotlin。C 和 C++ 仍然是 AOSP 中的主导语言,但 Android 13 是首个大部分新代码都由内存安全语言编写的版本。在谷歌于 2021 年 4 月首次将 Rust 用于 AOSP 之后,短短一年后,这种编程语言在新代码贡献量中就占比约 21%。
在 Android 的新代码中使用 Rust,也是为了减少与内存相关的漏洞。2019 年发布的 Android 10 版本存在 223 项内存安全漏洞,而 Android 13 的已知内在安全问题已经大幅减少至 85 个。
Android 安全软件工程师 Jeffery Vander Stoep 于 2022 年指出,内存安全漏洞占 Android 总漏洞的比例从 76% 下降到了 35%。随着内存安全漏洞的减少,谷歌还发现关键及远程可利用漏洞的数量同样有所缩减。
Vander Stoep 补充说,这一变化并非源自代码贡献者的“灵光乍现”,只是人们开始使用更好的工具来完成工作。Android 团队计划加强对 Rust 的使用,但这也并不意味着要在其系统编程中彻底淘汰 C 和 C++。
他在推文中解释道,“如果一定要为此番成就找个理由,那我个人的答案就是‘谦逊’。Android 团队中的各个部门都一直在关注‘我们怎样才能做得更好’这个关键问题,同时也有毅力坚持到底并做出改变,包括系统层面的变革。”
“谦逊本身也应该是双向的。Rust 并不能解决所有问题,C/C++ 在某些领域仍将是开发实践中最实用的选择,至少在相当长的一段时间内依旧如此。这很正常。”
“我们将随时间推移努力减少这种情况,同时继续扩大我们的 Rust 使用率,并不断投资和部署对 C/C++ 代码的改进。”
Vander Stoep 还提到,相关性也并不等同于因果关系,但必须承认内存安全漏洞的百分比(即在高严重性漏洞中的比例)确实与新代码使用的语言类型有着很强的关联趋势。谷歌表示,模糊测试等安全工具也在打击内存安全漏洞方面贡献了重要力量。
Vander Stoep 表示,“我们将继续投资于工具开发以提高项目的 C/C++ 安全性。在过去几个版本当中,我们在生产 Android 设备上引入了 Scudo 强化分配器、HWASAN、GWP-ASAN 以及 KFENCE。我们还在现有代码库当中扩大了模糊测试的覆盖范围。使用这些工具发现的漏洞既有助于预防新代码中出现类似的问题,也有助于在上述评估中及时揪出旧代码中存在的漏洞。这些重要工具对我们的 C/C++ 代码至关重要。然而,单凭这些还不足以解释我们从安全漏洞中观察到的趋势性变化,其他同样部署了这些技术的项目也并未发生如此重大的结构性变化。因此我们认为,Android 从内存不安全语言向着内存安全语言的持续转变才是改善其安全态势的一大核心因素。”
他当时还指出,Android 13 中共包含 150 万行 Rust 代码,约占所有代码新贡献的 21%(Android 本身有数千万行代码)。而且谷歌也没有在 Android 的 Rust 代码中发现任何内存安全漏洞。
Vander Stoep 指出,“这表明 Rust 语言正一步步实现其预期目标,即防止 Android 中最常见的漏洞来源。在 Android 的不少 C/C++ 组件(包括媒体、蓝牙和 NFC 等)当中,过往内存漏洞的密度已经超过了 1/kLOC(即每千行代码一个漏洞)。以这样的历史水平为基准,对 Rust 语言的使用很可能已经将数百个漏洞阻挡在了生产环境之外。”
在 Android 项目之内,谷歌使用 Rust 建立用户空间硬件抽象层(HAL),并在越来越多的受信应用程序之内添加对 Rust 的支持。去年,谷歌还曾发布过公告,表示他们用 Rust 编程语言重新实现了 Linux 内核中的 Android Binder 代码,Binder 负责进程间通信(IPC)等任务。与 C 版 Binder 相比,Rust Binder 的 IPC 基准测试结果显示出良好的前景,但仍需在实际工作负载下进行进一步测试。至少在 Binder 吞吐量的基准测试中,Rust 版本与 C 版本的性能差异约为±2%。
如今谷歌进一步在现有固件代码库中部署了 Rust。
根据谷歌软件工程师 Ivan Lozano 和 Dominik Maier 的文章,使用 C 和 C++ 编写的旧固件代码库可以通过“直接替换为 Rust”来受益,以保证操作系统底层敏感层的内存安全。
“我们希望证明这种方法对于固件是可行的,能够以高效且有效的方式实现内存安全,”Android 团队表示。
“固件充当硬件和高级软件之间的接口。由于缺乏高级软件中标准的软件安全机制,固件代码中的漏洞可能会被恶意攻击者危险地利用,”谷歌警告说,并指出现有的固件由用内存不安全的语言(如 C 或 C++)编写的庞大的传统代码库组成。
“简单地用 Rust 编写任何新代码都可以减少新漏洞的数量,并随着时间的推移减少现有漏洞的数量,”Android 软件工程师表示,建议开发人员通过编写一个薄的 Rust shim 来替换现有的 C 功能,该 shim 在现有 Rust API 和代码库期望的 C API 之间进行转换。
“shim 作为 Rust 库 API 的包装器,连接了现有的 C API 和 Rust API。当用 Rust 替代重写或替换现有库时,这是一种常见的做法。”
参考链接:
https://www.theregister.com/2024/09/06/google_rust_c_code_language/
https://security.googleblog.com/2024/09/deploying-rust-in-existing-firmware.html
https://www.zdnet.com/article/google-after-using-rust-we-slashed-android-memory-safety-vulnerabilities/
https://www.reddit.com/r/rust/comments/18e6qrl/linus_on_rust_in_the_linux_kernel_december_2023/
https://www.phoronix.com/news/Google-Linux-Binder-In-Rust