本編で祝った「輪」と「種」の、暗い双子 ── 種は、信用できるのか
本編で私たちは、自己ホスティングの輪(第5回)と、手で彫った種(第9回)を、いわば希望として語りました。ソフトはソフトを作り、最初の一度だけ人間が持ち上げる ── 美しい話です。でも同じ構造には、ぞっとする裏面があります。もし種が毒されていたら? 初代 Unix を書いた当人・Ken Thompson が、1984年のチューリング賞講演「Reflections on Trusting Trust」で示したのは、まさにこれ ── 汚染は、輪に隠れて永遠に生き延びる。しかもソースをいくら読んでも、見つからない。
Thompson の講演は、一つの問いから始まります ── 「あるプログラムにトロイの木馬(悪意の仕掛け)が無い、という主張を、どこまで信用できるか?」。ふつうは「ソースを全部読んで、悪意が無ければ信用できる」と思う。彼は、その常識を鮮やかに崩してみせました。
Thompson の構成は、三段です。順に見ていきます。
① 自己再生産(自分のソースを出力するプログラム)
まず「自分自身のソースコードを出力するプログラム(クワイン)」が書けることを示す。プログラムは自分自身を“知り”、再生産できるという下ごしらえ。
② login にバックドアを仕込む
C コンパイラを改造し、login をコンパイルしていると気づいたら、魔法のパスワードを通す裏口をこっそり足す。── でもこれは、コンパイラのソースに証拠が残る。
③ コンパイラ自身も“認識”させ、証拠を消す
さらに改造し、コンパイラが「自分自身(Cコンパイラ)をコンパイルしている」と気づいたら、②の裏口コードと、この③の認識コードの両方を、こっそり再注入する。そのうえでコンパイラのソースから悪意を全部消す。一度だけ汚染版でコンパイルすれば ── 以後ソースは完全にクリーンなのに、バイナリはトロイを運び続ける。
ここが肝です。ソースはクリーン。誰が読んでも悪意は見つからない。でもそのクリーンなソースを、汚染バイナリの子孫であるコンパイラでビルドする限り、生まれるバイナリは毒されている。しかも新しいバイナリも「自分をコンパイルしたら再注入」する能力を受け継ぐ。下の図で、世代を進めて、ソース監査は毎回合格するのに、毒が消えない様子を見てください。
第5回で祝った自己ホスティングの輪、第9回で彫った種。そのまさに同じ構造が、この攻撃を可能にします。輪が「前の自分」を足場に回るなら、前の自分に仕込まれた毒も、そのまま受け継がれる。ソースは世代をまたいでクリーンなまま、毒だけがバイナリの系譜を伝って生き延びる。希望(自己再生産)と脅威(自己再生産する毒)は、同じ一枚のコインでした。
「ソースを読めば安心」が崩れたなら、どうすれば? ソースをコンパイルするのはコンパイラ(バイナリ)。そのバイナリを作ったのは別のコンパイラ。それを作ったのは…と、信頼もまた、コンパイルの鎖と同じように後退します。そして本編で見たとおり、その鎖は最後に自分が作っていない何か── 誰かのバイナリ、道具、そして第10回のハードウェア ── に行き着く。下の図で、その「信頼の後退」を降りてみてください。
この講演は、しばしば「だから何も信用できない」と悲観的に受け取られます。でも本シリーズの立場はもう少し前向きです。鶏と卵の希望の側(本編)に現代の答えがあったように、この脅威の側にも、対抗する現代の技術があります ── 信用しなければならない“種”を、極限まで小さくし、検証可能にすること。次回の番外編②「Bootstrappable Builds」で、その具体を見ます。Thompson の毒でさえ、原理的には見破れる方法(多様な二重コンパイル)が後に示されました。
(1) これはサプライチェーンの信頼を理解するための古典であり、攻撃の手引きではありません。要点は「ソース監査だけでは信頼の底に届かない」という防御側の教訓です。(2) Thompson は実際にこの仕掛けの実証版を作ったと後に認めていますが、広く配布されたわけではありません。講演は思考実験と実装の中間にある“実在する脅威モデル”です。
(3) 現代のコンパイラは巨大で、講演どおりの単純な攻撃はそのままは通りません。しかし原理は生きていて、実際のサプライチェーン攻撃として形を変えて現れます。(4) 対抗策(番外②の Diverse Double-Compiling や再現ビルド)は強力ですが万能薬ではなく、最下層(ハードウェア・マイクロコード=第10回の下)の信頼までは別問題として残ります。
初代 Unix を書いた Ken Thompson は、1984年のチューリング賞講演で問うた ── 「プログラムにトロイが無い、とどこまで信じられるか」。彼の三段の仕掛け(①自己再生産 ②login の裏口 ③コンパイラ自身を認識して裏口と認識コードを再注入し、ソースの証拠は消す)は、クリーンなソースからでも、汚染バイナリの子孫でビルドする限りトロイが生き延びることを示した。ソース監査は毎世代合格するのに、毒は消えない。
これは本編で祝った自己ホスティングの輪と種の、暗い双子だ ── 前の自分を足場にする輪は、前の自分の毒も受け継ぐ。信頼もまたコンパイルの鎖と同じく後退し、最後は「自分が作っていないもの」(バイナリ・道具・第10回のハードウェア)で底を打つ。教訓は「自分で完全に作ったのでないコードは信用できない」。でも絶望ではない ── 信用する種を極小化し検証する道がある。次回、その現代の答えへ。
印刷 / PDF 化:⌘+P(Windows は Ctrl+P)。画面では図1のスライダーでトロイの世代伝播(ソース監査は毎回合格・毒は残る)を、図2で信頼の後退を追えます。「答えを見る」で解答が開きます。