
PD2229B的43499(ghostlock)可行性研究
# Resumen del fallo de explotación de GhostLock en PD2229 (SM8475, 5.10.233 GKI)
## 1. Hechos sobre la vulnerabilidad y el dispositivo
### 1.1 Información básica de CVE-2026-43499 (GhostLock)
| Elemento | Valor |
|---|---|
| Tipo de vulnerabilidad | Use-After-Free **en la pila** en la ruta rt_mutex / futex PI |
| Versión introducida | Linux 2.6.39-rc1 (mayo de 2011, commit 8161239a8bcc) |
| Versión corregida | mainline 7.1 (commit 3bfdc63936dd), ramas estables: 6.1.175 / 6.6.140 / 6.12.86 / 6.18.27 / 7.0.4 |
| Requisito previo | `CONFIG_FUTEX_PI=y` (habilitado por defecto en kernels principales) |
| CVSS | 7.8 High |
| Estabilidad de explotación | Cadena original de NebuSec 97%, root en ~5 segundos |
| Recompensa kernelCTF | $92,337 USD |
**Rango de kernels afectados**:
- 2.6.39 ≤ Linux < 6.1.175 ✅ Afectado
- 6.2 ≤ Linux < 6.6.140 ✅ Afectado
- 6.7 ≤ Linux < 6.12.86 ✅ Afectado
- 6.13 ≤ Linux < 6.18.27 ✅ Afectado
- 6.19 ≤ Linux < 7.0.4 ✅ Afectado
- **Android GKI 5.10 no está en ninguna rama corregida** → el 5.10.233 de PD2229 **teóricamente afectado**
### 1.2 Pruebas reales en el dispositivo PD2229
| Elemento | Valor |
|---|---|
| SoC | Qualcomm SM8475 (Snapdragon 8 Gen 1 Plus) |
| Versión del kernel | 5.10.233-gki-g6e61de9f5b58 #1 SMP PREEMPT (24 nov 2025) |
| Versión de Android | 15 (OriginOS 5) |
| Fecha de compilación | 2025/11/25 |
| Parche de Android | 2025/11/01 |
| `CONFIG_FUTEX_PI` | y ✅ |
| `CONFIG_UNMAP_KERNEL_AT_EL0` | y (KPTI habilitado) |
| `kptr_restrict` | enforced |
| `CONFIG_IO_URING` | y ✅ (confirmado por símbolos de vmlinux, y seccomp no bloquea `io_uring_setup`) |
---
## 2. Cadena de explotación ideal vs progreso real en PD2229
### 2.1 Cadena original de NebuSec (exitosa en x86_64 / Pixel 10)
```
1. Bypass de KASLR → prefetch timing / PR_SET_MM_MAP auxv
2. Disparo de UAF → deadlock de dependencia PI de tres hilos → FUTEX_CMP_REQUEUE_PI devuelve -EDEADLK
3. Reciclaje de pila → PR_SET_MM_MAP copia auxv al marco de pila del waiter
4. Escritura restringida rb_erase → sobrescribe inet6_protos[IPPROTO_UDP]
5. CEA + ROP → secuestro del flujo de control
6. Cambio de core_pattern → shell root (97% de éxito)
```
### 2.2 Progreso real por etapa en PD2229
| Etapa | Estado | Descripción |
|---|---|---|
| 1. Bypass de KASLR | ✅ **Implementado** | Canal lateral `perf_event_open` + muestreo de callchain (mismo método de adaptación que OPPO Find X6 Pro 5.15.149) |
| 2. Disparo de UAF | ✅ **Implementado** | Deadlock PI de tres hilos exitoso, FUTEX_CMP_REQUEUE_PI devuelve -EDEADLK |
| 3. Primitiva de reciclaje de pila | ❌ **Fallo arquitectónico** | Los marcos de pila de todas las syscalls conocidas no se superponen con el waiter (ver sección 3) |
| 4. Escritura restringida rb_erase | ❌ Bloqueado | Requisito previo no cumplido |
| 5. Sobrescritura de inet6_protos | ❌ No iniciado | Depende de la etapa 4 |
| 6. ROP / secuestro del flujo de control | ❌ No iniciado | Depende de la etapa 5 |
| 7. Shell root | ❌ No iniciado | Depende de la etapa 6 |
---
## 3. Resultados de enumeración exhaustiva de la primitiva de reciclaje de pila (pruebas reales en PD2229)
### 3.1 Cálculos clave del diseño del marco de pila
```
Profundidad total de la ruta futex:
__arm64_sys_futex 0x90
+ do_futex 0xc0
+ futex_wait_requeue_pi 0x1b0
= 0x300
Posición del waiter = SYS_SP - 0x300 + 0x20 = SYS_SP - 0x2e0
Ruta pselect:
marco de pila core_sys_select 0x1c0, stack_fds en sp+0x50
Rango cubierto: SYS_SP - 0x1c0 + 0x50 = desde SYS_SP - 0x170
Diferencia con waiter (SYS_SP - 0x2e0) de 0x170 (368 bytes) → sin superposición
```
### 3.2 17 métodos de escritura en pila probados
| # | Método | Syscall | Resultado en PD2229 | Razón principal del fallo |
|---|---|---|---|---|
| 1 | `stamp_prctl` | `PR_SET_MM_MAP` | ❌ EPERM | Bloqueo duro de Android |
| 2 | `stamp_pselect` | `pselect6` (NFDS=320) | ❌ Sin superposición | waiter está 120B por debajo de fd_set |
| 3 | `stamp_pselect` | `pselect6` (NFDS>336) | ❌ Asignación en heap | Ruta kvmalloc |
| 4 | `stamp_socket` | `MCAST_JOIN_SOURCE_GROUP` | ❌ Cobertura insuficiente | Solo escribe el campo `lock` |
| 5 | `stamp_sendmsg` | `sendmsg` | ❌ A 80B del waiter | Profundidad del marco 0x90 insuficiente |
| 6 | `stamp_sendmmsg` | `sendmmsg` | ❌ A 112B del waiter | Marco insuficiente |
| 7 | `stamp_recvmmsg` | `recvmmsg` | ❌ Borra task/lock | El marco 0x1d0 corrompe punteros críticos |
| 8 | `stamp_process_vm` | `process_vm_writev` | ❌ Sin superposición | Pila del hilo hijo asignada por separado |
| 9 | `stamp_keyctl` | `KEYCTL_INSTANTIATE_IOV` | ❌ EOPNOTSUPP | Syscall no soportada + marco 0x40 |
| 10 | `stamp_tcp` | `TCP_ZEROCOPY_RECEIVE` | ❌ Marco insuficiente | Profundidad estimada insuficiente |
| 11 | `stamp_futex` | `FUTEX_CMP_REQUEUE_PI` recursivo | ❌ Lógicamente inviable | Corrompe la ventana de UAF |
| 12 | binder ioctl | `BINDER_WRITE_READ` | ❌ EACCES | shell sin permiso en /dev/binder |
| 13 | `poll` | `poll` | ❌ Asignación en heap | pollfd en el heap |
| 14 | `epoll_wait` | `epoll_wait` | ❌ Marco demasiado superficial | Marco 0xE0 |
| 15 | `sched_setattr` | `sched_setattr` | ❌ Profundidad insuficiente | Marco 0xb0 |
| 16 | `timerfd_settime` | `timerfd_settime` | ❌ Sin copia en pila | Sin buffer grande en pila |
| 17 | `io_uring_register` | `IORING_REGISTER_*` | ❌ **Doble fallo** | ①Marco de solo 0xF0, el destino de `copy_from_user` fijo en `sp+0x8` (diferencia de 424 bytes con `sp+0x1D0` del waiter); ②aunque `io_uring_setup` no está bloqueado por seccomp (devuelve EFAULT en lugar de ENOSYS), el diseño de pila no coincide |
**17/17 fallaron todos.**
### 3.3 Causa raíz del fallo
El diseño de pila generado por el compilador del SM8475 5.10 GKI de PD2229 (PGO + LTO + BOLT) hace que `stack_fds` de `core_sys_select` y `rt_mutex_waiter` de `futex_wait_requeue_pi` **no se superpongan arquitectónicamente**. Este es un hecho objetivo determinado por el compilador, no un problema de técnica de explotación.
El repositorio de JoinChang establece claramente: "The pselect stack overlay only works when the freed rt_mutex_waiter lands within the user-controllable region of the stack_fds buffer" — PD2229 no cumple esta condición.
---
## 4. Análisis comparativo de repositorios de referencia públicos
#### NebuSec/CyberMeowfia — Framework de explotación original
- **Repositorio**: https://github.com/NebuSec/CyberMeowfia
- **Objetivo**: x86_64 Linux / Pixel 10 (6.x GKI)
- **Reciclaje de pila**: `PR_SET_MM_MAP` copia auxv a la pila del kernel
- **Tasa de éxito**: 97%, ~5 segundos para [shell root]
- **Aplicabilidad a PD2229**: ❌ `PR_SET_MM_MAP` bloqueado con EPERM en Android
#### JoinChang/ghostlock-oneplus — Jailbreak de BL OnePlus
- **Repositorio**: https://github.com/JoinChang/ghostlock-oneplus
- **Dispositivos verificados**:
- OnePlus Ace 6T (PLR110, SM8845) — 6.12.38 GKI ✅
- OnePlus 15 (PLK110, SM8845) — 6.12.23 GKI ✅
- **Puntos técnicos clave**:
- Extracción automática de offsets: kallsyms (28) + BTF (57) + derivados (9) + constantes (12) = 103/103
- Superposición de pila pselect, **SP diff = -64**
- `PSELECT_SHIFT = -2`
- Cadena de explotación: futex UAF → waiter falsificado → pselect controla la pila → escritura restringida rb_erase → selinux_state.enforcing=0 → sobrescritura de cred con init_cred
- **Declaración explícita de inviabilidad**: "Not Feasible (stack layout incompatible)" — solo aplicable a kernels donde pselect stack_fds se superpone con el waiter
- **Aplicabilidad a PD2229**: ❌ Generación de kernel incompatible (6.12 vs 5.10), y diseño de pila sin superposición
#### p2p3p/GhostLock-for-OnePlus — Explotación completa OnePlus 6.12
- **Repositorio**: https://github.com/p2p3p/GhostLock-for-OnePlus
- **Verificado**: OnePlus Ace 6T (SM8845, 6.12.38) ✅
- **Aplicabilidad a PD2229**: ❌ Igual que JoinChang, generación de kernel incompatible
#### YuKongA/ghostlock-oplus — OPPO Find N5/X8
- **Repositorio**: https://github.com/YuKongA/ghostlock-oplus
- **Kernel**: 6.6.118 GKI
- **Aplicabilidad a PD2229**: ❌ Generación de kernel incompatible
#### Adaptación OPPO Find X6 Pro (PGEM10) — 5.15.149
- **Dispositivo**: SM8550, 5.15.149-android13, Android 15
- **Progreso**: ✅ Bypass de KASLR (perf_event_open + muestreo de callchain); etapas posteriores sin explotación completa publicada
- **Importancia**: demuestra que **el bypass de KASLR es viable en 5.15 GKI**, pero la etapa de reciclaje de pila no está verificada públicamente
#### pubglite55/oppo-ghostlock — OPPO Find N2
- **Repositorio**: https://github.com/pubglite55/oppo-ghostlock
- **Dispositivo**: OPPO Find N2 (CPH2413, **SM8475**)
- **Kernel**: **5.10.236**-android12-9-o-g74d132f4467a
- **Android**: 16 (BP2A.250605.015)
- **Implementado**:
- ✅ Firefox CVE-2026-10702 AAW (Stage 1)
- ✅ Bypass de KASLR (cálculo directo de kaslr_base)
- ✅ Disparo de GhostLock FUTEX (FUTEX_CMP_REQUEUE_PI ret=0)
- ✅ Fuga de mm_struct con KernelSnitch
- ✅ Heap spray de sk_buff (4/4 envíos exitosos)
- ✅ Verificación de 70+ offsets con IDA Pro
- **Bloqueo principal**:
> "pselect no puede manipular la estructura del waiter — con NFDS >336 fd_set está en el heap; configfs/ashmem no soportados (SET_NAME de ashmem truncado); todas las demás rutas de escritura al kernel bloqueadas (/proc/self/mem, /dev/mem, binder)"
- **Relación con PD2229**: **Misma plataforma y misma generación (SM8475, 5.10.236 vs 5.10.233)**, solo 3 versiones menores de diferencia, **enfrenta exactamente las mismas limitaciones arquitectónicas**
#### harry1080/oppo-ghostlock — OPPO Find N2
- **Repositorio**: https://github.com/harry1080/oppo-ghostlock
- **Dispositivo**: OPPO Find N2 (CPH2413, SM8475)
- **Kernel**: 5.10.236-android12-9-o-g74d132f4467a
- **Android**: 16 (BP2A.250605.015)
- **Declaración pública de la comunidad**:
> "En la versión explotable de pixel10, pselect stack_fds coincide exactamente con rt_waiter en la pila del kernel; esta parte es en realidad la más problemática. En el kernel del OPPO findN2, las pilas de estas dos llamadas no coinciden en absoluto, o si coinciden no es controlable; hay que encontrar otro método para controlar la pila, y se necesitan otras syscalls con pila del kernel controlable para construir la pila. Una simple adaptación de offsets es imposible que tenga éxito. **El rt_waiter de oppo no coincide en absoluto con pselect stack_fds**"
- **Relación con PD2229**: Al igual que PD2229, es SM8475 5.10 GKI, **la conclusión es totalmente aplicable**
### 4.3 Tabla comparativa general de repositorios de referencia
| Repositorio | Dispositivo | SoC | Kernel | Método de reciclaje de pila | Estado | Reutilizable en PD2229 |
|---|---|---|---|---|---|---|
| NebuSec/CyberMeowfia | Pixel 10 | - | 6.x | `PR_SET_MM_MAP` | ✅ 97% | ❌ Bloqueado por Android |
| JoinChang/ghostlock-oneplus | OnePlus Ace 6T | SM8845 | 6.12.38 | pselect (SP diff=-64) | ✅ Verificado | ❌ Generación de kernel incompatible |
| p2p3p/GhostLock-for-OnePlus | OnePlus Ace 6T | SM8845 | 6.12.38 | pselect | ✅ Verificado | ❌ Generación de kernel incompatible |
| YuKongA/ghostlock-oplus | Find N5/X8 | - | 6.6.118 | pselect | ✅ | ❌ Generación de kernel incompatible |
| Adaptación OPPO Find X6 Pro | Find X6 Pro | SM8550 | 5.15.149 | perf KASLR + ? | 🟡 KASLR ✅, resto no publicado | ❌ Plataforma diferente |
| **pubglite55/oppo-ghostlock** | **Find N2** | **SM8475** | **5.10.236** | Enumeración fallida | ❌ Bloqueo principal | ⚠️ **Misma plataforma y generación, mismo destino** |
| **harry1080/oppo-ghostlock** | **Find N2** | **SM8475** | **5.10.236** | Enumeración fallida | ❌ Arquitectónicamente inviable | ⚠️ **Misma plataforma y generación, mismo destino** |
| **PD2229 (este informe)** | **PD2229** | **SM8475** | **5.10.233** | **Los 17 candidatos fallaron** | ❌ **Arquitectónicamente inviable** | **—** |
---
## 5. Símbolos clave del kernel y offsets (medidos en vmlinux de PD2229)
> Base estática `0xffffffc008000000`, se debe añadir el slide de KASLR en tiempo de ejecución.
| Símbolo | Dirección | Propósito |
|---|---|---|
| `rt_mutex_start_proxy_lock` | `0xffffffc00822baa8` | Entrada de disparo de la vulnerabilidad |
| `futex_wait_requeue_pi` | `0xffffffc0082d7df4` | Asignación del waiter, marco 0x1b0 |
| `__arm64_sys_futex` | `0xffffffc0082dfe9c` | Marco 0x90 |
| `do_futex` | `0xffffffc0082d0768` | Marco 0xc0 |
| `core_sys_select` | `0xffffffc008634cf0` | Marco pselect 0x1c0 |
| `____sys_sendmsg` | `0xffffffc0093eda88` | Marco 0x90 |
| `do_recvmmsg` | `0xffffffc0093ef49c` | Marco 0x1d0 |
| `__arm64_sys_io_uring_register` | `0xffffffc008aae328` | Marco 0x10+0x70 |
| `__io_uring_register` | `0xffffffc008aae5f8` | Marco 0x80 |
| `inet6_protos` | `0xffffffc00ab0a278` | Destino de escritura de la etapa 4 |
| `selinux_state` | `0xffffffc00aee8c70` | Destino de desactivación de SELinux |
| `init_task` | `0xffffffc00ab0c240` | Fuente de lectura de cred |
### Estructura rt_mutex_waiter (personalizada de vivo 5.10.233)
```c
struct rt_mutex_waiter {
uint64_t private; // +0x00 (campo privado de vivo)
struct rb_node {
uint64_t rb_parent_color; // +0x08
uint64_t rb_right; // +0x10 (vivo invierte el orden)
uint64_t rb_left; // +0x18
} tree;
struct task_struct *task; // +0x20
struct rt_mutex *lock; // +0x28
};
// Tamaño total 0x30 (48 bytes)
```
---
## 6. Implementado vs pendiente de implementar
### ✅ Infraestructura implementada
1. **Bypass de KASLR** — `perf_event_open` + muestreo de callchain (mismo método que OPPO Find X6 Pro 5.15.149)
2. **Disparo de UAF** — Deadlock PI de tres hilos, FUTEX_CMP_REQUEUE_PI devuelve -EDEADLK
3. **Tabla de símbolos completa** — 103+ símbolos verificados con IDA (siguiendo la metodología de extracción 103/103 de JoinChang)
4. **Diseño de la estructura rt_mutex_waiter** — offsets personalizados de vivo confirmados
5. **Análisis preciso del diseño de marcos de pila** — cálculo de profundidad de rutas futex y pselect/io_uring completado
6. **Exclusión exhaustiva de 17 candidatos de reciclaje de pila** — matriz completa de "inviabilidad" establecida
### ❌ No implementado (bloqueo principal)
1. **Primitiva de reciclaje de pila** — el diseño de pila del compilador SM8475 5.10 GKI lo hace arquitectónicamente inutilizable
2. **Primitiva de escritura restringida** — no se puede disparar rb_erase debido al fallo del reciclaje de pila
3. **Todas las etapas posteriores** — bloqueo en cascada
---
## 7. Conclusión final
> ⚠️ **GhostLock (CVE-2026-43499) no es explotable en PD2229 (vivo X Fold+, SM8475, 5.10.233 GKI, Android 15 OriginOS 5).**
>
> **La causa raíz es el diseño de pila generado por el compilador SM8475 5.10 GKI (PGO+LTO+BOLT), que hace que los marcos de pila de todas las syscalls conocidas no se superpongan arquitectónicamente con `rt_mutex_waiter`**. Este es un hecho objetivo determinado por el compilador, no un problema de técnica de explotación.
**Todos los casos de explotación exitosa son en 6.6/6.12 GKI**, porque la salida del compilador en estos kernels más nuevos hace que pselect fd_set se superponga perfectamente con el waiter (SP diff=-64). El 5.10 GKI no tiene esta condición.
---
### Infraestructura establecida
- ✅ Primitiva de bypass de KASLR (canal lateral perf_event_open)
- ✅ 103+ símbolos del kernel y offsets
- ✅ Diseño de la estructura rt_mutex_waiter
- ✅ Capacidad de disparo de UAF
- ✅ Matriz de exclusión de 17 candidatos de reciclaje de pila
## 9. Índice de repositorios de referencia
| Repositorio | URL | Valor clave |
|---|---|---|
| NebuSec/CyberMeowfia | https://github.com/NebuSec/CyberMeowfia | Framework de explotación original, 97% de éxito |
| JoinChang/ghostlock-oneplus | https://github.com/JoinChang/ghostlock-oneplus | Adaptación exitosa en 6.12 GKI, metodología de extracción de 103 offsets |
| p2p3p/GhostLock-for-OnePlus | https://github.com/p2p3p/GhostLock-for-OnePlus | Cadena de explotación completa en 6.12 GKI |
| YuKongA/ghostlock-oplus | https://github.com/YuKongA/ghostlock-oplus | Adaptación OPPO en 6.6 GKI |
| pubglite55/oppo-ghostlock | https://github.com/pubglite55/oppo-ghostlock | **Referencia de fallo en misma plataforma SM8475 5.10.236** |
| harry1080/oppo-ghostlock | https://github.com/harry1080/oppo-ghostlock | **Referencia de fallo en misma plataforma SM8475 5.10.236** |
| Análisis técnico de NebuSec | https://nebusec.ai/research/ionstack-part-2/ | Detalles técnicos de la cadena original de GhostLock |
| Fix upstream | commit 3bfdc63936dd | Código de corrección |
---