
Prueba de concepto para CVE-2026-64788, un use-after-free en la extensión de kernel IOGPUFamily en iOS 26.6, que demuestra la explotación mediante la creación de texturas Metal y heap spraying.
Componente: Extensión de kernel IOGPUFamily (com.apple.iokit.IOGPUFamily)
Afecta: iOS / iPadOS 26.6 (23G71) y anteriores
Corregido en: iOS / iPadOS 26.6.1 (23G83)
Tipo: Use-After-Free en IOGPUDevice::create_resource_iosurface
Impacto: Corrupción de memoria del kernel; desreferencia UAF confirmada en A14 (iPhone 12)
Descubierto por: f00l (@PPPF00L), 3ndy1 (@_3ndy1), Minghao Lin (@Y1nkoc), 云散花折, Arjanit Isufi
(según Aviso de seguridad de Apple — iOS 26.6.1)
IOGPUDevice::create_resource_iosurface asigna un objeto IOGPUSysMemory (~0x100 bytes, zona ) y lo registra en la tabla de recursos IOSurface del dispositivo. Antes de retornar, se activa una comprobación de desbordamiento de dimensiones mediante . La ruta de desbordamiento se bifurca a un retorno de error , dejando una entrada viva en la tabla de recursos que apunta a memoria liberada.
kalloc.256ADDS width+height → b.hscreate_resource_iosurface:
kalloc(0x100) → obj ; IOGPUSysMemory asignado
table[new_id] = obj ; registrado con una referencia
ADDS w_result, w_width, w_height
b.hs error_path ; ← desbordamiento: salta aquí
error_path:
; objeto NO liberado, entrada de tabla NO borrada
return kIOReturnInvalid
La entrada obsoleta de la tabla persiste hasta que se reutiliza el mismo ID de recurso o se cierra el dispositivo.
IOGPUDevice::set_resource_purgeable(id) busca el ID obsoleto mediante get_resource_by_id(), encuentra la entrada colgante y accede a ella de forma no virtual:
| Offset | Operación | Descripción |
|---|---|---|
+0x010c | ldaddl w9(-4), w8, [obj+0x24] | Decremento atómico de [obj+0x24]; valor anterior → w8 |
+0x0128 | cbz w8, skip; ldr x1, [obj+0x28] | Si el valor anterior [+0x24] != 0: carga [obj+0x28] como argumento para IOGPUMemory::setAllocation |
+0x0134 | ldr x0, [obj+0x10] | Carga [obj+0x10] como argumento de IOCommandGate; cbz → skip si es 0 |
El PoC desencadena el UAF usando newTextureWithDescriptor:iosurface:plane: de Metal con dimensiones de desbordamiento manipuladas. Antes de la desreferencia UAF:
kalloc.256[+0x10]=0, [+0x24]=0, [+0x28]=0 → Call2 y Call3 se omiten de forma seguraDetección del disparador: set_resource_purgeable sobre un recurso inexistente retorna 0xe00002c2. Después de que el UAF + spray recupera la ranura, la misma llamada retorna 0xe0002be (recurso encontrado, Call1 disparada) — confirmando que la entrada obsoleta se está procesando con nuestros datos del spray.
La secuestración de zonas en iOS 26 coloca los objetos IOGPUSysMemory liberados de nuevo en una lista libre de zona estable por tipo. Tanto [obj+0x10] (IOMemoryDescriptor) como [obj+0x18] (IOGPUDevice) mantienen recuentos de retención externos y permanecen vivos después de que el objeto se libera. Como resultado, completeMemory() siempre se ejecuta sobre datos ivar válidos — la desreferencia UAF está confirmada pero una primitiva de lectura/escritura del kernel solo mediante esta ruta está bloqueada en iOS 26 sin una primitiva secundaria para romper la secuestración de zonas.
clang -arch arm64 -framework Metal -framework IOSurface \
-framework IOKit -framework Foundation \
-o poc poc/poc_iogpu_uaf.m
O abrir en Xcode, establecer un equipo de firma válido y ejecutar en el dispositivo.
| Fecha | Evento |
|---|---|
| 2026-08-17 | iOS 26.6.1 publicado con la corrección |
| 2026-08-17 | Créditos de Apple publicados en el aviso de seguridad |