Dirty Frag が強化した不変原理

Copy Fail については既稿で、Linux カーネルの暗号 API、AF_ALG、algif_aead、AEAD、splice、page cache、scatterlist、setuid root バイナリが結合し、本来読み取り専用であるはずの page cache が実行時に汚染される構造として整理した[1]。その記事は、CVE-2026-31431 の個別解説であると同時に、ファイルシステム上の権限、カーネル内部の page 参照、実行時に読まれる意味が必ずしも同じではないことを示す記事でもあった。つまり、Copy Fail の中心は、単に algif_aead が危険であるという話ではなく、読み取り専用由来の file-backed page が、別サブシステムへ copy されずに渡され、後段で writable destination として扱われ得るという構造にあった。

Dirty Frag は、この前稿を否定する事例ではない。むしろ、Copy Fail で見えた教訓を、個別モジュールの話からカーネル設計上の不変原理へ引き上げる事例である。V4bel の公開リポジトリと write-up は、Dirty Frag を xfrm-ESP Page-Cache Write と RxRPC Page-Cache Write の連鎖として説明している[2][3]。Microsoft も、Dirty Frag を Linux カーネルの networking and memory-fragment handling behavior を悪用する post-compromise risk の拡大として位置づけている[4]。この範囲だけを見れば、Dirty Frag は Copy Fail とは別の CVE 群であり、入口も、処理領域も、暫定 mitigation も異なる。

しかし、入口が違うことは、教訓が別物であることを意味しない。Copy Fail では AF_ALG、algif_aead、scatterlist が問題の入口になった。Dirty Frag では xfrm-ESP、RxRPC、skb frag、shared frag が問題の入口になる。個別名は違う。だが、読み取り専用由来の page cache が、copy されずに別の処理経路へ渡され、後段で in-place に書き換えられる可能性があるという抽象構造は共通している。したがって、Dirty Frag を読むときに必要なのは、どのモジュールが危険かを暗記することではなく、どの処理境界で page の由来、共有性、書き込み可否、入力と出力の区別が失われるかを見ることである。

観点 Copy Fail Dirty Frag 導入で確認すべきこと
入口 AF_ALG、algif_aead、AEAD、scatterlist が中心になる。 xfrm-ESP、RxRPC、skb frag、shared frag が中心になる。 入口は違うため、個別 mitigation は変わる。
処理領域 カーネル暗号 API と in-place crypto の領域で問題化する。 networking、ESP、RxRPC、fragment handling の領域で問題化する。 処理領域が違っても、page の意味保存という問題は共通する。
汚染対象 読み取り専用由来の page cache が writable destination として扱われ得る。 shared skb frag などを通じて、読み取り専用由来の page cache が in-place 処理され得る。 ディスク上の改ざんではなく、実行時に読まれる page cache の汚染が問題である。
暫定対策 algif_aead の無効化が焦点になった。 esp4、esp6、rxrpc の無効化が焦点になる。 暫定対策は入口依存であり、不変原理そのものではない。
不変原理 上位レイヤーの read-only、shared、input という意味が下位レイヤーで失われる。 同じ意味喪失が、別のネットワーク系入口で成立する。 Dirty Frag は Copy Fail の教訓を否定せず、抽象度を上げて強化する。

したがって、本稿の問いは、Dirty Frag によって Copy Fail の教訓が書き換わるのか、それとも不変原理として強化されるのかである。結論は明確である。Dirty Frag は、Copy Fail の教訓を書き換えたのではない。書き換わるのは、暫定対策として見るべきモジュール名である。Copy Fail では algif_aead が焦点だったが、Dirty Frag では esp4、esp6、rxrpc が焦点になる。一方で、変わらないのは、上位レイヤーで成立していた安全上の意味が、下位レイヤーの最適化、共有、断片化、in-place 処理を通過しても保存されなければならない、という不変原理である。

本稿では、Dirty Frag を単なる新しい Linux kernel LPE としてではなく、Copy Fail の後に現れた構造的な検証事例として読む。具体的には、Debian / Ubuntu などの対応状況、LPE としての脅威評価、page cache 汚染とディスク改ざんの違い、Copy Fail との共通点と相違点、横展開で心配すべき領域、対象外の切り分け、page cache write 以外の LPE 系統、意味保存モデル、脆弱性洪水と AI 時代の観測可能性、そして最終的な運用原則までを整理する。結論として示すのは、Dirty Frag が新しい例外を作ったという話ではない。Dirty Frag は、上位レイヤーの制約が下位レイヤーの最適化で消える場所こそ危険である、という Copy Fail 由来の教訓を、より強い不変原理として確認した事例である。


1. Dirty Frag は Copy Fail の教訓を検証する後続事例である

Dirty Frag は、単独でも Linux カーネルの local privilege escalation として説明できる。Tenable は、CVE-2026-43284 と CVE-2026-43500 を、Linux カーネル上で root 権限取得へ至り得る chained vulnerabilities として整理している[5]。NVD も、CVE-2026-43284 を xfrm-ESP が shared skb frags に対して in-place decrypt を避けるべき問題として説明している[6]。この範囲だけを見れば、Dirty Frag は xfrm-ESP と RxRPC に関わる新しい LPE であり、Copy Fail とは別の CVE 群である。

それでも Dirty Frag を Copy Fail の後続事例として読むべき理由は、時系列上の近さや名称の類似ではない。重要なのは、Copy Fail で抽出された教訓が、別のサブシステムでも成立するかどうかを検証できる点である。Copy Fail で問題になったのは、algif_aead そのものではなく、読み取り専用由来の page cache が copy されずに別文脈へ渡され、後段で出力先として扱われる構造だった。Dirty Frag は、この構造が crypto API の入口に閉じず、networking、ESP、RxRPC、skb frag の経路でも成立し得ることを示している。

この違いを明確にしないと、Dirty Frag は Copy Fail とは無関係な別件にも、逆に Copy Fail の単なる焼き直しにも見えてしまう。どちらも正確ではない。Copy Fail と Dirty Frag は、同じ CVE でも、同じモジュールの問題でも、同じ暫定対策で処理できる問題でもない。一方で、read-only file-backed shared page が、zero-copy や fragment 表現を通じて下位レイヤーへ渡り、in-place 処理で output 化するという抽象条件は共通している。したがって、比較すべきなのは固有名詞ではなく、不変条件の破れである。

観点 Copy Fail Dirty Frag この違いが示すこと
入口 algif_aead と scatterlist が主な入口になる。 xfrm-ESP、RxRPC、skb frag が主な入口になる。 入口が違うため、個別モジュール対策だけでは同じ系統の問題を封じ込められない。
処理領域 カーネル暗号 API の in-place 処理が問題になる。 ネットワーク処理、ESP、RxRPC、fragment handling が問題になる。 問題は暗号 API 固有ではなく、データを copy せずに別文脈へ渡す処理全般に広がり得る。
共通構造 読み取り専用由来の page cache が、出力先として扱われ得る。 読み取り専用由来の page cache が、shared skb frags 経由で in-place 処理され得る。 本質は、読み取り専用という上位レイヤーの意味が下位レイヤーで保存されないことにある。
暫定対策 algif_aead の無効化が一時的な回避策になる。 esp4、esp6、rxrpc の無効化が一時的な回避策になる。 無効化対象は変わるため、暫定対策は不変原理ではなく時間稼ぎとして理解する必要がある。
教訓 algif_aead の事故としてだけ読むと、教訓は狭くなる。 別入口で同じ危険が再現したことで、教訓の抽象度が上がる。 Dirty Frag は Copy Fail の教訓を否定せず、より一般的な意味保存の問題として強化する。

ここで見るべきなのは、個別モジュール名ではなく、抽象化された不変条件である。Copy Fail を algif_aead の事故としてだけ読むなら、Dirty Frag は別件に見える。しかし Copy Fail を「上位レイヤーで読み取り専用だった page cache の意味が、下位レイヤーの zero-copy と in-place 処理で失われた事例」と読むなら、Dirty Frag は同じ教訓を別の入口から再確認する事例になる。

したがって、第 1 章で確認すべきことは、Dirty Frag が Copy Fail の派生物であるかどうかではない。問うべきなのは、Copy Fail で抽出した教訓がどの抽象度で成立するかである。algif_aead を無効化するという暫定対策は Dirty Frag には通用しない。しかし、読み取り専用由来の page cache を、意味を保持しないまま別サブシステムへ渡し、出力先として扱ってはならないという原理は、Dirty Frag によってむしろ強化される。

この意味で Dirty Frag は、Copy Fail の単なる続報ではない。Copy Fail で見えた問題が、個別モジュールの事故ではなく、カーネル内部の意味保存に関わるより広い設計問題だったことを示す検証事例である。本稿では Dirty Frag を、Copy Fail の焼き直しとしてではなく、Copy Fail の教訓がどこまで一般化できるかを確認する後続事例として扱う。


2. Debian と Ubuntu の対応差は本質ではない

Dirty Frag を運用上どう扱うかを考えるとき、Debian と Ubuntu の対応差は無視できない。Debian Security Tracker では、CVE-2026-43284 について、MSG_SPLICE_PAGES が pipe 由来の pages を skb に直接 attach でき、IPv4 / IPv6 datagram append paths が UDP skbs に splice pages を入れる際に shared frag を示す flag を設定していなかったため、ESP input が private copy を作らず in-place decrypt してしまう、と説明している[7]。この説明は、Dirty Frag の技術的本質をよく表している。問題は、pipe 由来の page が skb に渡されたこと自体ではない。共有されている可能性のある page であるという意味が、後段の ESP 処理に十分伝わらず、private copy を作るべき場面で in-place decrypt が行われた点にある。

一方、Ubuntu 公式は、Dirty Frag の緩和策として esp4、esp6、rxrpc のロード抑止を案内し、IPsec ESP や AFS / RxRPC を使う環境では機能影響が出ると説明している[8]。また Ubuntu の CVE ページでは、CVE-2026-43284 と CVE-2026-43500 がそれぞれ High priority として扱われ、主要 kernel packages の評価状況が示されている[9][10]。ここで重要なのは、Ubuntu が示している暫定緩和策が Dirty Frag の本質を消すものではなく、未修正 kernel を使い続けざるを得ない期間に、危険な入口を一時的に閉じるための措置であるという点である。

観点 Debian Ubuntu 読み取るべきこと
説明の重心 MSG_SPLICE_PAGES、pipe pages、skb、shared frag、ESP input の in-place decrypt という内部構造を中心に説明している。 影響を受ける kernel packages、High priority、暫定緩和策、モジュール無効化を中心に説明している。 Debian は技術的原因の記述が読みやすく、Ubuntu は運用上の緩和策が読みやすいが、見ている問題は同じである。
暫定対策 修正済み kernel への更新を前提に、対象 CVE と修正状況を確認する流れになる。 esp4、esp6、rxrpc のロード抑止を、修正済み kernel 適用までの一時的な緩和策として案内している。 モジュール無効化は根本対策ではなく、修正版 kernel へ移行するまでの時間稼ぎである。
機能影響 対象 kernel の更新と再起動が中心になるため、主な影響はメンテナンス時間と再起動計画に現れる。 IPsec ESP、AFS、RxRPC を使っている環境では、モジュール無効化による機能影響が出る可能性がある。 暫定緩和策は常に安全側の単純操作ではなく、利用中の機能との衝突を確認する必要がある。
運用判断 security repository から修正済み kernel を取得し、再起動後に起動 kernel を確認する判断になる。 修正済み kernel の提供状況を確認し、未適用期間はモジュール無効化、更新後は再起動と確認を行う判断になる。 どちらも最終的には修正済み kernel で起動していることを確認しなければならない。
本質との関係 shared frag の意味が保存されず、in-place decrypt に進む構造を説明している。 危険な入口を一時的に閉じることで、同じ構造へ到達しにくくしている。 配布運用や表記は違っても、問題の本質は page の共有性と書き込み可能性の意味保存にある。

AlmaLinux や Red Hat も Dirty Frag を、それぞれ IPsec ESP 側と RxRPC 側の問題を含む LPE として整理している[11][12]。ここから読み取るべきなのは、ディストリビューションごとの表記、告知速度、緩和策の見せ方の差ではない。配布運用は違っても、問題の中心は、copy されずに渡された page の共有性、書き込み可能性、入力と出力の方向、後段処理での扱いが正しく保存されなかったことにある。

したがって、Debian と Ubuntu の対応差は、運用上は重要だが、脆弱性の本質ではない。Debian では修正済み kernel が提供されているかを確認し、更新後に再起動して実際の起動 kernel を確認する必要がある。Ubuntu では、修正済み kernel の提供状況を確認しつつ、未修正期間には esp4、esp6、rxrpc の無効化が暫定緩和策になる場合がある。しかし、どちらの場合でも最終的な到達点は同じである。危険な入口を一時的に閉じるだけでは不十分であり、脆弱な処理経路そのものが修正された kernel に更新し、その kernel で起動していることを確認しなければならない。


3. Dirty Frag は侵入口ではなく増幅器である

Dirty Frag は local privilege escalation である。Sophos は、Dirty Frag を xfrm-ESP と RxRPC subsystems に関連する networking-related components の improper handling of page cache operations による LPE として整理し、悪用には local access が必要だと説明している[13]。この点は、脅威評価の出発点として重要である。Dirty Frag は、単独でインターネット越しに任意の Linux サーバーへ侵入し、直接 root を取得する脆弱性ではない。攻撃者はまず、対象ホスト上で何らかの低権限コード実行またはローカルアクセスを得ている必要がある。

しかし、この限定は軽視を意味しない。local access が必要であることは、実運用上の危険が小さいことと同義ではない。Elastic Security Labs は、Copy Fail と Dirty Frag を、legitimate kernel interfaces、local execution、短い proof-of-concept code によって practical で reliable な root path になる page cache corruption bugs として扱っている[14]。つまり、Dirty Frag の危険は、最初の侵入口になることではなく、すでに得られた低権限実行を root 権限へ増幅することにある。

侵害の入口 Dirty Frag との関係 問題になる理由
SSH アカウント 漏えいした鍵、弱いパスワード、退職者アカウント、共有アカウントなどで低権限ログインされた後に使われ得る。 本来は一般ユーザーに閉じている侵害が、kernel LPE によって root 権限へ拡大する。
Web shell WordPress、CMS、管理画面、アップロード機能、脆弱なプラグインなどから得た Web サーバーユーザー権限の次段階として使われ得る。 www-data などの限定的な権限が、システム全体の制御権へ変わる可能性がある。
CI runner ビルドスクリプト、pull request、依存パッケージ、secret の扱いを通じて任意コード実行された runner 上で使われ得る。 一時的なビルド環境の侵害が、runner ホストや共有基盤の侵害へ拡大する可能性がある。
コンテナ内プロセス コンテナ内で低権限コード実行が成立した場合、ホストカーネルを共有しているため、条件次第で LPE の足場になり得る。 コンテナ内の権限とホスト側の安全性を混同すると、kernel LPE の影響を過小評価する。
低権限サービスアカウント バッチ処理、ログ収集、監視エージェント、アプリケーション専用ユーザーなどの権限から利用され得る。 本来限定されているサービス権限が、root 権限に近い破壊力を持つ。

したがって、Dirty Frag の脅威評価は、単体での remote exploitability だけで行ってはならない。Dirty Frag が remote code execution ではないことは事実である。しかし、現実の侵害は単発の脆弱性だけで完結しない。Web アプリケーションの任意コード実行、漏えいした SSH 認証情報、CI の設定不備、依存パッケージ経由のコード実行、コンテナ内での侵害など、別の入口から低権限実行が成立したとき、Dirty Frag はその権限を root へ引き上げる post-compromise risk になる。

この意味で、Dirty Frag は扉ではなく増幅器である。扉を開ける脆弱性ではなく、開いた扉から入ってきた攻撃者に、建物全体を支配する権限を与える脆弱性である。公開サーバー、共有開発環境、CI 基盤、コンテナホスト、複数ユーザーがログインするサーバーでは、この種の LPE は侵入の有無そのものではなく、侵入後の被害範囲を決定する。したがって、Dirty Frag の優先度は「外部から直接 exploit できるか」ではなく、「このホスト上で低権限コード実行に至る経路が現実に存在するか」によって評価する必要がある。


4. page cache 汚染はディスク改ざんではない

Dirty Frag を理解するうえで重要なのは、攻撃対象が必ずしもディスク上のファイルそのものではないという点である。Qualys は、Dirty Frag exploit は hard drive 上のファイルには触れず、ディスク上のハッシュに依存するセキュリティツールでは検知できない可能性があると説明している。また、汚染された cache は drop_caches または reboot まで残るとされる[15]。これは、Dirty Frag を通常のファイル改ざんと区別する決定的な点である。ファイルの実体が変わらなくても、実行時に参照される page cache が変われば、システムが読む意味は変わる。

通常、ファイル改ざんを考えるときは、ディスク上の inode、ファイル内容、ハッシュ値、パッケージ整合性、変更時刻などに注目する。これは多くの場合に有効である。しかし、page cache 汚染型の問題では、ディスク上のファイルが無傷であることと、実行時に読まれる内容が無傷であることは一致しない。たとえば、ディスク上の /usr/bin/su が変わらなくても、page cache 上でその内容が変われば、後続の実行時に参照される命令列は汚染済みになり得る。同じように、認証処理が参照するファイル、共有ライブラリ、dynamic loader、PAM 関連ファイルなども、ディスク上では正しく見えても、実行時に読まれる cache が汚染されていれば安全とは言えない。

観点 通常のディスク改ざん page cache 汚染 Dirty Frag で問題になる理由
改ざん対象 ディスク上のファイル本体が変更される。 メモリ上の page cache が変更される。 ファイル本体が変わっていなくても、実行時に読まれる内容が変わり得る。
検知方法 ファイルハッシュ、パッケージ整合性、mtime、監査ログなどで検知しやすい。 ディスク上のハッシュだけでは検知できない可能性がある。 ディスク整合性だけを見ていると、実行時の汚染を見落とす可能性がある。
持続性 ファイルを戻すまで改ざんが残る。 drop_caches または reboot まで残る場合がある。 永続改ざんではないが、短時間でも root 文脈で読まれれば LPE に十分つながる。
見かけ上の状態 ディスク上の内容と実行時内容が基本的に一致する。 ディスク上の内容と実行時に読まれる内容がずれる。 管理者がファイルを確認しても、実行時の安全性を確認したことにはならない。
本質 保存されている byte 列の改ざんである。 実行時に解釈される byte 列の改ざんである。 問題は保存状態ではなく、実行時意味が汚染されることにある。

このため、Dirty Frag の問題は、ディスク改ざんではなく実行時意味の改ざんとして捉える必要がある。CPU が後で読む命令列、認証処理が参照する内容、root 権限文脈で読み込まれるファイルの実行時表現が汚染されれば、ファイルシステム上の実体が無傷に見えても、システムの振る舞いはすでに変わっている。ここで壊れているのは、単なる byte 列ではない。ディスク上の内容、page cache 上の内容、実行時に読まれる内容は同じであるはずだという前提である。

この観点は Copy Fail でも同じだった。CERT-EU は Copy Fail を、algif_aead の in-place optimisation により page-cache pages が writable destination scatterlist に置かれ得る問題として説明している[16]。NVD も Copy Fail を CISA KEV に含まれる Linux Kernel Incorrect Resource Transfer Between Spheres Vulnerability として扱っている[17]。つまり、Copy Fail でも Dirty Frag でも、問題は「ファイルを書き換えたか」ではなく、「読み取り専用由来の page cache が、別文脈で書き込み対象として扱われたか」である。

したがって、Dirty Frag は Copy Fail と同じ種類の実行時意味汚染を、別の入口から再現した事例である。Copy Fail では algif_aead と scatterlist が入口になり、Dirty Frag では xfrm-ESP、RxRPC、skb frag が入口になる。入口は変わる。しかし、ディスク上では読み取り専用であるはずの内容が、page cache 上では書き換えられ、後で高権限文脈に読まれる可能性があるという構造は変わらない。この構造を見なければ、Dirty Frag を単なる新しい LPE として過小評価することになる。


5. Copy Fail と Dirty Frag の共通点

Copy Fail と Dirty Frag の共通点は、同じモジュールで起きたことではない。Copy Fail は algif_aead と scatterlist の経路で問題化し、Dirty Frag は xfrm-ESP、RxRPC、skb frag の経路で問題化する。入口も処理領域も異なる。それでも両者を同じ系列として読むべきなのは、どちらも「読み取り可能であること」が、カーネル内部の page 共有と in-place 処理を通じて、実質的な書き換え能力へ変質する構造を持つからである。Microsoft は Copy Fail について、unprivileged user が readable file の cache を corrupt でき、setuid binaries を含む readable files の cache corruption が root privilege での code execution につながり得ると説明している[18]

一般ユーザーが setuid root バイナリを読めることは異常ではない。/usr/bin/su や sudo、共有ライブラリ、dynamic loader、PAM 関連ファイルなどは、実行や参照のために一般ユーザーから読める場合がある。しかし、読めることと書けることは本来まったく違う。問題は、その読み取り対象の page cache が、カーネル内部で別の処理文脈に渡され、後段で出力先または作業領域として扱われることである。ファイルシステム文脈では「読めるが書けない」 page が、暗号処理やネットワーク処理の文脈では単なる page pointer、scatterlist entry、skb frag として扱われる。その瞬間、読み取り専用という上位レイヤーの意味が失われる。

共通構造 Copy Fail での現れ方 Dirty Frag での現れ方 本質的な意味
読み取り可能な file-backed page が関与する。 攻撃者は通常の読み取り権限で対象ファイル由来の page cache に到達する。 攻撃者は pipe や skb を経由して、読み取り専用由来の page を後段処理へ到達させる。 読み取り権限だけで到達できる page が、書き換え可能な作業対象へ変質することが問題である。
copy されずに別経路へ渡る。 splice や scatterlist により、byte 列のコピーではなく page 参照が暗号処理へ渡る。 MSG_SPLICE_PAGES、pipe pages、skb frag などにより、page 参照がネットワーク処理へ渡る。 copy しない最適化は性能上有効だが、page の由来、共有性、書き込み可否を保持できなければ危険になる。
後段処理が in-place に扱う。 AEAD 処理が入力 page を writable destination scatterlist として扱い得る。 ESP input などが shared skb frags に対して private copy を作らず in-place 処理し得る。 入力として渡された page が出力先として扱われると、読み取り専用という意味が崩れる。
共有 page cache が汚染される。 読み取り専用ファイル由来の page cache が暗号処理経路で汚染され得る。 読み取り専用ファイル由来の page cache がネットワーク処理経路で汚染され得る。 ディスク上のファイルではなく、実行時に読まれるメモリ上の内容が変わる。
root 文脈で再利用される。 汚染された setuid binary などが root 権限文脈で実行される可能性がある。 汚染された page cache が、認証処理、setuid 実行、共有ライブラリ読み込みなどの高権限文脈で読まれ得る。 低権限ユーザーの読み取り操作が、後続の root 権限実行に影響する経路を作る。
ディスク上の変更ではない。 ファイル本体を改ざんしなくても、page cache の内容を通じて実行時の意味が変わり得る。 ファイル本体を改ざんしなくても、cache が drop されるか reboot されるまで実行時汚染が残り得る。 ファイルハッシュやパッケージ整合性だけでは、実行時の安全性を確認したことにならない。

この一覧から分かるように、Copy Fail と Dirty Frag の共通点は、個別モジュール名ではなく、上位レイヤーの意味が下位レイヤーで失われることにある。ファイルシステムは、その page を「読み取り専用ファイル由来の page cache」として扱っている。メモリ管理は、それを file-backed shared page として扱っている。ところが、処理経路を下ると、それは pipe buffer、scatterlist entry、skb frag、crypto buffer、network payload のような別の表現へ変換される。この変換の途中で、「読めるが書けない」「入力である」「共有 page cache である」「後で root 文脈で読まれ得る」という意味が保存されなければ、低権限ユーザーの読み取りが実質的な書き換え能力へ変わる。

したがって、Copy Fail と Dirty Frag を同じ系列として読む理由は、どちらも page cache を直接扱うから、というだけではない。より正確には、どちらも「読み取り専用の意味を持つ page が、copy されずに別サブシステムへ渡され、そこで出力先または作業領域として扱われる」という不変条件違反を含んでいるからである。入口が algif_aead であっても、xfrm-ESP であっても、RxRPC であっても、この不変条件が壊れれば、結果として同じ種類の実行時意味汚染が起きる。

この意味で、共通点は技術部品の一致ではなく、意味保存の失敗である。Copy Fail は暗号処理側でそれを示し、Dirty Frag はネットワーク処理側でそれを示した。両者を並べて読むことで、問題が特定 API の事故ではなく、zero-copy、fragment 表現、in-place 処理、page cache 共有が交差する場所に潜む構造的な危険であることが見えてくる。


6. Copy Fail と Dirty Frag の相違点

Copy Fail と Dirty Frag は同じ不変条件違反として読めるが、同じ脆弱性ではない。相違点は、入口、処理領域、内部表現、暫定対策にある。Copy Fail は AF_ALG / algif_aead / AEAD socket interface が入口だった。Cloudflare は Copy Fail 対応記事で、AF_ALG と kernel crypto API、AEAD、algif_aead の関係を実務的に整理している[19]。Linux Kernel Documentation も、AF_ALG によって user space から kernel crypto API にアクセスでき、AEAD ciphers も対象に含まれると説明している[20]。つまり、Copy Fail は user space から kernel crypto API を使う経路において、読み取り専用由来の page cache が暗号処理の入出力境界で誤って扱われた事例である。

Dirty Frag では入口が xfrm-ESP と RxRPC に移る。Linux Kernel Documentation は、RxRPC を UDP 上で信頼性のある two-phase transport を提供し、AF_RXRPC family の sockets によって sendmsg と recvmsg を行う protocol driver と説明している[21]。Ubuntu の rxrpc(7) も、RxRPC が AFS network filesystem で使われる transport protocol であると説明している[22]。ここで問題になるのは、暗号 API そのものではなく、networking、ESP、RxRPC、skb frag、shared frag、fragment handling の側である。したがって、Dirty Frag は Copy Fail と同じ現象を別モジュールで繰り返しただけではなく、同じ危険が crypto API の外側、すなわちネットワーク処理とフラグメント処理の領域にも広がることを示した事例である。

観点 Copy Fail Dirty Frag この違いが意味すること
主な入口 AF_ALG、algif_aead、AEAD socket interface が入口になる。 xfrm-ESP と RxRPC が入口になる。 同じ page cache write 系列でも、攻撃面は crypto API に閉じない。
処理領域 user space から kernel crypto API を呼び出す経路が中心になる。 networking、ESP、RxRPC、fragment handling の経路が中心になる。 問題は暗号処理固有ではなく、複数サブシステムを横断する page 参照の扱いにある。
内部表現 scatterlist を通じて、入力 page と出力先の意味が混ざり得る。 skb frag や shared frag を通じて、共有 page が後段処理に渡り得る。 表現形式は違っても、page の由来、共有性、書き込み可否を失う危険は共通する。
危険の見え方 crypto API の in-place 処理の問題として見えやすい。 networking と fragment handling の問題として見えやすい。 見え方だけで分類すると別件に見えるが、抽象化すれば同じ不変条件違反として読める。
暫定対策 algif_aead の無効化が一時的な回避策になる。 esp4、esp6、rxrpc の無効化が一時的な回避策になる。 無効化対象は変わるため、暫定対策を根本原理と取り違えてはならない。
機能影響 user space から kernel crypto API を利用する処理に影響し得る。 IPsec ESP、AFS、RxRPC などを使う環境に影響し得る。 緩和策は常に環境依存であり、利用中の機能との衝突を確認する必要がある。
根本対策 脆弱な in-place 処理経路が修正された kernel に更新し、その kernel で再起動する必要がある。 共有 frag に対する不適切な in-place 処理が修正された kernel に更新し、その kernel で再起動する必要がある。 入口が違っても、最終的な対策は修正済み kernel への移行と再起動で一致する。

この相違点は重要である。Copy Fail を crypto API の問題としてだけ見れば、AF_ALG、algif_aead、AEAD、scatterlist を調べればよいように見える。Dirty Frag を networking の問題としてだけ見れば、xfrm-ESP、RxRPC、skb frag、shared frag を調べればよいように見える。しかし、そのように個別領域へ閉じ込めると、両者を貫く危険を見落とす。重要なのは、どのサブシステムで起きたかではなく、file-backed shared page が copy されずに渡され、その後段で入力専用という意味を失い、出力先または作業領域として扱われるかどうかである。

したがって、相違点は本質を否定するものではなく、本質を見つけるための手がかりである。Copy Fail と Dirty Frag は入口が違うから別物である、という理解は半分だけ正しい。確かに CVE、対象モジュール、暫定対策、機能影響は異なる。しかし、入口が違っても同じ種類の意味喪失が成立するなら、より深い層では同じ bug class として扱う必要がある。ここで見るべきなのは、個別モジュール名ではなく、上位レイヤーの「読めるが書けない」「入力である」「共有 page cache である」という意味が、下位レイヤーの表現変換と in-place 処理で保存されているかどうかである。

この意味で、Copy Fail と Dirty Frag の相違点は、教訓を狭めるためではなく、広げるために重要である。Copy Fail は、暗号 API 側で意味保存が壊れると LPE になることを示した。Dirty Frag は、ネットワーク処理側でも同じ種類の意味保存が壊れ得ることを示した。両者を比較することで、問題が algif_aead の事故でも、xfrm-ESP や RxRPC の事故でもなく、zero-copy、page 参照、fragment 表現、in-place 処理が交差する場所に共通する設計上の危険であることが見えてくる。


7. skb frag と scatterlist は意味を薄める抽象である

Dirty Frag と Copy Fail を同じ系列として理解するには、skb frag と scatterlist を単なる実装詳細として扱ってはならない。Linux networking APIs のドキュメントには、buffer が page cache pages を inline に含む場合に安全でない操作があることが示されている[23]。この種の記述は、今回の問題を理解するうえで重要である。page cache page は、ファイルシステム文脈ではファイル内容の cache である。しかし、ネットワーク処理の文脈では fragment、payload、buffer として見え、暗号処理の文脈では scatterlist entry や変換対象として見える。この文脈の切り替わりこそが、意味境界を薄める。

scatterlist も skb frag も、それ自体が危険な仕組みではない。むしろ、コピーを減らし、I/O を効率化し、ネットワークや暗号処理を高性能化するための正当な抽象である。scatterlist は、連続していない複数のメモリ領域を処理対象としてまとめるために使われる。skb frag は、ネットワーク packet の一部を page fragment として扱い、余分なコピーを避けるために使われる。どちらも、カーネル内部で大量のデータを効率よく扱うためには必要な仕組みである。

しかし、抽象化は情報を落とす。ある page が file-backed であること、shared page cache であること、読み取り専用ファイル由来であること、入力として渡されたこと、後で root 文脈で読まれ得ることは、ファイルシステムやメモリ管理の文脈では重要な意味を持つ。ところが、scatterlist entry や skb frag として扱われると、それは単なる処理対象の断片として見えやすくなる。ここで意味が落ちると、効率化のための抽象が安全境界を壊す。

抽象 本来の役割 薄まりやすい意味 危険になる条件
page cache ファイル内容をメモリ上に保持し、読み取りや実行を高速化する。 file-backed であること、ディスク上のファイル内容と対応していること、共有され得ること。 読み取り専用由来の page cache が、後段で書き込み可能な作業領域として扱われると危険になる。
scatterlist 複数の非連続メモリ領域を、暗号処理や I/O 処理の対象としてまとめる。 各 page の由来、書き込み可否、入力と出力の区別、共有性。 入力 page が writable destination として扱われ、読み取り専用 page cache が書き換えられると危険になる。
skb frag ネットワーク packet の一部を page fragment として保持し、余分な copy を避ける。 page が pipe 由来か、shared か、private copy が必要かという意味。 shared frag であることが後段に伝わらず、ESP などが in-place 処理すると危険になる。
zero-copy byte 列をコピーせず、page 参照を渡すことで性能を上げる。 参照先 page の ownership、writability、sharing、lifetime。 copy を省略した結果、書き換えてはならない page が別サブシステムの出力先になると危険になる。
in-place 処理 入力 buffer と出力 buffer を同じ領域にして、メモリ使用量や copy を減らす。 入力専用であること、読み取り専用由来であること、出力してよい領域かどうか。 入力として渡された file-backed shared page を、そのまま出力先として書き換えると危険になる。

この表から分かるように、問題は scatterlist や skb frag の存在そのものではない。問題は、それらの抽象が page の意味を十分に運べないまま、後段処理に渡されることである。カーネル内部では、処理対象を page pointer、fragment、entry、payload として扱う必要がある。しかし、その page がどこから来たのか、誰が書けるのか、共有されているのか、入力なのか出力なのかという意味が消えると、処理効率を上げるための抽象が、権限境界を迂回する経路になる。

LWN で紹介された AF_ALG の zero-copy support removal は、この危険をよく示している。そこでは、AF_ALG はもともと hardware crypto accelerators へのアクセスを意図していたが、実際には効率的な interface でもなく、zero-copy support の risk が benefits を大きく上回るとして、splice syscall はサポートしつつも data は copy されるようにする方針が示されている[24]。これは、性能最適化が意味保存を破るなら、最適化そのものを捨てる判断である。つまり、copy を減らすことは常に善ではない。copy を省略することで、page の由来、共有性、書き込み可否、入力と出力の区別が保存できなくなるなら、その zero-copy は安全性よりも危険を増やす。

したがって、skb frag と scatterlist は、性能のために意味を圧縮する抽象だと言える。抽象は、扱う情報を減らすことで処理を単純化し、高速化する。しかし、セキュリティ上必要な意味まで減らしてしまうと、上位レイヤーで成立していた安全性が下位レイヤーで消える。Copy Fail では scatterlist がその場所になり、Dirty Frag では skb frag がその場所になった。両者の比較から見えるのは、危険な抽象とは、単に低レベルな表現のことではなく、安全性に必要な意味を運ばないまま高性能化を実現してしまう表現のことである。


8. 暫定対策はモジュール名に依存する

Dirty Frag の暫定対策は、Copy Fail の暫定対策とは異なる。Ubuntu 公式は、Dirty Frag の mitigation として esp4、esp6、rxrpc を無効化する方法を示している[8]。Sysdig も、Dirty Frag は IPsec encryption / ESP と RxRPC が受信ネットワークデータを fresh buffer にコピーせず、in-place に decrypt する最適化に関係すると説明している[25]。したがって、Dirty Frag で塞ぐべき入口は、Copy Fail で問題になった algif_aead ではない。Copy Fail では algif_aead が暫定対策の焦点になり、Dirty Frag では esp4、esp6、rxrpc が焦点になる。

ここで重要なのは、モジュール名の違いをそのまま本質と見なさないことである。暫定対策は常に、その時点で見えている攻撃入口を塞ぐ操作である。Copy Fail では、AF_ALG / algif_aead / AEAD socket interface を通る経路が問題になったため、algif_aead の無効化が意味を持った。Dirty Frag では、xfrm-ESP と RxRPC を通る経路が問題になるため、esp4、esp6、rxrpc の無効化が意味を持つ。つまり、暫定対策は脆弱性クラスそのものを修正するのではなく、既知の到達経路を一時的に閉じているにすぎない。

対応の種類 Copy Fail での対象 Dirty Frag での対象 意味
暫定的な入口封鎖 algif_aead を無効化する。 esp4、esp6、rxrpc を無効化する。 その時点で知られている exploit 経路を通りにくくするための時間稼ぎである。
ロード済みモジュールの除去 対象モジュールが使用中でなければ unload できる可能性がある。 esp4、esp6、rxrpc が使用中でなければ rmmod できる可能性がある。 すでに kernel に入っている危険な入口を一時的に消す操作である。
機能影響 user space から kernel crypto API を使う処理に影響し得る。 IPsec ESP、AFS、RxRPC を使う環境に影響し得る。 暫定対策は安全側の単純操作ではなく、利用中の機能を壊す可能性がある。
cache 汚染への緊急処置 page cache 汚染が疑われる場合、drop_caches や reboot が必要になる。 page cache 汚染が疑われる場合、drop_caches や reboot が必要になる。 これは脆弱性修正ではなく、汚染済みの実行時状態を消すための処置である。
根本対策 脆弱な in-place 処理経路が修正された kernel に更新し、その kernel で再起動する。 共有 frag や RxRPC 側の問題が修正された kernel に更新し、その kernel で再起動する。 根本対策はモジュール名ではなく、脆弱な処理経路そのものの修正である。

この表から分かるように、暫定対策はモジュール名に依存する。入口が algif_aead なら algif_aead を止める。入口が esp4、esp6、rxrpc なら、それらを止める。入口が別のサブシステムに広がれば、暫定対策の対象もさらに変わる。したがって、暫定対策の名前を不変の教訓として扱ってはならない。Copy Fail の教訓を algif_aead 無効化に縮減すると、Dirty Frag には対応できない。同じように、Dirty Frag の教訓を esp4、esp6、rxrpc 無効化に縮減すると、将来別の入口から同じ bug class が現れたときに対応できない。

一方、根本対策は変わらない。脆弱な処理経路そのものが修正された kernel に更新し、その kernel で再起動する必要がある。module blacklist、rmmod、drop_caches は、それぞれ意味が異なる。module blacklist は、次回以降その入口をロードさせないための抑止である。rmmod は、すでにロード済みの入口を取り除くための操作である。drop_caches は、汚染された可能性のある page cache を捨てるための緊急処置である。reboot は、修正済み kernel への切り替えと、実行時状態の初期化を兼ねる。これらはどれも重要だが、脆弱性クラスそのものを修正するものではない。

したがって、Dirty Frag の暫定対策を理解するときには、モジュール名と原理を分ける必要がある。esp4、esp6、rxrpc を止めることは、Dirty Frag という既知の入口に対する実務的な防御である。しかし、本稿で追っている不変原理はそこではない。不変原理は、読み取り専用由来の page cache を、意味を保持しないまま別サブシステムへ渡し、出力先または作業領域として扱ってはならない、という点にある。暫定対策は入口を塞ぐ。根本対策は壊れた意味保存の経路を修正する。この二つを混同してはならない。


9. 横展開で心配すべきもの

Dirty Frag を単独の CVE として閉じると、調査対象は xfrm-ESP と RxRPC に限定される。しかし、Copy Fail と並べて読むなら、そこで止めるべきではない。Wiz は Dirty Frag を、xfrm-ESP と RxRPC の 2 つの page-cache write primitives を組み合わせる vulnerability chain として説明し、race-condition-based exploits とは異なる deterministic で highly reliable な bug class として整理している[26]。ここで重要なのは、Dirty Frag が単なる個別実装ミスではなく、同じ構造が別の処理経路にも現れ得る bug class として読める点である。

横展開で見るべきなのは、固有名詞ではない。algif_aead、xfrm-ESP、RxRPC、skb frag という名前は、あくまで今回観測された入口である。より重要なのは、同じ不変条件違反が起きる場所である。すなわち、読み取り専用由来の page cache ページが、copy されずに別サブシステムへ渡され、その先で in-place に書き換えられる可能性がある場所である。この条件を満たすなら、入口が暗号 API であっても、ネットワーク処理であっても、ファイルシステムであっても、同じ種類の実行時意味汚染につながり得る。

この横展開条件は、性能最適化が集中する場所に現れやすい。copy を減らす、page 参照を再利用する、複数の fragment をまとめて扱う、入力と出力を同じ buffer にする、非同期に I/O を進める、ネットワークとファイルシステムをまたぐ、といった設計は、いずれも正当な最適化である。しかし、それらは同時に、page の由来、共有性、書き込み可否、入力と出力の区別、呼び出し元の権限、後続の実行文脈を薄める。したがって、横展開で心配すべきなのは、単に「似たモジュール」ではなく、「意味を保持しないまま page 参照を運ぶ経路」である。

調査対象 心配する理由 確認すべき観点
zero-copy API copy を省略し、byte 列ではなく page 参照を別サブシステムへ渡す。 渡された page の provenance、writability、sharing が後段でも保持されているかを確認する。
splice / sendfile / vmsplice file-backed page cache が、pipe や別 I/O 経路を通じて移動し得る。 読み取り専用ファイル由来の page が、後段で出力先または作業領域として扱われないかを確認する。
pipe buffer ファイル由来の page が、ファイルシステム文脈を離れて一時的な buffer として扱われる。 pipe に入った page が shared page cache であることを後段処理が識別できるかを確認する。
scatterlist 複数のメモリ領域をまとめる過程で、入力 page と出力 page の意味が混ざりやすい。 source と destination が同じ page にならないか、read-only page が writable destination に入らないかを確認する。
skb frag / shared frag ネットワーク処理が page fragment を直接扱い、copy せず後段へ渡す。 shared frag であることが保持され、private copy が必要な場面で in-place 処理に進まないかを確認する。
iov_iter 複数種の I/O buffer を抽象化し、user buffer、kernel buffer、pipe、page などを統一的に扱う。 抽象化によって buffer の由来、書き込み可否、寿命が失われないかを確認する。
in-place crypto 入力 buffer を出力 buffer として再利用し、copy とメモリ使用量を減らす。 入力 page が file-backed read-only shared page である場合に out-of-place 処理へ退避できるかを確認する。
compression / decompression 入力と出力の関係が変換処理で複雑になり、作業領域への書き込みが発生しやすい。 入力専用 page が変換後の出力先や scratch buffer として扱われないかを確認する。
tunnel / encapsulation payload を別形式へ包み直す過程で、networking、crypto、fragment handling が交差する。 encapsulation / decapsulation の途中で shared page の意味が失われないかを確認する。
RxRPC / AFS ネットワーク、ファイルアクセス、メモリ管理が交差し、page の意味が複数文脈をまたぐ。 ネットワーク payload と file-backed data の境界で、page の所有権と書き込み可否が保存されているかを確認する。
overlayfs / FUSE 上位ファイルシステムの意味と下位実体の意味がずれやすい。 上位で read-only に見える対象が、下位の buffer や page として別の権限意味を持たないかを確認する。
io_uring / async I/O 非同期処理により、buffer lifetime、authority、completion context が複雑化しやすい。 submit 時点と completion 時点で、buffer の所有者、寿命、書き込み権限が変化していないかを確認する。

この一覧は、Dirty Frag と同じ CVE を探すためのものではない。同じ不変条件違反を探すためのものである。重要なのは、read-only file-backed page が関与するか、copy されずに移動するか、後段で in-place 処理されるか、高権限文脈で再利用されるかである。これらの条件が重なるほど、Copy Fail / Dirty Frag 型の page cache write bug class として疑う優先度は高くなる。

ただし、この条件は Linux kernel LPE 全体の必要十分条件ではない。今回の条件に当てはまらないから安全とは言えない。use-after-free、out-of-bounds write、refcount bug、type confusion、namespace escape、capability bypass、eBPF verifier bug、filesystem logic bug などは、page cache 汚染とは別の経路で LPE になり得る。したがって、ここで述べているのは「Linux kernel security 全体で心配すべきもの」ではなく、「Copy Fail / Dirty Frag と同じ page cache write bug class を横展開するときに最優先で心配すべきもの」である。

この限定は重要である。横展開調査では、対象を広げすぎるとすべてが危険に見えてしまう。一方、対象を狭めすぎると、algif_aead、xfrm-ESP、RxRPC のような既知入口だけを見て終わってしまう。必要なのは、固有名詞ではなく構造条件で範囲を切ることである。すなわち、copy されずに page 参照が移動し、後段で入力と出力の意味が混ざり、read-only file-backed shared page の意味が保存されない場所を、同じ bug class の候補として調べる。この見方によって、個別 CVE の追跡ではなく、不変条件の破れを基準にした調査が可能になる。


10. 対象外は安全と同義ではない

横展開調査では、対象を広げるだけでなく、対象外も定義する必要がある。ただし、ここでいう対象外とは、危険がないという意味ではない。今回の page cache write bug class、すなわち読み取り専用由来の file-backed page が copy されずに別サブシステムへ渡され、後段で in-place に書き換えられる系列としては優先度が低い、という意味である。この区別をしないと、copy しているから安全、page cache と無関係だから安全、root 権限でしか呼べないから安全、という粗い誤解が生まれる。

今回の系列として優先度が下がるのは、常に private anonymous buffer だけを扱う処理、入力を必ず kernel-private buffer に copy する処理、in-place 変換をしない処理、read-only file-backed page を受け取れない API、root 権限でしか呼べない経路、setuid や root 実行経路に到達しない一時データなどである。これらは、Copy Fail / Dirty Frag 型の実行時意味汚染に直結しにくい。なぜなら、読み取り専用 file-backed page が共有されたまま後段の出力先になるという中心条件を満たしにくいからである。

今回の系列として優先度が低いもの 優先度が下がる理由 それでも残る別種のリスク
private anonymous buffer だけを扱う処理 file-backed page cache を直接汚染しにくい。 サイズ計算を誤れば out-of-bounds write になり得る。
必ず kernel-private buffer に copy する処理 read-only file-backed page が destination になりにくい。 copy 先の lifetime、境界、初期化、所有権管理を誤れば別種の kernel bug になり得る。
in-place 変換をしない処理 入力 page を出力先として書き換えにくい。 out-of-place でも出力先 buffer のサイズや権限を誤ればメモリ破壊や情報漏えいになり得る。
read-only file-backed page を受け取れない API 今回の page cache 汚染条件を満たしにくい。 user buffer、kernel buffer、device buffer の扱いを誤れば別の権限境界が破れる可能性がある。
root 権限でしか呼べない経路 unprivileged LPE としては成立しにくい。 capability check、namespace 境界、権限判定が誤っていれば低権限から到達できる可能性がある。
setuid や root 実行経路に到達しない一時データ page cache を汚染しても LPE への接続が弱い。 機密情報、認証 token、設定値、後続処理の入力に影響するなら、LPE 以外の被害につながり得る。

この表で重要なのは、対象外を安全宣言として扱っていない点である。private anonymous buffer だけを扱う処理は、Dirty Frag 型の page cache 汚染にはつながりにくい。しかし、buffer boundary を誤れば out-of-bounds write になる。必ず copy している処理は、read-only page を destination にする危険は下がる。しかし、copy 先の lifetime 管理を誤れば use-after-free になる。in-place 処理をしない場合でも、出力先 buffer のサイズ、初期化、権限、所有権を誤れば別の脆弱性になる。

したがって、横展開調査では二つの層を分ける必要がある。第一の層は、Copy Fail / Dirty Frag 型の page cache write bug class として疑うかどうかである。この層では、read-only file-backed page、zero-copy、fragment 表現、in-place 処理、高権限文脈での再利用が中心条件になる。第二の層は、Linux kernel security 全体として危険かどうかである。この層では、use-after-free、out-of-bounds write、refcount bug、type confusion、race、namespace escape、capability bypass、eBPF verifier bug、filesystem logic bug なども対象になる。

この区別をしないと、議論は二つの方向に崩れる。一方では、対象を広げすぎて、すべての kernel subsystem が同じ程度に危険に見えてしまう。他方では、対象を狭めすぎて、今回の条件に当てはまらないものを安全だと誤解してしまう。必要なのは、危険を否定することではなく、危険の種類を分類することである。今回の系列として対象外であることは、Copy Fail / Dirty Frag 型の実行時意味汚染としては優先度が低いという意味にすぎない。

最終的に、対象外の定義は調査の精度を上げるために使うべきである。今回見るべきものは、読み取り専用由来の page cache が copy されずに別経路へ渡り、in-place 処理で出力先化し、高権限文脈で再利用される場所である。それ以外を無視してよいわけではない。ただし、それ以外は別の bug class として、別の観点で調査すべきである。対象外とは、安全の証明ではなく、今回の不変条件違反とは異なる問題として切り分けるための分類である。


11. page cache write 以外の LPE 系統

Copy Fail / Dirty Frag 型の条件を外れたとしても、Linux kernel LPE の心配が消えるわけではない。ここを誤ると、議論が page cache write に過度に閉じる。今回の中心は、読み取り専用由来の page cache が copy されずに別サブシステムへ渡され、後段で in-place に書き換えられる構造である。しかし、Linux kernel LPE 全体には、use-after-free、out-of-bounds write、refcount bug、type confusion、TOCTOU、credential overwrite、namespace escape、capability bypass、eBPF verifier bug、io_uring bug、filesystem logic bug など、別の系統が存在する。これらは page cache を汚染しなくても、別の意味が壊れることで権限境界を破る。

したがって、今回の話は page cache に閉じない。page cache write は、上位の安全意味が下位で失われる具体例である。Copy Fail / Dirty Frag では、失われた意味は provenance、writability、sharing、direction、execution context だった。つまり、どこから来た page なのか、書いてよいのか、共有されているのか、入力なのか出力なのか、後でどの権限文脈で読まれるのか、という意味が保存されなかった。別の LPE では、失われる意味が lifetime なら use-after-free、type なら type confusion、authority なら credential overwrite や capability bypass、boundary なら out-of-bounds write になる。

LPE 系統 失われる意味 何が起きるか page cache write との関係
use-after-free object lifetime 解放済み object がまだ有効であるかのように参照され、別用途に再利用されたメモリを操作できる。 page cache 汚染とは別系統だが、意味保存の失敗という点では同じである。
out-of-bounds write buffer boundary 本来の buffer 境界を越えて隣接領域を書き換え、kernel object や制御情報を破壊できる。 read-only page の意味ではなく、書き込み可能範囲の意味が壊れる。
refcount bug ownership / lifetime 参照数の増減が壊れ、まだ使われている object が解放されたり、不要な object が残り続けたりする。 page の共有性ではなく、object の所有と寿命の意味が壊れる。
type confusion object type ある型の object が別の型として解釈され、想定外の field や function pointer を操作できる。 page cache ではなく、object が何であるかという意味が壊れる。
TOCTOU check と use の一貫性 検査時点では安全だった対象が、使用時点では別の対象や状態にすり替わる。 page そのものではなく、検査された意味が使用時まで保存されない。
credential overwrite authority cred 構造体などが書き換えられ、実効 UID、capability、権限状態が不正に変わる。 page cache を介さず、権限主体そのものの意味が壊れる。
namespace escape isolation boundary container、mount namespace、user namespace などの隔離境界を越えて、外側の資源へ到達する。 read-only page ではなく、閉じ込められている範囲の意味が壊れる。
capability bypass privilege model 本来必要な capability check が抜けたり、誤った namespace 文脈で評価されたりする。 書き込み対象ではなく、操作主体が何を許可されているかの意味が壊れる。
eBPF verifier bug safety proof verifier が安全だと判断した eBPF program が、実際には不正な memory access や kernel 情報操作を行う。 page cache ではなく、検証済みであるという意味が壊れる。
io_uring bug async context / lifetime submit 時点と completion 時点の buffer、file、credential、task context の関係がずれ、想定外の操作が成立する。 非同期処理により、所有権、寿命、権限文脈の意味が保存されにくくなる。
filesystem logic bug path / mount / ownership meaning overlayfs、FUSE、network filesystem などで、上位の path や権限意味と下位の実体がずれる。 page cache write と近い場合もあるが、主問題はファイルシステム上の意味対応の破綻である。

この一覧から分かるように、LPE の系統は多様である。しかし、抽象化すれば、いずれも「安全上必要な意味が処理経路のどこかで失われる」問題として読める。use-after-free では、object がまだ生きているという意味が失われる。type confusion では、object が何であるかという意味が失われる。TOCTOU では、検査時に確認した意味が使用時まで保存されない。credential overwrite では、誰の権限で動いているかという意味が壊れる。namespace escape では、どの境界の内側にいるかという意味が壊れる。

この観点に立つと、Copy Fail / Dirty Frag 型の page cache write は、Linux kernel LPE の中の一事例として位置づけられる。特殊なのは、ファイルシステム上では読み取り専用であるはずの file-backed shared page が、別サブシステムでは単なる fragment や buffer として扱われ、実行時に読まれる内容が汚染される点である。しかし、根本原理は他の LPE と連続している。安全性は、byte 列そのものではなく、byte 列や object に付随する意味が処理経路全体で保存されることで成立する。

したがって、page cache write 以外の LPE 系統を本文に含めることには意味がある。それは論点を散らすためではない。今回の話を page cache だけの特殊事情に閉じ込めず、Linux kernel security 全体に通じる原理へ引き上げるためである。Copy Fail と Dirty Frag は、provenance、writability、sharing、direction、execution context の保存に失敗した事例である。別の LPE は、lifetime、type、authority、boundary、isolation、safety proof の保存に失敗した事例である。失われる意味は違うが、意味保存の破綻が権限境界を壊すという構造は共通している。


12. byte と意味を分ける

カーネルは byte 列を扱っているように見える。実際、メモリ上に存在するのは、最終的には数値として解釈可能な byte の並びである。しかし、安全性は byte 列だけでは決まらない。同じ byte 列でも、それが file-backed page なのか、anonymous page なのか、shared なのか、private なのか、入力なのか、出力なのか、誰の権限で操作されているのか、後でどの権限文脈で読まれるのかによって、安全上の意味は変わる。つまり、カーネルが扱っている対象は、単なる byte 列ではなく、byte 列とそれに付随する文脈情報の組である。

たとえば、同じ 4096 byte の page であっても、それが一般ユーザーが読み取り可能な通常ファイル由来の page cache である場合と、kernel 内部で確保された private buffer である場合では、書き換えてよいかどうかがまったく異なる。前者は、ファイルシステム上では「読めるが書けない」対象であり、後で setuid root バイナリ、共有ライブラリ、認証処理、dynamic loader などから読まれる可能性がある。後者は、特定の処理が作業領域として確保した一時 buffer かもしれない。byte 列だけを見れば両者は同じ長さのメモリ領域にすぎないが、安全上の意味は異なる。

観点 byte として見た場合 意味として見た場合 Dirty Frag / Copy Fail で重要になる理由
由来 ある page に載っている byte 列である。 file-backed page なのか、anonymous page なのか、kernel-private buffer なのかが異なる。 file-backed read-only page cache なら、呼び出し元が書き換えてよいとは限らない。
共有性 同じ物理 page 上の byte 列である。 shared page なのか、private page なのかが異なる。 shared page cache を書き換えると、別文脈で読まれる内容まで変わる。
書き込み可否 メモリ上では値を書き換えられる可能性がある。 権限モデル上、その主体が書いてよいかどうかは別である。 読み取り専用由来の page が destination 化すると、読み取り権限が実質的な書き換え能力へ変わる。
入出力方向 buffer として処理対象になる。 入力なのか、出力なのか、入出力兼用なのかが異なる。 入力として渡された page が in-place 処理で出力先になると、意味境界が壊れる。
実行文脈 byte 列が後で読まれる。 一般ユーザー文脈で読まれるのか、root 文脈で読まれるのかが異なる。 汚染された page が root 文脈で読まれると、LPE に接続する。

Copy Fail / Dirty Frag の問題は、byte 列が通常の意味で変換されたことではない。問題は、byte 列に付随していた安全上の意味が保存されなかったことである。ファイルシステムは、この page が読み取り専用ファイル由来であることを知っている。メモリ管理は、これが shared page cache であることを知っている。しかし、scatterlist や skb frag に包まれた瞬間、それは単なる fragment、buffer、payload、処理対象として見えやすくなる。ここで file-backed、shared、read-only、input、root-reachable という意味が落ちると、後段処理はその page を書き換えてよい作業領域のように扱ってしまう。

この意味の剥落が、実行時意味の汚染を生む。byte は同じ page に載っている。しかし、そこに付随していた「書いてはいけない」「入力である」「共有されている」「後で root 文脈で読まれる」という意味が消える。Dirty Frag と Copy Fail は、いずれもこの意味の剥落が page cache 汚染として現れた事例である。したがって、この問題を理解するには、byte 列と意味を分けて考える必要がある。


13. 意味保存モデルを導入する

この構造は、簡単な数理モデルとして表せる。まず、カーネル内部で扱われる対象を、単なる byte 列ではなく、byte 列と意味の組として定義する。データ本体を \(D\)、そのデータに付随する安全上の意味を \(M\) と置く。このとき、処理対象 \(X\) は次のように表せる。

\[
X = (D, M)
\]

この式は、処理対象 \(X\) が byte 列 \(D\) だけではなく、意味 \(M\) と一体で存在していることを表す。ここで \(D\) は実際のデータである。たとえば、ファイル内容、実行ファイルの命令列、認証処理が読む設定、共有ライブラリの内容などである。一方、\(M\) は、その byte 列がどのような安全上の文脈に置かれているかを表す。たとえば、どこから来た page なのか、誰が所有しているのか、書いてよいのか、共有されているのか、いつまで有効なのか、入力なのか出力なのか、誰の権限で扱われているのか、後でどの権限文脈で読まれるのか、という情報である。

この \(M\) を、もう少し分解して書く。ここでは、provenance を \(P\)、ownership を \(O\)、writability を \(W\)、sharing を \(S\)、lifetime を \(L\)、direction を \(T\)、authority を \(A\)、execution context を \(C\) と置く。すると、意味 \(M\) は次のような組として表せる。

\[
M = (P, O, W, S, L, T, A, C)
\]

この式の意味は、\(M\) が一つの抽象語ではなく、複数の安全属性の束であるということである。\(P\) は provenance、つまりデータの由来である。file-backed page なのか、anonymous page なのか、kernel-private buffer なのかを表す。\(O\) は ownership、つまり誰がその object や page を所有しているかである。\(W\) は writability、つまり書き込み可能かどうかである。\(S\) は sharing、つまり shared なのか private なのかである。\(L\) は lifetime、つまり object がいつまで有効かである。\(T\) は direction、つまり入力なのか出力なのかである。\(A\) は authority、つまりどの権限主体の操作なのかである。\(C\) は execution context、つまり後でどの権限文脈で読まれるかである。

記号 意味 Dirty Frag / Copy Fail での例 失われると何が起きるか
\(P\) provenance、つまりデータの由来を表す。 file-backed page cache である。 通常ファイル由来の page が、単なる作業 buffer のように扱われる。
\(O\) ownership、つまり誰が所有しているかを表す。 呼び出し元ユーザーが所有していない page を参照している。 自分のものではない page を書き換えられるように見えてしまう。
\(W\) writability、つまり書いてよいかを表す。 読み取り専用由来であり、呼び出し元は書けない。 read-only page が destination として扱われる。
\(S\) sharing、つまり共有されているかを表す。 shared page cache である。 一つの汚染が別文脈で読まれる内容に波及する。
\(L\) lifetime、つまり有効期間を表す。 page や object が後段処理中も有効である必要がある。 別系統では use-after-free などにつながる。
\(T\) direction、つまり入力か出力かを表す。 入力として渡された page である。 入力 page が in-place 処理で出力先になる。
\(A\) authority、つまり操作主体の権限を表す。 低権限ユーザーの操作である。 低権限操作が、本来許されない書き換え効果を持つ。
\(C\) execution context、つまり後で読まれる権限文脈を表す。 setuid binary や認証処理として root 文脈で読まれ得る。 汚染された byte 列が root 権限で意味を持つ。

次に、カーネル内部の処理を写像として表す。ある処理 \(f\) が、処理対象 \(X\) を受け取り、別の処理対象 \(X’\) を返すとする。このとき、\(X = (D, M)\) であるから、処理 \(f\) は次のように書ける。

\[
f(X) = f(D, M) = (D’, M’)
\]

この式は、処理 \(f\) が byte 列 \(D\) を \(D’\) に変えるだけでなく、意味 \(M\) も \(M’\) に変えることを表している。ここで重要なのは、\(D\) が変わること自体は必ずしも悪ではないという点である。暗号化、復号、圧縮、展開、ネットワーク処理、checksum 計算、fragment handling では、データが変換されることは当然あり得る。問題は、\(D\) の変換に伴って、安全上必要な \(M\) の制約が失われることである。

安全な処理であるためには、変換後の意味 \(M’\) が、少なくとも安全上必要な意味 \(M_{\text{required}}\) を満たしていなければならない。これを次のように書く。

\[
M’ \succeq M_{\text{required}}
\]

この式で、\(\succeq\) は大小関係ではなく、「必要な安全制約を失っていない」という関係を表す。つまり、\(M’\) が \(M_{\text{required}}\) 以上に大きいという意味ではない。変換後の意味 \(M’\) が、安全性に必要な条件を保持している、という意味である。たとえば、元の page が read-only file-backed shared page であり、入力として渡されたなら、変換後も「書いてはいけない」「共有されている」「入力である」「必要なら private copy を作るべきである」という制約が保持されていなければならない。

Copy Fail / Dirty Frag 型で必要になる不変条件は、次のように表せる。

\[
P = file\text{-}backed \land W = read\text{-}only \land S = shared \Rightarrow no\_inplace\_write
\]

この式は、file-backed で、read-only で、shared である page に対しては、in-place write をしてはならない、という意味である。左辺の \(P = file\text{-}backed\) は、その page がファイル由来であることを表す。\(W = read\text{-}only\) は、呼び出し元が書き込んではならないことを表す。\(S = shared\) は、その page が他の文脈でも読まれ得る共有 page であることを表す。この 3 条件がそろうなら、右辺の \(no\_inplace\_write\)、つまりその page をそのまま出力先として書き換えてはならない、という制約が必要になる。

Dirty Frag と Copy Fail で起きたことは、この不変条件の破れとして表せる。危険な状態は次のように書ける。

\[
P = file\text{-}backed \land W = read\text{-}only \land S = shared \land T = output
\]

この式は、file-backed で、read-only で、shared である page が、出力先 \(T = output\) として扱われている状態を表す。これは矛盾した状態である。なぜなら、読み取り専用由来で共有されている page は、入力として参照されることはあっても、低権限ユーザーの処理によって出力先にされてはならないからである。Copy Fail では、この危険な状態が algif_aead と scatterlist の経路で現れた。Dirty Frag では、xfrm-ESP、RxRPC、skb frag の経路で現れた。

ここで重要なのは、数式が何か新しい脆弱性検出器を与えているわけではないという点である。このモデルの役割は、Copy Fail と Dirty Frag の同型性を明確にすることである。個別には、Copy Fail は crypto API の問題に見える。Dirty Frag は networking / fragment handling の問題に見える。しかし、意味保存モデルで見ると、どちらも \(M\) のうち provenance、writability、sharing、direction が保存されず、read-only shared file-backed page が output 化した事例として読める。

したがって、意味保存モデルの結論は明確である。カーネル内部の処理は、\(D\) だけを正しく変換すればよいわけではない。\(D\) に付随する \(M\) を、サブシステム境界を越えて保存しなければならない。byte 列の処理としては正常に見えても、意味の保存に失敗すれば、読み取り権限が書き換え能力へ変質し、実行時意味の汚染を通じて LPE へ接続する。


14. メタ意味を分解する

前章では、カーネル内部で扱われる対象を \(X=(D,M)\) と表した。ここで \(D\) は byte 列であり、\(M\) はその byte 列に付随する安全上の意味である。しかし、\(M\) を単に「意味」と呼ぶだけでは、どこで何が壊れたのかを十分に追跡できない。そこで \(M\) を、provenance、ownership、writability、sharing、lifetime、direction、authority、execution context という 8 つの成分へ分解する。

\[
M = (P, O, W, S, L, T, A, C)
\]

この式は、意味 \(M\) が一つの抽象的な属性ではなく、複数の安全属性の束であることを表している。\(P\) は provenance、つまりデータがどこから来たかである。\(O\) は ownership、つまり誰がその page や object を所有しているかである。\(W\) は writability、つまり書き込み可能かどうかである。\(S\) は sharing、つまり shared なのか private なのかである。\(L\) は lifetime、つまりいつまで有効な object なのかである。\(T\) は direction、つまり入力なのか出力なのかである。\(A\) は authority、つまりどの権限主体の操作なのかである。\(C\) は execution context、つまり後でどの権限文脈で読まれるかである。

記号 意味 Dirty Frag / Copy Fail での具体例 失われた場合の危険
\(P\) provenance、つまりデータの由来を表す。 file-backed page なのか、anonymous page なのか、kernel-private buffer なのかを区別する。 読み取り専用ファイル由来の page が、単なる一時 buffer のように扱われる。
\(O\) ownership、つまり誰がその page や object を所有しているかを表す。 呼び出し元ユーザーが所有していない page cache を参照している。 自分のものではない page に対して、書き換え効果を及ぼせるように見えてしまう。
\(W\) writability、つまり書き込み可能かどうかを表す。 読み取り専用ファイル由来であり、低権限ユーザーは書き込めない。 read-only page が writable destination として扱われ、読み取り権限が書き換え能力へ変質する。
\(S\) sharing、つまり共有されているかどうかを表す。 shared page cache として、複数の文脈から読まれ得る。 一つの書き換えが、後続の実行、認証、ライブラリ読み込みなどへ波及する。
\(L\) lifetime、つまり object や page がいつまで有効かを表す。 処理中に参照される page や buffer が、後段処理まで有効である必要がある。 寿命管理が壊れると use-after-free や stale reference につながる。
\(T\) direction、つまり入力なのか出力なのかを表す。 読み取り専用 file-backed page は、本来 input として扱われる。 input page が output または work area として扱われ、in-place write の対象になる。
\(A\) authority、つまりどの権限主体の操作なのかを表す。 低権限ユーザーが読み取り可能なファイルを処理している。 低権限操作が、本来許されない高権限文脈への書き換え効果を持つ。
\(C\) execution context、つまり後でどの権限文脈で読まれるかを表す。 setuid binary、PAM、共有ライブラリ、dynamic loader などとして root 文脈で読まれ得る。 汚染された page が root 文脈で意味を持ち、LPE へ接続する。

この分解は、抽象的な言葉遊びではない。Dirty Frag では、少なくとも \(P\)、\(W\)、\(S\)、\(T\)、\(C\) が直接問題になった。読み取り専用ファイル由来の page であること、shared page cache であること、入力 page であること、後で root 文脈で読まれ得ることが、後段の処理で十分に保存されなかった。Copy Fail でも同じ方向の意味喪失が起きた。入口は algif_aead と scatterlist だったが、壊れた意味は同じである。

このモデルを使うと、Copy Fail と Dirty Frag は、同じ不変条件違反として読める。重要なのは、\(M\) のすべての成分が常に同じ重みを持つわけではないという点である。page cache write 型では、特に provenance、writability、sharing、direction、execution context が重要になる。一方、use-after-free では lifetime、type confusion では object type、capability bypass では authority が中心になる。つまり、LPE の系統ごとに壊れる意味は違うが、意味が保存されないことで安全境界が破れるという構造は共通している。


15. 意味保存を不変条件として表す

次に、カーネル内部の処理を状態遷移として表す。あるサブシステムの処理を写像 \(f_i\) と置く。ここで \(i\) は、処理経路の何番目の段階かを表す添字である。たとえば、読み取り、pipe への移動、scatterlist 化、skb frag 化、暗号処理、ネットワーク処理、実行時読み込みなどを、それぞれ別の \(f_i\) として考えることができる。

\[
f_i(D, M) = (D’, M’)
\]

この式は、処理 \(f_i\) が byte 列 \(D\) と意味 \(M\) を受け取り、変換後の byte 列 \(D’\) と変換後の意味 \(M’\) を返すことを表す。ここで重要なのは、カーネル処理は \(D\) だけを変換しているわけではない、という点である。暗号処理、ネットワーク処理、I/O 処理、fragment handling では、byte 列の見え方だけでなく、その byte 列がどの文脈で扱われるかも変わる。したがって、安全性を考えるには、\(D \to D’\) だけでなく、\(M \to M’\) も追跡する必要がある。

安全な処理では、\(D\) が変換されても、安全上必要な \(M\) は保存されなければならない。この条件を、次のように表す。

\[
M’ \succeq M_{\text{required}}
\]

この式で、\(M_{\text{required}}\) は後続処理に必要な安全制約の集合である。たとえば、file-backed、read-only、shared、input、unprivileged、root-reachable という制約が必要なら、それらが \(M_{\text{required}}\) に含まれる。\(M’\) は変換後に残っている意味である。そして \(\succeq\) は、「\(M’\) が \(M_{\text{required}}\) を満たしている」ことを表す関係である。これは通常の数値比較ではない。意味の包含、制約の保存、後続処理に必要な安全条件の維持を表す記号として使っている。

式の要素 意味 Dirty Frag / Copy Fail での読み方
\(f_i\) カーネル内部の各処理段階を表す。 splice、scatterlist 化、skb frag 化、ESP 処理、RxRPC 処理、AEAD 処理などに対応する。
\(D\) 処理前の byte 列を表す。 読み取り対象ファイル由来の page cache に載っている内容を表す。
\(M\) 処理前の安全上の意味を表す。 file-backed、read-only、shared、input、unprivileged、root-reachable などを含む。
\(D’\) 処理後の byte 列を表す。 暗号処理、ネットワーク処理、in-place 処理などの後に見える内容を表す。
\(M’\) 処理後に保存されている安全上の意味を表す。 後段処理が、その page を read-only shared input として認識できているかを表す。
\(M_{\text{required}}\) 安全のために後続処理へ引き継がれるべき意味を表す。 read-only page を output にしない、shared page なら private copy を作る、といった制約を含む。
\(\succeq\) 必要な安全制約を失っていないことを表す。 \(M’\) が \(M_{\text{required}}\) を満たしていれば安全側であり、満たしていなければ意味保存に失敗している。

Copy Fail / Dirty Frag 型の問題は、この関係が壊れることである。byte 列処理としては合法に見えても、読み取り専用、shared、input、unprivileged、root-reachable という意味が保存されなければ、安全性は壊れる。たとえば、ある処理が page の内容を復号すること自体は正常な処理である。しかし、その page が read-only file-backed shared page であるにもかかわらず、出力先として in-place に書き換えられるなら、\(M’ \succeq M_{\text{required}}\) は成り立たない。

したがって、意味保存の不変条件は、処理結果の byte 列だけではなく、処理後に残る意味を対象にする。Dirty Frag と Copy Fail の本質は、\(D’\) が何であるかだけではなく、\(M’\) から必要な制約が落ちていたことにある。カーネル内部の高速化は、\(D\) の copy を減らす方向に進みやすい。しかし、\(D\) の copy を避けるなら、代わりに \(M\) をより厳密に運ばなければならない。


16. Copy Fail と Dirty Frag を同じ式で読む

Copy Fail / Dirty Frag 型の初期状態は、読み取り専用の file-backed shared page が低権限主体によって入力として扱われ、後で root 文脈で読まれ得る状態である。この初期状態を、前章の記号で表す。ここでは、\(P = file\text{-}backed\)、\(W = read\text{-}only\)、\(S = shared\)、\(T = input\)、\(A = unprivileged\)、\(C = root\text{-}reachable\) と置く。

\[
M_0 = (P=file\text{-}backed,\; W=read\text{-}only,\; S=shared,\; T=input,\; A=unprivileged,\; C=root\text{-}reachable)
\]

この式は、初期状態 \(M_0\) を具体的に書いたものである。\(P=file\text{-}backed\) は、対象が通常ファイル由来の page cache であることを表す。\(W=read\text{-}only\) は、呼び出し元がその page を書き換える権限を持たないことを表す。\(S=shared\) は、その page が共有され、別の文脈で読まれ得ることを表す。\(T=input\) は、その page が入力として渡されたことを表す。\(A=unprivileged\) は、操作主体が低権限ユーザーであることを表す。\(C=root\text{-}reachable\) は、その page が後で root 文脈で読まれ得ることを表す。

この状態で守るべき不変条件は、次のように表せる。

\[
P = file\text{-}backed \land W = read\text{-}only \land S = shared \Rightarrow no\_inplace\_write
\]

この式は、file-backed で、read-only で、shared である page に対しては、in-place write をしてはならない、という条件を表す。左辺は、危険な page の性質を表している。\(P = file\text{-}backed\) によって、その page はファイル内容と対応している。\(W = read\text{-}only\) によって、呼び出し元はその page を書いてはならない。\(S = shared\) によって、その page は別文脈で再利用され得る。この 3 つがそろうなら、右辺の \(no\_inplace\_write\)、すなわち in-place に書き換えてはならないという制約が必要になる。

逆に、危険な状態は次のように表せる。

\[
P = file\text{-}backed \land W = read\text{-}only \land S = shared \land T = output
\]

この式は、file-backed、read-only、shared である page が、出力先 \(T = output\) として扱われている状態を表す。これは安全上の矛盾である。読み取り専用で共有されている file-backed page は、低権限ユーザーの処理では入力として参照されることはあっても、出力先になってはならない。したがって、この式が成立する経路は、読み取り権限を実質的な書き換え能力へ変質させる。

意味 Copy Fail での現れ方 Dirty Frag での現れ方
\(M_0 = (P=file\text{-}backed,\; W=read\text{-}only,\; S=shared,\; T=input,\; A=unprivileged,\; C=root\text{-}reachable)\) 低権限ユーザーが、後で root 文脈で読まれ得る読み取り専用 file-backed shared page を入力として扱っている。 読み取り可能な setuid binary などの page cache が、暗号処理経路に渡される。 pipe や skb frag を経由して、読み取り専用由来の page がネットワーク処理経路に渡される。
\(P = file\text{-}backed \land W = read\text{-}only \land S = shared \Rightarrow no\_inplace\_write\) 読み取り専用 file-backed shared page は in-place write してはならない。 scatterlist 経由で writable destination に入れてはならない。 shared skb frag に対して private copy なしで in-place 処理してはならない。
\(P = file\text{-}backed \land W = read\text{-}only \land S = shared \land T = output\) 読み取り専用 file-backed shared page が出力先として扱われている危険状態である。 algif_aead と scatterlist の経路でこの状態が成立し得る。 xfrm-ESP、RxRPC、skb frag の経路でこの状態が成立し得る。

この式は、Copy Fail と Dirty Frag の同型性を表している。Copy Fail では、scatterlist 経由で入力 page が writable destination として扱われることで、この条件が破れた。Dirty Frag では、skb frag、ESP、RxRPC の経路で、shared page に対する private copy が十分に行われず、in-place 処理に進むことで、この条件が破れた。入口は違う。しかし、read-only file-backed shared page が output 化するという構造は同じである。

ここで注意すべきなのは、この数式が Dirty Frag や Copy Fail の exploit 手順を記述しているわけではないという点である。この数式は、個別 exploit の詳細ではなく、両者に共通する安全条件の破れを表している。したがって、数式の役割は予測や検出ではなく、抽象構造の整理である。Copy Fail が crypto API の問題に見え、Dirty Frag が networking の問題に見えても、同じ式で読めるのは、両者が同じ不変条件を破っているからである。


17. 横展開調査もモデルから導ける

意味保存モデルを使うと、横展開調査の観点も明確になる。見るべきなのは、どのサブシステム名かではない。どの遷移で \(M\) のどの成分が失われるかである。つまり、調査対象は「algif_aead に似ているか」「xfrm-ESP に似ているか」ではなく、「\(P\)、\(W\)、\(S\)、\(T\)、\(A\)、\(C\) の必要な制約が、処理経路の途中で落ちるか」で決まる。

この観点から見ると、zero-copy は \(D\) の copy を避ける処理である。しかし、\(D\) を copy しないなら、\(M\) を正しく運ぶ必要がある。provenance \(P\) と sharing \(S\) が後段へ伝わらなければ、file-backed shared page が単なる buffer として扱われる。in-place crypto は performance を上げる処理である。しかし、direction \(T\) と writability \(W\) が保存されなければ、input であり read-only である page が output になる。async I/O は throughput を高める処理である。しかし、lifetime \(L\) と authority \(A\) が保存されなければ、submit 時点では安全だった buffer や権限文脈が completion 時点では別の意味を持つ可能性がある。

横展開対象 失われやすい \(M\) の成分 危険の形 確認すべき不変条件
zero-copy \(P\)、\(S\)、\(O\)、\(W\) copy を省略した page 参照が、由来や共有性を失ったまま後段へ渡る。 file-backed shared page であることが、後段処理でも保持されているかを確認する。
splice / pipe buffer \(P\)、\(S\)、\(T\) 読み取り対象の page cache が、pipe を経由して別の処理対象へ移る。 入力として渡された page が、出力先または作業領域として扱われないかを確認する。
scatterlist \(W\)、\(T\)、\(S\) 複数 page をまとめる過程で、source と destination の意味が混ざる。 read-only shared page が writable destination に入らないかを確認する。
skb frag \(P\)、\(S\)、\(T\) ネットワーク fragment として扱われる過程で、page の由来や共有性が薄まる。 shared frag であれば private copy が必要な場面で、in-place 処理に進まないかを確認する。
in-place crypto \(W\)、\(T\)、\(A\) 入力 buffer を出力 buffer として再利用し、読み取り専用由来の page を書き換える。 input かつ read-only の page が output として扱われないかを確認する。
compression / decompression \(T\)、\(W\)、\(L\) 変換処理の途中で、入力 buffer と出力 buffer や scratch buffer の境界が曖昧になる。 入力 page が作業領域として書き換えられないか、出力先の lifetime が正しいかを確認する。
tunnel / encapsulation \(P\)、\(S\)、\(T\)、\(C\) payload が複数のネットワーク層や暗号層を通過する過程で、page の意味が薄まる。 元の page が高権限文脈で読まれ得る場合、その意味が後段まで保存されているかを確認する。
io_uring / async I/O \(L\)、\(A\)、\(O\)、\(T\) submit 時点と completion 時点で、buffer、file、credential、権限文脈がずれる。 非同期境界を越えて、lifetime と authority が保存されているかを確認する。
filesystem layer / overlayfs / FUSE \(P\)、\(O\)、\(W\)、\(C\) 上位ファイルシステムの権限意味と下位実体の page や object の意味がずれる。 上位で read-only に見える対象が、下位で writable な別文脈として扱われないかを確認する。

このように、数理モデルは脆弱性を予測するためではなく、同じ構造を見抜くために使う。Dirty Frag は、Copy Fail と同じ不変条件違反の別入口である。したがって、横展開調査では、既知のモジュール名を暗記するのではなく、意味のどの成分がどの遷移で失われるかを見る必要がある。

最終的に、横展開調査は次の問いに集約できる。処理対象 \(X=(D,M)\) がサブシステム境界を越えるとき、\(D\) だけでなく \(M\) も保存されているか。特に、read-only file-backed shared page が関与する場合、\(P\)、\(W\)、\(S\)、\(T\)、\(A\)、\(C\) は後段でも正しく保持されているか。この問いに答えられない経路は、Copy Fail / Dirty Frag 型の bug class として疑うべきである。


18. 運用論では kernel update と reboot が本筋である

運用上は、Dirty Frag の対応は複雑に見える。しかし、原則は単純である。未修正期間には、不要な入口を無効化して時間を稼ぐ。修正済み kernel が提供されたら更新する。そして再起動し、実際に修正済み kernel で起動していることを確認する。この流れは Copy Fail でも Dirty Frag でも変わらない。違うのは、暫定的に塞ぐ入口の名前であり、根本対策の構造ではない。

Unit 42 や Bugcrowd の Copy Fail 解説も、Copy Fail を deterministic logic flaw、AF_ALG / algif_aead / splice / page cache の結合として説明し、実務上は kernel 更新を優先すべき問題として扱っている[27][28]。Theori の Copy Fail 公開情報も、この脆弱性が algif_aead と page cache を介する LPE として注目された背景にある[29]。つまり、Copy Fail でも Dirty Frag でも、脆弱性の技術的入口は異なるが、運用上の終着点は修正済み kernel で起動することにある。

対応段階 実施内容 目的 注意点
影響確認 対象 kernel、配布元の advisory、対象 CVE、ロード済み module、利用中機能を確認する。 自分の環境が Dirty Frag の影響を受けるか、どの程度急ぐべきかを判断する。 CVE の存在だけで判断せず、実際の kernel version、module、利用機能、低権限実行経路を見る必要がある。
暫定緩和 未修正期間に不要な esp4、esp6、rxrpc などの入口を無効化する。 修正済み kernel へ移行するまで、既知の exploit 経路へ到達しにくくする。 IPsec ESP、AFS、RxRPC を利用している環境では機能影響が出るため、無条件に適用してよいわけではない。
cache 汚染対処 汚染が疑われる場合は drop_caches や reboot によって実行時状態を初期化する。 ディスク上ではなく page cache 上に残った可能性のある汚染を消す。 drop_caches は脆弱性修正ではなく、汚染済み状態を捨てるための緊急処置である。
kernel 更新 配布元が提供する修正済み kernel package を適用する。 脆弱な処理経路そのものを修正する。 package をインストールしただけでは、実行中 kernel は切り替わらない。
再起動 システムを reboot し、修正済み kernel で起動する。 修正済み kernel を実際に有効化し、古い kernel と実行時 cache 状態を捨てる。 再起動しなければ、更新済み package が存在しても脆弱な kernel で動き続ける可能性がある。
起動確認 起動中 kernel version と配布元の修正状況を照合する。 更新したつもりで旧 kernel のまま運用する事故を防ぐ。 複数 kernel が残る環境、手動 boot selection、仮想基盤では確認を省略してはならない。

CISA の Known Exploited Vulnerabilities Catalog に Copy Fail が追加されたことも、運用上の重みを示している[30]。KEV に入るということは、単に理論的に危険であるという話ではなく、実際の悪用や運用上の優先度を考慮すべき段階にあることを意味する。Dirty Frag についても、local access が前提であることだけを理由に軽く扱うべきではない。低権限実行に到達する別の入口がある環境では、Dirty Frag は侵害後の root 化に使われる増幅器になる。

したがって、運用論で最も避けるべき誤解は、暫定対策を根本対策と取り違えることである。module blacklist は入口を閉じるための一時策である。rmmod はロード済みの入口を消す操作である。drop_caches は汚染済み page cache を捨てる処置である。いずれも重要だが、脆弱な kernel code を修正するものではない。最終的には、修正済み kernel を導入し、その kernel で再起動し、起動中 kernel を確認する。この一連の流れが、Copy Fail と Dirty Frag に共通する運用上の本筋である。


19. 脆弱性の洪水では CVE ではなく露出を管理する

Dirty Frag の運用上の意味は、単に新しい CVE が増えたということではない。より大きな問題は、脆弱性の数が増え続ける状況では、CVE 番号を知ることや CVSS を眺めることだけでは、実際に守るべき環境の優先順位を決められなくなるという点である。Tenable は、AI による脆弱性発見の加速、NVD による CVE enrichment の縮小、年間 CVE 件数の増加が重なり、従来型の脆弱性管理が限界に来ると論じている[31]

この議論は、Dirty Frag の後半に独立した章として置く必要がある。なぜなら、Dirty Frag のような LPE は、CVE として存在するだけでは運用上の優先度が決まらないからである。対象 host の kernel が該当するか、修正版 kernel が提供されているか、再起動できるか、esp4、esp6、rxrpc がロードされているか、IPsec ESP や AFS / RxRPC を使っているか、SSH、Web shell、CI runner、container など低権限実行経路が存在するかによって、同じ CVE の実務上の意味は変わる。

評価軸 CVE 単位で見た場合 露出単位で見た場合 Dirty Frag での意味
対象判定 CVE が存在するか、CVSS が高いかを見る。 自分の kernel、distribution、package 状態、module 状態が該当するかを見る。 同じ CVE でも、対象 kernel でなければ直接の影響はない。
攻撃到達性 脆弱性の一般的説明を読む。 その host 上で低権限コード実行に至る経路があるかを見る。 SSH、Web shell、CI runner、container などがある環境では優先度が上がる。
機能利用 影響を受ける module 名を確認する。 esp4、esp6、rxrpc、IPsec ESP、AFS / RxRPC を実際に使っているかを見る。 使っていない module は無効化しやすいが、使っている場合は機能影響を考える必要がある。
悪用可能性 PoC や exploit の有無を一般情報として見る。 自分の環境で PoC 条件が満たされるか、攻撃者が前提権限を得やすいかを見る。 LPE は侵入口ではなく増幅器なので、既存の侵入口との組み合わせが重要になる。
修正可能性 advisory に修正済みと書かれているかを見る。 自分の環境で kernel update と reboot をいつ実施できるかを見る。 更新済み package があっても、再起動できなければ脆弱な kernel が残る。
優先順位 CVSS、priority、severity を機械的に見る。 公開面、低権限実行経路、修正可否、業務影響、再起動可否を合わせて判断する。 公開サーバー、共有 login 環境、CI host、container host は優先度が高い。

したがって、必要なのは CVE 単位の反応ではなく、露出単位の判断である。Dirty Frag であれば、公開サーバー、共有 login 環境、CI host、container host、Web application から任意コード実行に到達し得る host は優先度が高い。一方、外部実行経路がなく、単独利用で、該当 module も使っていない環境では、緊急度は相対的に下がる。ただし、緊急度が下がることと、修正が不要であることは同じではない。優先度は対応順を決めるための概念であり、放置を正当化するための概念ではない。

ここでも、技術層と運用層の原理は対応している。技術層では、byte 列だけでなく、その byte 列に付随する provenance、writability、sharing、direction、authority、execution context を見る必要があった。運用層でも同じで、CVE 番号だけでなく、その CVE が自分の資産、公開面、実行経路、悪用可能性、修正可能性、再起動可能性の中でどの意味を持つかを見る必要がある。脆弱性管理とは、CVE を収集する作業ではなく、自分の環境における露出の意味を読み取る作業である。

このため、Dirty Frag の教訓は、個別 kernel bug の理解に留まらない。脆弱性が増え続け、公開情報の整理が追いつかず、優先順位付けの外部基盤が不完全になるほど、運用者は個別 CVE の表層ではなく、攻撃面、到達可能性、権限昇格経路、復旧可能性を自分の環境に即して評価しなければならない。これは、Copy Fail から Dirty Frag へ進んだ技術的抽象化と同じである。個別名ではなく、意味と構造を見る必要がある。


20. AI が見つけた脆弱性と、AI が見つけやすくした脆弱性

Dirty Frag を脆弱性の洪水という文脈に置くとき、もう一つ区別しておくべき点がある。それは、AI が直接見つけた脆弱性と、AI によって見つけやすくなった脆弱性は同じではない、という点である。Copy Fail については、Theori の Xint Code による探索が発見経路として説明されており、Bugcrowd も AI system によって短時間で見つかった事例として整理している[28][29]。一方で Dirty Frag については、公開情報上、AI が直接発見した脆弱性とは断定できない。Dirty Frag は Hyunwoo Kim による公開 write-up と PoC を中心に説明されており、Tenable も Copy Fail の bug class を横展開した Linux kernel LPE として整理している[2][5]

しかし、この違いは Dirty Frag と AI 時代の脆弱性管理が無関係であることを意味しない。むしろ重要なのは、Copy Fail が AI 支援探索によって可視化した page cache write bug class が、その後 Dirty Frag によって別サブシステムへ横展開された点である。AI が直接見つけたかどうかとは別に、AI によって一つの脆弱性クラスが可視化されると、研究者、攻撃者、防御者のすべてが、同じ不変条件違反を別入口で探すようになる。ここで脆弱性管理の焦点は、個別 CVE の一覧から、脆弱性クラス、攻撃面、到達可能性、不変条件の破れへ移る。

区分 意味 今回の例 運用上の含意
AI が直接見つけた脆弱性 AI system や AI 支援探索が、具体的な脆弱性の発見経路として説明されているもの。 Copy Fail は Theori の Xint Code による探索が発見経路として説明されている。 AI により、従来より短時間で深いコード経路の弱点が表面化し得る。
AI が見つけやすくした脆弱性 AI が直接発見したとは限らないが、AI によって可視化された bug class の横展開として調査対象になりやすいもの。 Dirty Frag は AI 発見とは断定できないが、Copy Fail と同じ page cache write bug class の別入口として読める。 一つの発見が、同じ不変条件違反を持つ別サブシステムの探索へ波及する。
AI が増幅する観測可能性 AI が脆弱性を魔法のように作るのではなく、既存の不整合をより速く、広く、高解像度で見つけやすくすること。 Copy Fail で可視化された意味境界の破れが、Dirty Frag のような横展開調査を促す。 CVE 単位ではなく、bug class、攻撃面、不変条件、露出の意味を見なければ追いつかなくなる。
AI 時代の防御側の課題 発見数が増えるだけでなく、同じ構造の派生探索が速くなることに対応する必要がある。 algif_aead だけを塞いでも、xfrm-ESP や RxRPC のような別入口が問題化し得る。 個別モジュール名ではなく、不変条件の破れを基準に横展開して評価する必要がある。

この点は、Claude Mythos についての既稿とも接続する。既稿では、AI が世界を変えたというより、世界の中に既に存在していた不整合、依存関係、意味境界の破れ、制度上の観測限界が、従来より速く、広く、高解像度で露出するようになったと整理した[32]。Copy Fail と Dirty Frag は、その変化が Linux kernel security の現場でどのように現れるかを示す連続事例である。AI は脆弱性を魔法のように生成しているのではない。既に存在していた不変条件違反を、より短時間で見つけ、同じ構造を別領域へ展開しやすくしている。

したがって、Dirty Frag 記事で Claude Mythos の論点を入れる意味は、AI 脅威論を付け足すことではない。ここで必要なのは、AI が個別の発見主体であったかどうかよりも、AI によって観測可能性が変わるという構造を捉えることである。Copy Fail は AI が見つけた脆弱性として位置づけられる。Dirty Frag は AI が見つけたとは断定できない。しかし、Dirty Frag は、AI 時代に重要になる「一つの発見から bug class を横展開する」思考そのものを体現している。

この章を入れることで、本稿の運用上の結論も強くなる。脆弱性が増える時代に必要なのは、CVE を多く知ることだけではない。AI によって一つの意味境界の破れが見つかったとき、その破れがどのサブシステム、どの最適化、どの共有構造、どの実行文脈へ横展開し得るかを考える必要がある。Dirty Frag は、Copy Fail の後に現れた別名の脆弱性ではなく、AI 時代における脆弱性理解の単位が、個別 CVE から不変条件の破れへ移ることを示す事例である。


21. Debian / Ubuntu 運用の話は過去記事とも接続する

Debian と Ubuntu の対応差は、単なる好き嫌いの問題ではない。Dirty Frag のような kernel LPE では、ディストリビューションの違いは、修正済み kernel がいつ提供されるか、CVE tracker がどの粒度で状態を示すか、暫定 mitigation がどの程度具体的に案内されるか、再起動までの運用をどう組み立てるかという差として現れる。これは、日常的なパッケージ選好ではなく、脆弱性公開後の状態遷移をどう管理するかという問題である。

Ubuntu 26.04 LTS の設計と運用判断については、既稿で、OS の採用判断を機能一覧ではなく、保守期間、更新モデル、互換性、運用リスク、復旧可能性を含む状態遷移として捉えた[33]。Dirty Frag でも同じである。重要なのは、あるディストリビューションが好みかどうかではない。その OS を使うことで、脆弱性情報をどの速度で受け取り、修正済み kernel をどの経路で取得し、暫定策をどの精度で適用し、どのタイミングで reboot し、どの方法で修正済み kernel で起動していることを確認できるかである。

観点 表面的な見方 運用上の見方 Dirty Frag での意味
ディストリビューション選好 Debian が好きか、Ubuntu が好きかという印象で判断する。 修正提供、CVE 情報、互換性、再起動計画、復旧確認を含む状態遷移として判断する。 好みではなく、脆弱性対応の運用経路が安定しているかが問題になる。
CVE tracker fixed、needed、needs evaluation などの表示だけを見る。 自分の kernel package、release、repository、適用済み状態と照合する。 tracker 上の状態と、自分の host が実際に安全かどうかは別である。
暫定 mitigation 案内された module を無効化すればよいと考える。 その module を実際に使っているか、機能影響があるか、修正済み kernel までの時間稼ぎになるかを見る。 esp4、esp6、rxrpc の無効化は環境によって影響が変わる。
kernel update package を更新した時点で対応完了と考える。 更新後に reboot し、起動中 kernel が修正済みであることを確認する。 更新済み package が存在しても、旧 kernel で動いていれば脆弱性は残る。
復旧判断 ディスク上のファイルや package 状態が正常なら安全と考える。 page cache、実行中 kernel、ロード済み module、侵害可能性、ログ確認まで含めて判断する。 Dirty Frag は実行時状態の汚染を含むため、静的な整合性確認だけでは足りない。

あるディストリビューションが速く fixed kernel を出すか、CVE tracker で Needs evaluation と表示されるか、暫定 mitigation をどの粒度で案内するかは、運用上の差として現れる。しかし、それは Dirty Frag の本質ではない。本質は、脆弱な処理経路が修正された kernel に移行し、その kernel で実際に起動しているかどうかである。配布元の情報は、その状態へ到達するための経路を与えるにすぎない。

したがって、Dirty Frag は Debian と Ubuntu の優劣だけを論じる材料ではない。むしろ、OS 運用とは、脆弱性公開、パッケージ提供、暫定回避、機能影響評価、再起動、起動確認、必要なら復旧確認までを含む更新過程であることを示している。この意味で、Dirty Frag は OS 選定論と脆弱性対応論を接続する事例である。OS は導入した時点で安全になるものではなく、脆弱性情報に応じて状態を更新し続ける運用対象である。


22. 復旧可能性も安全性の一部である

Dirty Frag では、page cache 汚染が drop_caches または reboot まで残り得るという点が重要である[15]。これは、単に exploit を防げばよいという話ではない。汚染された実行時状態をどう消すか、どの時点から安全とみなすか、どの手順で確認するかという復旧可能性の問題でもある。脆弱性対応は、侵入防止だけでは完結しない。すでに汚染された可能性のある状態を、どのように正常状態へ戻すかまで含めて考える必要がある。

バックアップについての既稿では、安全とは保存していることではなく、復元可能性を設計することであると整理した[34]。Dirty Frag でも同じである。脆弱性対応とは、パッケージ更新コマンドを打つことだけではない。修正済み kernel で起動しているか、汚染状態が残っていないか、機能影響がないか、必要ならログと監査情報で侵害可能性を確認することまで含む。つまり、安全性は、修正の有無ではなく、安全な状態へ戻れるかどうかでも決まる。

復旧観点 見るべき対象 Dirty Frag での意味 不十分な判断
修正状態 配布元が提供する修正済み kernel package と適用状況を見る。 脆弱な処理経路そのものが修正されているかを確認する。 更新コマンドを実行しただけで対応完了とみなす。
起動状態 実際に動作中の kernel version を確認する。 修正済み kernel で起動していなければ、脆弱な kernel が残る。 package が入っていることと、実行中 kernel が新しいことを混同する。
実行時状態 page cache、ロード済み module、実行中 process、汚染可能性を見る。 page cache 汚染が残るなら、ディスク上の整合性だけでは安全を確認できない。 ファイルハッシュが正常であれば実行時も安全だとみなす。
機能影響 IPsec ESP、AFS、RxRPC、関連サービスへの影響を見る。 module 無効化や kernel 更新によって必要機能が壊れていないかを確認する。 暫定 mitigation を適用しただけで業務影響を確認しない。
侵害確認 低権限実行経路、ログ、監査情報、異常な権限昇格痕跡を見る。 LPE は侵入後の増幅器なので、既存の侵入口と組み合わせて評価する。 Dirty Frag が remote exploit ではないことだけを理由に調査不要とみなす。

物理媒体管理に関する既稿でも、情報は抽象的に見えても、実際には媒体、ファイルシステム、符号化、鍵、復元手順に依存すると整理した[35]。Dirty Frag では、情報はディスク上のファイルだけでなく、page cache という実行時媒体にも存在する。したがって、ディスク上の整合性だけを見ても、実行時安全性を完全には見たことにならない。これは、媒体管理の問題が、ストレージだけでなくメモリ上の実行時状態にも拡張されることを示している。

したがって、復旧可能性は Dirty Frag 対応の一部である。修正済み kernel を入れること、再起動すること、起動中 kernel を確認すること、必要なら page cache を捨てること、機能影響を確認すること、侵害可能性を調べることは、それぞれ別の作業ではなく、安全な状態へ戻るための連続した手順である。安全とは、単に脆弱性が存在しない状態ではない。脆弱性が存在し、情報が公開され、攻撃可能性が示されたあとでも、理解可能な手順で正常状態へ戻れることである。


23. 意味は差異の読み取りから生まれる

今回の議論で「意味」という語を使うのは、比喩ではない。意味は、byte 列がどの文脈で読まれ、どの差異として扱われ、どの後続更新へ接続されるかによって成立する。意味は差異の読み取りから生まれるという既稿の整理は、ここに接続する[36]。同じ byte 列であっても、それを読む主体、読む権限文脈、読む目的、読むタイミングが変われば、システム上の意味は変わる。

同じ byte 列でも、一般ユーザーが読むなら単なるファイル内容である。setuid root バイナリとして loader や CPU が読むなら、特権実行の命令列になる。PAM や sudo が読むなら、認証や権限判断の一部になる。共有ライブラリとして読まれるなら、複数の実行プロセスに影響する共通コードになる。つまり、byte 列の危険性は、それがどの実行文脈で意味を持つかによって決まる。

同じ byte 列が読まれる文脈 成立する意味 Dirty Frag での危険
一般ユーザーが通常ファイルとして読む。 単なるファイル内容として意味を持つ。 この段階では、読み取り行為そのものは通常の権限範囲に収まる。
page cache としてメモリ上に保持される。 ディスク上の内容を高速に再利用する実行時表現として意味を持つ。 ここが汚染されると、ディスク上のファイルが無傷でも実行時内容が変わる。
setuid root バイナリとして実行される。 root 権限で実行される命令列として意味を持つ。 汚染された命令列が root 文脈で読まれれば LPE に接続する。
PAM、sudo、認証処理から読まれる。 認証、権限判定、実行可否を左右する情報として意味を持つ。 汚染された内容が権限判断を変える可能性がある。
共有ライブラリや dynamic loader として読まれる。 複数プロセスが共有する実行時コードやロード処理として意味を持つ。 一つの page cache 汚染が複数の実行文脈へ波及し得る。

Dirty Frag の危険は、byte 列を変えたことだけにあるのではない。より正確には、後続文脈で読まれる意味を変えたことにある。ディスク上のファイルが同じでも、page cache 上の内容が変われば、実行時に読まれる差異は変わる。その差異が root 文脈の命令列、認証判断、共有コードとして解釈されれば、低権限ユーザーの読み取り操作が、特権文脈の動作変更へ接続する。

これが、実行時意味の汚染である。意味は byte 列単体に閉じていない。意味は、byte 列がどこから来て、どの状態で保持され、どの文脈で読まれ、どの後続処理へ接続されるかで決まる。Copy Fail と Dirty Frag が危険なのは、読み取り専用の byte 列そのものではなく、その byte 列が root 文脈で読まれる意味を汚染できるからである。


24. 構造として見ると、問題は境界条件の保存である

構造・時間・生命・意味・知能・自己・AI を生成連鎖として整理した既稿では、構造を単なる形状ではなく、要素間の関係、情報の流れ、制約、境界条件、安定性として捉えた[37]。Dirty Frag も同じく、個別部品の問題ではなく、境界条件の保存問題として読める。ここでいう境界条件とは、read-only、shared、input、unprivileged、root-reachable といった安全上の制約である。

AF_ALG、xfrm-ESP、RxRPC、splice、page cache、skb frag、scatterlist は、それぞれ単体では正当な仕組みである。AF_ALG は user space から kernel crypto API にアクセスするための仕組みであり、xfrm-ESP は IPsec ESP の処理に関わる仕組みであり、RxRPC は AFS などで使われる transport protocol であり、splice や zero-copy は copy を減らすための仕組みであり、page cache はファイル I/O を効率化する仕組みであり、skb frag や scatterlist は fragment や非連続 memory を扱うための仕組みである。問題は、これらの部品が単体で存在することではない。結合したときに、境界条件が保存されるかどうかである。

構成要素 単体での正当な役割 結合時に保存すべき境界条件
page cache ファイル内容をメモリ上に保持し、読み取りや実行を高速化する。 file-backed、read-only、shared であることを後段へ伝える必要がある。
splice / pipe copy を減らし、page 参照を別経路へ移す。 読み取り対象の page が出力先へ変質しないようにする必要がある。
scatterlist 非連続 memory をまとめて暗号処理や I/O 処理に渡す。 source と destination の意味を混同しない必要がある。
skb frag network packet の fragment を page 単位で効率よく扱う。 shared frag であれば private copy が必要な場面を保持する必要がある。
in-place 処理 入力と出力を同じ buffer にして性能やメモリ効率を上げる。 read-only input page を output として扱わない必要がある。
setuid / root 文脈 必要な操作を高権限で実行する。 低権限操作によって汚染された page を信頼しない必要がある。

したがって、Dirty Frag は、正当な部品が組み合わさった結果、不正な全体構造が生じる事例である。個々の部品は、性能、互換性、暗号処理、ネットワーク処理、ファイル I/O を支えるために必要である。しかし、部品間を移動する対象が \(D\) だけとして扱われ、\(M\) が保存されなければ、安全性は失われる。これは単なる実装ミスではなく、複数の抽象境界をまたぐ設計上の注意点である。

構造として見れば、Dirty Frag の中心は「どの部品が悪いか」ではなく、「部品をつないだときに境界条件が保存されたか」である。read-only であること、shared であること、input であること、低権限操作であること、root 文脈で読まれ得ることは、それぞれ独立した意味ではない。これらが組み合わさったとき、初めて危険な状態が成立する。つまり、脆弱性は単体部品ではなく、部品間の意味接続に生じる。


25. 観測と更新の問題として見る

観測を情報更新として定式化した既稿では、観測とは外界をそのまま写すことではなく、内部状態を更新し、以後の履歴と判断を変える過程であると整理した[38]。セキュリティ運用でも同じである。脆弱性情報、CVE、vendor advisory、kernel package、module 状態、reboot、検証結果は、運用状態を更新する観測点である。これらを観測し、内部状態を更新し、次の行動を決めることが脆弱性対応である。

Dirty Frag のような LPE では、観測が遅れれば、低権限侵害が root 侵害へ増幅される時間が長くなる。観測が粗ければ、patched と unpatched、module disabled と module loaded、updated と rebooted の差を取り違える。観測が不十分なら、ディスク上のハッシュが正常であることをもって、実行時汚染がないと誤認する。つまり、Dirty Frag 対応では、何を観測するかによって、安全判断そのものが変わる。

観測点 更新される判断 観測が粗い場合の誤り
CVE 情報 脆弱性の存在、影響範囲、緊急度を判断する。 CVE 名だけを見て、自分の環境での露出を判断しない。
vendor advisory 対象 package、修正状況、暫定 mitigation を判断する。 配布元ごとの package 名や kernel 系列の違いを見落とす。
ロード済み module esp4、esp6、rxrpc などの入口が現在存在するかを判断する。 blacklist を書いただけで、すでにロード済みの module が消えたと誤認する。
kernel package 修正済み kernel がインストールされているかを判断する。 インストール済みであることと、実行中であることを混同する。
起動中 kernel 実際に修正済み kernel で動作しているかを判断する。 reboot していないため、旧 kernel のまま動いていることを見落とす。
page cache / 実行時状態 汚染された実行時内容が残っている可能性を判断する。 ディスク上のファイルハッシュだけを見て、実行時汚染がないと誤認する。
ログと監査情報 低権限実行や権限昇格の兆候を判断する。 LPE が remote exploit ではないことを理由に、侵害後の増幅可能性を見落とす。

したがって、Dirty Frag 対応は、単なるパッチ適用ではなく、観測、更新、確認、復旧の連鎖である。CVE を知ることで状態が更新される。配布元 advisory を読むことで、自分の OS における影響範囲が更新される。kernel package を更新することで、修正済み code が導入される。reboot することで、実行中 kernel と実行時状態が更新される。起動確認をすることで、安全判断が更新される。必要ならログ確認や cache 汚染対処によって、復旧判断が更新される。

この意味で、Dirty Frag は技術的にも運用的にも、観測と更新の問題である。技術層では、page cache がどの文脈で読まれ、どの意味を持つかを観測しなければならない。運用層では、CVE、advisory、kernel、module、reboot、実行時状態を観測しなければならない。観測が不十分なら、意味を取り違える。意味を取り違えれば、安全だと判断した状態が実際には安全でない可能性が残る。


26. 時間と履歴の問題として見る

時間についての既稿では、時間を不可逆な更新構造として整理し、履歴が増えることによって現在が形成されると論じた[39]。Dirty Frag においても、脆弱性公開、PoC 公開、vendor 対応、kernel 更新、再起動、確認という履歴が運用判断を作る。脆弱性対応は、ある瞬間に一回だけ行う作業ではない。情報が公開され、評価され、配布元に取り込まれ、各環境で適用され、再起動され、確認されるという時間的な連鎖である。

特に重要なのは、脆弱性対応には時間差があることだ。upstream の修正、ディストリビューションへの取り込み、パッケージ配布、各ホストでの更新、再起動、確認は同時には起きない。ある時点では upstream に修正が入っていても、利用中の distribution kernel にはまだ降りてきていない場合がある。別の時点では、修正済み package は提供されていても、host はまだ旧 kernel で起動している場合がある。この時間差が、暫定 mitigation の必要性を生む。

時点 起きること 運用上の意味 誤りやすい判断
脆弱性公開 CVE、write-up、PoC、vendor 情報が公開される。 自分の環境が影響を受けるかを調べる起点になる。 公開された時点で、すべての distribution に修正済み kernel があると誤解する。
upstream 修正 Linux kernel 側で問題経路が修正される。 根本修正の方向が定まる。 upstream に修正があるだけで、自分の host も安全になったと誤解する。
distribution 取り込み Debian、Ubuntu、Red Hat 系などが各 kernel package へ修正を取り込む。 実際に利用可能な修正済み package が提供される。 別 distribution の修正状況を、自分の distribution にそのまま当てはめる。
package 更新 対象 host に修正済み kernel package をインストールする。 修正済み kernel が boot 可能な状態になる。 package 更新だけで、実行中 kernel も更新されたと誤解する。
再起動 host を reboot し、修正済み kernel で起動する。 脆弱な実行中 kernel と古い実行時状態を捨てる。 再起動を後回しにして、対応済みと記録する。
確認 起動中 kernel、module 状態、機能影響、必要なら侵害痕跡を確認する。 対応済みという判断に根拠を与える。 確認を省略し、作業履歴だけで安全状態を判断する。

この意味で、Dirty Frag はカーネル内部の意味保存だけでなく、運用上の履歴管理の問題でもある。どの時点で何が分かっており、どの環境にどの対策が入っており、どの kernel で起動しているかを記録しなければ、対応済みという判断も意味を失う。脆弱性対応における「現在」は、単なる日付ではない。公開情報、配布状況、適用状況、再起動状況、確認結果という履歴の蓄積によって成立する。

したがって、Dirty Frag の運用では、時間差を前提にした管理が必要である。修正済み kernel がまだない時点では、暫定 mitigation によって既知の入口を塞ぐ。修正済み kernel が提供された時点では、更新と再起動を計画する。再起動後には、実際に修正済み kernel で動いていることを確認する。この一連の履歴がそろって初めて、対応済みという判断に意味が生じる。


27. Dirty Pipe、Copy Fail、Dirty Frag をどう読むべきか

Dirty Pipe、Copy Fail、Dirty Frag は、名前が似ているだけではない。いずれも、通常のファイル権限モデルとは別の経路から、実行時に読まれる内容へ影響を与える点でつながっている。Dirty Pipe は pipe buffer 周辺の問題として知られ、Copy Fail は algif_aead と scatterlist、Dirty Frag は xfrm-ESP / RxRPC と skb frag へ広がった。入口は異なるが、ファイル、page cache、pipe、fragment、in-place 処理、実行文脈の境界で意味が壊れるという点では、連続した問題として読める。

この系列を、単に「Dirty 系脆弱性」として表面的に並べるだけでは足りない。重要なのは、ファイル権限、page cache、pipe、fragment、in-place 処理、実行文脈の間で、どの意味が保存されなかったのかを見ることである。名前が似ているから同じだと見るのではない。同じ構造を持つから、比較する価値がある。

脆弱性 主な入口 関係する抽象 壊れる意味 読み取るべき教訓
Dirty Pipe pipe buffer 周辺の処理。 pipe、page cache、buffer flag、file-backed page。 読み取り専用ファイル由来の page と、pipe buffer として扱われる page の意味がずれる。 ファイル権限とは別の経路で page cache に影響が及ぶと、ディスク上の権限モデルだけでは安全を保証できない。
Copy Fail AF_ALG、algif_aead、AEAD socket interface。 splice、page cache、scatterlist、in-place crypto。 read-only file-backed page が、暗号処理の writable destination として扱われ得る。 暗号処理の最適化で、入力 page と出力 page の意味を混同してはならない。
Dirty Frag xfrm-ESP、RxRPC。 MSG_SPLICE_PAGES、pipe pages、skb frag、shared frag、in-place decrypt。 shared page であることが後段へ伝わらず、private copy なしに in-place 処理され得る。 ネットワーク処理や fragment handling でも、page の由来、共有性、書き込み可否を保存しなければならない。

Dirty Frag が示したのは、Copy Fail の教訓が algif_aead 固有ではなかったことだ。Copy Fail を algif_aead の事故としてだけ読むなら、Dirty Frag は別件に見える。しかし、Copy Fail を「読み取り専用由来の page cache が copy されずに別サブシステムへ渡され、後段で in-place に書き換えられる問題」として読むなら、Dirty Frag は同じ教訓の横展開になる。入口は変わる。危険な最適化の形も変わる。しかし、上位の安全意味が下位で失われる場所が危険である、という原理は変わらない。

したがって、Dirty Pipe、Copy Fail、Dirty Frag を読むときには、固有名詞ではなく、意味保存の失敗を見る必要がある。pipe buffer、scatterlist、skb frag は異なる抽象である。しかし、それらはいずれも page を別文脈へ運ぶ。そこで file-backed、read-only、shared、input、root-reachable という意味が保存されなければ、通常の読み取りが実質的な書き換え能力へ変質する。この系列を通じて見えるのは、Linux kernel の高性能化が、意味保存を伴わない場合に権限境界を破るという構造である。


28. Dirty Frag が強化した不変原理

Dirty Frag が強化した不変原理は、次の一文にまとめられる。カーネルの安全性は、権限チェックの一点ではなく、意味保存の連鎖に依存している。入口で権限チェックをしても、その後の処理で file-backed、read-only、shared、input、unprivileged、root-reachable という意味が失われれば、安全性は破れる。逆に、下位レイヤーの最適化がどれほど有効でも、上位レイヤーの制約を消してしまうなら、その最適化は安全性を壊す。

この原理は、Copy Fail にも Dirty Frag にも通用する。Copy Fail では algif_aead の in-place 最適化が問題だった。Dirty Frag では xfrm-ESP と RxRPC の in-place / fragment handling が問題だった。違いは入口であり、本質ではない。両者の共通点は、読み取り専用由来の page cache が、別サブシステムの内部表現に包まれたあと、入力であるという意味と書き込み禁止であるという意味を十分に保持できなかった点にある。

不変原理 技術層での意味 運用層での意味
byte 列だけでなく意味を保存する。 page の provenance、writability、sharing、direction をサブシステム境界で失わせない。 CVE 番号だけでなく、自分の環境における露出、機能利用、実行経路を見る。
read-only file-backed shared page を output にしない。 shared page なら private copy を作るか、in-place 処理を避ける。 暫定 mitigation で入口を塞ぎ、最終的には修正済み kernel へ移行する。
暫定対策と根本対策を混同しない。 module 無効化は既知入口を閉じるだけで、処理経路の修正ではない。 kernel update、reboot、起動確認までを対応完了の条件にする。
実行時状態を安全判断に含める。 ディスク上のファイルが無傷でも、page cache が汚染されていれば実行時意味は変わる。 必要に応じて drop_caches、reboot、ログ確認、侵害可能性の評価を行う。
個別 CVE ではなく bug class を見る。 algif_aead、xfrm-ESP、RxRPC という名前ではなく、不変条件の破れを見る。 脆弱性の洪水では、CVE 単位ではなく露出と横展開可能性で優先順位を決める。

この表から分かるように、Dirty Frag が強化したのは、特定モジュールの危険性ではない。Dirty Frag が強化したのは、上位レイヤーの安全意味を下位レイヤーへ運ばなければならないという原理である。Copy Fail の段階では、この原理は algif_aead と scatterlist の問題として見えやすかった。Dirty Frag によって、同じ原理が xfrm-ESP、RxRPC、skb frag という別領域にも現れることが分かった。つまり、Dirty Frag は Copy Fail の教訓を否定したのではなく、抽象度を上げた。

したがって、不変原理は単なるスローガンではない。設計では、page の由来、共有性、書き込み可否、入力と出力の区別を保持する必要がある。実装では、in-place 処理の前に、対象 page が本当に書き換えてよい領域かを判断する必要がある。運用では、暫定 mitigation と kernel update と reboot を区別する必要がある。脆弱性管理では、CVE 番号ではなく、自分の環境における露出と到達可能性を見る必要がある。これらはすべて、意味保存の連鎖という同じ原理に従っている。


29. 結論

Dirty Frag は、Copy Fail の教訓を書き換えたのではない。Copy Fail の教訓を、個別モジュールの危険から、カーネル設計上の意味保存原理へ引き上げた。Copy Fail の時点では、問題は algif_aead、AF_ALG、scatterlist、page cache の結合として見えた。Dirty Frag によって、同じ種類の問題が xfrm-ESP、RxRPC、skb frag、shared frag、in-place decrypt の結合としても成立することが示された。入口は変わったが、壊れた構造は同じである。

個別対策は変わる。Copy Fail では algif_aead が焦点だった。Dirty Frag では esp4、esp6、rxrpc が焦点になる。Debian、Ubuntu、AlmaLinux、Red Hat などの対応状況も時間とともに変わる。しかし、最終的に修正済み kernel へ更新し、再起動し、実際にその kernel で起動していることを確認するという運用原則は変わらない。module blacklist、rmmod、drop_caches は、それぞれ有用な場面を持つが、根本対策ではない。根本対策は、壊れた意味保存の経路が修正された kernel で動くことである。

根本的には、安全性とは byte 列の保護ではなく、byte 列に付随する意味の保存である。file-backed であること、read-only であること、shared page cache であること、入力であること、低権限主体の操作であること、後で root 文脈で読まれ得ること。これらの意味がサブシステム境界を越えて保存される限り、安全性は維持される。これらの意味が最適化によって剥落したとき、読み取り権限は実質的な書き換え能力へ変質し、LPE が成立する。

最終教訓 意味
上位レイヤーの制約が、下位レイヤーの最適化で消える場所が危険である。 file permission、page cache、pipe、scatterlist、skb frag、in-place 処理の境界で、read-only や shared という意味が保存されなければ、権限境界は破れる。
暫定対策は入口を塞ぐが、不変原理を修正しない。 algif_aead、esp4、esp6、rxrpc の無効化は時間稼ぎであり、最終的には修正済み kernel への更新と reboot が必要である。
LPE は侵入口ではなく増幅器として評価する。 remote exploit ではなくても、SSH、Web shell、CI runner、container などの低権限実行経路と結合すれば、root 化の実務的リスクになる。
CVE ではなく露出を管理する。 脆弱性の数が増える時代には、CVE 番号や CVSS だけでなく、自分の環境での到達可能性、修正可能性、再起動可能性を見る必要がある。
AI 時代には bug class の横展開を見る。 一つの脆弱性が見つかったとき、同じ不変条件違反が別サブシステムで成立しないかを調べる必要がある。

したがって、Dirty Frag から得るべき最終教訓は、次である。上位レイヤーの制約が、下位レイヤーの最適化で消える場所が危険である。これは Copy Fail の時点でも見えていたが、Dirty Frag によって、より強く確認された。教訓は書き換わらない。むしろ、不変原理として強化された。


参考文献

  1. id774, CVE-2026-31431 について徹底的に考える(2026-05-06). https://blog.id774.net/entry/2026/05/06/4730/
  2. V4bel, dirtyfrag. GitHub. https://github.com/V4bel/dirtyfrag
  3. V4bel, dirtyfrag/assets/write-up.md. GitHub. https://github.com/V4bel/dirtyfrag/blob/master/assets/write-up.md
  4. Microsoft Defender Security Research Team, Active attack: Dirty Frag Linux vulnerability expands post-compromise risk. https://www.microsoft.com/en-us/security/blog/2026/05/08/active-attack-dirty-frag-linux-vulnerability-expands-post-compromise-risk/
  5. Tenable, Dirty Frag (CVE-2026-43284,CVE-2026-43500). https://www.tenable.com/blog/dirty-frag-cve-2026-43284-cve-2026-43500-frequently-asked-questions-linux-kernel-lpe
  6. NVD, CVE-2026-43284 Detail. https://nvd.nist.gov/vuln/detail/CVE-2026-43284
  7. Debian Security Tracker, CVE-2026-43284. https://security-tracker.debian.org/tracker/CVE-2026-43284
  8. Ubuntu, Dirty Frag Linux kernel local privilege escalation vulnerability fixes available. https://ubuntu.com/blog/dirty-frag-linux-vulnerability-fixes-available
  9. Ubuntu Security, CVE-2026-43284. https://ubuntu.com/security/CVE-2026-43284
  10. Ubuntu Security, CVE-2026-43500. https://ubuntu.com/security/CVE-2026-43500
  11. AlmaLinux, Dirty Frag (CVE-2026-43284, CVE-2026-43500). https://almalinux.org/blog/2026-05-07-dirty-frag/
  12. Red Hat, CVE-2026-43284. https://access.redhat.com/security/cve/cve-2026-43284
  13. Sophos, Advisory: Linux Kernel LPE – Dirty Frag. https://www.sophos.com/en-us/security-advisories/sophos-sa-20260508-dirtyfrag
  14. Elastic Security Labs, Copy Fail and DirtyFrag: Linux Page Cache Bugs in the Wild. https://www.elastic.co/security-labs/copy-fail-dirtyfrag-linux-page-bugs-in-the-wild
  15. Qualys, Dirty Frag: Using the Page Caches as an Attack Surface. https://blog.qualys.com/product-tech/vulnmgmt-detection-response/2026/05/09/dirty-frag-using-the-page-caches-as-an-attack-surface
  16. CERT-EU, High Vulnerability in the Linux Kernel “Copy Fail”. https://cert.europa.eu/publications/security-advisories/2026-005/
  17. NVD, CVE-2026-31431 Detail. https://nvd.nist.gov/vuln/detail/CVE-2026-31431
  18. Microsoft Defender Security Research Team, CVE-2026-31431: Copy Fail vulnerability enables Linux root privilege escalation across cloud environments. https://www.microsoft.com/en-us/security/blog/2026/05/01/cve-2026-31431-copy-fail-vulnerability-enables-linux-root-privilege-escalation/
  19. Cloudflare, How Cloudflare responded to the “Copy Fail” Linux vulnerability. https://blog.cloudflare.com/copy-fail-linux-vulnerability-mitigation/
  20. Linux Kernel Documentation, User Space Interface. https://docs.kernel.org/crypto/userspace-if.html
  21. Linux Kernel Documentation, RxRPC Network Protocol. https://docs.kernel.org/networking/rxrpc.html
  22. Ubuntu Manpages, rxrpc(7). https://manpages.ubuntu.com/manpages/jammy/man7/rxrpc.7.html
  23. Linux Kernel Documentation, Linux Networking and Network Devices APIs. https://docs.kernel.org/networking/kapi.html
  24. LWN.net, crypto: af_alg – Remove zero-copy support from AF_ALG. https://lwn.net/Articles/1071203/
  25. Sysdig, Dirty Frag (CVE-2026-43284 and CVE-2026-43500). https://www.sysdig.com/blog/dirty-frag-cve-2026-43284-and-cve-2026-43500-detecting-unpatched-local-privilege-escalation-via-linux-kernel-esp-and-rxrpc
  26. Wiz, Dirty Frag (CVE-2026-43284) Linux Privilege Escalation. https://www.wiz.io/blog/dirty-frag-linux-kernel-local-privilege-escalation-via-esp-and-rxrpc
  27. Unit 42, Copy Fail: What You Need to Know About the Most Severe Linux Kernel Vulnerability. https://unit42.paloaltonetworks.com/cve-2026-31431-copy-fail/
  28. Bugcrowd, What we know about Copy Fail (CVE-2026-31431). https://www.bugcrowd.com/blog/what-we-know-about-copy-fail-cve-2026-31431/
  29. Theori, CVE-2026-31431: Copy Fail. https://theori.io/blog/cve-2026-31431-copy-fail
  30. CISA, Known Exploited Vulnerabilities Catalog. https://www.cisa.gov/known-exploited-vulnerabilities-catalog
  31. Tenable, Why the approaching flood of vulnerabilities changes everything — and what to do about it. https://www.tenable.com/blog/why-the-approaching-flood-of-vulnerabilities-changes-everything-and-what-to-do-about-it
  32. id774, Claude Mythos は世界をどう変えたのか(2026-05-08). https://blog.id774.net/entry/2026/05/08/4737/
  33. id774, Ubuntu 26.04 LTS の設計と運用判断(2026-04-12). https://blog.id774.net/entry/2026/04/12/4406/
  34. id774, バックアップとは復元可能性を設計することである(2026-05-07). https://blog.id774.net/entry/2026/05/07/4728/
  35. id774, バックアップ・リカバリー戦略における物理媒体管理の考え方(2026-05-10). https://blog.id774.net/entry/2026/05/10/4743/
  36. id774, 意味は差異の読み取りから生まれる(2026-05-09). https://blog.id774.net/entry/2026/05/09/4740/
  37. id774, 構造・時間・生命・意味・知能・自己・AI を生成連鎖として説明する(2026-04-14). https://blog.id774.net/entry/2026/04/14/4438/
  38. id774, 観測を情報更新として定式化する宇宙論(2026-03-30). https://blog.id774.net/entry/2026/03/30/4239/
  39. id774, 時間はなぜ一方向に進むのか(2026-04-26). https://blog.id774.net/entry/2026/04/26/4613/