如何从头开始编译C编译器,然后从头开始编译Unix / Linux


64

假设我在美国/英国以外的大型服务机构工作。我们广泛使用UNIX和Linux服务器。

通读本文时,提到将后门插入C编译器很容易,然后使用该编译器编译的任何代码也将包含后门。现在,鉴于最近有关NSA / GCHQ要求在所有加密方法,硬件和软件中放置后门/弱点的漏洞,编译器现在是失败的关键点。可能所有标准UNIX / Linix发行版都可能受到损害。我们无力让流氓政府破坏我们的系统,数据和客户数据。

有了这些信息,我想从头开始构建一个受信任的编译器,然后就可以建立一个安全的基础,这样我就可以使用该编译器从源代码构建操作系统和应用程序。

从源代码编译编译器(看似鸡蛋的场景)然后从头开始编译受信任的Unix / Linux发行版的正确(安全方式)是什么?

您可以假设我或其他人具有阅读和理解源代码的安全漏洞的能力,因此在编译之前将首先对源代码进行审查。我真正需要的是一个工作指南,可以从头开始安全地生产此编译器,并且可以用于编译内核,操作系统和应用程序的其他部分。

如果我们要对在该堆栈上运行的操作系统或应用程序有信心,则安全堆栈必须从基本级别开始。是的,我知道可能存在硬件后门,这些后门可能会在构建编译器时向编译器中插入一些微代码。目前我们对此无能为力,只能使用非美国设计的芯片。让我们首先对这一层进行排序,并假设我可以在插入任何后门之前将其构建在旧计算机上。

正如布鲁斯·施耐尔(Bruce Schneier)所说:“我向工程师说:我们建立了互联网,我们中的一些人已经颠覆了互联网。现在,那些热爱自由的人必须加以修复。”

额外链接:


7
该死,这是一个非常有趣的问题,我不想迁移它,但我真的不认为它是这里的话题。它更适合stackoverflow.com,因为您的基本问题是关于如何从头开始编译编译器,这与操作系统无关,并且是编程问题。如果过一会儿仍未在此处找到答案,请考虑使用问题标记下的“标志”链接,并要求主持人将其移至SO。
terdon

2
@terdon实际上,它可能更适合Programmers.SE,因为它更多地是关于一般的编程问题,而不是特定的开发问题。实际上,那里可能是重复的
CVn

2
GCC是开源的,如何插入任何后门?
Michael Pankov

2
请记住,稳定的Thompson漏洞利用需要能够在登录程序或编译器编译时识别的代码。如果您可以手动将源代码转换为编译器无法识别为这些程序之一的格式,则不会传播后门程序。
罗素·博罗戈夫

2
@Constantius-阅读第一行中链接的Thompson文章。谁编译编译器?
罗素·博罗戈夫

Answers:


30

AFAIK唯一可以确保安全的方法是使用汇编语言编写编译器(或直接自行修改磁盘)。只有这样,您才能确保编译器没有插入后门-之所以有效,是因为您实际上是在完全淘汰编译器。

从那里,您可以使用从头开始的编译器进行引导,例如GNU工具链。然后,您可以使用自定义工具链来编译Linux From Scratch系统。

请注意,为了使事情变得容易,您可以使用C(或其他任何语言)编写的第二个中间编译器。因此,您将用汇编语言编写编译器A,然后用C / C ++ / Python / Brainfuck /以任何方式重写该编译器,以获取编译器B,您将使用编译器A对其进行编译。然后,您将使用编译器B来编译gcc和它的好友。


13
即使这样,这仍然只能防止恶意编译器。您仍然需要信任在其上执行编译器的系统。没有孤立的软件。
CVn

3
任何自治都是天生的危险。您实际上是在提出一种工具链编译器(尽管很奇怪),这意味着可以完全按照您要避免的方式对其进行修改。更好的是,可以通过MitM在运输过程中对其进行修改。
奋斗

1
你们必须意识到,这个答案来自15岁。继续奋斗!
mtahmed 2014年

3
一个人不要忘了也从头开始编写代码编辑器-谁知道您是使用良好的编译器从预编译的<code> vim </ code>或<code> vim </ code>编译的,还是仅使用受感染程序进行审计的源代码? <code> vim </ code>是否值得信赖?
哈根·冯·埃森

1
永远不要忘记,除非您亲自编写了第一台机器代码(而不是汇编代码或实际机器代码),并且您是识别安全漏洞不足的专家,并且阅读并检查了正在编译的每一行代码……或者至少知道谁做的人的个人相信他做到这一点...。这些都没有帮助。这就是为什么试图在Kickstarter上破坏整个观点的原因。这是:高信任度。
Evi1M4chine

22

一种可能的方法,尽管在实践中会花费很长时间,但要回到根源。GNU的开发始于1984年,Minix的原始版本(在早期Linux开发中用于引导目的)于1987年发布。

完整的答案是基于您的前提,即“ [您或其他人具有阅读和理解安全漏洞源代码的能力,因此在编译之前将首先对源代码进行审查”,并且您可以相信这种分析的结果。没有这个答案,这个答案可能会比一文不值的糟糕,因为您将花费大量的时间完全没有任何好处。

如果您可以找到带有源代码的Minix原始书的副本,则可以从书中键入它。对其进行编译,然后在不同的系统上使用不同的反编译器来验证编译器是否生成了预期的机器语言二进制输出。(代码只有12,000行,大概是C,所以这样做很耗时,但是如果您对这样的项目很认真的话,这仍然是合理的。)您甚至可以编写自己的反汇编程序。那应该不是很难。

抓住您可能会接触到的最旧版本的GNU实用程序(因为这些代码可能具有较少的代码,并且对外部库的依赖较少),遍历代码,为Minix构建(尽管这可能需要一些工作;但是,您会发现)绝对要避免的是对源代码进行调整,因为这会使以后添加补丁程序非常容易出错),并且会为GNU工具经历类似的反汇编验证周期。那时,您已经信任了操作系统和工具链,因此您只需要遍历补丁集中的源代码(补丁集中的所有内容都已经被信任),但是与您使用的工具相比,这些工具仍然非常原始和粗糙到今天。例如,除了系统工具的最基本功能之外,别无所求。阅读很多XKCD。

在某个时候,您将拥有一个可以编译和引导Linux内核的早期版本的系统,就像在1990年代初Linux开始受到黑客的欢迎时所做的那样。我建议此时迁移到Linux(针对Linux重建系统库和工具链,构建Linux内核,引导至Linux并可能在Linux中重建Linux内核和GNU工具链;最后一个证明该系统现在可以自我托管),但这完全取决于您。不断验证补丁程序,修补内核,库和基本的GNU工具,以及重新构建,直到获得最新版本为止。

那就是当您拥有可用于构建现代软件的受信任的基本OS和编译器时。届时,您可以按照《Linux From Scratch》指南进行操作,以构建能够执行有用任务的系统。

“编译器”系统绝不能以任何方式(包括作为联网主机上的VM)连接到网络;您可能会冒险渗透到包括内核在内的任何具有网络功能的组件。如果您担心Thompson编译器攻击,则必须期望任何VM主机也可能受到威胁。使用sneakernet可以在要编译内容的物理主机上获取源代码并从中获取二进制文件。至少在实现USB大容量存储支持之前,至少要在系统上打开和关闭文件时遇到麻烦。如果你真的偏执,打印源代码列表和手型他们(和希望,打印机驱动程序和打印机不具备类似的代码它们),或在一台计算机显示器上读取代码,然后将其键入物理上相邻但未连接的另一台计算机。

是的,这将花费很多时间。但是这种方法的优点是每个步骤都是渐进式的,这意味着,除非经过许多版本的逐步采用,否则任何恶意软件都很难通过。这是因为每个步骤的更改集相对较小,因此更容易查看。将补丁集与变更日志进行比较,并确保您可以准确确定哪个变更日志条目对应于源代码中的每个变更。再一次,这确实假设您有能力(可能通过您信任的人)验证这种更改是否没有潜入代码库中,但是它应该使您与仅软件一样接近受信任的系统,除了-固件方法可以。


反汇编验证方法存在很大缺陷,因为它仍然做出了巨大的假设,即验证机是完全可信的。除非您从头开始构建该机器及其软件,或者不知道亲自做过的人并信任她,否则这将不会发生。因此,这仍然是不安全的。抱歉。……此外,在这些问题上,“接近……”仍然意味着“不安全”,因为它只需要一个不可信任的点就可以破坏整个观点。
Evi1M4chine

9

如果您需要一个受信任的编译器,则可以研究一下学术工作,例如compcert项目。它是由INRIA(法国IT公共实验室)构建的编译器,旨在进行“认证”,即生成在语义上与代码完全等效的可执行文件(当然,它已经在数学上得到了证明)。


1
每个人都需要一个受信任的编译器。数学如何工作才能生成“受信任的”编译器?
大卫·J

@DavidJ引导程序,最有可能。构建一些可以完全验证和证明正确的小片段,然后将其用作构建更复杂的编译器的基础。
CVn

1
“”“使CompCert C与任何其他生产编译器不同的地方在于,它使用机器辅助数学证明进行了正式验证,可以避免错误 编译问题。”“” compcert.inria.fr/compcert-C.html编译不像以前那样经验丰富。
lgeorget13年

1
@MichaelKjörling可能没有考虑到当编译器读取内核时,内核可能会被妥协以在编译器源代码中包含后门程序
棘手的问题2013年

1
我也发现此链接也可以工作。
David J

2

虽然以手动方式创建自己的编译器作为起点是最安全的,但另一种选择是从存在这些漏洞的5(或10)年旧CD中安装您信任的CD。然后以此为基础,从中编译新的审核源。


5
自从1984年以来,该攻击就一直为公众所知。大概是汤普森并不是第一个考虑这种可能性的人。回溯到那意味着我们今天想当然的大多数事情都不存在。考虑20年前计算机的功能,并将其与当前状态进行比较。甚至原始的Linux引导系统Minix直到87年才发布,GNU的开发始于84年。因此,尽管从理论上讲这可以回答问题,但在实践中它几乎没有用。
CVn

2
我可能会接触到的最早的计算机是286。我必须查看我的祖父母是否仍然拥有它。
大卫·J

1
实际考虑到这一点的奖励点:-)。@DavidJ
3684年

@MichaelKjörling:并非如此;因为它只会使您的引导链更长。但是,也许只要不使用机器语言从头开始编写自己的编译器就可以了。
Evi1M4chine
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.