
CVE-2026-43499(GhostLock)vivo Y200i Android 14 におけるカーネル UAF に関する調査ノートと PoC 開発。futex PI チェーンのスタック再利用プリミティブとフレームレイアウトの制約を扱う。
デバイス: vivo Y200i (PD2354C)、Snapdragon 4 Gen 2 (SM4450)、Android 14 / OriginOS 4 カーネル: 5.10.218-gki-g3a51ea9d5834 (39-bit VA、4K ページ、KASLR 有効、STACKLEAK=y、SVE なし)
目標: CVE-2026-43499 (GhostLock) による一時的な root 取得。
ここまで成功:
ブロック中: スタック再利用プリミティブが rt_mutex_waiter の rb_node に到達できない。
主要な数値 (2 つの独立したファームウェアパッケージで同一):
__arm64_sys_futex 0xe0
do_futex 0xc0 (インライン化されていない - bl do_futex が存在する)
futex_wait_requeue_pi 0x1b0 (waiter は sp+0x20)
=> futex チェーン深さ T0-0x330
__arm64_sys_pselect6 0xa0 core_sys_select 0x1c0 (fd_set は sp+0x50) => pselect チェーン深さ T0-0x210、制御可能なウィンドウはわずか 120 バイト => ギャップ 0x120、アーキテクチャ上重複しない
waiter レイアウト (5.10 コンパクト、PFEM10 と一致): +0x18 pi_tree_entry.__rb_parent_color <- rt_mutex_adjust_prio_chain が走査する対象 +0x20 pi_tree_entry.rb_right +0x28 pi_tree_entry.rb_left +0x30 task +0x38 lock +0x40 prio +0x48 deadline
rt_mutex_adjust_prio_chain からの証拠: ldr x8, [task, #0x888] ; task->pi_waiters.rb_leftmost sub x8, x8, #0x18 ; rb_entry(node, rt_mutex_waiter, pi_tree_entry)
copy_from_user はより高いアドレスに向かって書き込むため、pi_tree_entry を カバーするにはコピー元が T0-0x318 以下である必要がある。
試行済みのパス: pselect6/core_sys_select T0-0x210 -> 0x120 不足 poll/do_sys_poll ウィンドウは T0-0x344 で終了、最大 0xf0B (N_STACK_PPS=30) -> 0x14 不足 rt_sigreturn (fpsimd) T0-0x300 -> waiter+0x30 にしか到達しない rt_sigreturn (SVE) T0-0x310 -> waiter+0x10 をカバーするはずだが、この CPU には SVE がなく、カーネルは SVE sigframe レコードを -EINVAL で拒否する compat rt_sigreturn / vfp T0-0x2c0 -> さらに浅い
全 copy_from_user サイトのカーネル全体スキャン: 合計 655、到達可能 118、 最大深さ 0x300 (bpf_prog_get_info_by_fd、これも CAP_BPF で制限)。0x318 が必要。
結論: このカーネルのスタックジオメトリはスタックベースの copy_from_user で 0x300 が上限であり、pi_tree_entry をカバーするには 0x318 が必要。これはチューニングの 問題ではなく、コンパイル時のフレームレイアウトの違いである。ここでは do_futex が インライン化されておらず、PFEM10 (5.10.236、Clang 12.0.5) とは異なる。おそらく インライン化コストモデルが異なるためである。
求めているもの: