
PD2229Bの43499(ghostlock)実現可能性調査
| 項目 | 値 |
|---|---|
| 脆弱性タイプ | rt_mutex / futex PI パスにおけるスタック上の Use-After-Free |
| 導入バージョン | Linux 2.6.39-rc1 (2011年5月、commit 8161239a8bcc) |
| 修正バージョン | メインライン 7.1 (commit 3bfdc63936dd)、各安定ブランチ: 6.1.175 / 6.6.140 / 6.12.86 / 6.18.27 / 7.0.4 |
| 前提条件 | CONFIG_FUTEX_PI=y(主流カーネルではデフォルト有効) |
| CVSS | 7.8 High |
| 悪用安定性 | NebuSec オリジナルチェーン 97%、約 5 秒で root 取得 |
| kernelCTF 報奨金 | $92,337 USD |
影響を受けるカーネル範囲:
| 項目 | 値 |
|---|---|
| SoC | Qualcomm SM8475 (Snapdragon 8 Gen 1 Plus) |
| カーネルバージョン | 5.10.233-gki-g6e61de9f5b58 #1 SMP PREEMPT (Nov 24 2025) |
| Android バージョン | 15 (OriginOS 5) |
| コンパイル日時 | 2025/11/25 |
| Android パッチ | 2025/11/01 |
CONFIG_FUTEX_PI | y ✅ |
CONFIG_UNMAP_KERNEL_AT_EL0 | y (KPTI 有効) |
kptr_restrict | enforced |
CONFIG_IO_URING | y ✅(vmlinux シンボルで確認、seccomp も io_uring_setup をブロックしていない) |
1. KASLR バイパス → prefetch timing / PR_SET_MM_MAP auxv
2. UAF トリガー → 3スレッド PI 依存デッドロック → FUTEX_CMP_REQUEUE_PI が -EDEADLK を返す
3. スタック再利用 → PR_SET_MM_MAP で auxv を waiter スタックフレームにコピー
4. rb_erase 制限付き書き込み → inet6_protos[IPPROTO_UDP] を上書き
5. CEA + ROP → 制御フロー乗っ取り
6. core_pattern 反転 → root shell (97% 成功率)
| 段階 | ステータス | 説明 |
|---|---|---|
| 1. KASLR バイパス | ✅ 実装済み | perf_event_open + callchain sampling サイドチャネル(OPPO Find X6 Pro 5.15.149 適応方法と同一) |
| 2. UAF トリガー | ✅ 実装済み | 3スレッド PI デッドロック成功、FUTEX_CMP_REQUEUE_PI が -EDEADLK を返す |
| 3. スタック再利用プリミティブ | ❌ アーキテクチャ上失敗 | 既知の全 syscall のスタックフレームが waiter と重ならない(詳細は第3節) |
| 4. rb_erase 制限付き書き込み | ❌ ブロック中 | 前提条件未達 |
| 5. inet6_protos 上書き | ❌ 未開始 | 段階 4 に依存 |
| 6. ROP / 制御フロー乗っ取り | ❌ 未開始 | 段階 5 に依存 |
| 7. root shell | ❌ 未開始 | 段階 6 に依存 |
futex パスの総深度:
__arm64_sys_futex 0x90
+ do_futex 0xc0
+ futex_wait_requeue_pi 0x1b0
= 0x300
waiter 位置 = SYS_SP - 0x300 + 0x20 = SYS_SP - 0x2e0
pselect パス:
core_sys_select スタックフレーム 0x1c0、stack_fds は sp+0x50
カバー範囲: SYS_SP - 0x1c0 + 0x50 = SYS_SP - 0x170 から
waiter (SYS_SP - 0x2e0) との差 0x170 (368 バイト) → 重ならない
| # | 方法 | システムコール | PD2229 結果 | 核心的な失敗理由 |
|---|---|---|---|---|
| 1 | stamp_prctl | PR_SET_MM_MAP | ❌ EPERM | Android がハードにブロック |
| 2 | stamp_pselect | pselect6 (NFDS=320) | ❌ 重ならない | waiter が fd_set の 120B 下 |
| 3 | stamp_pselect | pselect6 (NFDS>336) | ❌ ヒープ割り当て | kvmalloc パス |
| 4 | stamp_socket | MCAST_JOIN_SOURCE_GROUP | ❌ 書き込み不足 | lock フィールドのみ書き込み |
| 5 | stamp_sendmsg | sendmsg | ❌ waiter から 80B | スタックフレーム 0x90 で深度不足 |
| 6 | stamp_sendmmsg | sendmmsg | ❌ waiter から 112B | スタックフレーム不足 |
| 7 | stamp_recvmmsg | recvmmsg | ❌ task/lock をゼロ化 | 0x1d0 スタックフレームが重要ポインタを破壊 |
| 8 | stamp_process_vm | process_vm_writev | ❌ 重ならない | 子スレッドスタックは独立割り当て |
| 9 | stamp_keyctl | KEYCTL_INSTANTIATE_IOV | ❌ EOPNOTSUPP | システムコール非対応 + スタックフレーム 0x40 |
| 10 | stamp_tcp | TCP_ZEROCOPY_RECEIVE | ❌ スタックフレーム不足 | 推定深度が不十分 |
| 11 | stamp_futex | FUTEX_CMP_REQUEUE_PI 再帰 | ❌ 論理的に不可 | UAF ウィンドウを破壊 |
| 12 | binder ioctl | BINDER_WRITE_READ | ❌ EACCES | shell に /dev/binder 権限なし |
| 13 | poll | poll | ❌ ヒープ割り当て | pollfd がヒープ上 |
| 14 | epoll_wait | epoll_wait | ❌ フレームが浅すぎ | スタックフレーム 0xE0 |
| 15 | sched_setattr | sched_setattr | ❌ 深度不足 | スタックフレーム 0xb0 |
| 16 | timerfd_settime | timerfd_settime | ❌ スタックコピーなし | 大きなスタックバッファなし |
| 17 | io_uring_register | IORING_REGISTER_* | ❌ 二重失敗 | ①スタックフレームは 0xF0 のみ、copy_from_user ターゲットは固定 sp+0x8(waiter の sp+0x1D0 と 424 バイト差);②io_uring_setup は seccomp にブロックされていないが(ENOSYS ではなく EFAULT を返す)、スタックレイアウトが不一致 |
17/17 全て失敗。
PD2229 の SM8475 5.10 GKI コンパイラ(PGO + LTO + BOLT)が出力するスタックレイアウトにより、core_sys_select の stack_fds と futex_wait_requeue_pi の rt_mutex_waiter がアーキテクチャ上重ならない。これはコンパイラによって決定される客観的事実であり、悪用テクニックの問題ではない。
JoinChang リポジトリは明確に述べている: "The pselect stack overlay only works when the freed rt_mutex_waiter lands within the user-controllable region of the stack_fds buffer"——PD2229 はこの条件を満たさない。
PR_SET_MM_MAP で auxv をカーネルスタックにコピーPR_SET_MM_MAP は Android で EPERM によりブロックPSELECT_SHIFT = -2"pselect は waiter 構造を操作できない — NFDS >336 では fd_set がヒープ上;configfs/ashmem は非対応(ashmem SET_NAME は切り詰められる);他の全てのカーネル書き込みパスはブロック(/proc/self/mem, /dev/mem, binder)"
"pixel10 で悪用可能なバージョンの pselect stack_fds は rt_waiter とカーネルスタック上でちょうど重なるが、この部分が実際には最も面倒な箇所で、OPPO findN2 のカーネルではこれら 2 つの呼び出しのスタック部分が完全に重ならないか、重なっても制御不能であり、別のスタック制御方法を見つける必要がある。他の制御可能なカーネルスタックを持つシステムコールに切り替えてスタックを構築する必要があり、単純なオフセット適応では成功不可能である。oppo の rt_waiter は pselect stack_fds と完全に重ならない"