
Cilium Tetragon TracingPolicy を使用して、実行時に DirtyFrag Linux LPE チェーン (CVE-2026-43284 / CVE-2026-43500) をブロックする
実行中に DirtyFrag Linux 特権昇格チェーン (CVE-2026-43284 / CVE-2026-43500) を、Cilium Tetragon の TracingPolicy でブロックします。このポリシーは、一般に公開されている概念実証コードを、ソケットセットアップ段階で SIGKILL し、ルート権限を得るページキャッシュ書き込みに到達する前に阻止します。
これが何か。 ラボのレポートです。初めて Tetragon をセットアップし、実際の最新カーネル LPE を止められるかどうかを確認したかったのです。止められました。この文書では、実行した内容、発動した内容、そして同様に重要なこととして、それが証明することの限界を正確に記録しています。これは パッチ適用の代替ではありません。
ファイル: この README(自己完結型、証拠をインラインで掲載)・block-dirtyfrag.yaml(ポリシー)
| エクスプロイト | DirtyFrag - 公開 PoC: V4bel/dirtyfrag |
| CVE | CVE-2026-43284(xfrm-ESP ページキャッシュ書き込み)、CVE-2026-43500(RxRPC ページキャッシュ書き込み) |
| ホスト | Ubuntu 24.04.4 LTS、Tetragon v1.7.0(スタンドアロン、systemd) |
ベースライン - ポリシーなし、カーネル 6.8.0-88(脆弱) | PoC → uid=0(root) |
ポリシーあり - カーネル 6.8.0-88 | PoC が socket(AF_RXRPC) で SIGKILL され、ユーザーは uid=1000 のまま |
パッチ適用済みカーネル 6.8.0-134 | PoC は単体で失敗(rc=4)。ソケットフックは依然として発動。検出であり、緩和ではない([注](#パッチ適用済みカーネル-680-134 に関する注記)) |
| 制御の性質 | 補完的制御/仮想パッチ。カーネルの修正ではない |
DirtyFrag は、Linux カーネルにおける 2 つの独立したページキャッシュ書き込みプリミティブ(一方は xfrm/ESP (IPsec) のインプレース復号パス内 (CVE-2026-43284)、もう一方は RxRPC パス内 (CVE-2026-43500))から構成されるローカル特権昇格チェーンです。それぞれにより、権限のないローカルユーザーが、攻撃者が制御するバイトを読み取り専用のページキャッシュページ(例えば、/bin/su のような setuid-root バイナリのキャッシュイメージ)に書き込むことができ、そこからルート権限を取得できます。書き込みはメモリ内のみで行われ、ディスク上のファイルは変更されないため、ファイル整合性監視では検出できません。これは Dirty Pipe や Copy Fail と同じバグクラスです。2 つの CVE は意図的に連鎖されています。特定の環境で一方のパスが利用できない場合でも、もう一方が機能します。
このホストでは、非特権ユーザーネームスペースが AppArmor によって制限されているため(kernel.apparmor_restrict_unprivileged_userns = 1)、チェーンの ESP 部分はブロックされます。そのため残るのは RxRPC パス であり、AF_RXRPC ソケット(アドレスファミリ 33)を開きます。このポリシーが殺すのはそのステップです。
本当の修正はパッチ適用済みカーネルです。 ここにあるものはすべて、まだパッチを適用できないホストのための暫定措置です。Ubuntu はこのテストより前に DirtyFrag の修正を出荷しているため、これは既知の N-day であり、生の 0-day ではありません。ポイントは、何らかの理由で脆弱なカーネルを実行し続けているホストで、ランタイム制御が何ができるかを示すことです。
完全なポリシー: block-dirtyfrag.yaml。2 つの kprobe をインストールします。
フック 1 - グルーミングソケット(sys_socket)。 耐荷重制御。エクスプロイトの RxRPC パスは、カーネルモジュールが既にロードされているかどうかに関わらず、毎回 socket(AF_RXRPC, …) を呼び出す必要があります。ポリシーはアドレスファミリに基づいて一致します:
AF_RXRPC)→ Sigkill。 AFS クライアントではないホストでは、AF_RXRPC ソケットを開く正当なものは事実上存在しないため、ここでの完全な kill は安全で信頼性が高いです。AF_ALG)→ Post(監査のみ、kill なし)。 AF_ALG はユーザー空間のカーネル暗号 API であり、正当な利用者(cryptsetup、libkcapi ツール、一部の FIPS ワークフロー)が存在します。ファミリだけで kill すると誤検出が発生するため、この部分はログのみ行います。強制への道筋は次のとおりです:しばらく監査して、実際に観測されたバイナリから NotIn 許可リストを作成し、その後 Sigkill への昇格を検討します。フック 2 - 脆弱なモジュールの自動ロード(security_kernel_module_request)。 多層防御。カーネルが脆弱なモジュールファミリ(esp4、esp6、rxrpc、net-pf-33/net-pf-38 ソケットエイリアス、pcbc/fcrypt 暗号テンプレート)の自動ロードを要求されたときに発動します。制限事項: モジュールがまだ常駐していない場合にのみ発動します。最初のエクスプロイト実行後、これらのモジュールはロードされ、このフックは沈黙します。これはコールドブートレイヤーであり、主要な制御ではありません。
合わせて:フック 1 はモジュールがウォームでもコールドでもエクスプロイトをキャッチします。フック 2 はコールドホストでより早期の、より特異的なトリップを追加します。
6.8.0-88-generic でのものです(ベースラインはルートに到達します)。このマシンには 6.8.0-134-generic(パッチ適用済みカーネル)もインストールされており、これは直接確認されています:-134 に再起動すると、ポリシーの有無に関わらず PoC は単体で失敗します(rc=4、ルートなし)([下記の注](#パッチ適用済みカーネル-680-134 に関する注記) を参照)。緩和デモを再現するには、GRUB から 6.8.0-88 を起動してください(まだインストールされています)。パッチ適用済みカーネルでは緩和すべきものはありません。AF_ALG 部分は注意が必要です。lockdown,capability,landlock,yama,apparmor — bpf はなし)。そのため、強制には kprobe からの Sigkill を使用し、カーネル内 LSM による拒否は使用しません。kill は socket() システムコールで発生します。これは書き込みプリミティブより前であるため、プロセスを必須の早期ステップで終了させ、「脆弱性そのものをブロック」するのではありません。手順 1~5 はすべて同じ 6.8.0-88 ブートからのものです(脆弱なカーネル)。
1. 環境 - Ubuntu 24.04.4、カーネル 6.8.0-88-generic、Tetragon v1.7.0 が systemd でアクティブ、非特権 userns は制限付き。
$ uname -r
6.8.0-88-generic
$ tetra version
CLI version: v1.7.0
$ systemctl is-active tetragon
active
2. 前提条件(ポリシー OFF) - クリーンな開始点:脆弱なモジュールは常駐せず、xfrm 状態なし、ポリシー未ロード。
$ lsmod | grep -E 'esp4|esp6|rxrpc' || echo "(none loaded)"
(none loaded)
$ sudo ip xfrm state # (empty)
$ sudo tetra tp list
ID NAME STATE FILTERID NAMESPACE SENSORS KERNELMEMORY MODE NPOST NENFORCE NMONITOR
3. ベースライン(ポリシー OFF)- エクスプロイトが動作する。 これによりカーネルが実際に脆弱であることが証明されます。レポート全体はこれに基づいています。
$ ./exp ; id
uid=0(root) gid=0(root) groups=0(root)
4. ポリシーをロードする。
$ sudo tetra tp add /etc/tetragon/tetragon.tp.d/block-dirtyfrag.yaml
tracing policy "…/block-dirtyfrag.yaml" added
5. 強制(ポリシー ON)- kill。 エクスプロイトは socket() 呼び出しで シグナルにより 終了され、su に到達しません。
🚀 process /home/…/dirtyfrag/exp
❓ syscall /home/…/dirtyfrag/exp __x64_sys_socket
Kernel:
0x0: __x64_sys_socket+0x5
0x0: do_syscall_64+0x7f
0x0: entry_SYSCALL_64_after_hwframe+0x78
💥 exit /home/…/dirtyfrag/exp SIGKILL
構造化イベントは、一致と kill の両方を確認します。ソケットシステムコールに対する process_kprobe、続いて同じ PID に対するシグナルによる process_exit です。
// process_kprobe — AF_RXRPC 一致
{ "process_kprobe": {
"process": { "pid": 24083, "uid": 1000, "binary": ".../dirtyfrag/exp" },
"function_name": "__x64_sys_socket",
"args": [ { "int_arg": 33, "label": "family" } ],
"policy_name": "block-dirtyfrag",
"action": "KPROBE_ACTION_POST"
} }
// process_exit — 同じ PID、シグナルで kill
{ "process_exit": {
"process": { "pid": 24083, "binary": ".../dirtyfrag/exp" },
"signal": "SIGKILL"
} }
kprobe の action が KPROBE_ACTION_POST と表示されるのは、Post アクションが可視イベントを出力するためです。Sigkill アクションが別個の SIGKILL 終了を生成します。2 つのイベントが一緒になって、一致と kill の証拠となります。
注: 生の
07キャプチャには、以前のリビジョンのポリシーからのmessage文字列も含まれています(AF_ALG部分が監査専用に分割される前のもの)。family: 33一致と結果のSIGKILLはリビジョン間で同一であり、異なるのはそのテキストだけです。
脆弱なカーネルでの実行後、ホストを 6.8.0-134-generic(Ubuntu のパッチ適用済みカーネル)に再起動し、PoC を再度実行しました。
$ ./exp # ポリシー OFF
dirtyfrag: failed (rc=4) # エクスプロイトは単体で失敗 — ルート権限なし
$ ./exp # ポリシー ON
Killed # socket(AF_RXRPC) で SIGKILL
これが示す内容を正確に説明します:
rc=4、ルートなし)。ポリシーが防ぐべきものは何もありません。緩和の主張を支える前後比較は、脆弱な -88 カーネルにのみ存在します。socket(AF_RXRPC) を呼び出すため、Tetragon はパッチ適用済みカーネルでもパッチ未適用カーネルと同様に SIGKILL し、ログに試行を表示します。これは 試行の検出 および多層防御として価値がありますが、動作しているエクスプロイトを停止することとは異なります。AF_RXRPC は正当であり、全面的な kill はそれを壊します。ノードごとに確認してください。AF_ALG 部分は設計上監査専用です。 モジュールが既にウォームである状態で のみ AF_ALG パスを使用する亜種は、その部分を強制に昇格させるまで(許可リスト作成後)、ログに記録されるだけで kill されません。AF_RXRPC ソケットが書き込みプリミティブより前に開かれるため、これが機能します。この順序が早期 kill を効果的にする理由ですが、考えられるすべてのエクスプロイトについて保証するものではありません。セットアップ: Tetragon v1.7.0 スタンドアロン、systemctl で起動。ポリシーは tetra tracingpolicy add で読み込み。