
Analisi della race condition CVE-2026-43805 in IOKit IODMACommand e proof of concept
Questa è un'analisi che individua il lock di stato mancante in IODMACommand::PerformOperation_Impl di Apple IOKit tramite il diff dei binari del kernel di macOS 26.5/26.6. Nelle build vulnerabili, CompleteDMA può rilasciare lo stesso stato mentre PerformOperation utilizza lo stato di preparazione e il memory descriptor. La patch di 26.6 applica anche a PerformOperation_Impl il fDextLock che i due percorsi già condividevano.
Stato di verifica
Il diff dei binari, i target delle chiamate, la mappatura con il sorgente XNU pubblico e il modello deterministico della race sono stati verificati. Il trigger nativo DriverKit presente nel repository è stato scritto in ambiente Linux/WSL e non è ancora stato compilato con Xcode né eseguito in A/B su macOS vulnerabile/patched. Pertanto questo repository attualmente non afferma di aver osservato un kernel panic reale né un kernel write controllabile.
Apple ha classificato questo problema come race condition in IOKit, spiegando che un'app locale può causare un arresto imprevisto del sistema o una scrittura in memoria del kernel. Il segnalatore è 이재영. Avviso di sicurezza Apple macOS Tahoe 26.6, Avviso di sicurezza Apple iOS/iPadOS 26.6
| Prodotto | Versione con prima correzione | Coppia vulnerabile/corretta usata nell'analisi |
|---|---|---|
| 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 versione corretta confermata dall'avviso |
| macOS Sonoma | 14.8.8 | Solo versione corretta confermata dall'avviso |
| watchOS | 26.6 | Solo versione corretta confermata dall'avviso |
Le versioni corrette di Sequoia e Sonoma sono consultabili rispettivamente nell'avviso Apple 15.7.8 e nell'avviso Apple 14.8.8, mentre watchOS nell'avviso Apple 26.6.
Il 2026-09-27 sono state effettuate ricerche combinando l'ID CVE con PoC, exploit, GitHub, IOKit e il nome del segnalatore, ma non è stato trovato alcun codice di riproduzione pubblico né analisi della causa. Questa affermazione riflette l'osservazione al momento della ricerca e non significa che un PoC pubblico non possa assolutamente esistere.
Poiché il sorgente XNU corrispondente alla versione corretta non è stato reso pubblico, invece del diff dei commit del sorgente sono stati confrontati i kernel KDK. Il lato vulnerabile corrisponde esattamente a xnu-12377.121.6 pubblicato da Apple, ma alla data dell'analisi il tag xnu-12377.161.13 del lato corretto non esisteva. Il KDK è un artefatto di debug e simboli del kernel fornito da Apple, e Apple stessa raccomanda di utilizzare il KDK corrispondente alla versione. Guida Apple KDK
I file utilizzati per il confronto non sono inclusi nel repository.
| Categoria | File | SHA-256 |
|---|---|---|
| KDK DMG vulnerabile | Kernel_Debug_Kit_26.5_build_25F71.dmg | 90ed319cd1ba6e23d1eefcee89fa1b10743f4cf60b85208ae52aa9f45543c7aa |
| KDK DMG corretto | Kernel_Debug_Kit_26.6_build_25G70.dmg | edaa0b3d431b43ba7dda2f0e82314b19d5476ba4089a7d8c1de18c49b3ad168b |
| Kernel x86_64 vulnerabile | XNU 12377.121.6~2 | f4dcaa7e59ae59f3d945c2332862772596b71e9823cc202983ba4f9d897b5bec |
| Kernel x86_64 corretto | XNU 12377.161.13~4 | 754db65cb15599183ccebfaa2e4909f673de5d7da42ba4293256cb1184587efd |
| kernelcache iOS vulnerabile | XNU 12377.122.8~1 | 7bd856548a2d170a5f8c962e9a5740290e5a4ba9a6ac39c96c927d4dd400d890 |
| kernelcache iOS corretto | XNU 12377.162.13~2 | 680fa3925641e2b81541c8455fc6d8d432acad9f059ac44bb48324791049c9d6 |
tools/diff_macho_symbols.py legge i simboli Mach-O e le sezioni eseguibili, ripristina i nomi C++, normalizza i target di salto/chiamata e gli indirizzi relativi a RIP, quindi confronta le istruzioni per funzione. Tra le 19 funzioni modificate con nomi IOKit, escludendo i cambiamenti nei numeri di riga per la diagnostica, la modifica del flusso di controllo di IODMACommand::PerformOperation_Impl corrispondeva all'"improved state handling" menzionato nell'avviso.
IODMACommand::PerformOperation_Impl(...)
vulnerable: 0xffffff8000a39080, 512 bytes
fixed: 0xffffff8000a3b860, 544 bytes
normalized similarity: 0.621429
Nel kernel corretto viene aggiunta la seguente chiamata.
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
Osservando il sorgente pubblico vulnerabile, PrepareForDMA_Impl e CompleteDMA_Impl acquisiscono già fDextLock. Al contrario, PerformOperation_Impl controlla fActive e poi utilizza fMemory, readBytes, writeBytes senza lo stesso lock.
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
Se CompleteDMA_Impl viene eseguito tra il controllo e l'utilizzo in PerformOperation_Impl, lo stato di preparazione inizialmente verificato non è più valido. fMemory è un OSSharedPtr<IOMemoryDescriptor>, ma questo percorso non ottiene un riferimento o lock separato per proteggere l'intera operazione. Di conseguenza, è possibile continuare a utilizzare uno stato di memoria DMA rilasciato o sostituito.
Dopo la patch, le tre RPC DMA serializzano le transizioni di stato con lo stesso lock.
flowchart LR
P[PrepareForDMA] -->|fDextLock| S[(fActive / fMemory)]
O[PerformOperation] -->|fDextLock 추가| S
C[CompleteDMA] -->|fDextLock| S
L'avviso Apple specifica il kernel-memory write come possibile impatto, ma il solo diff dei binari non dimostra il controllo stabile dell'indirizzo e del valore di scrittura. Ciò che si può confermare qui è la race sul ciclo di vita/stato di preparazione e l'aggiunta del lock che la impedisce.
poc/model/race_model.cpp riproduce l'interleaving problematico senza chiamare le API del kernel. Nel percorso vulnerabile forza il thread del lifecycle a rilasciare la memoria subito dopo il controllo dello stato, mentre nel percorso corretto verifica che lo stesso lock ritardi il rilascio.
make model
Output verificato:
vulnerable path: stale memory access = observed
fixed path: stale memory access = not observed
Questo modello è un PoC ausiliario che verifica il principio della patch e non rappresenta il risultato reale di un crash della vulnerabilità del kernel Apple.