
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 :
ScalerTeardownUAF.ipa.AppleM2ScalerCSCDriver.IOSurface source/destination.0xDEAD0001 sur la connexion victime.IOServiceClose, libérant les objets d’opération appartenant à la victime tandis que les entrées obsolètes du planificateur subsistent.0xBEEF0002.x9 = 0x00000000BEEF0002.Condition de preuve attendue :
x9 = 0x00000000BEEF0002 signifie que le planificateur a lu le marqueur de remplacement dans une mémoire qui appartenait à l’origine à l’opération victime libérée.0xBEEF0002 n’est pas le marqueur victime ; c’est le marqueur de la connexion de remplacement.Le code source inclus effectue la séquence suivante :
open victim connection
create IOSurface source/destination pair
submit sync baseline scaler request
set victim marker = 0xDEAD0001 through selector 10
submit 50 async scaler operations
close victim connection
open 50 spray connections
set spray marker = 0xBEEF0002 through selector 10
submit repeated async scaler operations on spray connections
wait for SpringBoard/compositor scheduler trigger
Le fichier source pertinent est ScalerTeardownUAF.m.
xcrun -sdk iphoneos clang -framework Foundation -framework UIKit -framework IOKit \
-framework IOSurface -isysroot $(xcrun --sdk iphoneos --show-sdk-path) \
-arch arm64 -arch arm64e -miphoneos-version-min=16.0 -fobjc-arc \
-o iPhoneProbe.app/iPhoneProbe ScalerTeardownUAF.m
ldid -S entitlements.plist iPhoneProbe.app/iPhoneProbe
mkdir -p /tmp/pkg/Payload
cp -r iPhoneProbe.app /tmp/pkg/Payload/
cd /tmp/pkg && zip -qr ScalerTeardownUAF.ipa Payload
| Fichier | Description |
|---|---|
ScalerTeardownUAF.m | Code source Objective-C de la PoC implémentant la séquence fermeture victime + remplacement/réutilisation. |
ScalerTeardownUAF.ipa | Artefact IPA compilé pour la reproduction. |
entitlements.plist | Fichier d’autorisations minimales contenant get-task-allow. |
AppleM2ScalerCSCDriver.0xDEAD0001, remplacement 0xBEEF0002.