├── .gitignore ├── snakes_bridging.h ├── README.md └── snakes.swift /.gitignore: -------------------------------------------------------------------------------- 1 | snakes 2 | vvv 3 | -------------------------------------------------------------------------------- /snakes_bridging.h: -------------------------------------------------------------------------------- 1 | @import CoreFoundation; 2 | @import IOKit; 3 | @import IOSurface; 4 | 5 | // https://github.com/WebKit/WebKit/blob/main/Source/WTF/wtf/spi/cocoa/IOSurfaceSPI.h 6 | 7 | typedef struct __IOSurfaceAccelerator *IOSurfaceAcceleratorRef; 8 | 9 | extern const CFStringRef kIOSurfaceAcceleratorUnwireSurfaceKey; 10 | extern const CFStringRef _Nonnull kIOSurfaceAcceleratorComm; 11 | extern const CFStringRef _Nonnull kIOSurfaceAcceleratorHDREnable; 12 | extern const CFStringRef _Nonnull kIOSurfaceAcceleratorDirectionalScalingEnable; 13 | 14 | IOReturn IOSurfaceAcceleratorCreate(CFAllocatorRef, CFDictionaryRef properties, IOSurfaceAcceleratorRef* acceleratorOut); 15 | CFRunLoopSourceRef IOSurfaceAcceleratorGetRunLoopSource(IOSurfaceAcceleratorRef); 16 | 17 | typedef void (*IOSurfaceAcceleratorCompletionCallback)(void* completionRefCon, IOReturn status, void* completionRefCon2); 18 | 19 | typedef struct IOSurfaceAcceleratorCompletion { 20 | IOSurfaceAcceleratorCompletionCallback completionCallback; 21 | void* completionRefCon; 22 | void* completionRefCon2; 23 | } IOSurfaceAcceleratorCompletion; 24 | 25 | IOReturn IOSurfaceAcceleratorTransformSurface(IOSurfaceAcceleratorRef, IOSurfaceRef sourceBuffer, IOSurfaceRef destinationBuffer, CFDictionaryRef options, void* pCropRectangles, IOSurfaceAcceleratorCompletion* pCompletion, void* pSwap, uint32_t* pCommandID); 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Learning IOSurfaceAccelerator's comm output API. 2 | 3 | Currently crashes on macOS 13 beta 22A5266r with a (non-exploitable) null pointer dereference with ASE (Apple Scaling Engine???) enabled, since I don't know how to use ASEProcessing to generate a set of valid ASE inbound params. 4 | 5 | This calls the userspace IOSurfaceAccelerator framework instead of calling the userclient directly: I didn't want to figure out the layout of the userclient's TransformSurfaceData argument. 6 | 7 | # Notes 8 | 9 | Other documentation about the IOSurfaceAccelerator framework and AppleM2ScalerCSC driver: 10 | 11 | - https://iphonedevwiki.net/index.php/IOSurfaceAccelerator 12 | - https://github.com/WebKit/WebKit/commit/5e7ebb4f4f0592ad2911b8eb84da81ba900b0f4a 13 | - https://muirey03.blogspot.com/2020/09/cve-2020-9964-ios-infoleak.html?m=1 14 | - https://i.blackhat.com/us-18/Wed-August-8/us-18-Chen-KeenLab-iOS-Jailbreak-Internals-wp.pdf 15 | 16 | 17 | Notes about how the comm output api works: 18 | 19 | ``` 20 | M2ScalerScalingASEControl::collectASEApiOutput_gatedContext 21 | -> AppleM2ScalerCSCDriver::completeRequest_gatedContext 22 | 23 | The length (0xa60 in 13.3.1) is written in __ZN18M2ScalerCSCRequest28validateAndInitializeCommAPIEPK19AppleM2ScalerCSCHal 24 | 25 | also written in 26 | __ZN30M2ScalerScalingASEControlMSR1024getASEStats_gatedContextEP18M2ScalerCSCRequest 27 | 28 | length read in 29 | __ZN25M2ScalerScalingASEControl24getASEStats_gatedContextEP18M2ScalerCSCRequest 30 | 31 | -> __ZN22AppleM2ScalerCSCDriver24perfControllerWorkSubmitEP18M2ScalerCSCRequest might also write to it?? 32 | 33 | For getting the memory used by the ASE/HDR APIs: 34 | Probably M2ScalerCSCRequest::mapAPIParams since this mentions "HDR/ASE API ERROR" -> reads from 0x910, etc to make memory descriptors 35 | -> M2ScalerCSCRequest::validateAndInitializeCommAPI 36 | --> AppleM2ScalerCSCDriver::transformGeneral 37 | ---> AppleM2ScalerCSCDriver::prepareTransform -> writes to 0x910, etc from TransformSurfaceData 0xd8, etc 38 | ----> AppleM2ScalerCSCDriver::transform_surface 39 | -----> IOSurfaceAcceleratorClient::transformSurface_asynchronous/synchronous 40 | -> IOSurfaceAcceleratorClient::user_transform_surface 41 | -> sizeof TransformSurfaceData = 170 42 | ``` 43 | -------------------------------------------------------------------------------- /snakes.swift: -------------------------------------------------------------------------------- 1 | import CoreVideo 2 | import IOSurface 3 | 4 | // size is 0x28 5 | struct CommArg { 6 | let inboundType: Int32 // 0x0 7 | let inboundAddress: UInt64 // 0x8 8 | let inboundSize: Int32 // 0x10 9 | let outboundType: Int32 // 0x14 10 | let outboundAddress: UInt64 // 0x18 11 | let unused20: Int64 // 0x20 12 | } 13 | 14 | // Not supported on M1 Mac Mini 15 | let kInboundTypeASELegacy = 1 16 | // Not supported on M1 Mac Mini 17 | let kInboundTypeHDRLegacy = 2 18 | // ??? 19 | let kInboundTypeHDR = 3 20 | // Args constructed by ASEProcessing - CA::ASEScalerStatistics::create_iosa_params(__IOSurface*, __IOSurface*) 21 | let kInboundTypeASE = 4 22 | 23 | // Hardcoded length = 0x17c 24 | let kOutboundTypeASE = 1 25 | // Hardcoded length = 0x1008 26 | let kOutboundTypeHDR = 2 27 | 28 | func snakesOnAPlane() { 29 | // ASE prints an error if width/height < 32 30 | guard 31 | let sourceSurface = IOSurface(properties: [ 32 | .width: 32, .height: 32, .pixelFormat: kCVPixelFormatType_32BGRA, 33 | ]) 34 | else { 35 | print("source surface is null") 36 | return 37 | } 38 | guard 39 | let destinationSurface = IOSurface(properties: [ 40 | .width: 32, .height: 32, .pixelFormat: kCVPixelFormatType_32BGRA, 41 | ]) 42 | else { 43 | print("dest surface is null") 44 | return 45 | } 46 | // https://github.com/WebKit/WebKit/commit/5e7ebb4f4f0592ad2911b8eb84da81ba900b0f4a 47 | var accelerator: IOSurfaceAcceleratorRef? = nil 48 | var err = IOSurfaceAcceleratorCreate(nil, nil, &accelerator) 49 | guard err == kIOReturnSuccess else { 50 | print("accelerator fail: \(err)") 51 | return 52 | } 53 | guard let accelerator = accelerator else { 54 | print("accelerator null") 55 | return 56 | } 57 | let firstMutableInput = NSMutableData(length: 0x4000)! 58 | let firstMutableOutput = NSMutableData(length: 0x4000)! 59 | let inboundAddress = UInt64(UInt(bitPattern: firstMutableInput.mutableBytes)) 60 | let outboundAddress = UInt64(UInt(bitPattern: firstMutableOutput.mutableBytes)) 61 | #if false 62 | var firstCommArg = CommArg( 63 | inboundType: Int32(kInboundTypeASE), inboundAddress: inboundAddress, 64 | inboundSize: Int32(firstMutableInput.length), outboundType: Int32(kOutboundTypeASE), 65 | outboundAddress: outboundAddress, unused20: 0) 66 | #endif 67 | var firstCommArg = CommArg( 68 | inboundType: 0, inboundAddress: inboundAddress, inboundSize: Int32(firstMutableInput.length), 69 | outboundType: 1, 70 | outboundAddress: outboundAddress, unused20: 0) 71 | let firstData = Data(bytes: &firstCommArg, count: MemoryLayout.size(ofValue: firstCommArg)) 72 | // kIOSurfaceAcceleratorDirectionalScalingEnable turns on ASE 73 | let transformOptions: [String: Any] = [ 74 | String(kIOSurfaceAcceleratorDirectionalScalingEnable): true, 75 | String(kIOSurfaceAcceleratorComm): [firstData], 76 | ] 77 | err = IOSurfaceAcceleratorTransformSurface( 78 | accelerator, sourceSurface, destinationSurface, /*options=*/ 79 | transformOptions as CFDictionary, /*pCropRectangles=*/ 80 | nil, /*pCompletion=*/ nil, /*pSwap=*/ nil, /*pCommandID=*/ nil) 81 | guard err == kIOReturnSuccess else { 82 | print("transform fail: \(err) \(String(cString: mach_error_string(err)!))") 83 | return 84 | } 85 | } 86 | 87 | snakesOnAPlane() 88 | --------------------------------------------------------------------------------