
CVE-2026-43655 AppleM2ScalerCSCDriver use-after-free の公開開示
CVE-2026-43655 に関する公開技術情報です。AppleM2ScalerCSCDriver / IOSurfaceAccelerator の use-after-free であり、特別な entitlements を必要とせず、デフォルトの iOS アプリサンドボックスから到達可能です。
Apple はこの問題を iOS 26.5 / iPadOS 26.5 / macOS Tahoe 26.5 で修正しました。このリポジトリには、Objective-C で書かれた概念実証 (PoC) ソース、最小限の entitlements、ビルド済み IPA、および影響を受けるデバイス上でこの問題を理解・再現するために必要な技術解説が含まれています。
このバグは、スケーラースケジューラにおける破棄/ライフタイムのエラーです。ユーザープロセスは、非同期スケーラー操作を送信し、それらの操作を所有する IOSurfaceAcceleratorClient 接続を閉じ、ドライバ全体で共有されるスケジューラ構造体に古いエントリを残すことができます。その後のスケジューラパスは、すでに解放され再利用された操作ストレージを指すエントリを処理できます。
PoC は、2 つの異なるマーカー値を使用してライフタイムバグを実証します:
0xDEAD00010xBEEF0002被害接続は非同期操作を送信してから閉じられます。その後、置換接続が開かれ、独自のマーカーを 0xBEEF0002 に設定します。次のスケーラー・スケジューリング・サイクルが実行されると、フォールトは被害マーカーではなく置換マーカー (x9 = 0x00000000BEEF0002) を観測します。これは、スケジューラが解放され、その後別の接続に再割り当てされた操作スロットから読み取ったことを証明します。
com.apple.driver.AppleM2ScalerCSCDriverIOSurfaceAcceleratorClientget-task-allow のみAppleM2ScalerCSCDriver は、スケーラークライアント間で共有されるスケジューラ状態を保持します。関連するライフタイムの不一致は次のとおりです:
IOServiceClose で閉じられる。破棄パスは、閉じられるクライアントの保留中のスケジューラエントリを共有スケジューラヒープから削除しません。スケジューラは後でそれらの古いポインタを通じてフィールドを読み書きします。
分析中に観測された重要なフィールド:
| オフセット | スケジューラの動作 |
|---|---|
operation + 0xc94 | クレジット/マーカー値として読み取られる (クレジット解決パスで使用) |
operation + 0xc1c | スケジューラのクレジット会計パスによって書き込まれる |
operation + 0x1fe4 | スケジューラの状態/フラグ更新パスによって書き込まれる |
操作アロケータの動作により、このバグは観測可能になります: 解放された操作スロットは、後で別の接続からの操作によって再利用される可能性があります。被害接続を閉じてすぐに新しい接続をスプレーすることで、PoC は古いスケジューラエントリが現在スプレー接続が所有するメモリを指すようにできます。
x9 = 0xBEEF0002 が UAF を証明する理由PoC は被害/スプレーの区別を使用します:
0xDEAD0001 を設定する。0xBEEF0002 を設定する。スケジューラがまだ有効な被害所有オブジェクトを読み取っていた場合、観測される値は 0xDEAD0001 になるはずです。代わりに、再現されたフォールトは 0xBEEF0002 (置換スプレー接続によって書き込まれた値) を観測します。これは、スケジューラが解放されて再利用されたカーネルメモリへの古いポインタを逆参照していることを示す重要な証拠です。
これはまた、接続間の影響を示しています: スケジューラエントリはある接続によって作成されましたが、後でスケジューラが触れたメモリは別の接続用にリサイクルされていました。再現した実行では、最終的なスケジューラアクティビティは、元の PoC プロセスではなく、通常の SpringBoard/コンポジタ/UI アクティビティによって駆動される可能性があります。
Apple の公開アドバイザリでは、この影響は次のように説明されています: 「アプリがシステムの予期しない終了を引き起こしたり、カーネルメモリを読み取ったりする可能性があります。」
重要な再現の詳細: TEARDOWN UAF をタップした後、デバイスがすぐにパニックするとは限りません。PoC は最初に古いスケジューラ状態を準備します。このバグは次のスケーラー・スケジューリング・サイクルでトリガーされます。これは実際には SpringBoard/コンポジタのアクティビティがスケーラーを駆動したときに発生します。私の実機での再現では、PoC が古いスケジューラ状態の準備を終えた後、ダイナミックアイランド をタップ/操作してスケジューラサイクルをトリガーしました。
手順:
ScalerTeardownUAF.ipa をインストールして起動します。AppleM2ScalerCSCDriver 接続を開きます。IOSurface オブジェクトを作成します。0xDEAD0001 に設定します。IOServiceClose で被害接続を閉じ、被害所有の操作オブジェクトを解放します (古いスケジューラエントリは残ります)。0xBEEF0002 に設定します。x9 = 0x00000000BEEF0002 が含まれていることを確認します。期待される証明条件:
x9 = 0x00000000BEEF0002 は、スケジューラが解放された被害操作に元々属していたメモリからスプレーマーカーを読み取ったことを意味します。0xBEEF0002 は被害マーカーではなく、置換接続マーカーです。含まれているソースは、次のシーケンスを実行します:
open victim connection
create IOSurface source/destination pair
submit sync baseline scaler request
set victim marker = 0xDEAD0001 through selector 10
submit 50 async scaler operations
close victim connection
open 50 spray connections
set spray marker = 0xBEEF0002 through selector 10
submit repeated async scaler operations on spray connections
wait for SpringBoard/compositor scheduler trigger
関連するソースファイルは ScalerTeardownUAF.m です。
xcrun -sdk iphoneos clang -framework Foundation -framework UIKit -framework IOKit \
-framework IOSurface -isysroot $(xcrun --sdk iphoneos --show-sdk-path) \
-arch arm64 -arch arm64e -miphoneos-version-min=16.0 -fobjc-arc \
-o iPhoneProbe.app/iPhoneProbe ScalerTeardownUAF.m
ldid -S entitlements.plist iPhoneProbe.app/iPhoneProbe
mkdir -p /tmp/pkg/Payload
cp -r iPhoneProbe.app /tmp/pkg/Payload/
cd /tmp/pkg && zip -qr ScalerTeardownUAF.ipa Payload
AppleM2ScalerCSCDriver の動作をテスト中に最初のクラッシュを発見。0xDEAD0001、スプレー 0xBEEF0002。| ファイル |
|---|
| 説明 |
|---|
ScalerTeardownUAF.m | 被害接続のクローズ + スプレー再利用シーケンスを実装した Objective-C PoC ソース。 |
ScalerTeardownUAF.ipa | ビルド済み IPA 再現アーティファクト。 |
entitlements.plist | get-task-allow を含む最小限の entitlement ファイル。 |