
CVE-2026-43805 анализ гонки IOKit IODMACommand и proof of concept
Это анализ отсутствующей блокировки состояния в IODMACommand::PerformOperation_Impl из Apple IOKit, обнаруженной путём сравнения бинарных файлов ядра macOS 26.5/26.6. В уязвимой сборке, пока PerformOperation использует состояние готовности и дескриптор памяти, CompleteDMA может освободить то же самое состояние. Патч 26.6 применяет fDextLock, который уже использовался обоими путями, также и к PerformOperation_Impl.
Статус проверки
Бинарный diff, цели вызовов, сопоставление с публичными исходниками XNU и детерминированная модель гонки были проверены. Нативный триггер DriverKit в репозитории написан в среде Linux/WSL и ещё не был собран в Xcode и не проходил A/B-запуск на уязвимой/пропатченной macOS. Поэтому данный репозиторий в настоящее время не утверждает, что наблюдалась реальная паника ядра или управляемая запись в память ядра.
Apple классифицировала эту проблему как состояние гонки (race condition) в IOKit и пояснила, что локальное приложение может вызвать неожиданное завершение работы системы или запись в память ядра. Автор отчёта — 이재영. Уведомление безопасности Apple macOS Tahoe 26.6, Уведомление безопасности Apple iOS/iPadOS 26.6
| Продукт | Первая исправленная версия | Пара уязвимой/исправленной версий, использованная в анализе |
|---|---|---|
| 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 | Только исправленная версия подтверждена уведомлением |
| macOS Sonoma | 14.8.8 | Только исправленная версия подтверждена уведомлением |
| watchOS | 26.6 | Только исправленная версия подтверждена уведомлением |
Исправленные версии для Sequoia и Sonoma можно проверить в уведомлении Apple 15.7.8 и уведомлении Apple 14.8.8 соответственно, а для watchOS — в уведомлении Apple 26.6.
2026-09-27 был выполнен поиск по комбинации CVE ID и PoC, exploit, GitHub, IOKit, имени автора отчёта, но публичный код воспроизведения или анализ первопричины найти не удалось. Это утверждение отражает наблюдение на момент поиска и не означает, что публичный PoC абсолютно не существует.
Поскольку исходники XNU, соответствующие исправленной версии, не были опубликованы, вместо diff коммитов исходников сравнивались ядра KDK. Уязвимая сторона точно соответствует опубликованному Apple xnu-12377.121.6, но на дату анализа тега xnu-12377.161.13 для исправленной стороны не существовало. KDK — это предоставляемые Apple артефакты символов и отладки ядра, и Apple также рекомендует использовать KDK, соответствующий версии. Руководство Apple по KDK
Файлы, использованные для сравнения, не включены в репозиторий.
| Категория | Файл | SHA-256 |
|---|---|---|
| Уязвимый KDK DMG | Kernel_Debug_Kit_26.5_build_25F71.dmg | 90ed319cd1ba6e23d1eefcee89fa1b10743f4cf60b85208ae52aa9f45543c7aa |
| Исправленный KDK DMG | Kernel_Debug_Kit_26.6_build_25G70.dmg | edaa0b3d431b43ba7dda2f0e82314b19d5476ba4089a7d8c1de18c49b3ad168b |
| Уязвимое ядро x86_64 | XNU 12377.121.6~2 | f4dcaa7e59ae59f3d945c2332862772596b71e9823cc202983ba4f9d897b5bec |
| Исправленное ядро x86_64 | XNU 12377.161.13~4 | 754db65cb15599183ccebfaa2e4909f673de5d7da42ba4293256cb1184587efd |
| Уязвимый iOS kernelcache | XNU 12377.122.8~1 | 7bd856548a2d170a5f8c962e9a5740290e5a4ba9a6ac39c96c927d4dd400d890 |
| Исправленный iOS kernelcache | XNU 12377.162.13~2 | 680fa3925641e2b81541c8455fc6d8d432acad9f059ac44bb48324791049c9d6 |
tools/diff_macho_symbols.py читает символы и исполняемые секции Mach-O, восстанавливает имена C++, нормализует цели ветвлений и вызовов, а также RIP-относительные адреса, и сравнивает инструкции по функциям. Среди 19 изменённых функций с именами IOKit, за исключением изменений номеров строк для диагностики, изменение потока управления в IODMACommand::PerformOperation_Impl совпало с «improved state handling» из уведомления.
IODMACommand::PerformOperation_Impl(...)
vulnerable: 0xffffff8000a39080, 512 bytes
fixed: 0xffffff8000a3b860, 544 bytes
normalized similarity: 0.621429
В исправленном ядре появляется следующий вызов.
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
Если посмотреть на уязвимые публичные исходники, PrepareForDMA_Impl и CompleteDMA_Impl уже захватывают fDextLock. В то же время PerformOperation_Impl проверяет fActive, а затем использует fMemory, readBytes, writeBytes без той же блокировки.
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
Если CompleteDMA_Impl выполняется между проверкой и использованием в PerformOperation_Impl, состояние готовности, проверенное изначально, больше не является действительным. fMemory имеет тип OSSharedPtr<IOMemoryDescriptor>, но этот путь не получает отдельную ссылку или блокировку для защиты всей операции. В результате можно продолжать использовать освобождённое или заменённое состояние памяти DMA.
После патча три DMA RPC сериализуют переходы состояния с помощью одной и той же блокировки.
flowchart LR
P[PrepareForDMA] -->|fDextLock| S[(fActive / fMemory)]
O[PerformOperation] -->|fDextLock 추가| S
C[CompleteDMA] -->|fDextLock| S
Уведомление Apple указывает запись в память ядра как возможное воздействие, но только на основе бинарного diff нельзя доказать стабильное управление адресом и значением записи. Здесь можно утверждать лишь о гонке времени жизни/состояния готовности и о добавлении блокировки, которая её предотвращает.
poc/model/race_model.cpp воспроизводит проблемное чередование, не вызывая API ядра. В уязвимом пути он заставляет поток lifecycle освободить память сразу после проверки состояния, а в исправленном пути проверяет, задерживает ли та же блокировка освобождение.
make model
Проверенный вывод:
vulnerable path: stale memory access = observed
fixed path: stale memory access = not observed
Эта модель — вспомогательный PoC, проверяющий принцип патча, а не фактический результат сбоя реальной уязвимости ядра Apple.