
CVE-2026-64788の概念実証。iOS 26.6のIOGPUFamilyカーネル拡張におけるuse-after-freeであり、Metalテクスチャ生成とヒープスプレーによる悪用を実証する。
コンポーネント: IOGPUFamily カーネル拡張(com.apple.iokit.IOGPUFamily)
影響を受けるバージョン: iOS / iPadOS 26.6(23G71)以前
修正バージョン: iOS / iPadOS 26.6.1(23G83)
種別: IOGPUDevice::create_resource_iosurface における Use-After-Free
影響: カーネルメモリ破壊。A14(iPhone 12)で UAF の逆参照を確認
発見者: f00l(@PPPF00L)、3ndy1(@_3ndy1)、Minghao Lin(@Y1nkoc)、云散花折、Arjanit Isufi
(Apple セキュリティアドバイザリ — iOS 26.6.1 より)
IOGPUDevice::create_resource_iosurface は IOGPUSysMemory オブジェクト(約 0x100 バイト、kalloc.256 ゾーン)を割り当て、デバイスの IOSurface リソーステーブルに登録します。戻る前に、ADDS width+height → b.hs による次元オーバーフローチェックが発動します。オーバーフローパスは オブジェクトを解放せずに エラーリターンへ分岐し、解放済みメモリを指すライブエントリがリソーステーブルに残ります。
create_resource_iosurface:
kalloc(0x100) → obj ; IOGPUSysMemory を割り当て
table[new_id] = obj ; 参照付きで登録
ADDS w_result, w_width, w_height
b.hs error_path ; ← オーバーフロー: ここへジャンプ
error_path:
; オブジェクトは解放されず、テーブルエントリもクリアされない
return kIOReturnInvalid
古いテーブルエントリは、同じリソース ID が再利用されるかデバイスが閉じられるまで残り続けます。
IOGPUDevice::set_resource_purgeable(id) は get_resource_by_id() で古い ID を検索し、ダングリングエントリを見つけて非仮想的にアクセスします:
PoC は Metal の newTextureWithDescriptor:iosurface:plane: を細工したオーバーフロー次元で使用して UAF をトリガーします。UAF の逆参照の前に:
kalloc.256 スロットを埋める[+0x10]=0、[+0x24]=0、[+0x28]=0 を設定 → Call2 と Call3 は安全にスキップされるトリガー検出: 存在しないリソースに対する set_resource_purgeable は 0xe00002c2 を返します。UAF + スプレーでスロットが再利用された後、同じ呼び出しは 0xe0002be(リソースが見つかり、Call1 が発火)を返します — 古いエントリがスプレーデータで処理されていることを確認します。
iOS 26 のゾーン隔離(zone sequestration)により、解放された IOGPUSysMemory オブジェクトは型安定ゾーンのフリーリストに戻されます。[obj+0x10](IOMemoryDescriptor)と [obj+0x18](IOGPUDevice)はどちらも外部参照カウントを保持しており、オブジェクト解放後も生存し続けます。その結果、completeMemory() は常に有効な ivar データ上で実行されます — UAF の逆参照は確認されていますが、iOS 26 ではこの経路のみによるカーネル読み書きプリミティブは、ゾーン隔離を破る二次プリミティブなしではブロックされます。
clang -arch arm64 -framework Metal -framework IOSurface \
-framework IOKit -framework Foundation \
-o poc poc/poc_iogpu_uaf.m
または Xcode で開き、有効な署名チームを設定してデバイス上で実行します。
| 日付 | イベント |
|---|---|
| 2026-08-17 | 修正を含む iOS 26.6.1 がリリース |
| 2026-08-17 | Apple がセキュリティアドバイザリでクレジットを公開 |
| オフセット | 操作 | 説明 |
|---|
+0x010c | ldaddl w9(-4), w8, [obj+0x24] | [obj+0x24] のアトミック減算。旧値 → w8 |
+0x0128 | cbz w8, skip; ldr x1, [obj+0x28] | 旧 [+0x24] != 0 の場合: [obj+0x28] を IOGPUMemory::setAllocation の引数としてロード |
+0x0134 | ldr x0, [obj+0x10] | [obj+0x10] を IOCommandGate の引数としてロード。0 の場合は cbz → skip |