2013年10月20日星期日

反思信任的可靠性

TURING AWARD LECTURE: Reflections on Trusting Trust
KEN THOMPSON 1984年图灵奖演讲:反思信任的可靠性
英文原文:http://cm.bell-labs.com/who/ken/trust.html
翻译:曹文盲

背景:
Ken Thompson和Dennis M. Ritchie在1970间用汇编在PDP-7上写出了UNIX的第一个版本。装了UNIX的PDP-11被安装在BellLab里供大家日常使用。很快大家发现Ken总能进入他们的帐户,获得最高权限。有人分析了UNIX代码,找到了后门,于是修改代码,然后重新编译了整个UNIX。可是很快他们发现Ken又拿到他们的帐户权限。大家都知道他一定是在源代码中加入了后门,可是虽然源码已经公开,就是找不到后门在哪里。直到14年后,Ken 才在下面这个演讲中透露谜底:
原来当年他们在编写Unix的时候,在内部留了个只有自己知道的小后门,可以让他获得操作系统的最高权限。后来Unix开放源码,于是Ken把Unix源码中的后门代码移除,把后门加到了C语言编译器中,当编译器检测到这是Unix的源代码,就自动给里面嵌入后门。。。所以尽管公开的Unix源码中没有后门,但一旦用这个编译器编译,则会自动带上后门……
再后来这个编译器也要开放源码,于是他又在未开源前的最后一个版本的编译器中留下另一个后门:如果检测到这是那个编译器的源码,则给这个编译器加入后门,这个后门的作用是给Unix系统以及别的编译器中加入后门…… (详细点的解释点击此处

===================================================================
 
我们到底要去到什么程度才能相信某个程序是完全没有木马后门的?这个问题可能比信任程序的作者更要紧。
 
谢谢ACM的授奖。除开技术上的成功,我不禁想自己得到这项荣誉也是因为碰到意外之财的好运气。今天UNIX 1 已经广泛流行,横扫大型主机到自动小型机,改变了整个软件工业的面貌。如果当初Daniel Bobrow 买不起PDP-10,要等到PDP-11出现才出手,那么今天站在这里的恐怕是他而不是我。另外,UNIX能达到今天的成就同时也是许许多多其他人的功劳。

俗话说“和带你来的人一起跳舞”,照此我今天的讲题本该是UNIX。可是我已经好多年不在主流UNIX上工作,可还在继续领受本不属于我的他人功劳。因此我不准备谈UNIX,只是我要感谢在其中作出了贡献的每一位。

这就说到了Dennis  Ritchie,我们的合作真是一件美好的事。在我们一起工作的十年中,我只记得一件没有配合好的事。在那次事件中,我发现我们各自单独写了20行同样的汇编程序,我仔细比照我们的源程序,惊人地发现它们完全一样,一字不差。我们一起合作的成果远远超出我们各自单独的贡献。

我是一名程序员。在我的1040报税表格上,职业那一栏就是这样填写的。作为一名程序员,我写程序。我想向你们展示一下我写得最酷的一个程序。下面我分三步来实现,最后再将它们合并在一起。 

第一阶段 

在大学的时候,在视频游戏出现以前,我们以写程序来互相挑战取乐。其中最喜好的一个节目是写一个最短的可以自我复制的程序。由于这是一个脱离实际的练习,因此通常就用FORTRAN语言。其实,选FORTRAN来写的原因同“两人三足”比赛流行的原因一样。更准确地说,这个挑战就是要写一出段代码,当编译执行后,它的输出结果必须是同它的源代码一模一样的拷贝。如果你从来没有这样玩过,我强烈建议你现在就试一试。当你自己去发现怎样做时,获益将远超只是被动地教怎样做得到的。之所以要求程序“最短”,目的是要激发参与者尽量展示技巧,同时也用来决断胜负。
[figure 1]
 
图1 展示的是一段自我复制的C程序代码。(讲求纯粹的人也许会注意到这还不能准确地说是一个自我复制程序,不过它会生成一个自我复制的程序)。 这段入门级的程序大概得不了奖,它太大个了,但它展示了技巧,而且包含完成我的故事需要的两个重要的因素:1)这个程序可以容易地用其它语言实现 。2)这个程序可以嵌入一段任意大小的额外模块中,与主程序一同复制。在这个例子中,哪怕是连注释部分都被复制了。

第二阶段 

C编译器也是用C写的。当一种语言的编译器是用这种语言自己来写的时候,我其实是在谈论一个“先有鸡还是先有蛋”的问题。在这个例子中,我将采用来自C编译器的一个特例。C允许一个字符串结构指定一个初始化的字符序列,里面每一个字符都可以转义成表示一个不可打印字符。比如:
"Hello world\n"
这段代码有一个用"\n,"  结尾表示换行的字符串。
[figure 2]

图 2.1 是一段C编译器中的一个代表转义字符序列的理想代码。
这是一段非常令人吃惊的代码。它居然能够以一种完全可移植的方式“知道”任何一个字符代码被编译成了新的一行。知道这一动作就可以让它重新编译自己,于是知识得以永续。
[figure 3]

假设我们想让编译器包含一个 "\v"  序列来代表垂直列制表符。图2.1的扩展是显而易见的,如图2.2所示。于是我们重新编译编译器,但是得到一个诊断信息,显然,因为二进制版本的编译器不知道 "\v"  ,源代码不是合法的C。我们必须“训练”编译器。等它知道 "\v"  是什么时,这些改变就变为合法的C了。查一下ASCII码字符表,找到垂直制表符代码是11,再更改一下源代码如图2.3所示。现在编译器可以接受新的源代码了。我们把安装最终的二进制文件作为官方C编译器,于是可以写图2.2所示的那种可移植版本了。
[figure 4]

这是一个非常深的概念。它非常接近我所见到的“学习”程序。你只需告诉它一次,然后你就可以利用它的这种定义来自我学习了。
 

第三阶段 

[figure 5]
 
同样地,图3.1是调用例程“compile”来编译下一行代码实现对C编译器的上层控制。图3.2展示对编译器的一个小改动,使它匹配上一段特定的代码语句时就有意地歪曲编译一下源码。如果不是有意的,它就叫编译器的一个bug。但现在它是有意植入的,所以就叫“木马”。
[figure 6]
 
我在编译器中实际植入的bug是让它匹配UNIX代码中的"login"命令。这段置换的代码会歪曲编译登录命令,让它既可以通过真正设定的加密密码,也可以通过一个已知的通用密码。这样一旦这个代码装进了二进制,而后被用来编译登录命令,那么我就可以进入任何一个用户的帐户。
这样一段赫然的代码不可能长期不被人发现,即使是在最随意的C编译器代码审核中也会引起怀疑。
[figure 7]
 
这最后的一步在图3.3中。它只是简单地在前面的那个木马上再套一层木马。这第二个匹配序列是C编译器。置换代码是阶段一中的那个自我复制代码,让它把木马插入到编译器中去。这需要一个类似第二阶段例子的学习步骤。首先我们编译用正常的C编译器编译修改的代码生产一个有bug的二进制文件,然后安装这个二进制文件作为官方C,这时就可以将编译器源代码里的bug移除,而每当用这新的二进制代码编译时它就会自动插入bug。那登录命令也就总有一个bug,尽管它在源码中毫无踪迹。 

道德 

道德是明显的。不能信任不是由你自己完全创建的代码 (特别是雇用像我这样的人的公司的代码)。没有多少源代码级的审查可以保护你免受非信任的代码。这里我是选择C编译器来作为这种可能攻击的一个示范,我也可以选择任何一种其它处理程序的程序,像汇编器,加载器,甚至硬件微代码。当程序越来越底层,这些bugs也越难检测得到。一个安装得很好的微代码bug几乎是不可能被检测出来。 在试图向你们证明我是不可以信任之后,我现在想正义化一下自己。我要批评媒体处理“黑客",414帮,Dalton帮 的方式。往好里说这些小孩是破坏艺术的故意行为,往坏里说这也许是入侵甚至盗窃。只不过法律条文的不足让黑客们躲过了严重罪行的指控。那些受这种活动威胁的公司(大部分的大公司都有易受这攻击)正在努力施压去更新法律条文。没有受权就访问计算机系统在一些州已经是一种严重罪行,国会和许多其它州都正在跟进立法。 快要爆发的情况正在酝酿,一边媒体,电视,电影却将这些蓄意搞破坏的神童呼作英雄,另一边这些小孩的行为却可能很快招致他们几年监狱的惩罚。 我看过这些小孩在国会的听证。非常明显,他们完全没意识到他们行为的严重性。这里有一个显然的文化断层。入侵计算机系统应该和潜入邻居的房屋一样耻辱,不管邻居的房屋是否上锁。媒体应该知道到不正当使用计算机和醉驾是一样事情。

致谢

我是在空军一份关于早期Multics实现安全的评论(文献4)上读到第一次看到这种木马入侵可能性的。

参考文献:

1,  Bobrow,  D.G., Burchfiel, J.D., Murphy, D.L., and Tomlinson, R.S.  TENEX, a paged time-sharing  system for the PDP-10. Commun. ACM 15, 3 (Mar. 1972),  135-143. 
2.  Kernighan, B.W., and Ritchie, D.M. The C Programming Language.  Prentice-Hall, Englewood Cliffs, N.J., 1978. 
3.  Ritchie, D.M., and Thompson, K. The UNIX time-sharing system.  Commun. ACM 17, 7(July 1974), 365-375.
4.  Karger, P.A., and Schell, R.R. Multics Security Evaluation: Vulnerability Analysis. ESD-TR-74-193, Vol II, June 1974, p 52.