Linuxカーネルのcrypto/algif_aeadサブシステムにおいて、非特権ローカルユーザーが任意の可読ファイルのページキャッシュに対し、制御された4バイトの書き込みを行えることが確認された。CVE-2026-31431として登録された本脆弱性は、Theori社のXint Codeチームが「Copy Fail」と名付け、2026年4月29日に公開した。同日付で主要ディストリビューションのカーネルパッケージへ修正コミット(a664bf3d603d)の取り込みが進んでいる。
再現には732バイトのPython PoCで足り、レース条件・ディストリ固有オフセット・コンパイル済みペイロードのいずれも必要としない、極めて移植性の高いストレートライン論理バグである。setuidバイナリのページキャッシュを書き換えることで、一般ユーザーが即座にrootシェルを取得できる。さらにページキャッシュはホスト全体で共有されるため、コンテナからホストへの脱出プリミティブとしても機能し、Kubernetesノードへの侵入経路となり得る点が、今回の影響範囲を一段押し広げている。
この記事では、公開された一次資料を踏まえ、本脆弱性の構造、9年間検出されずに残った理由、筆者自身による再現検証、そしてAF_ALGという「ほとんど誰も使わないのにほぼ全ディストリで有効化されている」インターフェースの存在意義を、段階を追って整理していく。
何が起きたのか──3つのコンポーネントが交わった場所
Copy Fail を成立させているのは、それぞれ単独では問題のない3つのコンポーネントです。これらが2017年の最適化を経て一本の経路上に並んだ瞬間、ページキャッシュへの任意書き込みプリミティブが完成しました。
第一にAF_ALGは、ユーザー空間からカーネルのcryptoサブシステムを叩くためのソケットインターフェースです。非特権ユーザーが任意のAEADテンプレートにバインドし、暗号化・復号を発行できます。
第二にsplice()は、ファイルディスクリプタとパイプの間でデータをコピーせずに移送するシステムコールです。重要なのは「コピーせずに」という点で、ページキャッシュページを参照のままパイプ越しに渡せます。これを AF_ALG ソケットに流し込むと、ソケットの入力scatterlistにはカーネルがキャッシュしている当該ファイルの物理ページへの直接参照が乗ります。read() や mmap()、execve() が読むのと同じページです。
第三にauthencesnは、IPsecの拡張シーケンス番号(ESN)処理に使われるAEADラッパーです。HMAC計算のためにシーケンス番号の上位32ビットと下位32ビットを並べ替える際、呼び出し元の出力バッファをスクラッチ領域として使い回します。dst[assoclen + cryptlen]、つまりタグ領域の直後に4バイトを書き込み、しかもその位置の元の値を復元しません。
ここまでは2011年から存在していた挙動です。問題は、2017年に algif_aead.c に in-place 最適化が入ったこと(コミット 72548b093ee3)でした。これにより、splice() 由来のページキャッシュページが書き込み可能なdestination scatterlistの末尾にチェーンされるようになりました。authencesn のスクラッチ書きはこのチェーン領域に達し、結果として攻撃者が選んだファイルのページキャッシュ上に、攻撃者が選んだオフセットで、攻撃者が選んだ4バイトを書き込むことになります。
HMACは当然失敗し、recvmsg() はエラーを返します。しかし書き込みはすでに済んでいます。
9年間気付かれなかった理由──「合理的な変更」の積層
Copy Fail で印象深いのは、これが古典的なメモリ破壊バグではなく、それぞれが当時の文脈では合理的だった3つの変更が積み重なった結果としての論理バグだという点です。
- 2011年:
authencesn追加。当時の旧AEADインターフェースでは関連データ(AAD)が別scatterlistに置かれており、唯一の呼び出し元はカーネル内部のxfrm層でした。スクラッチ書きの中間状態を観測する者はいませんでした。 - 2015年:
algif_aead.c(AF_ALGのAEADサポート)追加。splice()経由でページキャッシュがcrypto scatterlistに到達する経路がここで開きます。同年、authencesnも新AEADインターフェースに移行しますが、この時点ではreq->srcとreq->dstは別のscatterlistでした。書き込み先はユーザーのバッファ。まだ悪用できません。 - 2017年:
algif_aead.cの in-place 最適化。req->src = req->dstの構造になり、ページキャッシュページが書き込み可能なdestination scatterlistの末尾に並びました。この瞬間に Copy Fail は成立しています。
公開された解説は「誰も2017年のin-place最適化と、authencesn のスクラッチ書きと、splice() のページキャッシュ起源を結び付けなかった」と書いています。私はこの記述を、責任の所在の話としてではなく、システムの脆弱性は単一の悪い意思決定からではなく、合理的な意思決定の交差点から生まれるという観察として読みます。本コラムで以前扱った「.JPドメインのDNSSEC普及率1%」も、「LINEのLetter Sealing v2」も、「TLDが対応している」「クライアントが暗号化している」「サーバが鍵管理している」のそれぞれは正しいのに、交差点で前提が崩れていました。Copy Fail も同じ系列の問題です。
筆者による再現検証
筆者が管理する自宅ラボの検証環境(一般ユーザーアカウントでログインし、root権限を別途保有する自所有マシン)にて、公開済みの732バイトPoCを実行しました。何も改変せず、依存ライブラリの追加もなく、そのまま走りました。観察された挙動を、追加の運用情報を伴わない範囲で整理します。
実行から数秒のうちに、/usr/bin/su のページキャッシュが書き換わり、その直後の su 起動で一般ユーザーのプロンプトがrootシェル(#)に切り替わりました。recvmsg() 自体はエラーを返しますが、これは攻撃成功の指標としては逆方向──カーネル側から見れば「HMACが失敗した正常系」のログにしかなりません。エラーパスとしてあまりに普通であるため、デフォルト構成の監査ログだけを見ていても異常を察知することは困難でした。
注目すべき副次的な観察として、ファイルシステム上の /usr/bin/su のチェックサムは一切変化しません。書き込みはページキャッシュ層に閉じており、kernel の writeback メカニズムは当該ページを dirty とマークしないため、ディスクには反映されません。このため sha256sum /usr/bin/su も、debsums や rpm -V のようなパッケージ整合性チェックも、何もこれを検出しません。再起動すれば /usr/bin/su のページキャッシュはディスクから読み直され、跡形もなく正常に戻ります──ただし、その間に取得されたroot権限と、それで仕掛けられた永続化は当然ながら残ります。
このことが意味するのは明確です。ディスク基準のファイル整合性監視は今回のクラスの攻撃を視認できません。ライブのページキャッシュをサンプリングする仕組み、もしくはランタイムでの実行ファイル検査が併用されていない限り、痕跡を取り損ねます。
AF_ALGという「裏口」──ほとんど誰も使わない機能が抜け穴に
ここで一段引いて考えたいのは、そもそも AF_ALG は誰のためにある機能なのか、という問いです。
公式の緩和ガイダンスを読むと、algif_aead を無効化しても、ほとんどのシステムで何も壊れないことが明記されています。dm-crypt / LUKS、kTLS、IPsec/XFRM、in-kernel TLS、OpenSSL/GnuTLS/NSSの標準ビルド、SSH、kernel keyring暗号──これらはすべてカーネル内で直接 crypto API を叩いており、AF_ALG を経由しません。
実際に AF_ALG を必要とするのは、OpenSSLを afalg エンジン明示有効でビルドした特殊構成、一部の組み込みクリプトオフロード経路、そして aead/skcipher/hash ソケットを直接 bind する個別アプリケーションだけです。多くの本番環境にとって、AF_ALG は「あれば動くが、なくても誰も困らない」インターフェースです。
にもかかわらず、ほぼすべての主要ディストリで algif_aead モジュールはデフォルト有効です。今回のCVEのインパクトの大きさ──9年間、2017年以降のほぼ全てのLinuxが影響圏内──は、技術的にはそれぞれ合理的な3つの変更の積層によって説明できますが、運用上は「ほぼ使われていないが有効な機能」が静かに脆弱性を積み上げてきた結果です。
これは私の過去の記事において「誰のためのセキュリティか」「周縁化されるIT」で繰り返してきた指摘そのものです。デフォルト有効の便利さは誰のためのものか。攻撃面は誰のために残されているのか。Copy Fail はこの問いに、9年分のツケとして請求書を送ってきたのかもしれません。
AIによる発見が示す方向性
もう一つ書き留めておきたいのは、本脆弱性の発見プロセスです。
Theori社の研究者 Taeyang Lee氏は、過去のkernelCTF研究で AF_ALG のアタックサーフェスをマップしており、AF_ALG + splice() がページキャッシュ経由でcrypto側にread-onlyファイルの参照を流し込む経路になり得ることを把握していました。彼はこの仮説を「operator prompt」として同社のAI監査ツール Xint Code に与え、crypto/ サブシステム全体を約1時間でスキャンさせました。Copy Fail は、その出力の中で最も深刻度が高かった結果でした。
ここで重要なのは、人間の仮説(attack surface に対する直感)とAIのスケール(同パターンを大規模コードベースに適用する能力)が分業した点です。AIが単独でゼロから「面白い」攻撃面を発見したわけではなく、また人間だけで crypto/ 全体を網羅的にレビューできたわけでもありません。
筆者はinnovaTopiaで以前、「AIが環境になるとき」と題して、AIが特定タスクを「環境化」していく過程──個別の判断ではなく、もはや前提条件として組み込まれていく過程──について書きました。脆弱性発見もまた、いま静かに環境化しつつある領域です。Xint Codeは1時間で crypto/ を読み切り、しかも最重要のものはすでに公開、その他のhigh severity findingsはなお coordinated disclosure 中だと書かれています。
これは防御側にとっても、攻撃側にとっても、同じ事実です。1時間のスキャンが9年分の論理バグを見つける時代を、私たちはすでに迎えているということです。今後 stable tree や LTS 系列のサブシステムに対し、同様のAI監査が継続的に走り、潜在脆弱性が短い周期で表面化することは、むしろ標準の運用シナリオとして織り込んでおくべきでしょう。
緩和と対応──今すぐできること
優先度順に整理します。
第一に、カーネルの更新です。コミットa664bf3d603d(mainline)を含むカーネルパッケージへ更新してください。Ubuntu、Debian、RHEL、SUSEを含む主要ディストリでは順次配信が始まっています。アップストリームではカーネル6.18.22 / 6.19.12で修正済みです。
第二に、直ちにパッチが当てられない環境では algif_aead モジュールを無効化します。
echo "install algif_aead /bin/false" | sudo tee /etc/modprobe.d/disable-algif-aead.conf
sudo rmmod algif_aead 2>/dev/null || true
前述の通り、ほとんどのワークロードはこれで何も困りません。念のため lsof | grep AF_ALG や ss -xa で AF_ALG ソケットを開いているプロセスがいないことを確認してから無効化することを推奨します。
第三に、信頼境界が薄い環境──共有開発機、CI runner、コンテナ、マルチテナントPaaS──ではパッチ適用状況にかかわらず、seccompで AF_ALG ソケットの作成自体を拒否することを検討してください。コンテナ脱出としての側面はパッチによって閉じますが、未パッチのノードが1台でも混ざる移行期には防御深度として意味を持ちます。
第四に、過去の検知です。すでに述べたように、ディスク基準のファイル整合性監視はこの攻撃を見ません。本脆弱性のwindow(2017年〜パッチ適用前)に多人数共有環境を運用していた組織は、メモリフォレンジック・実行ファイルランタイム検査・特権昇格イベントの相関分析などをログ可能な範囲で見直すことを推奨します。「跡形は残らない」が「跡形は最初からなかった」を意味しないからです。
【用語解説】
- PoC (Proof of Concept)
実証、あるいはそのためのコード。 - Attack surface (攻撃面)
脆弱性の存在する可能性のある、あるいは潜在的に攻撃可能な部分の大きさを表す抽象的な概念。
【編集部後記】
9年。それが Copy Fail が Linux カーネルの中で気付かれずに眠っていた期間です。SSH の鍵生成、TLS のハンドシェイク、ファイル整合性検証──私たちが当然のように頼ってきた多くの操作が、その9年間、すぐ隣で機能していた脆弱な面を前に平然と行われてきました。
私が自宅ラボの隔離されたマシンで PoC を走らせ、一般ユーザーのプロンプト $ が瞬時に # (=ルート/特権ユーザ)に変わるのを見たとき、最初に頭に浮かんだのは「軽さ」という言葉です。732バイトの Python。標準ライブラリのみ。コンパイルなし。これが、ほぼすべての主要 Linux ディストリビューションに9年にわたって残っていた脆弱性でした。
すべての技術には「誰のため、何のため」という問いが欠かせません。AF_ALG は誰のためにあったのでしょうか。dm-crypt も kTLS も IPsec も SSH も標準の OpenSSL も、これを使いません。実際に必要としているのは、明示的に afalg エンジンを有効化した特殊構成と、一部の組み込みクリプトオフロードだけであるといいます。それでも algif_aead はほぼ全ディストリでデフォルト有効でした。
「あったほうがよい」「とりあえず有効にしておく」は、静かに脆弱性を積み上げます。Copy Fail は、その文化が9年越しに送ってきたツケです。そしてこの負債を1時間で読み取った AI 監査ツールの存在は、これからのカーネル開発、ディストリのデフォルト設定、そして中小法人が自前で運用するインフラの設計判断に、新しい時間軸の制約を導入するかもしれません。脆弱性は、見つかるのを待ってくれない時代がそこに来ています。
まずはパッチを当てましょう。それから、自分のシステムで AF_ALG が本当に必要かを、一度だけでよいので問い直してみてください。多くの場合、答えは「使っていない」のはずです。「使っていないものをデフォルトで動かさない」は、たぶん、私たちが Copy Fail からくみ取れる最も具体的な教訓なのではないかと私は思います。











