Skip to content
KitploitKITPLOIT
ИнструментыЭксплойтыБлог
Log in
Отправить
ИнструментыЭксплойтыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

ЛентыКонтактыКонфиденциальность© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
CVE-2026-43805-analysis — Однодневный анализ + PoC-санитайзер для CVE-2026-43805 (гонка RPC в IOKit IODMACommand DriverKit, CWE-362) | Kitploit
Инструменты/GitHubGitHub/wtcyj/cve-2026-43805-analysis
Статический анализКриминалистика памятиАнализ уязвимостейЭксплуатацияОбратная инженерияСтатьи и ИсследованияОбучение и Образование
GitHubwtcyj/cve-2026-43805-analysis

CVE-2026-43805-analysis

Однодневный анализ + PoC-санитайзер для CVE-2026-43805 (гонка RPC в IOKit IODMACommand DriverKit, CWE-362)

Репозиторий
1 месяц назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

CVE-2026-43805 — гонка в RPC DriverKit IODMACommand из IOKit

Однодневный анализ состояния гонки в Apple IOKit, исправленной в iOS/iPadOS 26.6, macOS Tahoe 26.6, Sequoia 15.7.8, Sonoma 14.8.8 и watchOS 26.6. На момент написания публичного proof-of-concept не существовало, поэтому работа здесь заключается в следующем: найти исправленный код, прочитав первичный исходный код XNU, объяснить первопричину вплоть до освобождённого объекта и воспроизвести дефект в виде достоверной модели, проверенной санитайзерами.

Уведомление Apple лаконично:

Состояние гонки было устранено за счёт улучшенной обработки состояния. Приложение может вызвать неожиданное завершение работы системы или запись в память ядра.

Классифицировано как CWE-362 (конкурентное выполнение с некорректной синхронизацией), CVSS 9.8. Уведомления: 128066 · 128067 · 128068 · 128071 · 128072.

Где находится ошибка

IODMACommand доступен расширениям DriverKit (dext) через RPC. Реализации этих точек входа RPC на стороне ядра — это методы _Impl в iokit/Kernel/IOUserServer.cpp. Dext управляет DMA-буфером через три из них:

Метод RPCстрока (xnu-12377.121.6)Удерживает fInternalState->fDextLock?
PrepareForDMA_Impl1009да — IOLockLock @1033, разблокировка @1078
CompleteDMA_Impl1084да — IOLockLock @1096, разблокировка @1118
PerformOperation_Impl1154нет — читает fActive и fMemory без блокировки

Блокировка существует. IODMACommand::init выделяет её (iokit/Kernel/IODMACommand.cpp, строка 342). Два из трёх «собратьев» её захватывают. Третий — нет, и именно третий разыменовывает общий дескриптор памяти. Эта асимметрия и есть уязвимость.

xnu-12377.121.6 (macOS 26.x, последний тег, для которого Apple опубликовала исходный код) по-прежнему содержит незаблокированный PerformOperation_Impl, поэтому это уязвимое дерево; публикация исходного кода 26.6, содержащая исправление, пока не общедоступна. Соответствующий исходный код зеркалирован в analysis/IOUserServer_excerpt.cpp.

Первопричина

PerformOperation_Impl выполняет проверку fActive по времени, а затем использует fMemory:

    if (!fActive) {                        // time-of-check  (no lock held)
        return kIOReturnNotReady;
    }
    ...
    if (length > fMemory->getLength()) {   // time-of-use   (fMemory may be gone)
        return kIOReturnBadArgument;
    }
    ...
    copiedDMA = writeBytes(dmaOffset, buffer.data(), length);   // write into the mapping

CompleteDMA_Impl выполняет демонтаж под блокировкой:

    IOLockLock(fInternalState->fDextLock);
    ...
    ret = clearMemoryDescriptor(true);     // see below
    ...
    IOLockUnlock(fInternalState->fDextLock);

и clearMemoryDescriptor(true) (IODMACommand.cpp, строка 455) — это то, что фактически освобождает объект, к которому PerformOperation собирается обратиться:

    if (fMemory) {
        while (fActive) {
            complete();                    // drains fActive to 0
        }
        ...
        fMemory.reset();                   // releases the IOMemoryDescriptor
    }

Итак, опасное чередование выглядит так:

  1. PerformOperation_Impl передаёт if (!fActive), пока команда всё ещё активна.
  2. CompleteDMA_Impl захватывает блокировку, опустошает fActive и выполняет fMemory.reset(), освобождая дескриптор памяти и позволяя его закреплённому backing быть освобождённым/переиспользованным.
  3. PerformOperation_Impl, всё ещё выполняющийся, разыменовывает теперь уже устаревший fMemory в getLength(), а затем в writeBytes().

Поскольку PerformOperation так и не захватил блокировку, шаг 2 может беспрепятственно попасть в промежуток между шагами 1 и 3. writeBytes копирует предоставленные вызывающим кодом байты в DMA-отображение, чей backing уже освобождён — как только эта страница будет переиспользована для другого выделения ядра, это и есть «запись в память ядра», о которой предупреждает advisory. Если же попасть на путь чтения, получите use-after-free при чтении / неожиданное завершение.

sequenceDiagram
    participant W as dext thread A — PerformOperation_Impl (no lock)
    participant O as dext thread B — CompleteDMA_Impl (holds fDextLock)
    W->>W: if (!fActive) → active, continue
    Note over W: passed the check, about to use fMemory
    O->>O: IOLockLock(fDextLock)
    O->>O: clearMemoryDescriptor(true): fActive=0, fMemory.reset()  ← FREE
    O->>O: IOLockUnlock(fDextLock)
    W->>W: fMemory->getLength() / writeBytes()  ← USE-AFTER-FREE

Воспроизведение без уязвимой macOS

Для запуска реального пути требуется подписанный DriverKit dext с правом DriverKit от Apple на уязвимой сборке, что недостижимо с хоста Windows. Вместо этого poc/race_model.cpp повторно реализует точную логику разделяемого состояния трёх методов — та же дисциплина блокировок, тот же порядок «проверка-затем-освобождение-затем-использование» — так что дефект можно наблюдать напрямую:

  • PrepareForDMA и CompleteDMA захватывают мьютекс; PerformOperation — нет (если только не собрано с -DFIXED, что добавляет одну недостающую блокировку).
  • CompleteDMA освобождает дескриптор, повторяя fMemory.reset().
  • Драйверный harness запускает PerformOperation в одном потоке, а CompleteDMA в другом, помещая teardown внутрь окна гонки с помощью атомарного сигнала (только для синхронизации — это никогда не блокировка разделяемого состояния).
cd poc
bash run.sh

Уязвимая сборка:

  • ThreadSanitizer сообщает о гонке данных — operator delete внутри CompleteDMA конкурирует с чтением getLength() внутри PerformOperation, причём мьютекс удерживается только удаляющим потоком. Полный лог: evidence/tsan_vulnerable.txt.
  • AddressSanitizer сообщает об использовании после освобождения (heap-use-after-free): объект, освобождённый в CompleteDMA, читается в PerformOperation::getLength, а выделен в PrepareForDMA. Полный лог: evidence/asan_vulnerable.txt.
==ERROR: AddressSanitizer: heap-use-after-free ... in MemoryDescriptor::getLength()
freed by thread T0 here:   ... IODMACommand::CompleteDMA()  race_model.cpp:70
allocated by thread T0:    ... IODMACommand::PrepareForDMA() race_model.cpp:61

Исправленная сборка (-DFIXED, блокировка добавлена в PerformOperation): оба санитайзера чисты, и каждая операция корректно сериализуется относительно teardown. Логи: evidence/tsan_fixed.txt, evidence/asan_fixed.txt.

Это доказывает, что гонка реальна в логике и что блокировка одновременно необходима и достаточна. Это не живой kernel panic — см. область применимости ниже.

Исправление

Скачать инструмент