Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2026-64468 — 権限のない概念実証と、LinuxカーネルBinderのuse-after-free(CVE-2026-64468)に対するx86_64ローカル権限昇格。KASANラボと、脆弱/修正版の差分比較を備えています。 | Kitploit
ツール/GitHubGitHub/aramosf/cve-2026-64468
特権昇格エクスプロイトフレームワーク脆弱性分析エクスプロイト学習と教育バイナリエクスプロイト
GitHubaramosf/cve-2026-64468

CVE-2026-64468

権限のない概念実証と、LinuxカーネルBinderのuse-after-free(CVE-2026-64468)に対するx86_64ローカル権限昇格。KASANラボと、脆弱/修正版の差分比較を備えています。

リポジトリを見る
115日前未レビュー

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

CVE-2026-64468 — LinuxカーネルBinder binder_free_transaction() のプロセスライフタイムuse-after-free

ライブQEMU/KVM実行: パッチ未適用の脆弱なカーネルがuse-after-freeを報告し、修正済みカーネルは報告しない

このリポジトリには、上流コミット f223d27a546c1e1f48d38fd67760e78f068fe8c4 によって修正されたLinuxカーネルBinderのuse-after-freeに関する以下の内容が含まれています:

  • binder_chain_64468.c — バグに到達し、カーネルにそれを証明させる非特権の概念実証。KASANラボと、脆弱/修正済みの差分検証(lab/、run.sh、verify.sh)を備えています。
  • exploit.c — x86_64向けの自己完結型ローカル権限昇格。gcc -O2 -pthread -o exploit exploit.c でコンパイルし、通常ユーザーとして実行すると、rootシェルで終了します。
  • demo/ — パッチ未適用のカーネル上で実際のDebian 13ユーザーランドを起動するラボ。エクスプロイトを標的自身のgccでコンパイルし、乗っ取る対象のマシン上で実行できます。

すべては、いかなる種類のパッチも適用されていないストックの上流カーネルに対して、通常ユーザー(uid/gid 1000、ケーパビリティなし、名前空間なし)として実行されます。

警告

このコードは意図的にカーネルオブジェクトのライフタイムを競合させ、その後カーネルの制御フローを乗っ取ります。競合に負けるとカーネルのヒープ状態が破損し、マシンがパニックまたはハングする可能性があります。所有する隔離された使い捨てVMでのみ実行してください。ホスト上では実行しないでください。

ステータスと範囲

脆弱性

binder_free_transaction() は、t->lock の下でトランザクションから対象プロセスを読み出し、そのロックを解放した後、対象の内部ロックを取得します:```c spin_lock(&t->lock); target_proc = t->to_proc; spin_unlock(&t->lock);

root@kitploit:~
if (target_proc) {
	binder_inner_proc_lock(target_proc);   /* use after free */
root@kitploit:~
Nothing keeps `target_proc` alive across that gap. A process that is being torn
down in parallel can reach `binder_proc_dec_tmpref() -> kfree()` in between, so
the lock is taken on freed memory. The upstream fix pins `t->to_thread` while
`t->lock` is still held, which keeps the owning process alive until the inner
lock has been used and released.

The vulnerability was reported by **Alice Ryhl** and fixed by **Carlos
Llamas**, both of Google. The
[original report](https://lore.kernel.org/all/[email protected]/)
carries the reference KASAN trace.

### Reaching the vulnerable access

The only caller that can reach a *foreign* `to_proc` is
`binder_send_failed_reply()`, and it only walks to `t->from_parent` when
`t->from` is `NULL`:

このギャップの間、`target_proc` を生かし続けるものは何もない。並行して破棄
されているプロセスは、その間に `binder_proc_dec_tmpref() -> kfree()` に到達
できるため、解放済みメモリ上でロックが取得されることになる。上流の修正では、
`t->lock` が保持されている間 `t->to_thread` をピン留めし、内側のロックが使用
されて解放されるまで所有プロセスを生かし続ける。

この脆弱性は、Google の **Alice Ryhl** によって報告され、同じく Google の
**Carlos Llamas** によって修正された。[元のレポート](https://lore.kernel.org/all/[email protected]/)
には、参照となる KASAN トレースが記載されている。

### 脆弱なアクセスに到達する方法

*外部* の `to_proc` に到達できる唯一の呼び出し元は
`binder_send_failed_reply()` であり、`t->from` が `NULL` の場合にのみ
`t->from_parent` へと辿る:```c
	target_thread = binder_get_txn_from_and_acq_inner(t);
	if (target_thread) { ...; binder_free_transaction(t); return; }
	next = t->from_parent;
	binder_free_transaction(t);
	t = next;

from_parent は正確に 1 か所でのみ代入され、その代入は数行前にバインダーの 不正なトランザクションスタック チェックによって保護されています。つまり、スレッドは、そのスタックの先頭が自身が 受信している トランザクションである場合にのみ、同期トランザクションを送信できます。したがって、そのチェーンのすべてのリンクについて、子の送信者と親の受信者は 同じスレッド です。

これには重大な結果があります。binder_thread_release() は、終了するスレッドのスタックを proc->inner_lock を保持したまま走査し、以下の両方を書き込みます。``` iteration j : [holds child->lock ] child->from = NULL ; unlock child->lock spin_lock(parent->lock) iteration j+1 : [holds parent->lock] parent->to_proc = NULL

root@kitploit:~
`binder_chain_64468.c`は、脆弱なアクセスに到達する最短のチェーンを構築するため、そのギャップ内でのウォーカーの作業はbinderが許す限り小さくなります — 2回の`t->lock`取得と1回の`kfree()`で、外部の`inner_proc_lock`も`wake_up`も応答配信もありません:

in **adjacent iterations of a single walk**, each under the respective
`t->lock`. A walker learns `child->from == NULL` only once the walk has released
`child->lock`, and needs `parent->lock` for its own snapshot. So the entire
opportunity is the gap between that walk's `spin_unlock(&child->lock)` and its
`spin_lock(&parent->lock)` — a couple of instructions. The release walk holds a
spinlock and cannot be preempted there; only an interrupt can delay it.

This is why the race is narrow and why both the proof of concept and the
exploit are probabilistic.

### What the proof of concept builds

`binder_chain_64468.c` constructs the shortest chain that reaches the
vulnerable access, so the walker's work inside that gap is as small as binder
allows — two `t->lock` acquisitions and one `kfree()`, with no foreign
`inner_proc_lock`, no `wake_up` and no reply delivery:```
  B thread i   --e2 (sync, code 0x4442414b)-->  P thread Y_i
  P thread Y_i --e1 (sync, code 0x54414c4c)-->  B thread i   (nested target)

  B thread i   stack: [ e2 outgoing , e1 incoming (top) ]
  P thread Y_i stack: [ e2 incoming , e1 outgoing (top) ]

P がそのバインダー fd をドロップすると、binder_deferred_release() が Y_1..Y_K を解放し、最終的に binder_proc を解放する一方、すべての B スレッドが 同時に BINDER_THREAD_EXIT を発行します:``` binder_thread_release(B_i) nulls e1->to_proc (own proc) and e2->from binder_send_failed_reply(e1) e1->from == NULL once Y_i was released -> binder_free_transaction(e1) target_proc already NULL, kfree(e1) -> binder_free_transaction(e2) target_proc == P <-- vulnerable access

root@kitploit:~
第三のプロセスはバインダーコンテキストマネージャであり、他の2つが必要とするハンドルを配布するためだけに使用される。`exploit.c`はこの正確な構造を再利用する。

### 2つの独立した条件

KASANレポートには次の両方が必要である:

* **脆弱なアクセス** — ウォーカーが上記の狭いウィンドウ内で`parent->lock`を取得し、まだ生存している`to_proc`のスナップショットを取得すること;および
* **ウィンドウ内での解放の着地** — ウォーカーが`t->lock`を解放してから被害者の内部ロックを取得するまでの間にCPUを失い、遅延解放が完了して`binder_proc`が解放されるまでCPUに戻らないこと。

最初の条件にはKASANを必要としない独自のオラクルがある:バインダーは次のように出力する。```
binder: binder_free_proc: Unexpected outstanding_txns -1

それが発生するたびに、ウォーカーとbinder_thread_release()の両方が1つのトランザクションに対して同じカウンタをデクリメントするためです。これはそれ自体では脆弱性/修正済みの差分ではないことに注意してください — 修正は解放を止めるものであり、2回目のデクリメントを止めるものではないため、両方のカーネルに現れます。ここでは、脆弱なコードパスが実行されていることを示すためだけに使用されています。

use-after-freeからrootへ

概念実証は、解放されたメモリへの4バイトのデクリメントで停止します。それをuid 0にするには4つの要素が必要であり、そのどれもバグ自体からは得られません。バグは何も漏洩させないからです。

1. 共有キャッシュ

struct binder_procは648バイトで、通常のGFP_KERNELのkzalloc — __GFP_ACCOUNTではない — で割り当てられます。そのため、同じサイズの他のすべての非アカウント割り当てとともにkmalloc-1kに入り、kmalloc-cg-*の背後に隔離されません。この単一の事実が、オブジェクトをそもそも再利用可能にしているのです。

2. 追いつく再利用ポンプ

kfree()の瞬間はユーザー空間からは観測できず、ウォーカーが再びオブジェクトに触れる瞬間も同様です。したがって、タイミングを合わせる対象はありません。そのため、スプレーはポンプとして実行されます。つまり、遅延解放を実行したCPU上で、ウォーカーが実行されている間、kmalloc-1kオブジェクトの割り当てと解放を継続的に行います。

これにはSystem Vメッセージが使用されます。alloc_msg()は、48バイトのヘッダーとペイロードからなる通常の非アカウントkmallocであるため、976バイトのメッセージは1024バイトの割り当てになります。クォータはuidごとではなくキューごとであり、msgrcv()は同期的に解放します。測定されたスループット: 毎秒約198,000回の割り当て、失敗ゼロ。

add_key/user_key_payloadが最初に試されましたが、これは罠です。そのペイロードはuidごとのバイトクォータ(kernel.keys.maxbytes、デフォルト20000)に対して課金され、これはキーガベージコレクタがキーを破棄したときにのみ解放されます。そのため、タイトな割り当て/解放ループはミリ秒単位でこれを枯渇させます。測定結果: 2,121,009回の失敗に対して27,151回の成功した割り当て — スプレーの98.7%が静かに何もしておらず、これはスロットを獲得できないスプレーとまったく同じように見えます。KEYCTL_INVALIDATEは状況を悪化させました(4,775回の成功)。GC作業をキューに入れるためです。

3. 再利用されたオブジェクトが含まなければならないもの

ウォーカーは解放されたbinder_procの4つのフィールドに触れます(オフセットはターゲットビルドでpaholeを使用して測定):

outstanding_txns == 1かつis_frozen == 1の場合、デクリメントはゼロに達し、ウォーカーはwake_up_interruptible_all(&proc->freeze_wait)を呼び出します。__wake_up_commonはその後curr = head.next - 24を計算し、*(head.next - 8)を呼び出します: head.nextが指す場所から読み取られた関数ポインタであり、これは再利用されたオブジェクトが供給する値です。

4. サイドチャネルからの2つのアドレス

そのポインタは、攻撃者が制御するメモリにカーネルアドレスで到達しなければならず、バグは何も漏洩させません。両方のアドレスは代わりにプリフェッチタイミングから得られます — KASLD(Brendan Coles、MIT)と同じチャネルであり、その実装はこれに由来します:

  • カーネルテキスト。 マップされたカーネルアドレスのプリフェッチはページテーブルウォークで解決され、アクセスがアーキテクチャ的に可視になることはなくても、マップされていないアドレスのものよりも測定可能なほど速く完了します。テキスト範囲の2 MiBスロットをスキャンすると、イメージが高速スロットの連続として表示されます。その最初のスロットは_textです。

  • ダイレクトマップ。 CONFIG_RANDOMIZE_MEMORYを使用すると、ダイレクトマップは1 GiB単位でランダム化されるため、これも特定する必要があります。テキストとは異なり、RAM全体をカバーするため、マップされたスロットの最長の連続実行です。これを実用的にするには2つの改良が必要でした:

    • 単一のプリフェッチは、KVM下ではマップ済みと未マップをわずか約4サイクルでしか分離できず、ノイズに耐えられないため、各サンプルは400回のプリフェッチのバッチを計時します(311対523サイクルと測定 — 分離可能);
    • 単一のスキャンは競合するホスト上では信頼できません — 一度に1つのゲストでは10/10正解、一度に5つのゲストでは3/5 — そのためスキャンは5回実行され、過半数が必要です。合意がない場合、エクスプロイトは未検証のアドレスに向けて発射するのではなく、失敗を報告して停止します。

    実行が確実に開始するのはpage_offset_base自体ではなく、カーネルが1 GiBページでマップできる最初のスロット — 物理4 GiBをカバーするスロットです。その下では、PCIホールとファームウェア予約により2 MiBページが強制され、そのより長いウォークはここでは未マップと分離できません。そのスロットはスプレーが必要とするものと正確に一致するため、それが使用されます。

その後、物理メモリの約60%が、1つの巧妙に細工された4 KiBページのコピーで満たされ、そのアンカーからの固定オフセットは、レイアウトがどうなろうと、細工されたページによってバックアップされます。

チェーン```

freeze_wait.head.next -> entry1 (in the sprayed page)

entry1.func = mov 0x28(%rdi),%rdi ; mov 0x18(%rdi),%rax ; jmp *0x58(%rax) RDI <- entry1+0x28 = &cred RAX <- cred+0x18 jmp *(RAX+0x58) = commit_creds -> commit_creds(cred)

entry2.func = mov $-1,%rax ; ret __wake_up_common breaks out on ret < 0

root@kitploit:~
No stack pivot and no `iretq`: the hijacked thread returns out of its `ioctl()`
normally and is simply back in userspace, as root.

### The forged cred, and the bug that would have wasted it

The dispatcher gadget takes its `RAX` from `cred+0x18`, and `cred+0x18` is
`euid`/`egid`, so immediately after the chain `euid` is the low half of a kernel
pointer. That is cosmetic. What is not cosmetic is that `prepare_creds()` —
which **every later `fork()` and `execve()` calls** — dereferences three fields
with no NULL check:```c
	get_group_info(new->group_info);        /* refcount_inc(&gi->usage) */
	get_uid(new->user);                     /* refcount_inc(&u->__count) */
	new->ucounts = get_ucounts(new->ucounts);

偽造された資格情報をNULLにするとuid 0が得られるが、最初のexecveでマシンがパニックする——つまり、エクスプロイトは成功を報告した直後にマシンを破壊することになる。そこでチェーンはuser、ucounts、group_infoを実際のカーネルグローバル変数であるroot_user、init_ucounts、init_groupsに向け、それらのアドレスは同じ_textベースから取得される。これらが設定されると、ルート化されたスレッドはinit_user_ns上でCAP_SETUIDを保持するため、setresuid(0,0,0)を呼び出し、カーネルは偽造された資格情報の上にクリーンでカーネル割り当てのルート資格情報をインストールする。その後になって初めて他の処理が行われる。

特権は、setuid-rootのエクスプロイトバイナリのコピーを通じて親プロセスに渡され、そのバイナリはシェルをexecする前に自身をunlinkする。これにより、ルートシェルはクリーンなターミナル上のメインプロセスで実行され、setuidの残骸は何も残らない。

影響を受けるシステム

uname -rだけでは不十分である。ベンダーカーネルは、対応するメインライン版に変更することなくbinder修正をバックポートすることが日常的に行われている。ソースまたはパッケージのチェンジログを調査すること。

この修正にはCc: stableタグが付いているため、stableおよびベンダーブランチにバックポートが配布される。

バグの場所と、到達可能な場所

これらは異なる問題であり、影響を決定するのは後者である。

脆弱なコードはCONFIG_ANDROID_BINDER_IPCが設定されている場所ならどこでもコンパイルされる。これには汎用ディストリビューションも含まれる——しかし調査したすべてのディストリビューションで、ドライバはデフォルトではロードされないモジュールであり、ロードされた場合でもinit_binder_device()はmiscdev.modeを設定せずにmiscデバイスを登録するため、devtmpfsは/dev/binderを0600 root:rootとして作成する。Androidではueventdがこれを0666にオープンする。これこそが、このバグがAndroidで重要であり、ここではほとんど重要でない理由である。

ディストリビューション自身が配布するカーネルパッケージから読み取った構成:

したがって、デスクトップディストリビューションでの実際の露出は間接的である: binderをロードしてオープンするもの——Waydroid、Anbox、Androidエミュレータまたはコンテナランタイム——は、カーネルにまだバグがあるマシン上で、Androidとまったく同じ到達可能性を再導入する。

各ハードニングオプションがエクスプロイトに与えるコスト

これらは脆弱性には影響しない。このエクスプロイトに影響する。

検証済みターゲット

両カーネルともストックの上流ツリーである。何もパッチされていない。

最初の実験室のCONFIG_KASAN_GENERICは検出器であり、有効化手段ではない。レースはこれなしでも同一である。CONFIG_PREEMPTは実際の前提条件であり、Androidが配布するものである。

アーキテクチャはバグにとっては要因ではない——これはアーキテクチャ非依存のCにおけるライフタイムエラーである。エクスプロイトにとっては非常に大きな要因である: ガジェット、prefetchチャネル、ダイレクトマップレイアウトはすべてx86_64固有である。

ビルドと実行

要件: clang、lld、make、cpio、gzip、qemu-system-x86_64、docker (Debian rootfsの組み立てのみ)、Linux gitツリーのローカルクローン、およびgcc。

すでに脆弱なシステム上でのエクスプロイト```sh

gcc -O2 -pthread -o exploit exploit.c ./exploit

root@kitploit:~
カーネルが `demo/` 内のもの以外の場合、まずそのオフセットを抽出します:```sh
./mkoffsets.sh /path/to/vmlinux > offsets.h
gcc -O2 -pthread -DEXPLOIT_OFFSETS='"offsets.h"' -o exploit exploit.c

チューナブル(すべて任意、すべて環境変数から読み取ります): CVE64468_SECONDS、CVE64468_THREADS、CVE64468_SPRAY_PERCENT、 CVE64468_CALL_OFFSET_MB、CVE64468_KASLR_ATTEMPTS、CVE64468_DELAY_MAX_US、 CVE64468_DELAY_STEP_US、CVE64468_STAGGER_US、CVE64468_VERBOSE、 CVE64468_SHELL。

メモリ安全性ラボ```sh

LINUX_GIT=/path/to/linux ./lab/build.sh # x86_64 LINUX_GIT=/path/to/linux TARGET_ARCH=arm64 ./lab/build.sh # arm64 ./run.sh vulnerable ./verify.sh 600 16

root@kitploit:~
The script creates two detached worktrees at the commits above, refuses to run
if either worktree is dirty, verifies that the vulnerable tree lacks the fix and
the fixed tree carries it, builds both kernels, and packs the proof of concept
into an initramfs.

### The exploitation laboratory```sh
./demo/build-kernel.sh     # vulnerable kernel, KASAN off, hardening on
./demo/build-rootfs.sh     # Debian 13 userland + gcc, as an initramfs
./demo/run-demo.sh         # boot it; this is what the recording shows
./demo/verify.sh logs/     # unattended reliability run, one guest per trial

demo/run-demo.sh はゲストを起動し、コンソールを uid 1000 に渡します。これにより、ゲスト自身の gcc で exploit.c をコンパイルして実行します。

カーネルイメージ、ワークツリー、rootfs ツリー、initramfs は実験室の成果物であり、バージョン管理の対象外です。

実際の実行

メモリ安全性、脆弱版と修正版

docs/example-output.txt は実際の脆弱カーネルのトランスクリプトで、KASAN レポートを含みます。docs/patched-negative-output.txt は修正カーネルの対照実験です。docs/e2e-results.json は機械可読な結果です。

報告された呼び出しチェーンは、上流のレポートと正確に一致します。``` BUG: KASAN: slab-use-after-free in queued_spin_lock_slowpath+0x62/0x6a0 Read of size 4 at addr ffff888100282270 by task cve64468-B/91 CPU: 6 UID: 1000 PID: 91 Comm: cve64468-B Not tainted 7.2.0-rc1+ #2 PREEMPT _raw_spin_lock+0x55/0x60 binder_free_transaction+0x80/0x1f0 binder_send_failed_reply+0x98/0x340 binder_thread_release+0x528/0x5e0 binder_ioctl+0x1ca/0xeb0 __x64_sys_ioctl+0x8c9/0xcf0

Allocated by task 93: binder_open+0xb5/0x7b0

Freed by task 9: kfree+0x113/0x310 binder_deferred_func+0x104b/0x1180 process_scheduled_works+0x69f/0xbb0

root@kitploit:~
`UID: 1000` は概念実証自身の非特権IDであり、被害者である。
`binder_proc` は `binder_open()` によって割り当てられ、binder の遅延
ワークキューによって解放され、解放後にウォーカーによって読み取られる。

記録された実行、2026-08-16、`./verify.sh 1200 16 3` — 各バリアントにつき3つの同時 QEMU/KVM
ゲスト、各10 vCPU、16スレッド、各バリアントにつき1200秒、**どちらの側にもカーネルパッチなし**:

| | 脆弱な `114a116aaa5f` | 修正済み `f223d27a546c` |
| --- | --- | --- |
| 試行回数 | 158,384 | 158,471 |
| ウォーク数 | 2,534,144 | 2,535,536 |
| セットアップ失敗 | 0 | 0 |
| 脆弱なアクセス (`Unexpected outstanding_txns -1`) | 1,127 | 934 |
| **KASAN `slab-use-after-free`** | **8** | **0** |

これが差分である: 同じワークロード、試行回数は0.06%以内の差、
そして use-after-free はパッチ未適用の脆弱なカーネルでのみ発生する。

脆弱なアクセスは*両方の*カーネルに現れるが、これは想定通りである — 修正は
ウィンドウ内でプロセスが解放されるのを防ぐものであり、`outstanding_txns` の
2回目のデクリメントを防ぐものではない。そのため、この行は安価な
オラクルとしてのみ使用され、差分としては決して使用されない。

### 権限昇格

![ライブ QEMU/KVM 実行: Debian 13 ゲスト、非特権ユーザーがゲスト自身の gcc で exploit.c をコンパイルし、root プロンプトで終了する](https://assets.kitploit.com/production/public/readmes/54229/da1e333d7516671ffab64e10d89604ee2a8043de1c48306abc03aaeee88d0d62/205a1253ab216ae4b62a65f761fffb9f0329bcbf9e4feb38563647f68ad2c5e0-display-v1.webp)

`docs/lpe-output.txt` はデモンストレーションゲストからの実際のトランスクリプトであり、
`docs/lpe-demo.cast` は上記のアニメーションの元となった完全かつ無編集の Asciinema 録画である
(`asciinema play docs/lpe-demo.cast` で全体を再生できる)。アニメーションはその録画の
長いレースの中間部分を省略している — ゲストのシリアルコンソールは約24分間のレース全体にわたって
binder デバッグをストリーミングし、スクロールログが数十メガバイトになるため — Debian の
プリアンブルと root シェルは保持している。エクスプロイト自身の `hit after 26661 attempts ... in 1437s`
という行が、省略された内容を正確に示している。どちらも単一実行である: 予算内で勝利しない
ゲストは電源が切れ、録画は勝利に編集されるのではなく単に繰り返される。

測定された成功率については、下記の *信頼性* を参照。

## 信頼性

レースは両方の点で確率的であるため、失敗した実行はエクスプロイトの欠陥ではなく、
一部の時間で期待される挙動である。

### メモリ安全性

上記の実行から導出された、脆弱なカーネルでの率:

| 量 | 値 |
| --- | --- |
| 試行レート | ゲストあたり約44試行/秒、3つで約132/秒 |
| 脆弱なアクセス | 試行あたり 7.1e-3 |
| アクセスが与えられた場合の、ウィンドウ内での解放の着地 | 7.1e-3 |
| KASAN レポート | 約20,000試行に1回、すなわちこのレートでは約2.5分に1回 |

### 権限昇格

各ゲストは独立した試行である: 独自の KASLR、独自のダイレクトマップ
ランダム化を持ち、勝利したゲストはレースを停止する。したがって、この数値は
試行あたりではなく、**ブートあたりの成功率** である。

記録されたキャンペーン、2026-08-16 23:32 UTC、`GUESTS=6 CPUS=8 MEMORY_MB=9216 ./demo/verify.sh`
— 6つの同時 QEMU/KVM ゲスト、パッチ未適用の `114a116aaa5f`、Debian 13 ユーザーランド、
各60分の予算、エクスプロイトはゲスト内でコンパイルされ、uid 1000 として開始:

| | |
| --- | --- |
| uid 0 に到達したゲスト | **6台中2台** |
| root までの時間 | 623秒および1,344秒 |
| 勝利したレースでの試行回数 | 13,839および31,125 |
| 勝利しなかった各ゲストの試行回数 | 全3,600秒で約95,000 |
| キャンペーン全体の総試行回数 | 427,676 (6.8M スタックウォーク) |
| 観測された脆弱なアクセス (`Unexpected outstanding_txns -1`) | 256 |
| **カーネルクラッシュ、oops、パニック** | **0**、9ゲスト時間で |

この表から読み取る価値のある点が2つある。

**勝利したレースはほぼすべて root になった。** KASAN ラボは、脆弱なアクセスが
与えられた場合に解放がウィンドウ内に着地する確率を 7.1e-3 と測定している。
これをここで観測された256のアクセスに適用すると、キャンペーン全体で約1.8回の
use-after-free が予測される — そして2つの root が得られた。リクレーム、
アドレス発見、チェーンはボトルネックではない。レースこそがボトルネックである。

**何もクラッシュしなかった。** 勝利しなかった4台を含め、9ゲスト時間で oops を
起こしたゲストはなかった。チェーンは正しく配置されスプレーされたページに対して
発火するか、まったく発火しないかのどちらかである — それがステージ2の
多数決拒否の目的である。

その拒否は実際に発火する。すでに負荷がかかっているホスト上で6つのゲストを
同時に起動すると、ステージ2で諦めるものが1つ発生し、次のように出力された。```
[*] direct map not found; refusing to fire at an unverified address

and exited without racing. That is the intended behaviour: a wasted boot is the correct outcome when the timing channel cannot reach consensus, and it is much better than the alternative of firing the chain at an address that was never confirmed.

docs/lpe-results.json carries the machine-readable form, including the SHA-256 of the exact kernel and initramfs used.

Why several guests, and why an oversubscribed host

Running the guests concurrently is not only about parallelism. On a contended host, KVM deschedules guest vCPUs, and that is exactly the delay the second condition needs: the walker has to lose its CPU between dropping t->lock and taking the victim's inner lock. A single guest on an idle host was measured at roughly one twentieth of the vulnerable-access rate of three concurrent guests.

There is an upper bound, though. At eight guests of 8 vCPUs each on a 32-thread host, with ~5 GiB of direct-map spray per guest, the host went into swap and three of the eight guests made no progress at all. Six is the shipped default.

The optional in-guest preemption helper threads were measured to cost about three times the attempt rate without improving the hit rate, and are not used.

One environmental factor turned out to matter more than expected: binder's own debug output. With binder.debug_mask at its default the driver emits a large amount of rate-limited pr_info traffic during the race, and the printk and console-lock pressure that creates lengthens the exact preemption window the second condition needs. Silencing it with binder.debug_mask=0 for a tidier console — the obvious thing to do for a recording — measurably lowered the hit rate in testing: guests ran well past both winners' attempt counts without a hit. demo/run-demo.sh therefore leaves binder debug at its default, and a quiet console is an explicit opt-in. This is a property of the laboratory, not of the exploit — but it is a good illustration of how much this race depends on system-wide timing jitter rather than on anything the exploit itself controls.

Safety

  • Both guests are disposable initramfs images. Nothing is written to guest or host disk.
  • The proof of concept only opens /dev/binder, sends binder transactions and exits binder threads. It installs nothing and leaves nothing behind.
  • The exploit does write one file: a setuid-root copy of itself, used to hand privilege from the winning thread to the parent process. It unlinks that copy before exec'ing the shell, so nothing setuid survives the run.
  • A lost race can panic or hang the guest; the memory-safety laboratory boots with panic=1 oops=panic so a run terminates instead of continuing on corrupted state. Always restart from a clean boot.

Credits

  • Exploit author: A. Ramos <[email protected]> (Twitter: @aramosf)
  • Vulnerability discovery and report: Alice Ryhl, Google
  • Upstream fix: Carlos Llamas, Google
  • Prefetch KASLR side channel: derived from KASLD, Copyright (c) 2019 Brendan Coles, MIT licensed. The direct-map variant is new work here.

Public-exploit search

Checked on 2026-08-16 with SearchSploit (local Exploit-DB copy) and web search for CVE-2026-64468, binder_free_transaction and f223d27a546c. No public exploit or proof of concept for this CVE was found; SearchSploit returns only unrelated, older Android binder entries. This is a point-in-time check, not a permanent guarantee.

ツールをダウンロード
状態主張
確認済みこの脆弱性は実在し、非特権プロセスから到達可能であり、上流の修正によって除去されます。
実証済み消滅しつつあるbinder_procの脆弱な逆参照が、パッチ未適用のカーネル上で自然かつ繰り返し発生し、修正済みカーネルでは決して発生しません。
実証済みKASANによって報告された完全なuse-after-freeが、パッチ未適用のカーネル上で発生します。
実証済み解放されたbinder_procを攻撃者制御のバイトで再利用し、カーネルの制御フローを乗っ取り、x86_64上で非特権ユーザーからuid 0への権限昇格を達成します。
主張なし特定のベンダーまたはAndroidデバイスでのいかなる結果。テストされたのは以下に列挙する上流カーネルのみで、x86_64上です。
主張なし同梱のエクスプロイトがディストリビューションカーネルに対して無修正で動作すること。影響を受けるシステムを参照してください: カーネルごとのオフセットが必要であり、調査したすべての汎用ディストリビューションでは、そもそもbinderデバイスが非特権ユーザーから到達不能です。
オフセットフィールドウォーカーが行うこと
108int outstanding_txnsそれをデクリメントする
113bool is_frozenそれを読み取る
120wait_queue_head_t freeze_waitoutstanding_txns == 0 && is_frozenの場合にそれを走査する
624spinlock_t inner_lockそれを取得して解放する
状態コミット備考
導入された系統a370003cc301上流のFixes:タグによって特定される
脆弱性確認済み114a116aaa5f修正の直接の親。隣接するCVE-2026-64469修正を含むため、このペアがCVE-2026-64468単体を分離する
修正済みメインラインf223d27a546cテスト対象の修正
ディストリビューションカーネルANDROID_BINDER_IPCデバイスSLAB_BUCKETSRANDOM_KMALLOC_CACHES非特権で到達可能か?
Debian 13 (trixie)6.12.101mANDROID_BINDER_DEVICES="binder"、BINDERFSオフyオフいいえ — モジュールがロードされていない。/dev/binderは0600
Debian 12 (bookworm)6.1.0mANDROID_BINDER_DEVICES="binder"、BINDERFSオフn/a (6.11より前)n/a (6.6より前)いいえ — 同上
Ubuntu 24.04 LTS6.8.0mBINDERFS=m、ANDROID_BINDER_DEVICES=""n/a (6.11より前)yいいえ — mount -t binderにrootが必要
Ubuntu 22.04 LTS5.15.0mBINDERFS=m、ANDROID_BINDER_DEVICES=""n/an/aいいえ — 同上
Android (AOSP / ベンダー)6.1、6.6、6.12 GKIy/dev/binder、/dev/hwbinder、/dev/vndbinder——はい — ドライバはプラットフォームのIPCであり、ワールドアクセス可能
オプションここでの効果
CONFIG_SLAB_BUCKETS (6.11+)このリクレームにとって致命的。 msg_msgを独自のkmallocバケットに分離するため、ポンプはbinder_procのスロットに決して到達できない。Debian 13はこれを設定している。別の未計上の1 KiB割り当てを見つける必要があるだろう。対象となるAndroidデバイスが実行するカーネル6.6は、これを完全に先取りしている。
CONFIG_RANDOM_KMALLOC_CACHES (6.6+)kmalloc-1kをコールサイトごとに複数のキャッシュに分割するため、ポンプは同じキャッシュに当たる必要がある。リクレームに対する1/16の課税であり、壁ではない。Ubuntuはこれを設定し、Debianは設定しない。
ページテーブル分離 (noptiを使用しない)アドレス発見にとって致命的。 PTIがアクティブな場合、prefetchはカーネルテキストを見ることができず、エクスプロイトはこれを検出して停止する。PTIは上記のすべてのディストリビューションでコンパイルされているが、アクティブかどうかはCPUが決定する: Meltdownの影響を受けないハードウェアではオフになっており、これらの結果が測定されたのはそこである。
CONFIG_SLAB_FREELIST_RANDOM、..._HARDENEDディストリビューションが配布する通り、実験室で有効化されている。測定可能な効果はない: ポンプはフリーリストの順序を予測せず、単に非常に多くのオブジェクトを割り当てるだけである。
KASLR (RANDOMIZE_BASE、RANDOMIZE_MEMORY)有効。prefetchステージによって無効化される。nokaslrなし。
カーネルごとのオフセットチェーンはcommit_creds、3つのcred関連グローバル変数、2つのガジェットを_textからのオフセットとして必要とする。mkoffsets.shはこれらを対象のvmlinuxから抽出する。これらがないと、エクスプロイトは誤ったアドレスに向けて発火する。これはあらゆるカーネルエクスプロイトのビルドごとの特性であり、防御策ではない。
メモリ安全性実験室 (lab/)エクスプロイト実験室 (demo/)
カーネルバージョン7.2.0-rc1+7.2.0-rc1+
脆弱なコミット114a116aaa5f0295376cdf12da743c5bce3b20ce同じ
修正済みコミットf223d27a546c1e1f48d38fd67760e78f068fe8c4— (エクスプロイトは脆弱なカーネル上でのみ測定される)
アーキテクチャx86_64 (KVM) および arm64 (TCG)x86_64 (KVM)
コンパイラUbuntu clang 21.1.8 / LLD 21.1.8同じ
KASANオン — これが検出器であるオフ — スラブレイアウトを変更し、あらゆるリクレームを非代表的にするため
スラブハードニング—SLAB_FREELIST_RANDOM、SLAB_FREELIST_HARDENEDオン。SLAB_BUCKETS、RANDOM_KMALLOC_CACHESオフ
KASLR—RANDOMIZE_BASE、RANDOMIZE_MEMORYオン
ユーザーランド最小限のinitramfsDebian GNU/Linux 13 (trixie)、ディストリビューション自身のgccを使用
開始時の識別情報uid 1000、gid 1000、ケーパビリティなし、名前空間なし同じ
ブートコマンドラインconsole=ttyS0 rdinit=/init panic=1 oops=panic kasan_multi_shot=1console=ttyS0 loglevel=4 rdinit=/init — noptiなし、nokaslrなし、mitigations=offなし