
PD2229B的43499(ghostlock)可行性研究
| Élément | Valeur |
|---|---|
| Type de vulnérabilité | Use-After-Free sur la pile dans le chemin rt_mutex / futex PI |
| Version d'introduction | Linux 2.6.39-rc1 (mai 2011, commit 8161239a8bcc) |
| Version corrigée | Mainline 7.1 (commit 3bfdc63936dd), branches stables : 6.1.175 / 6.6.140 / 6.12.86 / 6.18.27 / 7.0.4 |
| Prérequis | CONFIG_FUTEX_PI=y (activé par défaut sur les noyaux grand public) |
| CVSS | 7.8 High |
| Stabilité de l'exploitation | 97 % sur la chaîne originale de NebuSec, root en ~5 secondes |
| Prime kernelCTF | 92 337 $ USD |
Plage de noyaux affectés :
| Élément | Valeur |
|---|---|
| SoC | Qualcomm SM8475 (Snapdragon 8 Gen 1 Plus) |
| Version du noyau | 5.10.233-gki-g6e61de9f5b58 #1 SMP PREEMPT (24 nov. 2025) |
| Version Android | 15 (OriginOS 5) |
| Date de compilation | 25/11/2025 |
| Correctifs Android | 01/11/2025 |
CONFIG_FUTEX_PI | y ✅ |
CONFIG_UNMAP_KERNEL_AT_EL0 | y (KPTI activé) |
kptr_restrict | enforced |
CONFIG_IO_URING | y ✅ (confirmé par les symboles vmlinux, et seccomp n'intercepte pas io_uring_setup) |
1. Contournement KASLR → timing prefetch / PR_SET_MM_MAP auxv
2. Déclenchement UAF → interblocage PI à trois threads → FUTEX_CMP_REQUEUE_PI retourne -EDEADLK
3. Récupération de pile → PR_SET_MM_MAP copie auxv dans le cadre de pile du waiter
4. Écriture limitée rb_erase → écrasement de inet6_protos[IPPROTO_UDP]
5. CEA + ROP → détournement du flux de contrôle
6. Bascule core_pattern → shell root (taux de réussite 97 %)
| Étape | Statut | Description |
|---|---|---|
| 1. Contournement KASLR | ✅ Implémenté | Canal auxiliaire perf_event_open + échantillonnage callchain (méthode identique à l'adaptation OPPO Find X6 Pro 5.15.149) |
| 2. Déclenchement UAF | ✅ Implémenté | Interblocage PI à trois threads réussi, FUTEX_CMP_REQUEUE_PI retourne -EDEADLK |
| 3. Primitive de récupération de pile | ❌ Échec architectural | Les cadres de pile de tous les appels système connus ne chevauchent pas le waiter (voir section 3) |
| 4. Écriture limitée rb_erase | ❌ Bloquée | Prérequis non satisfaits |
| 5. Écrasement inet6_protos | ❌ Non commencée | Dépend de l'étape 4 |
| 6. ROP / détournement du flux de contrôle | ❌ Non commencé | Dépend de l'étape 5 |
| 7. Shell root | ❌ Non commencé | Dépend de l'étape 6 |
Profondeur totale du chemin futex :
__arm64_sys_futex 0x90
+ do_futex 0xc0
+ futex_wait_requeue_pi 0x1b0
= 0x300
Position du waiter = SYS_SP - 0x300 + 0x20 = SYS_SP - 0x2e0
Chemin pselect :
cadre de pile core_sys_select 0x1c0, stack_fds à sp+0x50
Plage couverte : à partir de SYS_SP - 0x1c0 + 0x50 = SYS_SP - 0x170
Écart avec le waiter (SYS_SP - 0x2e0) de 0x170 (368 octets) → pas de chevauchement
| # | Méthode | Appel système | Résultat PD2229 | Raison principale de l'échec |
|---|---|---|---|---|
| 1 | stamp_prctl | PR_SET_MM_MAP | ❌ EPERM | Interception matérielle Android |
| 2 | stamp_pselect | pselect6 (NFDS=320) | ❌ Pas de chevauchement | waiter 120B sous fd_set |
| 3 | stamp_pselect | pselect6 (NFDS>336) | ❌ Allocation tas | Chemin kvmalloc |
| 4 | stamp_socket | MCAST_JOIN_SOURCE_GROUP | ❌ Couverture insuffisante | Écrit uniquement le champ lock |
| 5 | stamp_sendmsg | sendmsg | ❌ À 80B du waiter | Profondeur de cadre 0x90 insuffisante |
| 6 | stamp_sendmmsg | sendmmsg | ❌ À 112B du waiter | Cadre de pile insuffisant |
| 7 | stamp_recvmmsg | recvmmsg | ❌ Zéroise task/lock | Le cadre 0x1d0 corrompt les pointeurs critiques |
| 8 | stamp_process_vm | process_vm_writev | ❌ Pas de chevauchement | Pile du thread fils allouée séparément |
| 9 | stamp_keyctl | KEYCTL_INSTANTIATE_IOV | ❌ EOPNOTSUPP | Appel système non pris en charge + cadre 0x40 |
| 10 | stamp_tcp | TCP_ZEROCOPY_RECEIVE | ❌ Cadre insuffisant | Profondeur estimée insuffisante |
| 11 | stamp_futex | FUTEX_CMP_REQUEUE_PI récursif | ❌ Logiquement impossible | Corrompt la fenêtre UAF |
| 12 | binder ioctl | BINDER_WRITE_READ | ❌ EACCES | Le shell n'a pas les droits sur /dev/binder |
| 13 | poll | poll | ❌ Allocation tas | pollfd sur le tas |
| 14 | epoll_wait | epoll_wait | ❌ Cadre trop peu profond | Cadre de pile 0xE0 |
| 15 | sched_setattr | sched_setattr | ❌ Profondeur insuffisante | Cadre de pile 0xb0 |
| 16 | timerfd_settime | timerfd_settime | ❌ Pas de copie de pile | Pas de grand tampon de pile |
| 17 | io_uring_register | IORING_REGISTER_* | ❌ Double échec | ①Cadre de pile de seulement 0xF0, cible copy_from_user fixe à sp+0x8 (écart de 424 octets avec le sp+0x1D0 du waiter) ; ②Bien que io_uring_setup ne soit pas intercepté par seccomp (retourne EFAULT et non ENOSYS), la disposition de la pile ne correspond pas |
17/17 ont tous échoué.
La disposition de la pile produite par le compilateur du SM8475 5.10 GKI du PD2229 (PGO + LTO + BOLT) fait que stack_fds de core_sys_select et rt_mutex_waiter de futex_wait_requeue_pi ne se chevauchent pas architecturalement. C'est un fait objectif déterminé par le compilateur, et non un problème de technique d'exploitation.
Le dépôt JoinChang indique clairement : « The pselect stack overlay only works when the freed rt_mutex_waiter lands within the user-controllable region of the stack_fds buffer » — le PD2229 ne satisfait pas cette condition.
PR_SET_MM_MAP copie auxv sur la pile du noyauPR_SET_MM_MAP est intercepté par EPERM sur AndroidPSELECT_SHIFT = -2