
Dépôt de recherche documentant les tentatives d'exploitation de la UAF futex CVE-2026-43499 sur le noyau 6.12.38 du Honor YLP-W00, incluant les sources de PoC, les offsets du noyau et l'analyse des chaînes d'élévation de privilèges ayant échoué.
Statut de la recherche : vulnérabilité confirmée comme déclenchable, le PI walk réussit sans crash, mais la chaîne complète d'élévation de privilèges n'a pas été réalisée. En attente d'une mise à jour amont.
Ce dépôt documente le processus complet de recherche sur l'exploitation de CVE-2026-43499 pour une élévation de privilèges temporaire sur la tablette Honor YLP-W00 (noyau 6.12.38, +pgo+bolt+lto+mlgo).
Le déclenchement de la vulnérabilité réussit (EDEADLK), le PI chain walk réussit (sched_setattr=0, pas de crash), mais la compilation PGO provoque l'inlining de do_futex, faisant échouer tous les porteurs de récupération de pile ; la primitive d'écriture late_refs de CyberMeowfiaNS ne peut pas non plus aboutir en raison d'une inadéquation de la géométrie du slab.
| Élément | Valeur |
|---|---|
| Modèle | Honor YLP-W00 (tablette) |
| Système | HONORYLP-W00/10DLDLD170SP3C00E144 |
| Version système | 10.0.0.170 (MagicOS 10.0) |
| Noyau | 6.12.38-android16-5-gfde7767f6ef6-abogki481467632-4k |
| Compilation | +pgo,+bolt,+lto,+mlgo (clang 19.0.1) |
| Kernel SHA-256 | 48b622a20a700cdde0b8f2f6e83959df00a7efedf52f347377cf542f7b58948e |
| Bootloader | Verrouillé |
| SELinux | Enforcing |
| Randomisation kstack | Désactivée |
| ashmem | Réécrit en Rust |
| MTE | Support matériel mais KASAN non activé |
L'audit CyberMeowfiaNS confirme VULNERABLE_PATTERN_PRESENT. Deux cas de succès existent sur le même kernel SHA-256 (honor-mt6993, honor8e5), mais ils utilisent la primitive d'écriture late_refs, non reproductible sur cet appareil (voir ci-dessous).
Le noyau Honor 6.12.38 est compilé avec +pgo+bolt+lto+mlgo, ce qui fait que __arm64_sys_futex appelle directement futex_wait_requeue_pi, en sautant la couche intermédiaire do_futex. La chaîne d'appel futex passe de trois couches standard à deux couches :
GKI standard : __arm64_sys_futex -> do_futex -> futex_wait_requeue_pi
Cet appareil : __arm64_sys_futex -> futex_wait_requeue_pi (do_futex inliné)
Cela fait que le waiter se trouve à une position de pile plus superficielle (profondeur 0x130 au lieu du standard 0x1b0+), et la géométrie de couverture de tous les porteurs de récupération de pile standard ne correspond plus.
| Champ | Offset | Taille |
|---|---|---|
| tree_entry (rb_node) | +0x00 | 24B |
| pi_tree_entry (rb_node) | +0x18 | 24B |
| lock | +0x38 | 8B |
| prio | +0x44 | 4B |
| deadline | +0x48 | 8B |
| task | +0x50 | 8B |
| ww_ctx | +0x58 | 8B |
| Taille totale | 0x70 | 112B |
| Symbole | Offset |
|---|---|
| init_task | 0x023ecf00 |
| init_cred | 0x02402cb0 |
| root_task_group | 0x0261a740 |
| selinux_state.enforcing | 0x026663c8 |
| rb_erase | 0x00bce274 |
| rt_mutex_adjust_prio_chain | 0x115060c |
| commit_creds | 0x00b89c10 |
| worker_thread | 0x00adfef8 |
| remove_waiter | 0x0112b20 |
En safe mode, confirmation du déclenchement de l'UAF et du succès du PI walk :
[futex] CMP_REQUEUE_PI ret=-1 errno=35 (EDEADLK) ← déclenchement UAF réussi
[futex] consumer sched_setattr ret=0 errno=0 ← PI walk réussi, pas de crash
L'appareil reste en ligne, le boot_id est inchangé, SELinux reste Enforcing. rb_erase a écrit à une adresse valide mais inutile.
Porteurs de récupération de pile essayés :
| Porteur | Principe | Résultat |
|---|---|---|
| pselect | copie de pile fd_set | shift=26 (inlining PGO), capacité fd_set insuffisante |
| MCAST_JOIN_SOURCE_GROUP | copie de pile de 0x108 octets | WAITER_OFF=0x308 >> 0x108, pas de chevauchement |
| adjtimex | copie de pile de la structure timex | buf depth 0x118 < waiter 0x130, pas de chevauchement |
| io_submit | écrasement de pile de struct iocb | écrase waiter[0x28..0x67], lock@0x58 hors plage |
| PR_SET_MM_MAP | écriture de pile prctl | EPERM |
| Livraison de signal (do_signal) | sauvegarde de pile pt_regs | la trame écrase waiter[0x00..0x28], task@0x50 et lock@0x58 écrasés par d'autres trames en valeurs invalides, crash |
| rt_sigreturn | fpsimd vregs 512B | sur 6.12.38, chargé via ldtr dans la zone per-cpu, ne passe pas par la pile noyau |
Obstacle principal : le waiter est à la profondeur 0x130, tree_entry(+0x00) et pi_tree_entry(+0x18) peuvent être partiellement écrasés par des porteurs, mais task(+0x50) et lock(+0x58) sont plus profonds, et aucun porteur connu ne peut les atteindre. Écraser tree_entry ne fait que faire emprunter à rb_erase un chemin vide (écriture NULL), sans pouvoir le diriger vers l'adresse cible.
CyberMeowfiaNS utilise une méthode complètement différente, contournant le problème de récupération de pile :
Toute la chaîne préalable réussit :
--info passe : authentification de l'identité du noyau réussie--check passe : pré-vérification du carrier DSO (libdumpstateaidl.so) confirmée
Échec de la course late_refs :
reclaim_hits=0 pour tous les délaisCause racine de l'échec : inadéquation de la géométrie du slab.
La fonction ep_get_upwards_depth_proc n'existe pas sur 6.12.38 (spécifique au noyau de référence 6.12.58). Mais ep_loop_check_proc écrit bien dans eventpoll.gen (+0xa8), donc ce n'est pas la cause directe.
La taille de la structure eventpoll est de 0xdc0 (3520 octets), allouée depuis kmalloc-4k (order=3, slab 32KB, 8 objets). L'hypothèse du code eventpoll_size=0xd0 (208 octets) est erronée.
eventpoll_epi (epitem) fait 128 octets, order=0, page 4KB, 32 objets par page. late_refs ne libère que 1-2 epitem par tour, insuffisant pour vider toute une page 4KB et permettre au page allocator de la récupérer.
late_refs nécessite une récupération de page cross-cache : page d'epitem libérée → page allocator → page SKB order-3. Mais cela exige que les 32 epitem de la même page soient tous libérés, ce que la disposition du graphe epoll du code ne peut garantir.
Le noyau de référence 6.12.58 peut avoir une configuration SLUB ou une disposition de slab différente, rendant la récupération cross-cache plus facile à déclencher.
| Fichier | Description | Taille |
|---|---|---|
firmware/boot_10.0.0.170.img | boot.img de la version système 10.0.0.170 | 96 MB |
firmware/honor_kernel_6.12.38.img | ELF du noyau extrait de boot.img (avec table de symboles) | 44 MB |
firmware/libdumpstateaidl_honor.so | Carrier DSO (extrait de l'appareil) | 52 KB |
boot.img permet d'extraire la table de symboles du noyau avec llvm-nm, et d'analyser la disposition des fonctions par désassemblage avec llvm-objdump.