
Preuve de concept pour CVE-2026-64788, une utilisation après libération dans l'extension noyau IOGPUFamily sur iOS 26.6, démontrant l'exploitation via la création de textures Metal et le heap spraying.
Composant : Extension noyau IOGPUFamily (com.apple.iokit.IOGPUFamily)
Affecté : iOS / iPadOS 26.6 (23G71) et versions antérieures
Corrigé dans : iOS / iPadOS 26.6.1 (23G83)
Type : Use-After-Free dans IOGPUDevice::create_resource_iosurface
Impact : Corruption de la mémoire du noyau ; déréférencement UAF confirmé sur A14 (iPhone 12)
Découvert par : f00l (@PPPF00L), 3ndy1 (@_3ndy1), Minghao Lin (@Y1nkoc), 云散花折, Arjanit Isufi
(selon Bulletin de sécurité Apple — iOS 26.6.1)
IOGPUDevice::create_resource_iosurface alloue un objet IOGPUSysMemory (~0x100 octets, zone ) et l'enregistre dans la table de ressources IOSurface du périphérique. Avant de retourner, un contrôle de débordement de dimensions se déclenche via . Le chemin de débordement bifurque vers un retour d'erreur , laissant une entrée active dans la table de ressources qui pointe vers de la mémoire libérée.
kalloc.256ADDS width+height → b.hscreate_resource_iosurface:
kalloc(0x100) → obj ; IOGPUSysMemory alloué
table[new_id] = obj ; enregistré avec une référence
ADDS w_result, w_width, w_height
b.hs error_path ; ← débordement : saute ici
error_path:
; objet NON libéré, entrée de table NON effacée
return kIOReturnInvalid
L'entrée obsolète de la table persiste jusqu'à ce que le même ID de ressource soit réutilisé ou que le périphérique soit fermé.
IOGPUDevice::set_resource_purgeable(id) recherche l'ID obsolète via get_resource_by_id(), trouve l'entrée pendante et y accède de manière non virtuelle :
| Décalage | Opération | Description |
|---|---|---|
+0x010c | ldaddl w9(-4), w8, [obj+0x24] | Décrémentation atomique de [obj+0x24] ; ancienne valeur → w8 |
+0x0128 | cbz w8, skip; ldr x1, [obj+0x28] | Si ancien [+0x24] != 0 : charge [obj+0x28] comme argument de IOGPUMemory::setAllocation |
+0x0134 | ldr x0, [obj+0x10] | Charge [obj+0x10] comme argument IOCommandGate ; cbz → skip si 0 |
Le PoC déclenche l'UAF en utilisant newTextureWithDescriptor:iosurface:plane: de Metal avec des dimensions de débordement conçues. Avant le déréférencement UAF :
kalloc.256 libéré[+0x10]=0, [+0x24]=0, [+0x28]=0 → Call2 et Call3 sont correctement ignorésDétection du déclenchement : set_resource_purgeable sur une ressource inexistante retourne 0xe00002c2. Après l'UAF + la pulvérisation qui récupère l'emplacement, le même appel retourne 0xe0002be (ressource trouvée, Call1 déclenché) — confirmant que l'entrée obsolète est traitée avec nos données de pulvérisation.
La séquestration de zones dans iOS 26 replace les objets IOGPUSysMemory libérés dans une liste libre de zone à type stable. Tant [obj+0x10] (IOMemoryDescriptor) que [obj+0x18] (IOGPUDevice) conservent des comptes de rétention externes et restent actifs après la libération de l'objet. Par conséquent, completeMemory() s'exécute toujours sur des données ivar valides — le déréférencement UAF est confirmé mais une primitive de lecture/écriture noyau via ce seul chemin est bloquée sur iOS 26 sans primitive secondaire pour briser la séquestration de zones.
clang -arch arm64 -framework Metal -framework IOSurface \
-framework IOKit -framework Foundation \
-o poc poc/poc_iogpu_uaf.m
Ou ouvrez dans Xcode, définissez une équipe de signature valide et exécutez sur l'appareil.
| Date | Événement |
|---|---|
| 2026-08-17 | iOS 26.6.1 publié avec le correctif |
| 2026-08-17 | Crédits Apple publiés dans le bulletin de sécurité |