
CVE-2025-8045のDirty Pagetableエクスプロイト
CVE-2025-8045 は Arm Mali GPU カーネルドライバー(kbase)の use-after-free であり、このエクスプロイトはローカル権限昇格を実現します。非特権のローカルプロセスが CSF KCPU キューのダンプパスと競合させて cpu_queue.buffer を解放・再取得し、解放済みアロケーションを自分が所有するページテーブル("dirty pagetable")に変え、そのプリミティブを使って任意のカーネル物理メモリ読み書きを獲得し、最終的に SELinux を permissive に設定した root シェルを取得します。
Pixel 7 Pro(ビルド
BP3A.250905.014)で実証済み。exploit.cにハードコードされたオフセットはこのターゲット向けに調整されています。他のデバイス/ビルドではオフセットの再導出が必要です(チューニングと移植性 を参照)。
CVE-2025-8045 は、Arm Valhall および第 5 世代 GPU アーキテクチャのカーネルドライバー(r53p0–r54p1)における use-after-free です。ローカルの非特権プロセスが GPU 処理操作を操作することで、ドライバーが解放済みメモリに対して動作し続ける状態を作り出し、カーネルメモリの漏えい、破壊、コード実行への扉を開きます。
このエクスプロイトは、/dev/mali0 が公開する CSF KCPU キューインターフェースを通じてバグに到達します。
CQS_WAIT に続いて FENCE_SIGNAL を指定してアームされます。この待機によりキューが停止し、フェンスタイマーが後で、予測可能なタイマーホイールのバケット境界で発火します。KBASE_IOCTL_CS_CPU_QUEUE_DUMP は kbase_csf_cpu_queue_dump_buffer() を駆動します。キューの状態遷移(ISSUED → COMPLETE/PENDING)をダンプパスと競合させることで、参照が残っている間に cpu_queue.buffer が解放されます — これが UAF です。このエクスプロイトはタイミング攻撃です。まずデッドラインを較正し、各ラウンドでそれを予測して、解放の瞬間を挟むレースウィンドウを広げるために無害なダンプ呼び出しの「ウェーブ」を発射します。
| 段階 | 内容 |
|---|---|
| 較正 | ラウンド 1 で ISSUED→COMPLETE のエッジを計測し、タイマーホイールのバケット位相を学習します。 |
| 予測+スイープ | 後続のラウンドでデッドラインを予測し、読み取りオフセットを ±ms スイープして解放のタイミングに正確に合わせます。 |
| Wave | 64 スレッドが CS_CPU_QUEUE_DUMP 呼び出しを csf.lock に集中させ、デッドラインを挟んでウィンドウを広げます。 |
| 再利用(リクレーム) | UNMOVABLE フリーリストを事前に枯渇させ、スタンプ付き GPU ページをスプレーして解放されたブロックを自らの制御下に戻します。 |
| Dirty pagetable | 再度解放し、直ちに同じページへ CPU ページテーブルをスプレーします。GPU アロケーションは、生存している最終レベルテーブルにエイリアスします。 |
| 任意読み書き | 再利用されないウィンドウ PTE をカーネル物理ページに向け、大きなスクラッチマッピング上で PROT_NONE ラウンドトリップにより TLB を強制フラッシュします。 |
| Root | selinux_state.enforcing をクリアし、sel_read_enforce を commit_creds(init_cred) でパッチし、待機中の子プロセスを解放して root シェルを exec させます。 |
1 つのページが Mali アロケーションであると同時に生存中の CPU ページテーブルにもなるため、プロセスは終了せずに**永久に待機(パーク)**します。解放すると二重解放になり、カーネルがパニックするためです。
# Android / arm64 (NDK)
aarch64-linux-android31-clang -O2 -o exploit exploit.c
./exploit
成功すると、SELinux permissive の root シェル(uid=0)が得られます。実行例:
[*] pid=... cpus=8 wave=64 harvest cpu=7 rounds=256
[*] round 1 calibrate deadline t0+... ms phase ... ms
[*] round N read +... us
[+] UAF page: spray region R page P @ ..., 1 live descriptor
[+] entry 0 = ... -- a CPU page table, writable through the GPU
[+] alias: dirty pagetable
[+] selinux_state.enforcing = 0 @ phys ...
[+] sel_read_enforce patched @ phys ...
[+] root shell: uid=0 euid=0
全ラウンドを勝利なしで終えた場合、dmesg 内の cpu_queue.c:71 はレースが着弾しているがリクレーム(再利用)が外れたことを示します。リクレーム/ウェーブのパラメーターを調整してください。
exploit.c 内の値は Pixel 7 Pro(ビルド BP3A.250905.014)向けに較正されています。オフセットと定数はデバイス/カーネル固有であり、他のターゲットでは再導出が必要です。
KERNEL_PA_BASE, SEL_READ_ENFORCE, INIT_CRED, COMMIT_CREDS, SELINUX_STATE — カーネルシンボル/物理オフセット。ARM64_PTE_FLAGS — ターゲット MMU 構成向けの最終レベルディスクリプタテンプレート。WAVE_*, SWEEP_*, BUCKET_NS, WAIT_NS、スプレーサイズ — レースのタイミングとヒープグルーミングの調整パラメーター。対策として、Arm が提供する修正済みドライバーリリースに更新してください。
このコードは、セキュリティ防御研究、検知エンジニアリング、および教育の目的に限って公開されています。自分が所有していない、または明示的な書面によるテスト許可がないシステムに対して実行しないでください。作者は、誤用または引き起こされた損害について一切の責任を負いません。許可なくシステムに対して使用することは違法です。