LWN: 自举编译(bootstrappable builds)!

Bootstrappable Builds项目旨在通过确保构建过程及其工具的可复现性,减少软件生态系统中对不透明二进制文件的依赖,增强安全性与源代码可移植性。

关注了就能看到更多这么棒的文章哦~

Bootstrappable builds

By Jake Edge
January 6, 2021
DeepL assisted translation
https://lwn.net/Articles/841797/

Reproducible Builds (可复现的构建)这种想法,也就是要求使用相同的源代码要能够重新创建出每个 bit 都相同二进制文件,这种概念在过去几年中得到了不少发展。reproducible builds 提供的这些保障,可以用来阻止软件供应链(software supply chain)中的心怀恶意的参与者。但是,编译软件的过程非常依赖用于编译生成二进制文件的工具,包括编译器和 build-automation 工具,其中许多工具都是现成的二进制文件。因此,我们需要在构建我们的软件生态系统(software ecosystem)时尽量减少对不透明的二进制文件的依赖,这就是 Bootstrappable Builds 项目(https://bootstrappable.org/)的目标。

例如,GCC 是使用 C 和 C++ 编写的,这意味着它需要使用这两种语言的编译器才能完成源码编译。在具体实践上来说,就意味着使用发行版中现有的这些编译器的二进制可执行文件来编译生成一个新的 GCC 版本,然后将其发布给用户。Unix 的发明者 Ken Thompson 的在获得图灵奖的演讲 "关于信任的思考(reflections on Trusting Trust)" 中描述了对这种方法的担忧。简单来说的话,Thompson 认为,人们信任二进制编译器的输出,其实这是一种盲目信任,他们总是假设没有人在编译的过程中插手做坏事,而其实这部分的源代码坏人也是可以看到并修改的。

Bootstrappable Builds 项目是在 2016 年柏林峰会期间启动的,当时是作为 Reproducible Builds 项目的一个分支。bootstrappable build 可以说是将 reproducibility (可重现性)的理念又向前推进了一步。编译生成目标二进制的过程,以及所依赖的工具的编译过程都需要是可重现的。从概念上讲,这就像用各种不同元素的原子来捏合建造出一座房子。

这显然是一个有趣的难题,并且从头开始引导(boostrapping)一个 Linux 发行版是一件很费劲的事,而且这样做的好处短期内其实并不大。这个项目的网页上 (https://bootstrappable.org/benefits.html) 概述了会有哪些好处,其中主要是关于安全方面以及源代码的可移植性方面的。对于用户来说,boostrapping 和 reproducibility 有助于预防恶意的后门,并且 Linux 发行版和工具开发者在将代码移植到新的架构上将会更加容易。

由于 C 语言是大部分开源生态系统的核心,因此我们希望拥有一种方法来 boostrap C 编译器(如 GCC),这就是 Bootstrappable Builds 正在推进的各个项目之一。其中,有一项工作是要维护 GCC 4.7 版本的一个子集,因为这是最后一个只能用 C 编译器来构建出来的 GCC 版本。GCC 4.7 本身更容易从更加简单的 C 编译器(如 Tiny C 编译器,即 TinyCC 或 tcc)中进行 boostrap,而不需要同时也使用一个 C++ 编译器。

还有一个相关的工作,是围绕着 GNU Mes 展开的。GNU mes 是一个用 C 语言写出的 Scheme 解释器,和一个用 Scheme 写的 C 编译器的组合体。这两个部分是 mutually self-hosting 的,也就是说其中一个总是可以从另一个(或从一个单独的二进制 C 编译器或 Scheme 解释器)来构建生成。这个工作已经用了起来,从而将 GNU Guix 发行版所需的 bootstrap 二进制文件(即所谓的 seeds)的数量减少了一半:

Mes+MesCC 可以编译生成一个只需要打少量 patch 的 TinyCC,而这个 TinyCC 是 self-hosting 的。使用这个 TCC 和 Mes C 库,我们现在针对 gnutools 的三大件(glibc-2.2.5, binutils-2.20.1, gcc-2.95.3) 已经只需要更少的 Binary Seed boostraop 程序了。这样一来就完全可以 bootstrap i686-linux 和 x86_64-linux 的 Guix 了。

虽然已经大大减少了从头开始创建发行版时所需的二进制文件的数量,但人们计划要走得更远。Stage0 项目,是一个旨在从一个真正最小的基础上进行 bootstrap 的项目,需要小到只有一个不到 500 字节的 hex monitor("如何创建它,这完全取决于你,我喜欢自己手动来修改它")。这个 monitor 实现了一个简单的十六进制代码到二进制的翻译器,可以用来构建更复杂的二进制文件,可以浏览项目仓库(https://github.com/oriansj/stage0) 来了解能有哪些功能。

在最近发布到 bootstrappable 邮件列表中的报告中,Jan Nieuwenhuizen 介绍了一些进展。Mes 已经不再是 Guix 的 bootstrap seed 了,因为它是变为了从十六进制代码工具(hex0)开始构建的。除了 Guix 之外,也有其他一些地方也在尝试,比如 https://www.freelists.org/post/bootstrappable/wipfullsourcebootstrap-from-a-357byte-hex0-to-hello,3 这里就成功地只用两个很小的 seed 工具(其中之一就是 hex0 工具)来 bootstrap 了一个系统,同时现在也已经能够构建 Mes 了,而 TinyCC 还正在进行中。

此外,在 2019 年的 Reproducible Builds summit 上,在三个发行版中,分别使用三个不同版本的 GCC 来编译 Mes,成功地创建了每个 bit 都相同的 Mes 二进制文件。Guix、NixOS 和 Debian 先用 GCC 来构建 Mes,然后用这个 Mes 再次构建,结果得到了完全相同的二进制文件。正如 David A. Wheeler 所指出的那样,这个做法正是他提出的 diverse double-compiling(DDC)方法在现实世界中的应用,可以对抗 Thompson 提出的 "trusting trust" 攻击。

他们使用了三个不同的发行版(GNU Guix、Nix 和 Debian)和三个不同的 GCC 主版本来重新编译 GNU Mes。后来,他们还使用了 tcc 编译器(虽然细节不详)。在所有这些做法之后,他们都成功创建出了一个与 GNU Mes C 编译器完全相同的二进制文件。

[…]这种结果表明,几个不同的发行版和不同的可执行文件产生了相同的结果。然而,其中有三个应用程序使用的是相同的编译器,也就是 GCC(尽管版本不同)。这些测试中使用了类似的、很有关联的发行版,它们甚至使用了许多相同的底层组件,如 glibc、Linux 内核等(尽管同样是不同的版本)。

所以,虽然这确实使用了 DDC,而且确实增加了我们的信心,但由于检查系统(checking system)比较相似,所以给我们增加的信心还是有限的。他们希望在未来尝试使用更加种类的编译器,这样我们会有更大的信心。

听起来,bootstrappability 是那种极其费事的底层工作。它并不适合所有人,但它很重要。如果我们能够确保我们软件生态系统的基础是健全的,并基于此向上搭建,那么我们就可以确定没有后门躲在我们的构建工具中来做破坏。这是一个非常好的结果,但事实上它只是把问题推向了更底层。某种硬件或固件的后门仍然可能潜伏在某个地方。解决这个问题将是非常困难的。

[感谢 Paul Wise 提出这个话题]

全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值