## https://sploitus.com/exploit?id=FA08775C-6E51-5C9C-9DFC-21E6FEE31DC0
# CVE-2026-43655: AppleM2ScalerCSCDriver shared scheduler use-after-free
Public technical disclosure for **CVE-2026-43655**, an `AppleM2ScalerCSCDriver` use-after-free reachable from the default iOS app sandbox with no special entitlements.
Apple addressed this issue in iOS 26.5 / iPadOS 26.5 / macOS Tahoe 26.5. This repository contains the source code, minimal entitlements, a built IPA, and a detailed technical explanation for public post-fix review.
## Root cause
`AppleM2ScalerCSCDriver` keeps a shared scheduler heap used by scaler operations. The PoC primes that scheduler with async operations from a victim `IOSurfaceAcceleratorClient` connection, then closes the victim connection.
The bug is that teardown frees the victim connection's per-client operation objects while stale scheduler entries can still reference those freed operations. A later scaler scheduling cycle can process those stale entries after the freed pool slots have been reused by another connection.
In the observed vulnerable behavior:
- victim operations carry marker `0xDEAD0001`;
- replacement spray operations carry marker `0xBEEF0002`;
- the later kernel fault observes `x9 = 0x00000000BEEF0002`, the replacement marker, not the victim marker.
That marker swap demonstrates that the scheduler read from a pool slot that was freed and then reallocated: a use-after-free.
## Physical-device reproduction sequence
Important reproduction detail: after tapping **TEARDOWN UAF**, the device does not necessarily panic immediately. The stale scheduler state is primed first. The bug triggers on the next scaler scheduling cycle, which in practice occurs when SpringBoard/compositor activity drives the scaler. In my physical-device reproduction, I triggered that scheduler cycle by tapping/interacting with the **Dynamic Island** after the PoC finished priming the stale scheduler state.
Reproduction flow:
1. Reboot the vulnerable device before running the PoC.
2. Install and launch the PoC app.
3. Tap **TEARDOWN UAF**.
4. Wait while the PoC creates victim async operations with marker `0xDEAD0001`.
5. The PoC closes the victim connection, leaving stale scheduler entries.
6. The PoC opens spray connections with marker `0xBEEF0002`.
7. When the app prints the trigger prompt, tap/interact with the **Dynamic Island** to force SpringBoard/compositor activity and drive the scaler scheduler.
8. The device panics/reboots when the stale scheduler entry is processed.
9. After reboot, verify the panic register state contains `x9 = 0x00000000BEEF0002`.
The `BEEF0002` value is the spray value. Seeing it instead of `DEAD0001` is the key proof that the scheduler touched memory after it had been freed and reused by a different connection.
## Files
| File | Description |
| --- | --- |
| [`ScalerTeardownUAF.m`](./ScalerTeardownUAF.m) | Objective-C PoC source. Opens the victim connection, submits async operations, tears it down, sprays replacement connections, and keeps scheduling pressure active. |
| [`ScalerTeardownUAF.ipa`](./ScalerTeardownUAF.ipa) | Built IPA preserving the reproduction artifact. |
| [`entitlements.plist`](./entitlements.plist) | Minimal entitlement file with `get-task-allow` only. |
## Build
```bash
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
```
## Notes
This is a post-fix CVE disclosure archive for technical verification and defensive research.