
CVE-2026-43499 (GhostLock) vivo Y200i Android 14 커널 UAF에 대한 연구 노트 및 PoC 개발로, futex PI-chain 스택 회수 프리미티브와 프레임 레이아웃 제한을 다룹니다.
기기: vivo Y200i (PD2354C), Snapdragon 4 Gen 2 (SM4450), Android 14 / OriginOS 4 커널: 5.10.218-gki-g3a51ea9d5834 (39-bit VA, 4K 페이지, KASLR on, STACKLEAK=y, SVE 없음)
목표: CVE-2026-43499 (GhostLock)를 통한 임시 루트.
현재까지 성공한 것:
차단 지점: stack-reclaim primitive가 rt_mutex_waiter의 rb_node에 도달하지 못함.
핵심 수치 (두 개의 독립적인 펌웨어 패키지에서 동일):
__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 compact, 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)과 다르며, 인라이닝 비용 모델이 다르기 때문일 가능성이 높음.
찾고 있는 것: