
CVE-2026-43655 AppleM2ScalerCSCDriver use-after-free 취약점 공개
CVE-2026-43655에 대한 공개 기술 공개 문서로, AppleM2ScalerCSCDriver / IOSurfaceAccelerator 사용 후 해제 취약점입니다. 기본 iOS 앱 샌드박스에서 특별한 자격 증명 없이도 접근 가능합니다.
Apple은 iOS 26.5 / iPadOS 26.5 / macOS Tahoe 26.5에서 이 문제를 수정했습니다. 이 저장소에는 Objective-C 개념 증명 소스, 최소 자격 증명, 빌드된 IPA, 그리고 영향을 받는 장치에서 문제를 이해하고 재현하는 데 필요한 기술 문서가 포함되어 있습니다.
이 버그는 스케일러 스케줄러의 해체/수명 오류입니다. 사용자 프로세스는 비동기 스케일러 작업을 제출하고, 해당 작업을 소유한 IOSurfaceAcceleratorClient 연결을 닫은 후 드라이버 전역 스케줄러 구조에 오래된 항목을 남길 수 있습니다. 이후 스케줄러 패스가 이미 해제되어 재사용된 작업 저장소를 가리키는 항목을 처리할 수 있습니다.
PoC는 두 개의 다른 마커 값을 사용하여 수명 오류를 보여줍니다:
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가 오래된 스케줄러 상태를 준비한 후 Dynamic Island를 탭하거나 상호작용하여 해당 스케줄러 주기를 트리거했습니다.
단계:
ScalerTeardownUAF.ipa를 설치하고 실행합니다.AppleM2ScalerCSCDriver 연결을 엽니다.IOSurface 객체를 생성합니다.0xDEAD0001로 설정합니다.IOServiceClose로 피해자 연결을 닫아 피해자 소유 작업 객체를 해제하지만 오래된 스케줄러 항목은 남아 있습니다.0xBEEF0002로 설정합니다.x9 = 0x00000000BEEF0002가 포함되어 있는지 확인합니다.예상되는 증명 조건:
x9 = 0x00000000BEEF0002는 스케줄러가 원래 해제된 피해자 작업에 속했던 메모리에서 스프레이 마커를 읽었음을 의미합니다.0xBEEF0002는 피해자 마커가 아닌 대체 연결 마커입니다.포함된 소스는 다음 순서를 수행합니다:
피해자 연결 열기
IOSurface 소스/대상 쌍 생성
동기 기준 스케일러 요청 제출
셀렉터 10을 통해 피해자 마커 = 0xDEAD0001 설정
50개의 비동기 스케일러 작업 제출
피해자 연결 닫기
50개의 스프레이 연결 열기
셀렉터 10을 통해 스프레이 마커 = 0xBEEF0002 설정
스프레이 연결에 반복 비동기 스케일러 작업 제출
SpringBoard/컴포지터 스케줄러 트리거 대기
관련 소스 파일은 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, spray 0xBEEF0002)으로 UAF 입증.| 설명 |
|---|
ScalerTeardownUAF.m | 피해자 닫기 + 스프레이 재사용 순서를 구현한 Objective-C PoC 소스. |
ScalerTeardownUAF.ipa | 빌드된 IPA 재현 아티팩트. |
entitlements.plist | get-task-allow를 포함하는 최소 자격 증명 파일. |