最新发布《数智时代的AI人才粮仓模型解读白皮书(2024版)》,立即领取! 了解详情
写点什么

Firefox 是怎样解决内存安全的?

  • 2020-03-10
  • 本文字数:2784 字

    阅读完需:约 9 分钟

Firefox是怎样解决内存安全的?


对于像 Firefox 这样复杂且高度优化的系统,内存安全是最大的安全挑战之一。Firefox 主要是用 C 和 C++编写的。众所周知,这些语言很难安全地使用,因为任何错误都有可能导致程序完全崩溃。


Firefox 软件工程师 Nathan Froyd 写道,“我们努力寻找并消除内存风险,但也在改进 Firefox 代码库,以便在更深的层次上解决这些问题。”


截至目前,Firefox 主要关注两项技术:


  1. 将代码分解成多个沙箱进程,减少特权

  2. 用一门安全的语言去重写代码,比如 Rust

一种新方法

“虽然我们继续在 Firefox 中使用沙箱和 Rust,但它们各有局限性。对已有的大型组件,进程级沙箱很有效,但这会消耗大量系统资源,因此必须谨慎使用。”Nathan Froyd 写道。


虽然 Rust 是轻量级的,但是重写现有的数百万行 C++代码是一件“劳神费力”的事。


Graphite字形库为例,Firefox 用它来正确呈现某些复杂字体。它太小了,不适合“放入”自己的进程中。


然而,如果发现内存风险,即使是站点隔离的进程架构也无法阻止恶意字体破坏加载它的页面。同时,重写和维护这种领域专用的代码并不是 Firefox 有限工程资源的理想用法。


如今,Firefox 在“军火库”中加入第三种方法。


加利福尼亚大学、圣地亚哥大学、德克萨斯大学、奥斯汀分校和斯坦福大学的研究人员开发出一种新的沙箱技术,叫RLBox


Nathan Froyd 表示,“它让我们能快速有效地将现有 Firefox 组件转换为在一个 WebAssembly 沙箱中运行。我们已经成功地将该技术集成到我们的代码库中,并将其用于沙箱化 Graphite。”


据悉,这种隔离将提供给 Firefox 74 的 Linux 用户和 Firefox 75 的 Mac 用户,不久之后还将提供 Windows 支持。

构建一个 wasm 沙箱

Wasm 沙箱背后的核心实现思想是,你可以将 C/C++编译成 wasm 代码,然后将该 wasm 代码编译成实际运行程序的机器的本机代码。


这些步骤与在浏览器中运行C/C++应用程序的步骤类似,但是,“我们在构建 Firefox 本身之前,就执行本地代码到 wasm 的转换。这两个步骤都各自依赖于重要的软件,我们还添加了第三个步骤,以使沙箱转换更简单、更不易出错。”Nathan Froyd 写道。


首先,你要将 C/C++编译成 wasm 代码。作为 WebAssembly 工作的一部分,在Clang和LLVM中添加一个 wasm 后端。光有一个编译器是不够的;你还需一个 C/C++的标准库。该组件是通过wsi -sdk提供的。一旦拥有这些组件,你就有足够能力将 C/C++转化成 wasm 代码。


其次,你需要将 wasm 代码转换为本机对象文件。Nathan Froyd 说,“当我们第一次实现 wasm 沙箱时,经常有人问我们,‘为什么需要这个步骤?’你可以分发 wasm 代码,并在 Firefox 启动时在用户的机器上动态编译它。我们本可以做到这一点,但这种方法要求针对每个沙箱实例重新编译 wasm 代码。“


在每个源都位于单独进程中的情况下,每个沙箱都编译代码是不必要的重复。他们选择的方法支持在多个进程间共享已编译的本机代码,从而能节省大量内存。


这种方法还提高了沙箱的启动速度,这对于细粒度的沙箱非常重要,例如,将每次字体访问或图像加载的相关联代码置入沙箱。

通过 Cranelift 实现预编译

这种方法并不意味着必须自己编写将 wasm 代码编译成本机代码的编译器。


“我们用相同的编译器后端实现这种提前编译”,它最终将通过字节码联盟的Lucet编译器和运行时来支持 Firefox JavaScript 引擎的 wasm 组件:Cranelift


这种代码共享可确保 JavaScript 引擎和 wasm 沙箱编译器共享改进所带来的好处。由于工程原因,这两段代码目前使用不同版本的 Cranelift。


然而,随着沙箱技术的成熟,“我们希望修改它们以使用完全相同的代码库”。


现在,Firefox 工程师已将 wasm 代码转换为本机对象代码,“我们需要能从 C++调用沙箱代码”。如果沙箱代码在单独的虚拟机中运行,这一步将涉及到在运行时查找函数名以及管理与虚拟机相关的状态。


但是,通过上面设置,沙箱代码是符合 wasm 安全模型的本机编译代码。因此,可以使用与调用常规本机代码相同的机制来调用沙箱函数。


“我们必须注意所涉及的不同机器模型:wasm 代码使用 32 位指针,而我们最初的目标平台 x86-64 Linux 使用 64 位指针。但是,还有其他障碍需要克服,这就把我们带到转换过程的最后一步。”Nathan Froyd 写道

确保沙箱正确

使用与常规本机代码相同的机制调用沙箱代码很方便,但它隐藏了一个重要细节。“我们不能相信任何来自沙箱的东西,因为对手可能已经损害沙箱”。


例如,有个沙箱函数:


/* 返回0到16之间的值。  */
int return_the_value();
复制代码


不能保证这个沙箱函数遵循它的契约。因此,“要确保返回的值落在我们期望范围内”。


类似地,对于一个返回指针的沙箱函数:


extern const char* do_the_thing();
复制代码


Nathan Froyd 表示,“我们不能保证返回的指针实际上指向沙箱控制的内存。对手可能会强迫返回的指针指向应用程序沙箱之外的某个地方。因此,我们在使用指针前要验证它。”


在阅读源代码时,还有一些其他的运行时约束并不明显。


例如,上面返回的指针可能指向沙箱中动态分配的内存。在这种情况下,应该由沙箱释放指针,而不是由主机应用程序释放。“我们可以依靠开发人员始终记住哪些值是应用程序值,哪些值是沙箱值”。


经验表明,这种方法是不可行的。

污染数据

上面两个例子说明一个普遍原则:从沙箱返回的数据应该被明确标识。有了这个标识,我们就可以确保以适当方式处理数据。


我们将与沙箱相关的数据标记为“污染”。污染数据可以自由地操作(例如指针运算、访问字段),生成更多污染数据。


但是,当我们将污染数据转换为非污染数据时,我们希望这些操作尽可能明确。污染数据不仅对管理从沙箱返回的内存很有价值,它对于识别从沙箱中返回的可能需要额外验证的数据也很有价值,例如指向某个外部数组的索引。


因此,我们将沙箱中所有公开的函数建模为返回污染数据。这些函数还将污染数据作为参数,因为它们所操作的任何东西在某种程度上都必须属于沙箱。


一旦函数调用有了这个接口,编译器就变成了一个污染检查器。当污染数据在需要非污染数据的上下文中使用时,编译器将发生错误,反之亦然。


这些上下文正是需要传播污染数据和/或需要验证数据的地方。RLBox处理污染数据的所有细节,并提供一些特性,可以直接将库的接口增量转换为沙箱接口。

下一步工作

有了 wasm 沙箱的核心基础结构,我们就可以集中精力提高它在 Firefox 代码库中的影响力了——既可以将它带到所有支持的平台上,也可以将它应用到更多的组件上。


由于这种技术是轻量级的,并且易于使用,我们希望在接下来的几个月里对 Firefox 的更多部件进行快速沙箱化。


我们最初的努力集中在与 Firefox 绑定的第三方库上。此类库通常具有定义良好的入口点,并且不会与系统的其他部分广泛共享内存。然而,在未来,我们也计划将这项技术应用于甲方代码。


关于作者


Nathan Froyd 是 Firefox 的软件工程师。在业余时间,他喜欢奥林匹克举重和阅读。


英文原文:


Securing Firefox with WebAssembly


2020-03-10 07:301746
用户头像

发布了 688 篇内容, 共 398.1 次阅读, 收获喜欢 1498 次。

关注

评论 1 条评论

发布
用户头像
曾firefox的忠实用户,但内存泄漏问题让人困惑啊.
2020-03-11 10:27
回复
没有更多了
发现更多内容

#JiraHero:Soumen Deb——重塑 Jira Software 中的 Bug 工作流,提高可见性、简化开发流程

龙智—DevSecOps解决方案

Atlassian Jira

【新布局】火绒安全企业产品Linux终端、macOS终端开启公测

火绒安全

macos Linux 服务器 终端安全 Windows Server

Tapdata 肖贝贝:实时数据引擎系列(六)-从 PostgreSQL 实时数据集成看增量数据缓存层的必要性

tapdata

数据库 实时数据

昇思MindSpore行至2022,开源社区成就生态共赢

这不科技

华为 昇思MindSpore

芯片变得更复杂的今天,你需要最大限度复用IP资源

龙智—DevSecOps解决方案

芯片行业思考 芯片开发 ip复用 ip资源 芯片行业

使用天翼云主机组功能让云主机不放在同一个篮子里

天翼云开发者社区

小程序开发入门教程

CRMEB

Rust Cell 与RefCell,有啥区别?

非凸科技

深入垂直业务场景,SaaS版供应商业务协同管理系统促进企业与供应商高效协同

数商云

数字化转型 供应链系统

向工程腐化开炮 | 治理思路全解

阿里巴巴终端技术

Java android 腐化治理 工程腐化

后端开发—一文详解网络IO模型

Linux服务器开发

reactor 后端开发 Linux服务器开发 网络io 网络模型

龙蜥开发者说:聊一聊我技术生涯的“三次迭代” | 第 3 期

OpenAnolis小助手

技术分享 开发者故事 龙蜥开发者说 突出贡献奖

外部数据的合规引入助力银行用户营销系统冷启动

易观分析

隐私计算

知识文档管理系统:帮助企业管理文档

小炮

知识管理 文档管理

OpenHarmony标准设备应用开发(二)——布局、动画与音乐

OpenHarmony开发者

动画 OpenHarmony 音乐播放

教你VUE中的filters过滤器2种用法

华为云开发者联盟

Vue 过滤器 filters过滤器 组件过滤器 全局过滤器

汉化版postman

Liam

Jmeter Postman 接口测试 API swagger

Git教程-帮助开发人员更好的运用Git | 云效

阿里云云效

git 云计算 阿里云 DevOps 开发者

叮咚!参与微服务免费试用,有机会获得腾讯内推资格!

InfoQ写作社区官方

腾讯云 微服务 热门活动

实战天翼云云主机系统盘扩容

天翼云开发者社区

云主机

资产动态管理系统解决方案

低代码小观

资产管理 企业管理系统 CRM系统 客户关系管理系统 资产安全

java版gRPC实战之一:用proto生成代码

程序员欣宸

Java gRPC

利用 IoTDB 替换 OpenTSDB,服务大唐集团60家电厂,减少95%运维成本

Apache IoTDB

Apache IoTDB

OpenHarmony标准设备应用开发(三)——分布式数据管理

OpenHarmony开发者

OpenHarmony 分布式数据

使用对等连接在天翼云两个用户的云网络之间架起一座天桥

天翼云开发者社区

Microchip推出模拟嵌入式SuperFlash技术解决边缘语音处理难题

Geek_2d6073

适合 Kubernetes 初学者的一些实战练习 (三)

Jerry Wang

云原生 集群 Kubernetes 集群 Kubernetes, 云原生, eBPF 3月月更

下拉推荐在 Shopee Chatbot 中的探索和实践

Shopee技术团队

算法 chatbot 推荐算法

产品FAQ(常见问题)文档模版

小炮

产品 FAQ

菜鸟不菜,职场小白大变身

龙智—DevSecOps解决方案

Jira Jira插件 工作流扩展 并行审批 jira并行审批

大数据培训-Flink面试知识分享

@零度

flink 大数据开发

Firefox是怎样解决内存安全的?_安全_Nathan Froyd_InfoQ精选文章