わかるUNIXの歴史 / 番外編 ①信頼のブートストラップ ①

本編で祝った「輪」と「種」の、暗い双子 ── 種は、信用できるのか

Trusting Trust ── 種は信用できるか 初代 Unix を書いた Ken Thompson が、1984年のチューリング賞講演で示した不気味な事実 ── コンパイラのソースがどれだけクリーンでも、バイナリにトロイが潜んでいれば、それは自己ホスティングの輪に乗って永遠に、しかも一切ソースに現れずに増殖する。

前提:第5回(自己ホスティング)・第9回(種) 教訓:自分が完全に作ったのでないコードは信用できない

本編で私たちは、自己ホスティングの輪(第5回)と、手で彫った種(第9回)を、いわば希望として語りました。ソフトはソフトを作り、最初の一度だけ人間が持ち上げる ── 美しい話です。でも同じ構造には、ぞっとする裏面があります。もし種が毒されていたら? 初代 Unix を書いた当人・Ken Thompson が、1984年のチューリング賞講演「Reflections on Trusting Trust」で示したのは、まさにこれ ── 汚染は、輪に隠れて永遠に生き延びる。しかもソースをいくら読んでも、見つからない。

01問い ── どこまで信じられるか

Thompson の講演は、一つの問いから始まります ── 「あるプログラムにトロイの木馬(悪意の仕掛け)が無い、という主張を、どこまで信用できるか?」。ふつうは「ソースを全部読んで、悪意が無ければ信用できる」と思う。彼は、その常識を鮮やかに崩してみせました。

02三段の仕掛け

Thompson の構成は、三段です。順に見ていきます。

Thompson の三段構え

① 自己再生産(自分のソースを出力するプログラム)

まず「自分自身のソースコードを出力するプログラム(クワイン)」が書けることを示す。プログラムは自分自身を“知り”、再生産できるという下ごしらえ。

② login にバックドアを仕込む

C コンパイラを改造し、login をコンパイルしていると気づいたら、魔法のパスワードを通す裏口をこっそり足す。── でもこれは、コンパイラのソースに証拠が残る。

③ コンパイラ自身も“認識”させ、証拠を消す

さらに改造し、コンパイラが「自分自身(Cコンパイラ)をコンパイルしている」と気づいたら、②の裏口コードと、この③の認識コードの両方を、こっそり再注入する。そのうえでコンパイラのソースから悪意を全部消す。一度だけ汚染版でコンパイルすれば ── 以後ソースは完全にクリーンなのに、バイナリはトロイを運び続ける。

ここが肝です。ソースはクリーン。誰が読んでも悪意は見つからない。でもそのクリーンなソースを、汚染バイナリの子孫であるコンパイラでビルドする限り、生まれるバイナリは毒されている。しかも新しいバイナリも「自分をコンパイルしたら再注入」する能力を受け継ぐ。下の図で、世代を進めて、ソース監査は毎回合格するのに、毒が消えない様子を見てください。

図1:トロイの世代伝播。汚染バイナリが「クリーンなソース」をビルドすると、新しいバイナリもやはり汚染される。ソース監査は毎世代“合格”なのに、login の裏口は生き続ける
今回の急所 ── 本編の「輪」の、暗い双子

第5回で祝った自己ホスティングの輪、第9回で彫った。そのまさに同じ構造が、この攻撃を可能にします。輪が「前の自分」を足場に回るなら、前の自分に仕込まれた毒も、そのまま受け継がれる。ソースは世代をまたいでクリーンなまま、毒だけがバイナリの系譜を伝って生き延びる。希望(自己再生産)と脅威(自己再生産する毒)は、同じ一枚のコインでした。

◇ ◇ ◇

03では、どこまで下れば信用できるのか

「ソースを読めば安心」が崩れたなら、どうすれば? ソースをコンパイルするのはコンパイラ(バイナリ)。そのバイナリを作ったのは別のコンパイラ。それを作ったのは…と、信頼もまた、コンパイルの鎖と同じように後退します。そして本編で見たとおり、その鎖は最後に自分が作っていない何か── 誰かのバイナリ、道具、そして第10回のハードウェア ── に行き着く。下の図で、その「信頼の後退」を降りてみてください。

図2:信頼の後退。自分のソースは読めても、それを訳すコンパイラ、そのまた親…と下るほど「自分で作っていないもの」を信じるしかなくなる。信頼は必ずどこかで底を打つ
// Thompson の結論(要約) "You can't trust code that you did not totally create yourself." ── 自分で完全に作ったのでないコードは、信用できない。 // しかし現実には、誰も“全部”は作れない。

04絶望ではない ── 種を検める方法はある

この講演は、しばしば「だから何も信用できない」と悲観的に受け取られます。でも本シリーズの立場はもう少し前向きです。鶏と卵の希望の側(本編)に現代の答えがあったように、この脅威の側にも、対抗する現代の技術があります ── 信用しなければならない“種”を、極限まで小さくし、検証可能にすること。次回の番外編②「Bootstrappable Builds」で、その具体を見ます。Thompson の毒でさえ、原理的には見破れる方法(多様な二重コンパイル)が後に示されました。

正直な線 ── 教育・防御の文脈で

(1) これはサプライチェーンの信頼を理解するための古典であり、攻撃の手引きではありません。要点は「ソース監査だけでは信頼の底に届かない」という防御側の教訓です。(2) Thompson は実際にこの仕掛けの実証版を作ったと後に認めていますが、広く配布されたわけではありません。講演は思考実験と実装の中間にある“実在する脅威モデル”です。

(3) 現代のコンパイラは巨大で、講演どおりの単純な攻撃はそのままは通りません。しかし原理は生きていて、実際のサプライチェーン攻撃として形を変えて現れます。(4) 対抗策(番外②の Diverse Double-Compiling や再現ビルド)は強力ですが万能薬ではなく、最下層(ハードウェア・マイクロコード=第10回の下)の信頼までは別問題として残ります。

練習問題(今回の話だけで解けます)
  1. コンパイラのソースが完全にクリーンでも、生成物にトロイが入りうるのはなぜか。
    答えを見る
    ソースをビルドするコンパイラ(バイナリ)が汚染されていれば、クリーンなソースからでも毒入りバイナリが作られるから。毒はソースでなくバイナリの系譜に潜む。
  2. なぜ毒は世代をまたいで消えないのか。本編のどの概念と同じ構造か。
    答えを見る
    汚染バイナリが「自分をコンパイルするとき毒を再注入」するため。自己ホスティングの輪(第5回)/種(第9回)と同じ構造で、前の自分を足場にする輪が、毒も受け継ぐ。
  3. 「信頼の後退」は、本編のどの後退と鏡写しか。どこで底を打つか。
    答えを見る
    「何が何をコンパイルしたか」の後退(本編)と鏡写し。信頼も、自分のソース→コンパイラ→その親…と下り、最後は自分が作っていないバイナリ/道具/ハードウェア(第10回)で底を打つ。
  4. Thompson の教訓を一文で。それは絶望を意味するか。
    答えを見る
    「自分で完全に作ったのでないコードは信用できない」。ただし絶望ではなく、信用する“種”を小さく・検証可能にする現代の対策(番外②)がある。

まとめ希望と脅威は、同じ一枚のコイン

初代 Unix を書いた Ken Thompson は、1984年のチューリング賞講演で問うた ── 「プログラムにトロイが無い、とどこまで信じられるか」。彼の三段の仕掛け(①自己再生産 ②login の裏口 ③コンパイラ自身を認識して裏口と認識コードを再注入し、ソースの証拠は消す)は、クリーンなソースからでも、汚染バイナリの子孫でビルドする限りトロイが生き延びることを示した。ソース監査は毎世代合格するのに、毒は消えない。

これは本編で祝った自己ホスティングの輪と種の、暗い双子だ ── 前の自分を足場にする輪は、前の自分の毒も受け継ぐ。信頼もまたコンパイルの鎖と同じく後退し、最後は「自分が作っていないもの」(バイナリ・道具・第10回のハードウェア)で底を打つ。教訓は「自分で完全に作ったのでないコードは信用できない」。でも絶望ではない ── 信用する種を極小化し検証する道がある。次回、その現代の答えへ。

この文書は「わかるUNIXの歴史」番外編①です。史実:Ken Thompson は1984年の ACM チューリング賞講演「Reflections on Trusting Trust」(Communications of the ACM, Vol. 27, No. 8, August 1984, pp. 761–763)で、コンパイラに自己伝播するトロイの木馬を仕込む構成を示した。手順は概略、(1) 自己複製プログラム(クワイン)、(2) C コンパイラが login を認識して裏口を挿入、(3) コンパイラ自身のコンパイルを認識して裏口挿入コードと認識コードを再注入し、コンパイラのソースからは痕跡を消す、というもの。結果として、ソースがクリーンでも、汚染バイナリの系譜でビルドされる限りトロイが持続する。結論は「自分で完全に作ったのでないコードは信用できない」。Thompson はこの実証版を作ったと後年述べている。対抗策として David A. Wheeler の Diverse Double-Compiling(多様な二重コンパイル)や再現ビルド/Bootstrappable Builds があり、番外編②で扱う。本稿は防御・教育目的の解説であり、攻撃手法の提供を意図しない。図は概念の模式化。 ── 印刷する場合はブラウザの「印刷」から「PDF に保存」を(印刷版では図の操作・解答は静止/非表示になります)。

印刷 / PDF 化:⌘+P(Windows は Ctrl+P)。画面では図1のスライダーでトロイの世代伝播(ソース監査は毎回合格・毒は残る)を、図2で信頼の後退を追えます。「答えを見る」で解答が開きます。