
GhostLock (CVE-2026-43499) exploit noyau pour appareils Android avec bootloader verrouillé
Exploit noyau pour appareils Android avec bootloader verrouillé. Obtient un root temporaire + installation de KernelSU sans déverrouiller le bootloader ni modifier l'image de boot. Détection automatique de la version du noyau à l'exécution avec table d'offsets multi-appareils.
CVE-2026-43499 — Use-After-Free dans Futex PI (Priority Inheritance)
Affecte le noyau Linux 5.7 ~ 7.1. Corrigé dans les versions stables 6.1.175, 6.6.140, 6.12.86. La plupart des appareils Android restent non corrigés en septembre 2026.
L'appel système pselect6 copie les données fd_set sur la pile du noyau. Combiné au mécanisme de waiter futex PI, une frame de pile libérée peut être récupérée comme structure rt_mutex_waiter. Le rééquilibrage de l'arbre rb lors du parcours de la chaîne PI écrit alors des valeurs contrôlées à des adresses noyau arbitraires.
| Appareil | SoC | Noyau | Branche 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 |
| Appareil | SoC | Noyau | Notes |
|---|---|---|---|
| OnePlus 15T (PLZ110) | SM8845 | 6.12.38 | Même noyau que l'Ace 6T |
| OPPO Reno10 Pro+ (CPH2521) | SM8475 | 5.10.236 | waiter compact 5.10, waiter word=0 |
| Sony Xperia 1 IV (nagara) | SM8450 | 5.10.218 | waiter compact 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 traditionnels |
| Vivo X Fold3 Pro (PD2337) | SM8650 | 6.1.124 | waiter compact 6.1, waiter word=3 |
| Vivo T4 | SM8650 | 6.1.145 | waiter compact 6.1, waiter word=3 |
La superposition de pile pselect exige que le rt_mutex_waiter libéré atterrisse dans la région stack_fds contrôlable par l'utilisateur (mots 0–14). L'endroit où il atterrit est déterminé par les profils PGO/LTO du compilateur, et non par la version du noyau. Voir Disposition de la pile.
| Appareil | SoC | Noyau | Cause racine |
|---|---|---|---|
| OPPO Find X9 Ultra | SM8750 | 6.12.58 | PGO élimine do_futex → waiter word=14 |
| OnePlus 15 (PLK110) | SM8850 | 6.12.69 | PGO inline do_futex → waiter word=20 |
| OnePlus 12 | SM8650 | 6.1.141 | PGO inline 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 | Non-OPLUS 6.1 : même résultat |
| iQOO Neo 10 CN | SM8650 | 6.1.84 | frame do_futex 0xD0 → waiter word=-11 |
| OPPO PKW110 | — | 5.15.180 | frame do_futex 0x140 → waiter word=-29 |
| iQOO Z9 5G | — | 5.15.178 | frame do_futex trop grande |
| CPH2763 (OPPO) | — | 6.1.115 | OPLUS 6.1 : PGO inliné, waiter word=24 |
| iQOO 12 | SM8650 | 6.1.145 | 6.1 : waiter word=9, task/lock dans zone zéroée |
Note sur la faisabilité en 6.1 : les noyaux OPLUS 6.1 sont systématiquement non faisables en raison de l'inlining de
do_futexpar PGO. Cependant, certains noyaux 6.1 non-OPLUS (vivo) conservent la chaîne d'appel standard et sont faisables (vivo T4, X Fold3 Pro). La faisabilité doit être vérifiée appareil par appareil.
Deux chemins de root, sélectionnés automatiquement selon les capacités de l'appareil :
Nécessite off_ashmem_misc_fops != 0 (ashmem C avec miscdevice statique dans 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 sur : OnePlus 13, OPPO Pad 4 Pro, appareils 5.10/6.1 C ashmem. Non disponible sur Rust ashmem (6.12 GKI) — miscdevice alloué sur le tas.
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
Après W1+W2, l'exploit modifie le champ de configuration du binaire de politique SELinux (|= 0xC0000000 pour ANDROID_NETLINK_ROUTE + GETNEIGH) et recharge via /sys/fs/selinux/load pour restaurer la connectivité réseau.
App (seccomp) → Write 1 → mini-adb TCP → adb shell: full exploit → root
Le lanceur au démarrage est fourni par l'application séparée GhostLock Anchor.
Avec NFDS=320, core_sys_select alloue un tampon stack_fds de 256 octets sur la pile du noyau :
stack_fds: 0 5 10 14 | 15 20 25 29
├─in─┤─out─┤─ex──┤ ├res_in┤res_out┤res_ex┤
◄── USER CONTROLLED ──►│◄── KERNEL ZEROED ──►
L'exploit place de faux champs waiter (task, lock) dans les bitmaps d'entrée fd_set. Pour le waiter imbriqué 6.12 (14 mots) : mot waiter maximal réalisable = 3. Pour le waiter compact 5.10/6.1 (10 mots) : mot waiter maximal réalisable = 7.
La position du waiter dépend de la profondeur de la chaîne d'appels :
| Motif | Chaîne d'appels | Réalisable |
|---|---|---|
| android16-5 (6.12) | sys_futex → do_futex → fwrpi | ✅ mot waiter=2 |
| android16-6 (6.12.58) | sys_futex → do_futex → fwrpi | ✅ mot waiter=2 |
| android16-6 (6.12.69 OPLUS) | sys_futex → fwrpi (PGO inlined) | ❌ mot waiter=20 |
| android16-6 (X9 Ultra) | sys_futex → fwrpi (PGO inlined) | ❌ mot waiter=14 |
| android15-8 (6.6) | sys_futex → do_futex → fwrpi | ✅ mot waiter=2 (SHIFT=-2) |
| vivo 6.1 | sys_futex → do_futex → fwrpi | ✅ mot waiter=3 |
| OPLUS 6.1 | sys_futex → fwrpi (PGO inlined) | ❌ mot waiter=13+ |
| 5.10 OPLUS | sys_futex → do_futex → fwrpi | ✅ mot waiter=0 |
Toutes les écritures kernel utilisent l'alias de la table linéaire. Le bootloader choisit kernel_phys_load, qui varie selon le 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 |
Une valeur incorrecte échoue silencieusement. Lisez-la sur un appareil rooté :
su -c 'grep -i "Kernel code" /proc/iomem' # c7810000-... → 0xc7800000
Remplacer à l'exécution : 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)
Les noyaux 5.10 utilisent 0xffffffc008000000 (VA_BITS=39, différent de la valeur par défaut 0xffffffc080000000 des 6.x). Ceci est géré automatiquement via le champ kimage_text_base dans l'entrée des offsets de l'appareil.