这是通过 macOS 26.5/26.6 内核二进制 diff 找出 Apple IOKit 中 IODMACommand::PerformOperation_Impl 缺失状态锁的分析。在存在漏洞的构建中,当 PerformOperation 使用就绪状态和内存描述符时,CompleteDMA 可以释放同一状态。26.6 补丁将两条路径已经共享的 fDextLock 也应用于 PerformOperation_Impl。
验证状态
已验证二进制 diff、调用目标、公开 XNU 源码映射以及确定性竞争模型。仓库中的原生 DriverKit 触发器是在 Linux/WSL 环境中编写的,尚未进行 Xcode 构建以及漏洞/补丁 macOS A/B 运行。因此,本仓库目前不声称观察到了实际的内核 panic 或可控的 kernel write。
Apple 将此问题归类为 IOKit 的 race condition,并说明本地应用可能导致意外的系统关机或内核内存写入。报告者是 이재영。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 源码未公开,因此比较了 KDK 内核而非源码提交 diff。漏洞侧与 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
如果在 PerformOperation_Impl 的检查与使用之间执行 CompleteDMA_Impl,则最初确认的就绪状态不再有效。fMemory 是 OSSharedPtr<IOMemoryDescriptor>,但此路径未获取用于保护整个操作的额外引用或锁。结果可能继续使用已释放或被替换的 DMA 内存状态。
补丁后,三个 DMA RPC 使用同一锁串行化状态转换。
flowchart LR
P[PrepareForDMA] -->|fDextLock| S[(fActive / fMemory)]
O[PerformOperation] -->|fDextLock 추가| S
C[CompleteDMA] -->|fDextLock| S
Apple 公告将 kernel-memory write 列为可能影响,但仅凭二进制 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 内核漏洞的实际崩溃结果。
poc/apple-driverkit-sample 基于 Apple 官方的 DriverKit user-client 示例。新增的 selector 6 在两个独立的 DriverKit dispatch queue 中重复执行以下操作。
Worker A: IODMACommand::PerformOperation(Zero, ...)
Worker B: IODMACommand::CompleteDMA()
IODMACommand::PrepareForDMA(...)
PerformOperation(Zero) 在准备大型临时缓冲区后写入 DMA 内存,因此扩大了 fActive 检查与实际 writeBytes 之间的竞争窗口。默认值为 1 MiB、10,000 次,可通过应用中的 SwiftRunDMACommandRace() 调整。
由于存在内核 panic 的可能性,请仅在无未保存工作的独立测试 Mac 或可回滚的测试卷上执行。
poc/apple-driverkit-sample/DriverKitUserClientSample/DriverKitUserClientSample.xcodeproj。DriverKitSampleApp 和 NullDriver target 的 Team 与唯一 bundle ID。DriverKitSampleApp scheme,然后点击 Install Dext。log stream --style compact --predicate 'eventMessage contains "CVE-2026-43805"'
修复版的预期结果是系统保持运行并输出 race completed without a kernel panic 日志。漏洞版在竞争命中时可能导致系统 panic/重启,这是失败信号。不能仅凭重复结束这一事实就断定不存在漏洞。由于这是依赖调度的 race,可能需要多次运行或提高缓冲区大小与重复次数。
原生 harness 尚未在实际 Apple 测试主机上运行。成功、panic、panic log 的 backtrace 只能在观察后记录为结果。
获取 KDK 的 Payload 并安装 Python 依赖后执行。
python3 -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt
python tools/extract_pbzx_cpio.py /path/to/25F71/Payload \
--match 'System/Library/Kernels/kernel$' --output /tmp/kdk-25F71
python tools/extract_pbzx_cpio.py /path/to/25G70/Payload \
--match 'System/Library/Kernels/kernel$' --output /tmp/kdk-25G70
python tools/diff_macho_symbols.py \
/tmp/kdk-25F71/System/Library/Kernels/kernel \
/tmp/kdk-25G70/System/Library/Kernels/kernel \
--name '^IODMACommand::PerformOperation_Impl' --json
python tools/disassemble_macho_symbol.py \
/tmp/kdk-25G70/System/Library/Kernels/kernel \
PerformOperation_Impl
详细地址与候选选取记录见 analysis/patch-diff.md,完整工作记录与验证边界见 docs/mission-log.md。
更新到受支持的最新版本。最低修复版本为 iOS/iPadOS/watchOS 26.6、macOS Tahoe 26.6、Sequoia 15.7.8、Sonoma 14.8.8。编写 DriverKit 代码时,最好在应用侧也不要随意同时调用 IODMACommand lifecycle 与 operation,但这不能替代 OS 更新。
analysis/patch-diff.md 바이너리 diff 근거
docs/mission-log.md 조사·검증 기록
poc/model/race_model.cpp 플랫폼 독립 결정론적 모델
poc/apple-driverkit-sample/ 네이티브 DriverKit 트리거
tools/ PBZX 추출기와 Mach-O diff 도구