
CVE-2026-43499 futex UAF의 Honor YLP-W00 커널 6.12.38에서의 익스플로잇 시도를 문서화한 연구 저장소로, PoC 소스, 커널 오프셋, 실패한 권한 상승 체인 분석을 포함합니다.
연구 상태: 취약점 트리거 확인됨, PI walk 성공 및 크래시 없음, 그러나 완전한 권한 상승 체인은 미구현. 업스트림 업데이트 대기 중.
본 저장소는 Honor YLP-W00 태블릿(커널 6.12.38, +pgo+bolt+lto+mlgo)에서 CVE-2026-43499를 이용한 임시 권한 상승의 전체 연구 과정을 기록합니다.
취약점 트리거 성공(EDEADLK), PI chain walk 성공(sched_setattr=0, 크래시 없음), 그러나 PGO 컴파일로 인해 do_futex가 인라인화되어 모든 스택 회수 캐리어가 실패; CyberMeowfiaNS의 late_refs 쓰기 원시 연산도 slab 지오메트리 불일치로 인해 적중 불가.
| 항목 | 값 |
|---|---|
| 기종 | Honor YLP-W00 (태블릿) |
| 시스템 | HONORYLP-W00/10DLDLD170SP3C00E144 |
| 시스템 버전 | 10.0.0.170 (MagicOS 10.0) |
| 커널 | 6.12.38-android16-5-gfde7767f6ef6-abogki481467632-4k |
| 컴파일 | +pgo,+bolt,+lto,+mlgo (clang 19.0.1) |
| Kernel SHA-256 | 48b622a20a700cdde0b8f2f6e83959df00a7efedf52f347377cf542f7b58948e |
| Bootloader | 잠금 |
| SELinux | Enforcing |
| kstack 무작위화 | 비활성화 |
| ashmem | Rust 재작성 |
| MTE | 하드웨어 지원되나 KASAN 미활성화 |
CyberMeowfiaNS 감사에서 VULNERABLE_PATTERN_PRESENT 확인. 동일 kernel SHA-256에서 두 개의 성공 사례(honor-mt6993, honor8e5)가 있으나, 이들은 late_refs 쓰기 원시 연산을 사용했으며 본 기기에서는 재현 불가(상세 내용은 하단 참조).
Honor 6.12.38 커널은 +pgo+bolt+lto+mlgo로 컴파일되어 __arm64_sys_futex가 직접 futex_wait_requeue_pi를 호출하며 do_futex 중간 계층을 건너뜁니다. futex 호출 체인이 표준 3계층에서 2계층으로 변경됩니다:
표준 GKI: __arm64_sys_futex -> do_futex -> futex_wait_requeue_pi
본 기기: __arm64_sys_futex -> futex_wait_requeue_pi (do_futex 인라인됨)
이로 인해 waiter가 더 얕은 스택 위치(깊이 0x130, 표준 0x1b0+가 아님)에 위치하며, 모든 표준 스택 회수 캐리어의 커버리지 지오메트리가 불일치합니다.
| 필드 | 오프셋 | 크기 |
|---|---|---|
| tree_entry (rb_node) | +0x00 | 24B |
| pi_tree_entry (rb_node) | +0x18 | 24B |
| lock | +0x38 | 8B |
| prio | +0x44 | 4B |
| deadline | +0x48 | 8B |
| task | +0x50 | 8B |
| ww_ctx | +0x58 | 8B |
| 총 크기 | 0x70 | 112B |
| 심볼 | 오프셋 |
|---|---|
| init_task | 0x023ecf00 |
| init_cred | 0x02402cb0 |
| root_task_group | 0x0261a740 |
| selinux_state.enforcing | 0x026663c8 |
| rb_erase | 0x00bce274 |
| rt_mutex_adjust_prio_chain | 0x115060c |
| commit_creds | 0x00b89c10 |
| worker_thread | 0x00adfef8 |
| remove_waiter | 0x0112b20 |
safe mode에서 UAF 트리거 및 PI walk 성공 확인:
[futex] CMP_REQUEUE_PI ret=-1 errno=35 (EDEADLK) ← UAF 트리거 성공
[futex] consumer sched_setattr ret=0 errno=0 ← PI walk 성공, 크래시 없음
기기는 온라인 상태 유지, boot_id 변경 없음, SELinux 여전히 Enforcing. rb_erase는 유효하지만 무용한 주소에 기록됨.
시도한 스택 회수 캐리어:
| 캐리어 | 원리 | 결과 |
|---|---|---|
| pselect | fd_set 스택 복사 | shift=26(PGO 인라인), fd_set 용량 부족 |
| MCAST_JOIN_SOURCE_GROUP | 0x108 바이트 스택 복사 | WAITER_OFF=0x308 >> 0x108, 미중첩 |
| adjtimex | timex 구조체 스택 복사 | buf depth 0x118 < waiter 0x130, 미중첩 |
| io_submit | struct iocb 스택 덮어쓰기 | waiter[0x28..0x67] 덮어씀, lock@0x58 범위 밖 |
| PR_SET_MM_MAP | prctl 스택 쓰기 | EPERM |
| 시그널 전달 (do_signal) | pt_regs 스택 저장 | 프레임이 waiter[0x00..0x28] 덮어씀, task@0x50 및 lock@0x58이 다른 프레임에 의해 무효값으로 덮어써져 크래시 |
| rt_sigreturn | fpsimd vregs 512B | 6.12.38에서 ldtr로 per-cpu 영역에 로드, 커널 스택을 거치지 않음 |
핵심 장애물: waiter가 깊이 0x130에 위치, tree_entry(+0x00)와 pi_tree_entry(+0x18)는 일부 캐리어로 덮어쓸 수 있으나 task(+0x50)와 lock(+0x58)은 더 깊은 곳에 있어 알려진 어떤 캐리어로도 도달 불가. tree_entry를 덮어써도 rb_erase가 빈 경로(NULL 쓰기)로만 진행될 뿐, 목표 주소로 유도할 수 없음.
CyberMeowfiaNS는 완전히 다른 방법으로 스택 회수 문제를 우회:
전제 체인 전부 성공:
--info 통과: 커널 신원 검증 성공--check 통과: carrier DSO (libdumpstateaidl.so) 사전 검사 확인
late_refs 경쟁 실패:
reclaim_hits=0실패 근본 원인: slab 지오메트리 불일치.
ep_get_upwards_depth_proc 함수가 6.12.38에 존재하지 않음(6.12.58 참조 커널 특유). 그러나 ep_loop_check_proc는 실제로 eventpoll.gen (+0xa8)에 기록하므로 이것이 직접 원인은 아님.
eventpoll 구조체 크기가 **0xdc0 (3520 바이트)**이며, kmalloc-4k에서 할당됨(order=3, 32KB slab, 8 객체). 코드가 가정한 eventpoll_size=0xd0 (208 바이트)는 잘못됨.
eventpoll_epi (epitem)는 128 바이트, order=0, 4KB 페이지, 페이지당 32 객체. late_refs는 매 라운드 1-2개의 epitem만 해제하므로, 전체 4KB 페이지를 비워 page allocator가 회수하게 하기에 불충분.
late_refs는 크로스 캐시 페이지 회수(cross-cache page reclaim)가 필요: 해제된 epitem 페이지 → page allocator → SKB order-3 페이지. 그러나 이를 위해서는 동일 페이지의 32개 epitem 전부가 해제되어야 하며, 코드의 epoll graph 레이아웃은 이를 보장할 수 없음.
6.12.58 참조 커널은 다른 SLUB 설정이나 slab 레이아웃을 가져 크로스 캐시 회수가 더 쉽게 트리거될 수 있음.
| 파일 | 설명 | 크기 |
|---|---|---|
firmware/boot_10.0.0.170.img | 시스템 버전 10.0.0.170의 boot.img | 96 MB |
firmware/honor_kernel_6.12.38.img | boot.img에서 추출한 커널 ELF(심볼 테이블 포함) | 44 MB |
firmware/libdumpstateaidl_honor.so | Carrier DSO(기기에서 추출) | 52 KB |
boot.img는 llvm-nm으로 커널 심볼 테이블을 추출하고, llvm-objdump로 디스어셈블하여 함수 레이아웃을 분석할 수 있습니다.
| 파일 | 설명 |
|---|---|
src/test_safemode.c | safe mode futex 트리거 + PI walk 검증(stamp 없음) |
src/test_trigger.c | futex UAF 트리거 테스트 |
src/futex_trigger.c | futex 트리거 핵심 코드 |
src/exploit_rtsig.c | rt_sigreturn 시그널 프레임 stamp 테스트 |
src/exploit_rtsig2.c | rt_sigreturn 시그널 프레임 stamp(개선판) |
src/exploit_regstamp.c | do_signal 레지스터 stamp 테스트 |
src/exploit_adjtimex.c | adjtimex primer 테스트 |
src/exploit_iosubmit.c | io_submit AIO primer 테스트 |
src/exploit_v3.c | KASLR + futex + adjtimex 조합 |
src/kaslr_tracefs.c | tracefs 바이너리 ring buffer KASLR 유출 |
src/kaslr_tracefs_v2.c | tracefs KASLR 유출(개선판) |
src/dump_sigframe.c | 시그널 프레임 읽기 전용 진단 |
src/cmwns_*.c/h | CyberMeowfiaNS 소스(적응판) |
src/cve_2026_43499_audit.py | CyberMeowfiaNS CVE-2026-43499 감사 스크립트 |
| 파일 | 설명 |
|---|---|
config/offsets.json | 커널 심볼 오프셋(BTF 검증) |
config/target.h | Honor YLP-W00 타깃 설정(ghostlock 경로) |
config/target_honor_ylp_w00.h | Honor YLP-W00 타깃 설정(CyberMeowfiaNS 경로) |
| 파일 | 설명 |
|---|---|
docs/ANALYSIS.md | 스택 프레임 분석 및 심볼 오프셋 |
docs/ALL_POC_ANALYSIS.md | 130+ PoC 프로젝트 분석 요약 |
docs/ADJTIMEX_BREAKTHROUGH.md | adjtimex 캐리어 발견(이후 미중첩 확인) |
docs/CRITICAL_FIX.md | adjtimex 중첩 계산 수정 |
docs/FINAL_STATUS.md | 최종 상태 및 모든 방안 |
docs/MULTI_PLAN.md | 다중 방안 비교 |
docs/PLAN.md | 전체 아키텍처 계획 |
docs/STATUS.md | 단계별 상태 |
| 속성 | 값 |
|---|---|
| 경로 | /system/lib64/libdumpstateaidl.so |
| 크기 | 52200 바이트 (0xcbe8) |
| SHA-256 | d5765759437291dc406ffe8775b3b2830c89ca5891956a3b58fcca7227815ff9 |
| .init_array 위치 | 파일 오프셋 0xb950 |
| .init_array[0] | 0x72ec (BnDumpstateListener::onTransact thunk) |
| .init_array[1] | 0x8db0 (BnDumpstate::onTransact thunk) |
| 생성자 preimage | fd 7b bd a9 f5 0b 00 f9 f4 4f 02 a9 fd 03 00 91 |
service dumpstatez /system/bin/dumpstate -S
socket dumpstate stream 0660 shell log
class main
disabled
oneshot
user root
service bugreportd /system/bin/dumpstate -w
class main
disabled
oneshot
user root
ep_loop_check_proc:
paciasp
stp x29, x30, [sp, #-0x40]!
...
ldr x0, [x19, #0x80] ; fllink 읽기 (자식 epitem 리스트)
ldr x8, [x22, #0xf88] ; 전역 generation counter 읽기
str x8, [x19, #0xa8] ; eventpoll.gen (+0xa8) 기록
...
ldr x8, [x8, #0x20] ; 자식 epitem의 ep 포인터 읽기
ldr x9, [x8, #0xa8] ; 자식 eventpoll.gen 읽기 (순환 검출)
...
bl ep_loop_check_proc ; 재귀 순회
ep_loop_check_proc는 실제로 eventpoll.gen (+0xa8)에 기록하지만, 목표 쓰기를 트리거하려면 fake eventpoll까지 순회해야 함. 이를 위해서는 해제된 epitem 메모리가 알려진 페이지(SKB order-3)로 회수되어야 함.