
Divulgation publique pour CVE-2026-43655 AppleM2ScalerCSCDriver utilisation après libération
Divulgation technique publique pour CVE-2026-43655, un use-after-free de AppleM2ScalerCSCDriver / IOSurfaceAccelerator accessible depuis le sandbox par défaut des applications iOS sans autorisations spéciales.
Apple a corrigé ce problème dans iOS 26.5 / iPadOS 26.5 / macOS Tahoe 26.5. Ce dépôt contient le code source de la preuve de concept (PoC) en Objective-C, les autorisations minimales, un IPA compilé et le compte-rendu technique nécessaire pour comprendre et reproduire le problème sur un appareil concerné.
Le bug est une erreur de cycle de vie / de démontage dans le planificateur du scaler. Un processus utilisateur peut soumettre des opérations asynchrones de mise à l’échelle, fermer la connexion IOSurfaceAcceleratorClient qui possède ces opérations et laisser des entrées obsolètes dans une structure de planification globale au pilote. Un passage ultérieur du planificateur peut alors traiter des entrées qui pointent encore vers un stockage d’opération déjà libéré et réutilisé.
La PoC démontre le bug de durée de vie avec deux valeurs de marqueur distinctes :
0xDEAD00010xBEEF0002La connexion victime soumet des opérations asynchrones puis est fermée. Des connexions de remplacement sont ouvertes ensuite et définissent leur propre marqueur à 0xBEEF0002. Lors du cycle de planification suivant, le défaut observe le marqueur de remplacement (x9 = 0x00000000BEEF0002), et non le marqueur victime. Cela prouve que le planificateur a lu dans un emplacement d’opération qui avait été libéré puis réalloué à une autre connexion.
com.apple.driver.AppleM2ScalerCSCDriverIOSurfaceAcceleratorClientget-task-allow uniquementAppleM2ScalerCSCDriver conserve un état de planificateur partagé entre les clients du scaler. La discordance de durée de vie pertinente est :
IOServiceClose.Le chemin de démontage ne supprime pas les entrées du planificateur en attente du client en cours de fermeture du tas partagé du planificateur. Le planificateur lit et écrit ensuite des champs à travers ces pointeurs obsolètes.
Champs importants observés durant l’analyse :
| Offset | Comportement du planificateur |
|---|---|
operation + 0xc94 | lu comme la valeur de crédit/marqueur utilisée par le chemin de résolution de crédit |
operation + 0xc1c | écrit par le chemin de comptabilité des crédits du planificateur |
operation + 0x1fe4 | écrit par le chemin de mise à jour de l’état/drapeau du planificateur |
Le comportement de l’allocateur d’opérations rend le bug observable : les emplacements d’opération libérés peuvent être réutilisés par des opérations ultérieures provenant de connexions différentes. En fermant une connexion victime et en ouvrant immédiatement de nouvelles connexions de remplacement (spray), la PoC peut faire en sorte que des entrées obsolètes du planificateur pointent vers de la mémoire désormais possédée par les connexions de remplacement.
x9 = 0xBEEF0002 prouve l’UAFLa PoC utilise une distinction victime/remplacement :
0xDEAD0001.0xBEEF0002.Si le planificateur lisait encore des objets vivants appartenant à la victime, la valeur observée serait 0xDEAD0001. Au lieu de cela, le défaut reproduit observe 0xBEEF0002, la valeur écrite par les connexions de remplacement. C’est la preuve clé que le planificateur déréférence un pointeur obsolète vers une mémoire du noyau libérée et réutilisée.
Cela montre également un impact entre connexions : l’entrée du planificateur a été créée par une connexion, mais la mémoire qu’elle a ensuite touchée a été recyclée pour une autre connexion. Lors des exécutions reproduites, l’activité finale du planificateur pouvait être déclenchée par l’activité normale de SpringBoard/compositeur/UI plutôt que par le processus PoC d’origine.
L’avis public d’Apple décrit l’impact comme : « Une application pourrait être capable de provoquer une terminaison inattendue du système ou de lire la mémoire du noyau. »
Détail important de la reproduction : après avoir tapé TEARDOWN UAF, l’appareil ne plante pas nécessairement immédiatement. La PoC prépare d’abord l’état obsolète du planificateur. Le bug se déclenche lors du cycle de planification suivant, ce qui en pratique se produit lorsque l’activité de SpringBoard/compositeur pilote le scaler. Dans ma reproduction sur appareil physique, j’ai déclenché ce cycle de planification en tapant/interagissant avec la Dynamic Island après que la PoC a fini de préparer l’état obsolète du planificateur.
Étapes :