WebAssembly与回溯:Firefox 95中的细粒度沙盒技术
作者:Bobby Holley | 2021年12月6日
在Firefox 95中,我们推出了一项名为RLBox的创新沙盒技术——这是与加州大学圣迭戈分校和德克萨斯大学的研究人员合作开发的成果。该技术能够轻松高效地隔离子组件,从而提升浏览器的安全性。RLBox突破了传统基于进程的沙盒限制,为我们带来了新的可能性。我们期待扩展其应用范围,并希望看到其他浏览器和软件项目采纳这一技术。
这项技术利用WebAssembly来隔离可能存在缺陷的代码,建立在去年向Mac和Linux用户推出的原型基础上。现在,我们将该技术推广到所有支持的Firefox平台(桌面和移动端),并隔离了五个不同的模块:Graphite、Hunspell、Ogg、Expat和Woff2[1]。
今后,我们可以将这些模块视为不可信代码。假设我们实施正确,即使其中任何一个模块存在零日漏洞,也不会对Firefox构成威胁。因此,我们更新了漏洞赏金计划,奖励研究人员即使在没有隔离库漏洞的情况下绕过沙盒。
进程沙盒的局限性
所有主流浏览器都在独立的沙盒进程中运行Web内容,理论上防止其利用浏览器漏洞入侵您的计算机。在桌面操作系统上,Firefox还将每个站点隔离在独立的进程中,以保护站点彼此不受影响。
不幸的是,威胁行为者经常通过串联两个漏洞来攻击用户:一个用于攻破包含恶意站点的沙盒进程,另一个用于逃离沙盒[2]。为了保护用户免受资金最充足的对手攻击,我们需要多层防护。
在已经按信任边界隔离的基础上,下一步逻辑是跨功能边界进行隔离。历史上,这意味着将子组件提升到自己的进程中。例如,Firefox在专用的、锁定的进程中运行音频和视频编解码器,该进程与系统其他部分的接口有限。然而,这种方法存在一些严重限制。首先,它需要解耦代码并使其异步,这通常耗时且可能带来性能成本。其次,进程具有固定的内存开销,增加进程数量会增大应用程序的内存占用。
由于这些原因,没有人会认真考虑将XML解析器之类的组件提升到自己的进程中。要在这种粒度级别进行隔离,我们需要不同的方法。
使用RLBox进行隔离
这就是RLBox的用武之地。我们不是将代码提升到单独的进程中,而是将其编译为WebAssembly,然后将该WebAssembly编译为本机代码。这不会导致我们在Firefox中分发任何.wasm文件,因为WebAssembly步骤只是我们构建过程中的中间表示。
然而,这种转换对目标代码施加了两个关键限制:它不能跳转到程序其他部分的意外区域,也不能访问指定区域之外的内存。这些限制共同使得在可信和不可信代码之间共享地址空间(包括栈)变得安全,允许我们在同一进程中运行它们,基本上像以前一样。这反过来使得应用变得容易,无需重大重构:程序员只需要清理来自沙盒的任何值(因为它们可能是恶意构造的),RLBox通过污点层使这一任务变得简单。
这种转换的第一步很简单:我们使用Clang编译Firefox,而Clang知道如何发出WebAssembly,因此我们只需将给定模块的输出格式从本机代码切换为wasm。对于第二步,我们的原型实现使用了Cranelift。Cranelift非常优秀,但第二个本机代码生成器增加了复杂性——我们意识到将WebAssembly映射回我们现有构建系统可以处理的东西会更简单。
我们通过wasm2c实现了这一点,它将WebAssembly直接转换为等效的C代码,然后我们可以将其与Firefox源代码的其他部分一起反馈给Clang。这种方法非常简单,并自动启用了一些我们对常规Firefox代码支持的重要功能:配置文件引导优化、跨沙盒边界的内联、崩溃报告、调试器支持、源代码索引,以及可能我们尚未意识到的其他功能。
下一步
RLBox在多个方面为我们带来了巨大收益:它保护用户免受意外缺陷和供应链攻击,并减少了我们在上游披露此类问题时匆忙应对的需要。因此,我们打算继续将其应用到更多组件中。有些组件不适合这种方法——要么因为它们过于依赖与程序其他部分共享内存,要么因为它们对性能过于敏感,无法接受适度的开销——但我们已经确定了其他一些合适的候选组件。
此外,我们希望看到这项技术进入其他浏览器和软件项目,使生态系统更安全。RLBox是一个独立项目,设计得非常模块化和易于使用,其团队欢迎其他用例。
谈到团队:我要感谢Shravan Narayan、Deian Stefan和Hovav Shacham,他们不懈努力将这项工作从研究概念推向生产。向数亿用户分发是困难的,他们做了一些非常令人印象深刻的工作。
在加州大学圣迭戈分校雅各布斯工程学院网站上阅读更多关于RLBox和此公告的信息。
— [1] Graphite、Hunspell和Ogg的跨平台沙盒在Firefox 95中发布,而Expat和Woff2将在Firefox 96中发布。 [2] 通过使用系统调用来利用操作系统中的漏洞,或通过使用IPC消息来利用托管浏览器更特权部分的进程中的漏洞。 —