2026年6月18日、Ingo Blechschmidtという数学者がMastodonに投稿した。書き出しの一行はこうだ。「ここ数日、私は興味深く、極めて充実感があり——しかし同時に恐ろしくもあるデバッグの旅に没頭していた。」彼が続けて明らかにした事実はこれである。2024年5月のLinuxカーネル6.9リリース以降、まる二年以上にわたり、彼の暗号化ハードディスクの復号鍵はノートPCの蓋を閉じた後もメモリ上に残り続け、一切消去されていなかった。
言い換えれば、彼のフルディスク暗号化はまったくの無駄だった。
この投稿は数日後、テクノロジーコミュニティHacker Newsに登場し、瞬く間に379ポイント、182コメントを集めた。筆者は全討論スレッドと関連するカーネルのコミット履歴を読み終えた後、この一件が表面的に見えるよりはるかに複雑であることに気づいた——大騒ぎになるような大規模脆弱性ではない。しかし、まさに「脆弱性とは呼べない」がゆえに、より味わい深いのだ。
図:Linuxフルディスク暗号化(LUKS)はメモリ上の鍵に依存してディスクデータを復号する。鍵が消去されなければ物理的攻撃者に抽出される。出典:hacknjill.com
まずは比喩から:あなたのスーツケースの鍵
この一件を理解するのに、プログラミングの知識は不要だ。日常的な比喩を使おう。
あなたはダイヤルロック付きのスーツケースを持っているとしよう。中身はすべて暗号化されていて——他人がケースを手に入れても、番号を知らなければ開けられない。この番号(コンピュータの用語では「鍵」)は普段あなたの頭の中に保存されている(コンピュータでは「メモリ」)。
スーツケースを閉じるたびに(「ノートPCの蓋を閉じる」に相当)、あなたがまずすべきことは番号を頭から消し去ることだ。そうすれば、あなたの留守中に誰かがケースを盗んでも開けられない。戻ってケースを使うときに、改めて番号を入力する。
これがLUKS(Linuxフルディスク暗号化標準)のluksSuspend機能のやっていることだ。ノートPCがスリープに入る前に、まずメモリ上の復号鍵をきれいに消去する。復帰後、システムはパスワードの再入力を求め、鍵が再ロードされ、ディスクへのアクセスが再開される。
このロジックは美しく、そして極めて重要だ。なぜならノートPCの蓋を閉じた後もマシンはシャットダウンしていない——メモリは通電したままで、データは中に残っている。もし鍵が消去されていなければ、悪意ある者はあなたのノートPCを手に取り(電源オンの状態を保ったまま)、いわゆる「コールドブート攻撃」——メモリチップを冷凍して取り外しデータを読み取るか、Thunderbolt/USBポート経由でメモリに直接アクセスする——によって暗号鍵を盗み出すことができる。
そしてIngo Blechschmidtの発見はこうだ。2024年5月以降、このluksSuspendの消去動作が音もなく機能しなくなっていた。
図:暗号鍵はRAMチップに格納される。システムがスリープに入る際に消去されなければ、攻撃者は物理的手段で鍵を直接抽出できる。出典:sesamedisk.com
「合理的な」カーネル再構築が、なぜセキュリティホールを生んだのか
Ingoはgit bisect——コードのバージョン履歴の中で問題の出所を半自動的に特定するツール——を用いた。彼が辿り着いたのは問題を引き起こしたコミットa28d893eb327、タイトル「md: port block device access to file」(ブロックデバイスアクセスをファイルへ移植)。
このコミット自体には何の悪意もなく、低レベルなミスでもない。Linuxカーネル開発者による合理的かつ有用なリファクタリング——カーネル内部でハードディスクの読み書きを扱う方法を古いインターフェースから新しいインターフェースへ移行する作業——である。家庭の電気配線を古いアルミ線から銅線に交換するようなもので、論理的には「よりクリーンで、よりモダン」だ。
問題は、このリファクタリングが一見無関係に見える低レイヤのメカニズムに手を加えたことにある。スレッドキーリング(thread keyring)のライフサイクル管理である。
ここで「キーリング」とは何かを説明しよう。Linuxカーネル内では、暗号鍵は「キーリング」と呼ばれる専用のデータ構造に格納される——メモリの片隅に適当に放り込まれているわけではない。スレッドキーリングは特殊なキーリングで、プログラムのスレッドに紐づいており、スレッドが終了すればキーリングも破棄され、中の鍵も当然消滅する、という建て付けだ。
luksSuspendの設計はまさにこの特性に依存していた。ディスク暗号鍵を一時的なスレッドキーリングにアップロードし、そのスレッドが終了するときにキーリングが自動破棄され、鍵もろとも消え去る——という仕組みである。
カーネルのドキュメントにはこれが明文化されており、公式の保証だった。しかし6.9バージョンで導入されたあのリファクタリングは、期せずしてスレッドキーリングが特定の状況下でもはや破棄されないようにしてしまった。スレッドは終了したのに、キーリングはゴーストのようにメモリ上にぶら下がり続ける——ディスク復号鍵も一緒に。
最も皮肉なのは、この脆弱性の修正に必要なコードはたった一行だったことだ。
そう、一行。Ingoは脆弱性発見後、カーネルメーリングリストにパッチを提出した。変更は極めて小さく、ある構造体に必要なクリーンアップ呼び出しを一行加えただけだ。具体的な中身に興味があれば、こういうロジックだ。あるカーネル関数内にkey_put(key)を一行追加し、使われなくなった鍵の参照が正しく解放されるようにする。
しかしIngoは自らの投稿の中でこうも正直に認めている。「形式検証なしには、私のパッチが正しいとは言い切れない。それが自らの長距離相互作用を引き起こさないとも確信できない……」 これは本物のエンジニアだけが言える正直な言葉だ。
NixOSのテストインフラがなければ、この脆弱性は永遠に発見されなかったかもしれない
この物語にはもう一人のキープレイヤーがいる。NixOSだ。
NixOSをご存じなければ、簡単に言えば「再現可能な」Linuxディストリビューション——システム全体の設定が一つのファイルに記述され、Gitでバージョン管理でき、別のマシンにコピペするだけで完全に同一のシステムを再構築できる。NixOSコミュニティの自動テストへの投資はLinux界隈でも群を抜いている。
発見者のIngo自身がNixOSコミュニティの出身だ。彼は脆弱性を発見した後、まず最初にNixOSのコードリポジトリに自動化された統合テストを提出した(PR #532499)。このテストは今後カーネルが更新されるたびに自動実行される。LUKS暗号化ディスクをシミュレート → luksSuspendを実行 → メモリ上に鍵が残留していないかチェック。
つまり彼は、自分のマシンを修理すると同時に、この脆弱性が二度と再発しないことを保証したのだ。
それだけではない。Ingoはcryptsetupプロジェクトにも別のパッチ(MR #936)を提出し、luksSuspendコマンドが失敗したときに「サイレント失敗」しないようにした——つまり、過去二年間それは音もなく鍵を消去し損ねていたのに、何のエラーも報告していなかったのだ。今後は消去に失敗すれば明示的に警告を発する。
この二つの操作が映し出すのは一つの工学的思考だ。問題を発見したら、その再発を防ぐテストを追加する。サイレント失敗を見つけたら、それを騒々しい失敗に変える。 これはどんな技術的な華麗さよりも、真に優れたエンジニアリングの実践を体現している。
影響範囲:誰が心配すべきか
ここまで読んで、こう思う人もいるだろう。私はWindows/Macを使っているから関係ない? LinuxノートPCを使っているが、今すぐシャットダウンすべきか?
答えはケースバイケースだ。
第一に、この脆弱性はDebian系ディストリビューション(Debian、Ubuntu、Linux Mintなど)を使用し、かつcryptsetup-suspendパッケージを導入しているユーザーにのみ影響する。 なぜならluksSuspendという機能自体がDebianコミュニティが独自に開発した拡張であり、Linuxアップストリームのデフォルト動作ではないからだ。他の多くのディストリビューション(Arch LinuxのデフォルトインストールやFedoraのデフォルトインストールなど)にはこの機能自体が存在せず、それらの暗号鍵はスリープ中もずっとメモリ上にある——これは脆弱性ではなく、意図された設計である。
第二に、影響を受ける場合でも、脆弱性は「蓋を閉じてスリープ」するシナリオでのみ存在する。 毎回ちゃんとシャットダウンしていれば(蓋を閉じるだけではなく)、鍵はシャットダウン時に正しく消去される。問題は「スリープ(suspend)」モードのみで発生する。
第三に、攻撃には物理的接触が必要だ。 リモートのハッカーがネットワーク越しにあなたのメモリ上の鍵を盗むことは不可能だ。あなたのまだ起動中のコンピュータを手にする実在の人物が、コールドブートやDMA攻撃などの物理的手段で抽出する必要がある。一般の人にとって、この脅威は大きくない——あなたのPCを盗む人は大抵、転売したいだけでメモリフォレンジックには興味がない。しかし弁護士、ジャーナリスト、反体制活動家、越境ビジネスパーソンといった「高価値ターゲット」のグループにとって、物理的攻撃は現実の脅威である。
IngoはHNの返信でわざわざこう明確化している。「これは標準設定を使っている人々には影響しない。理由はシンプルだ——彼らはそもそも鍵がスリープ中も安全であるとは期待していないからだ。」 しかしこの機能の設計意図そのものは、まさにスリープ中に鍵を守るためだった。二年間、このメカニズムを信頼した人々は裏切られたのである。
より深い教訓:ディストリビューション独自パッチのリスク
この脆弱性の背後には、実は二つの「敵役」がいる。
第一の敵役はあのカーネルのリファクタリング——善意のコード整理が、大域的な影響への十分な理解を欠いたためにセキュリティホールを生んだ。これはほとんどソフトウェア工学における古典的な悲劇だ。コードは「悪い」ものではない。ただ複雑すぎて、誰もそのすべての連鎖反応を完全に見通せないのだ。
第二の敵役はもっと興味深い。ディストリビューションが独自にパッチを当てることに伴うメンテナンスリスクである。
luksSuspendはDebianコミュニティが自前で書いた機能であり、Linuxカーネルのアップストリームが公式に提供するものではない。これはつまり、その正しさはLinus Torvaldsとカーネルメンテナチームの責任範囲外である、ということだ。アップストリームカーネルの何らかの低レイヤメカニズムが変更されたとき(たとえば6.9でのスレッドキーリングの挙動変化)、Debianのパッチはそれに追随して適応されたか?誰も保証できない。なぜならアップストリームの開発者はそもそもこのパッチの存在を知らないからだ。
これは、ディストリビューションが独自パッチを当てるべきではないと言っているのではない。むしろ逆だ——多くのLinuxディストリビューションの優れた機能は「独自パッチ」から始まっている。しかしこの一件が警告しているのは、見過ごされがちな現実だ。非アップストリームのパッチはすべて一種の「技術的負債」であり——今日は動いても、明日カーネルがアップグレードされたら壊れるかもしれない。 そのパッチがたまたまセキュリティ機能である場合、「壊れた」代償は単なる機能不全ではなく、信頼の崩壊なのだ。
IngoがMastodonの元投稿で引用した言葉で締めくくろう。「信頼できる著者によって提示された技術的主張は、検証が難しく、かつ正しいと知られている主張に似ている場合、詳細に検討されることはほぼない。」コードも同じだ。