
CVE-2026-43805 análisis de carrera de IOKit IODMACommand y prueba de concepto
Este es un análisis del bloqueo de estado faltante en IODMACommand::PerformOperation_Impl de Apple IOKit, descubierto mediante diff de binarios del kernel de macOS 26.5/26.6. En las compilaciones vulnerables, mientras PerformOperation usa el estado preparado y el descriptor de memoria, CompleteDMA puede liberar ese mismo estado. El parche de 26.6 aplica también a PerformOperation_Impl el fDextLock que ambas rutas ya compartían.
Estado de verificación
Se verificaron el diff de binarios, los destinos de llamada, el mapeo con las fuentes públicas de XNU y el modelo de carrera determinista. El trigger nativo de DriverKit del repositorio fue escrito en un entorno Linux/WSL y aún no se ha compilado con Xcode ni se ha ejecutado en A/B sobre macOS vulnerable/parcheado. Por lo tanto, este repositorio actualmente no afirma haber observado un kernel panic real ni una escritura de kernel controlable.
Apple clasificó este problema como una race condition en IOKit, y describe que una app local puede provocar un apagado inesperado del sistema o una escritura en memoria del kernel. El reportero es 이재영. Aviso de seguridad de Apple macOS Tahoe 26.6, Aviso de seguridad de Apple iOS/iPadOS 26.6
| Producto | Primera versión corregida | Par vulnerable/corregido usado en el análisis |
|---|---|---|
| iOS / iPadOS | 26.6 | iPhone 11: 26.5.2 (23F84) → 26.6 (23G71) |
| macOS Tahoe | 26.6 | KDK 26.5 (25F71) → KDK 26.6 (25G70) |
| macOS Sequoia | 15.7.8 | Solo se confirmó la versión corregida mediante el aviso |
| macOS Sonoma | 14.8.8 | Solo se confirmó la versión corregida mediante el aviso |
| watchOS | 26.6 | Solo se confirmó la versión corregida mediante el aviso |
Las versiones corregidas de Sequoia y Sonoma se pueden consultar en el aviso de Apple 15.7.8 y el aviso de Apple 14.8.8 respectivamente, y watchOS en el aviso de Apple 26.6.
El 2026-09-27 se buscó combinando el CVE ID con PoC, exploit, GitHub, IOKit y el nombre del reportero, pero no se encontró código de reproducción público ni análisis de causa raíz. Esta afirmación corresponde a la observación en el momento de la búsqueda y no significa que un PoC público no pueda existir jamás.
Como las fuentes de XNU correspondientes a la versión corregida no se publicaron, se compararon los kernels de KDK en lugar del diff de commits de código fuente. El lado vulnerable corresponde exactamente a xnu-12377.121.6 publicado por Apple, pero a la fecha del análisis no existía la etiqueta xnu-12377.161.13 del lado corregido. KDK es un artefacto de símbolos y depuración del kernel proporcionado por Apple, y Apple también recomienda usar el KDK correspondiente a la versión. Guía de KDK de Apple
Los archivos usados en la comparación no se incluyen en el repositorio.
| Clasificación | Archivo | SHA-256 |
|---|---|---|
| DMG de KDK vulnerable | Kernel_Debug_Kit_26.5_build_25F71.dmg | 90ed319cd1ba6e23d1eefcee89fa1b10743f4cf60b85208ae52aa9f45543c7aa |
| DMG de KDK corregido | Kernel_Debug_Kit_26.6_build_25G70.dmg | edaa0b3d431b43ba7dda2f0e82314b19d5476ba4089a7d8c1de18c49b3ad168b |
| Kernel x86_64 vulnerable | XNU 12377.121.6~2 | f4dcaa7e59ae59f3d945c2332862772596b71e9823cc202983ba4f9d897b5bec |
| Kernel x86_64 corregido | XNU 12377.161.13~4 | 754db65cb15599183ccebfaa2e4909f673de5d7da42ba4293256cb1184587efd |
| kernelcache de iOS vulnerable | XNU 12377.122.8~1 | 7bd856548a2d170a5f8c962e9a5740290e5a4ba9a6ac39c96c927d4dd400d890 |
| kernelcache de iOS corregido | XNU 12377.162.13~2 | 680fa3925641e2b81541c8455fc6d8d432acad9f059ac44bb48324791049c9d6 |
tools/diff_macho_symbols.py lee los símbolos y secciones ejecutables de Mach-O, restaura los nombres C++, normaliza los destinos de bifurcación/llamada y las direcciones relativas a RIP, y compara las instrucciones por función. De las 19 funciones modificadas con nombres de IOKit, excluyendo los cambios en números de línea de diagnóstico, el cambio en el flujo de control de IODMACommand::PerformOperation_Impl coincidía con el "improved state handling" del aviso.
IODMACommand::PerformOperation_Impl(...)
vulnerable: 0xffffff8000a39080, 512 bytes
fixed: 0xffffff8000a3b860, 544 bytes
normalized similarity: 0.621429
En el kernel corregido se añade la siguiente llamada.
mov rax, [r14 + 0x70] ; IODMACommand::reserved
mov rdi, [rax + 0xc0] ; IODMACommandInternal::fDextLock
call IOLockLock
; fActive 확인 및 readBytes/writeBytes 작업
mov rax, [r14 + 0x70]
mov rdi, [rax + 0xc0]
call IOLockUnlock
Si se observa el código fuente público vulnerable, PrepareForDMA_Impl y CompleteDMA_Impl ya toman fDextLock. En cambio, PerformOperation_Impl verifica fActive y luego usa fMemory, readBytes y writeBytes sin el mismo bloqueo.
sequenceDiagram
participant A as Worker A: PerformOperation
participant C as IODMACommand state
participant B as Worker B: CompleteDMA
A->>C: fActive == true 확인
A->>A: 임시 버퍼 할당/준비
B->>C: fDextLock 획득
B->>C: complete(), fActive 감소
B->>C: clearMemoryDescriptor(), fMemory 해제
B-->>C: fDextLock 해제
A->>C: readBytes/writeBytes에서 fMemory 사용
Note over A,C: 상태 검사와 사용 사이 TOCTOU
Si CompleteDMA_Impl se ejecuta entre la verificación y el uso en PerformOperation_Impl, el estado preparado verificado inicialmente ya no es válido. fMemory es OSSharedPtr<IOMemoryDescriptor>, pero esta ruta no asegura una referencia o bloqueo separado que proteja toda la operación. Como resultado, se puede seguir usando un estado de memoria DMA liberado o reemplazado.
Tras el parche, las tres RPC de DMA serializan las transiciones de estado con el mismo bloqueo.
flowchart LR
P[PrepareForDMA] -->|fDextLock| S[(fActive / fMemory)]
O[PerformOperation] -->|fDextLock 추가| S
C[CompleteDMA] -->|fDextLock| S
El aviso de Apple especifica kernel-memory write como posible impacto, pero solo con el diff de binarios no se demuestra el control estable de la dirección y el valor de escritura. Lo que se puede confirmar aquí es la carrera de vida útil/estado preparado y la adición del bloqueo que la previene.
poc/model/race_model.cpp reproduce el interleaving problemático sin llamar a las API del kernel. En la ruta vulnerable fuerza a que el hilo de lifecycle libere la memoria justo después de la verificación de estado, y en la ruta corregida verifica si el mismo bloqueo retrasa la liberación.
make model
Salida verificada:
vulnerable path: stale memory access = observed
fixed path: stale memory access = not observed
Este modelo es un PoC auxiliar que verifica el principio del parche, y no es el resultado real de colisión de la vulnerabilidad del kernel de Apple.