
PD2229B의 43499(ghostlock) 타당성 연구
# GhostLock의 PD2229 (SM8475, 5.10.233 GKI) 익스플로잇 실패 요약
## 1. 취약점 및 디바이스 사실
### 1.1 CVE-2026-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 |
**영향받는 커널 범위**:
- 2.6.39 ≤ Linux < 6.1.175 ✅ 영향받음
- 6.2 ≤ Linux < 6.6.140 ✅ 영향받음
- 6.7 ≤ Linux < 6.12.86 ✅ 영향받음
- 6.13 ≤ Linux < 6.18.27 ✅ 영향받음
- 6.19 ≤ Linux < 7.0.4 ✅ 영향받음
- **Android GKI 5.10은 어떤 패치 브랜치에도 없음** → PD2229의 5.10.233 **이론적으로 영향받음**
### 1.2 PD2229 디바이스 실측
| 항목 | 값 |
|---|---|
| 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` 차단하지 않음) |
---
## 2. 이상적 익스플로잇 체인 vs PD2229 실제 진행 상황
### 2.1 NebuSec 원체인 (x86_64 / Pixel 10 성공)
```
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% 성공률)
```
### 2.2 PD2229 각 단계 실제 진행 상황
| 단계 | 상태 | 설명 |
|---|---|---|
| 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단계에 의존 |
---
## 3. 스택 재활용 프리미티브 전수 조사 결과 (PD2229 실측)
### 3.1 스택 프레임 레이아웃 핵심 계산
```
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바이트) → 겹치지 않음
```
### 3.2 시도한 17가지 스택 쓰기 방법
| # | 방법 | 시스템 콜 | 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 0으로 초기화 | 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 전부 실패.**
### 3.3 실패의 근본 원인
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는 이 조건을 충족하지 않는다.
---
## 4. 공개 참조 저장소 비교 분석
#### NebuSec/CyberMeowfia — 원본 익스플로잇 프레임워크
- **저장소**: https://github.com/NebuSec/CyberMeowfia
- **대상**: x86_64 Linux / Pixel 10 (6.x GKI)
- **스택 재활용**: `PR_SET_MM_MAP`이 auxv를 커널 스택에 복사
- **성공률**: 97%, 약 5초 내 [root shell]
- **PD2229 적용 가능성**: ❌ `PR_SET_MM_MAP`이 Android에서 EPERM으로 차단됨
#### JoinChang/ghostlock-oneplus — OnePlus 잠금 해제 BL 탈옥
- **저장소**: https://github.com/JoinChang/ghostlock-oneplus
- **검증된 디바이스**:
- OnePlus Ace 6T (PLR110, SM8845) — 6.12.38 GKI ✅
- OnePlus 15 (PLK110, SM8845) — 6.12.23 GKI ✅
- **기술 요점**:
- 오프셋 자동 추출: kallsyms (28) + BTF (57) + 파생 (9) + 상수 (12) = 103/103
- pselect 스택 오버레이, **SP diff = -64**
- `PSELECT_SHIFT = -2`
- 익스플로잇 체인: futex UAF → 위조 waiter → pselect로 스택 제어 → rb_erase 제한적 쓰기 → selinux_state.enforcing=0 → cred를 init_cred로 덮어쓰기
- **불가능 명시**: "Not Feasible (stack layout incompatible)" — pselect stack_fds와 waiter가 겹치는 커널에만 적용 가능
- **PD2229 적용 가능성**: ❌ 커널 세대 불일치 (6.12 vs 5.10), 스택 레이아웃도 겹치지 않음
#### p2p3p/GhostLock-for-OnePlus — OnePlus 6.12 완전 익스플로잇
- **저장소**: https://github.com/p2p3p/GhostLock-for-OnePlus
- **검증됨**: OnePlus Ace 6T (SM8845, 6.12.38) ✅
- **PD2229 적용 가능성**: ❌ JoinChang과 동일, 커널 세대 불일치
#### YuKongA/ghostlock-oplus — OPPO Find N5/X8
- **저장소**: https://github.com/YuKongA/ghostlock-oplus
- **커널**: 6.6.118 GKI
- **PD2229 적용 가능성**: ❌ 커널 세대 불일치
#### OPPO Find X6 Pro (PGEM10) 적응 — 5.15.149
- **디바이스**: SM8550, 5.15.149-android13, Android 15
- **진행 상황**: ✅ KASLR 우회 (perf_event_open + callchain sampling); 이후 단계는 완전한 익스플로잇 미공개
- **의의**: **5.15 GKI에서 KASLR 우회 가능**을 증명했지만, 스택 재활용 단계는 공개 검증되지 않음
#### pubglite55/oppo-ghostlock — OPPO Find N2
- **저장소**: https://github.com/pubglite55/oppo-ghostlock
- **디바이스**: OPPO Find N2 (CPH2413, **SM8475**)
- **커널**: **5.10.236**-android12-9-o-g74d132f4467a
- **Android**: 16 (BP2A.250605.015)
- **구현 완료**:
- ✅ Firefox CVE-2026-10702 AAW (Stage 1)
- ✅ KASLR bypass (kaslr_base 직접 계산)
- ✅ GhostLock FUTEX 트리거 (FUTEX_CMP_REQUEUE_PI ret=0)
- ✅ KernelSnitch mm_struct 누출
- ✅ sk_buff 힙 스프레이 (4/4 send 성공)
- ✅ IDA Pro 70+ 오프셋 검증
- **핵심 차단**:
> "pselect가 waiter 구조를 조작할 수 없음 — NFDS >336일 때 fd_set이 힙에 있음; configfs/ashmem 미지원 (ashmem SET_NAME 잘림); 다른 모든 커널 쓰기 경로 차단됨 (/proc/self/mem, /dev/mem, binder)"
- **PD2229 관계**: **동일 플랫폼 동일 세대 (SM8475, 5.10.236 vs 5.10.233)**, 단 3개 마이너 버전 차이, **완전히 동일한 구조적 제약에 직면**
#### harry1080/oppo-ghostlock — OPPO Find N2
- **저장소**: https://github.com/harry1080/oppo-ghostlock
- **디바이스**: OPPO Find N2 (CPH2413, SM8475)
- **커널**: 5.10.236-android12-9-o-g74d132f4467a
- **Android**: 16 (BP2A.250605.015)
- **커뮤니티 공개 성명**:
> "pixel10에서 익스플로잇 가능한 버전의 pselect stack_fds가 정확히 rt_waiter와 커널 스택에서 겹치는데, 이 부분이 실제로 가장 골치 아픈 곳이다. OPPO findN2 커널에서는 이 두 호출의 스택 부분이 완전히 겹치지 않거나, 겹쳐도 제어할 수 없다. 다른 제어 가능한 커널 스택 시스템 콜을 찾아 스택을 구성해야 하며, 단순히 오프셋을 적응시키는 것으로는 성공할 수 없다. **oppo의 rt_waiter는 pselect stack_fds와 완전히 겹치지 않는다**"
- **PD2229 관계**: PD2229와 동일하게 SM8475 5.10 GKI, **결론 완전히 적용 가능**
### 4.3 참조 저장소 비교 총괄표
| 저장소 | 디바이스 | SoC | 커널 | 스택 재활용 방법 | 상태 | PD2229 재사용 가능성 |
|---|---|---|---|---|---|---|
| NebuSec/CyberMeowfia | Pixel 10 | - | 6.x | `PR_SET_MM_MAP` | ✅ 97% | ❌ Android 차단 |
| JoinChang/ghostlock-oneplus | OnePlus Ace 6T | SM8845 | 6.12.38 | pselect (SP diff=-64) | ✅ 검증됨 | ❌ 커널 세대 불일치 |
| p2p3p/GhostLock-for-OnePlus | OnePlus Ace 6T | SM8845 | 6.12.38 | pselect | ✅ 검증됨 | ❌ 커널 세대 불일치 |
| YuKongA/ghostlock-oplus | Find N5/X8 | - | 6.6.118 | pselect | ✅ | ❌ 커널 세대 불일치 |
| OPPO Find X6 Pro 적응 | Find X6 Pro | SM8550 | 5.15.149 | perf KASLR + ? | 🟡 KASLR ✅, 이후 미공개 | ❌ 플랫폼 상이 |
| **pubglite55/oppo-ghostlock** | **Find N2** | **SM8475** | **5.10.236** | 전수 조사 실패 | ❌ 핵심 차단 | ⚠️ **동일 플랫폼 동일 세대, 운명 동일** |
| **harry1080/oppo-ghostlock** | **Find N2** | **SM8475** | **5.10.236** | 전수 조사 실패 | ❌ 구조적 불가능 | ⚠️ **동일 플랫폼 동일 세대, 운명 동일** |
| **PD2229 (본 보고서)** | **PD2229** | **SM8475** | **5.10.233** | **17개 후보 전부 실패** | ❌ **구조적 불가능** | **—** |
---
## 5. 핵심 커널 심볼 및 오프셋 (PD2229 vmlinux 실측)
> 정적 베이스 주소 `0xffffffc008000000`, 런타임 시 KASLR slide 추가 필요.
| 심볼 | 주소 | 용도 |
|---|---|---|
| `rt_mutex_start_proxy_lock` | `0xffffffc00822baa8` | 취약점 트리거 진입점 |
| `futex_wait_requeue_pi` | `0xffffffc0082d7df4` | waiter 할당, 스택 프레임 0x1b0 |
| `__arm64_sys_futex` | `0xffffffc0082dfe9c` | 스택 프레임 0x90 |
| `do_futex` | `0xffffffc0082d0768` | 스택 프레임 0xc0 |
| `core_sys_select` | `0xffffffc008634cf0` | pselect 스택 프레임 0x1c0 |
| `____sys_sendmsg` | `0xffffffc0093eda88` | 스택 프레임 0x90 |
| `do_recvmmsg` | `0xffffffc0093ef49c` | 스택 프레임 0x1d0 |
| `__arm64_sys_io_uring_register` | `0xffffffc008aae328` | 스택 프레임 0x10+0x70 |
| `__io_uring_register` | `0xffffffc008aae5f8` | 스택 프레임 0x80 |
| `inet6_protos` | `0xffffffc00ab0a278` | 4단계 쓰기 대상 |
| `selinux_state` | `0xffffffc00aee8c70` | SELinux 비활성화 대상 |
| `init_task` | `0xffffffc00ab0c240` | cred 읽기 소스 |
### rt_mutex_waiter 구조체 (vivo 5.10.233 커스텀)
```c
struct rt_mutex_waiter {
uint64_t private; // +0x00 (vivo 프라이빗 필드)
struct rb_node {
uint64_t rb_parent_color; // +0x08
uint64_t rb_right; // +0x10 (vivo 순서 변경)
uint64_t rb_left; // +0x18
} tree;
struct task_struct *task; // +0x20
struct rt_mutex *lock; // +0x28
};
// 총 크기 0x30 (48바이트)
```
---
## 6. 구현 완료 vs 구현 필요
### ✅ 구현 완료된 인프라
1. **KASLR 우회** — `perf_event_open` + callchain sampling (OPPO Find X6 Pro 5.15.149 방식과 동일)
2. **UAF 트리거** — 3스레드 PI 교착, FUTEX_CMP_REQUEUE_PI가 -EDEADLK 반환
3. **완전한 심볼 테이블** — 103+ 심볼 IDA 검증 완료 (JoinChang의 103/103 추출 방법론 참조)
4. **rt_mutex_waiter 구조체 레이아웃** — vivo 커스텀 오프셋 확인 완료
5. **스택 프레임 레이아웃 정밀 분석** — futex와 pselect/io_uring 경로 깊이 계산 완료
6. **17개 스택 재활용 후보 전수 배제** — 완전한 "불가능" 매트릭스 구축
### ❌ 미구현 (핵심 차단)
1. **스택 재활용 프리미티브** — SM8475 5.10 GKI 컴파일러 스택 레이아웃으로 인해 구조적으로 사용 불가
2. **제한적 쓰기 프리미티브** — 스택 재활용 실패로 rb_erase 트리거 불가
3. **이후 모든 단계** — 연쇄 차단
---
## 7. 최종 결론
> ⚠️ **GhostLock (CVE-2026-43499)은 PD2229 (vivo X Fold+, SM8475, 5.10.233 GKI, Android 15 OriginOS 5)에서 익스플로잇 불가능.**
>
> **근본 원인은 SM8475 5.10 GKI 컴파일러(PGO+LTO+BOLT)가 생성한 스택 레이아웃으로 인해 알려진 모든 syscall의 스택 프레임이 `rt_mutex_waiter`와 구조적으로 겹치지 않기 때문**이다. 이는 컴파일러가 결정한 객관적 사실이며, 익스플로잇 기법의 문제가 아니다.
**성공한 익스플로잇 사례는 모두 6.6/6.12 GKI**인데, 이는 이러한 신형 커널의 컴파일러 출력이 pselect fd_set과 waiter를 완벽하게 겹치게 만들기 때문이다(SP diff=-64). 5.10 GKI는 이 조건을 갖추지 못한다.
---
### 구축 완료된 인프라
- ✅ KASLR 우회 프리미티브 (perf_event_open 사이드 채널)
- ✅ 103+ 커널 심볼 및 오프셋
- ✅ rt_mutex_waiter 구조체 레이아웃
- ✅ UAF 트리거 능력
- ✅ 17개 스택 재활용 후보 배제 매트릭스
## 9. 참조 저장소 인덱스
| 저장소 | URL | 핵심 가치 |
|---|---|---|
| NebuSec/CyberMeowfia | https://github.com/NebuSec/CyberMeowfia | 원본 익스플로잇 프레임워크, 97% 성공률 |
| JoinChang/ghostlock-oneplus | https://github.com/JoinChang/ghostlock-oneplus | 6.12 GKI 성공 적응, 103 오프셋 추출 방법론 |
| p2p3p/GhostLock-for-OnePlus | https://github.com/p2p3p/GhostLock-for-OnePlus | 6.12 GKI 완전 익스플로잇 체인 |
| YuKongA/ghostlock-oplus | https://github.com/YuKongA/ghostlock-oplus | 6.6 GKI OPPO 적응 |
| pubglite55/oppo-ghostlock | https://github.com/pubglite55/oppo-ghostlock | **SM8475 5.10.236 동일 플랫폼 실패 참조** |
| harry1080/oppo-ghostlock | https://github.com/harry1080/oppo-ghostlock | **SM8475 5.10.236 동일 플랫폼 실패 참조** |
| NebuSec 기술 분석 | https://nebusec.ai/research/ionstack-part-2/ | GhostLock 원체인 기술 세부 사항 |
| 업스트림 패치 | commit 3bfdc63936dd | 패치 코드 |
---