
GhostLock (CVE-2026-43499) exploit de kernel para dispositivos Android con bootloader bloqueado
Exploit del kernel para dispositivos Android con bootloader bloqueado. Logra root temporal + instalación de KernelSU sin desbloquear el bootloader ni modificar la imagen de arranque. Autodetección en tiempo de ejecución de la versión del kernel con tabla de offsets para múltiples dispositivos.
CVE-2026-43499 — Use-After-Free en Futex PI (Priority Inheritance)
Afecta al kernel de Linux 5.7 ~ 7.1. Corregido en las versiones estables 6.1.175, 6.6.140, 6.12.86. La mayoría de los dispositivos Android permanecen sin parchear a septiembre de 2026.
La syscall pselect6 copia datos de fd_set en la pila del kernel. Cuando se combina con el mecanismo de espera de futex PI, un marco de pila liberado puede reclamarse como una estructura rt_mutex_waiter. El rebalanceo del rb-tree durante el recorrido de la cadena PI escribe entonces valores controlados en direcciones arbitrarias del kernel.
| Dispositivo | SoC | Kernel | Rama GKI | SHIFT |
|---|---|---|---|---|
| OnePlus Ace 6T (PLR110) | SM8845 | 6.12.38 | android16-5 | 0 |
| OnePlus 15 (CPH2745/2747/2749) | SM8850 | 6.12.23 | android16-5 | 0 |
| OnePlus 15 (PLK110) | SM8850 | 6.12.58 | android16-6 | 0 |
| Xiaomi 17 (pudding) | SM8850 | 6.12.23 / 6.12.69 | android16-5 / android16-6 | 0 |
| OnePlus 13 (IN2060) | SM8750 | 6.6.89 | android15-8 | -2 |
| OPPO Pad 4 Pro | SM8750 | 6.6.89 | android15-8 | -2 |
| Dispositivo | SoC | Kernel | Notas |
|---|---|---|---|
| OnePlus 15T (PLZ110) | SM8845 | 6.12.38 | Mismo kernel que el Ace 6T |
| OPPO Reno10 Pro+ (CPH2521) | SM8475 | 5.10.236 | waiter compacto 5.10, waiter word=0 |
| Sony Xperia 1 IV (nagara) | SM8450 | 5.10.218 | waiter compacto 5.10, waiter word=0 |
| OPPO Find X9 Pro (PLG110) | D9400 | 6.12.23 | MediaTek, android16-5 |
| Vivo X200 Ultra (V2454A) | SM8750 | 6.6.89 | ashmem C, hooks tradicionales |
| Vivo X Fold3 Pro (PD2337) | SM8650 | 6.1.124 | waiter compacto 6.1, waiter word=3 |
| Vivo T4 | SM8650 | 6.1.145 | waiter compacto 6.1, waiter word=3 |
La superposición de pila de pselect requiere que el rt_mutex_waiter liberado caiga dentro de la región stack_fds controlable por el usuario (palabras 0–14). Dónde cae está determinado por los perfiles PGO/LTO del compilador, no por la versión del kernel. Véase Diseño de la pila.
| Dispositivo | SoC | Kernel | Causa raíz |
|---|---|---|---|
| OPPO Find X9 Ultra | SM8750 | 6.12.58 | PGO elimina do_futex → waiter word=14 |
| OnePlus 15 (PLK110) | SM8850 | 6.12.69 | PGO aplica inline a do_futex → waiter word=20 |
| OnePlus 12 | SM8650 | 6.1.141 | PGO aplica inline a do_futex → waiter word=13/19 |
| OnePlus 13R / Ace 5 | SM8650 | 6.1.x | OPLUS 6.1: waiter word=13 |
| realme RMX5070 | SM6650 | 6.1.141 | OPLUS 6.1: waiter word=13 |
| OPPO Pad 5 (OPD2502) | MT6878 | 6.1.134 | OPLUS 6.1: waiter word=13 |
| Motorola Edge 60 Fusion | MT6878 | 6.1.145 | No OPLUS 6.1: mismo resultado |
| iQOO Neo 10 CN | SM8650 | 6.1.84 | marco de do_futex 0xD0 → waiter word=-11 |
| OPPO PKW110 | — | 5.15.180 | marco de do_futex 0x140 → waiter word=-29 |
| iQOO Z9 5G | — | 5.15.178 | marco de do_futex demasiado grande |
| CPH2763 (OPPO) | — | 6.1.115 | OPLUS 6.1: PGO aplicado inline, waiter word=24 |
| iQOO 12 | SM8650 | 6.1.145 | 6.1: waiter word=9, task/lock en zona puesta a cero |
Nota sobre la viabilidad en 6.1: Los kernels OPLUS 6.1 son sistemáticamente inviables debido a que PGO aplica inline a
do_futex. Sin embargo, algunos kernels 6.1 que no son OPLUS (vivo) conservan la cadena de llamadas estándar y son viables (vivo T4, X Fold3 Pro). La viabilidad debe comprobarse por dispositivo.
Dos rutas de root, seleccionadas automáticamente según las capacidades del dispositivo:
Requiere off_ashmem_misc_fops != 0 (ashmem C con miscdevice estático en BSS).
PI write (mode=4) → redirect miscdevice fops to fake fops
→ configfs r/w → pipe physrw (1-byte precise kernel r/w)
→ SELinux enforcing = 0 (single byte, no policycap corruption)
→ UMH: inject work_struct into system_unbound_wq
→ root script → ksud late-load → KSU installed
Disponible en: OnePlus 13, OPPO Pad 4 Pro, dispositivos con ashmem 5.10/6.1 C. No disponible en ashmem de Rust (6.12 GKI) — miscdevice asignado en el heap.
Write 1 (mode=1) → SELinux enforcing = 0 (8-byte write, corrupts adjacent bytes)
Write 2 (mode=2) → task->cred = init_cred (uid=0, all capabilities)
Root shell → ksud late-load → KSU → SELinux policy fix
Tras W1+W2, el exploit parchea el campo de configuración del binario de la política SELinux (|= 0xC0000000 para ANDROID_NETLINK_ROUTE + GETNEIGH) y recarga mediante /sys/fs/selinux/load para restaurar la conectividad de red.
App (seccomp) → Write 1 → mini-adb TCP → adb shell: full exploit → root
El lanzador de arranque lo proporciona la aplicación independiente GhostLock Anchor.
Con NFDS=320, core_sys_select asigna un búfer stack_fds de 256 bytes en la pila del kernel:
stack_fds: 0 5 10 14 | 15 20 25 29
├─in─┤─out─┤─ex──┤ ├res_in┤res_out┤res_ex┤
◄── USER CONTROLLED ──►│◄── KERNEL ZEROED ──►
El exploit coloca campos waiter falsos (task, lock) en los bitmaps de entrada fd_set. Para el waiter anidado de 6.12 (14 palabras): palabra waiter máxima factible = 3. Para el waiter compacto de 5.10/6.1 (10 palabras): palabra waiter máxima factible = 7.
La posición del waiter depende de la profundidad de la cadena de llamadas:
| Patrón | Cadena de llamadas | Factible |
|---|---|---|
| android16-5 (6.12) | sys_futex → do_futex → fwrpi | ✅ palabra waiter=2 |
| android16-6 (6.12.58) | sys_futex → do_futex → fwrpi | ✅ palabra waiter=2 |
| android16-6 (6.12.69 OPLUS) | sys_futex → fwrpi (PGO inlined) | ❌ palabra waiter=20 |
| android16-6 (X9 Ultra) | sys_futex → fwrpi (PGO inlined) | ❌ palabra waiter=14 |
| android15-8 (6.6) | sys_futex → do_futex → fwrpi | ✅ palabra waiter=2 (SHIFT=-2) |
| vivo 6.1 | sys_futex → do_futex → fwrpi | ✅ palabra waiter=3 |
| OPLUS 6.1 | sys_futex → fwrpi (PGO inlined) | ❌ palabra waiter=13+ |
| 5.10 OPLUS | sys_futex → do_futex → fwrpi | ✅ palabra waiter=0 |
Todas las escrituras en el kernel usan el alias del mapa lineal. El bootloader elige kernel_phys_load, que varía según el SoC:
| SoC | kernel_phys_load |
|---|---|
| SM8845 (Ace 6T, 15T) | 0xa8000000 |
| SM8750 (OnePlus 13, OPPO Pad 4 Pro) | 0xa8000000 |
| SM8650 (vivo T4, X Fold3 Pro) | 0xa8000000 |
| SM8850 (OnePlus 15, Xiaomi 17) | 0xc7800000 |
Un valor incorrecto falla silenciosamente. Léalo en una unidad con root:
su -c 'grep -i "Kernel code" /proc/iomem' # c7810000-... → 0xc7800000
Anular en tiempo de ejecución: KPHYS=0xc7800000 /data/local/tmp/a/e
/data/local/tmp/a/e # Default (shift=0)
PSELECT_SHIFT=-2 /data/local/tmp/a/e # OnePlus 13 (6.6)