IOKit Drivers — Kernel Attack Surface
IOKit drivers là attack surface lớn nhất cho iOS kernel exploitation. Mỗi driver expose external methods qua IOUserClient mà userspace có thể gọi — tương tự ioctl() trên Linux.
IOKit Architecture
Driver Hierarchy
IOService (abstract base)
└── IORegistryEntry (device tree node)
└── Concrete driver class (e.g., IOSurface)
└── IOUserClient subclass (e.g., IOSurfaceRootUserClient)
↑
Userspace calls IOConnectCallMethod() vào đây
IOUserClient — The Interface
IOUserClient là bridge giữa userspace và kernel driver:
// Kernel side
class IOSurfaceRootUserClient : public IOUserClient {
// External method dispatch table
static const IOExternalMethodDispatch sMethods[] = {
// selector 0
{ &IOSurfaceRootUserClient::s_create_surface,
0, // scalar input count
kIOUCVariableStructureSize, // struct input size
0, // scalar output count
0 }, // struct output size
// selector 1
{ &IOSurfaceRootUserClient::s_release_surface,
1, 0, 0, 0 },
// ... more methods
};
IOReturn externalMethod(uint32_t selector,
IOExternalMethodArguments *args,
IOExternalMethodDispatch *dispatch,
OSObject *target,
void *reference) override;
};
// Userspace side
io_connect_t conn;
IOServiceOpen(service, mach_task_self(), 0, &conn);
IOConnectCallMethod(conn,
selector, // Method index
scalarInput, scalarInputCount,
structInput, structInputSize,
scalarOutput, &scalarOutputCount,
structOutput, &structOutputSize);
External Method Arguments
struct IOExternalMethodArguments {
uint32_t version;
uint32_t selector; // Method selector
// Scalar (register-like) arguments
const uint64_t *scalarInput;
uint32_t scalarInputCount;
uint64_t *scalarOutput;
uint32_t scalarOutputCount;
// Struct (buffer) arguments
const void *structureInput;
uint32_t structureInputSize;
void *structureOutput;
uint32_t structureOutputSize;
// Memory descriptor
IOMemoryDescriptor *structureInputDescriptor;
IOMemoryDescriptor *structureOutputDescriptor;
};
High-Value Targets
IOSurface / IOSurfaceRootUserClient
- Vai trò: Quản lý shared memory surfaces cho graphics
- Tại sao quan trọng: Reachable từ app sandbox, complex functionality
- Exploitation history: Nhiều CVEs, dùng trong hầu hết modern exploit chains
- Key methods: create_surface, set_value, get_value, release_surface
- iOS 16+: IOSurfaceRootUserClient bị restricted (duplicate table với fewer methods)
IOSurface kread/kwrite pattern:
1. Create IOSurface
2. Set serialized property values (controlled data in kernel)
3. Trigger vulnerability → overwrite IOSurface internal pointer
4. Get property value → reads from corrupted pointer address (kread)
5. Set property value → writes to corrupted pointer address (kwrite)
AGXAccelerator / IOGPU
- Vai trò: GPU driver
- Attack surface: Command buffer parsing, shader compilation
- iOS 16+: IOGPUDeviceUserClient restricted
AppleAVE2 / AppleAVE2UserClient
- Vai trò: Video encoding hardware
- Đặc điểm: iOS-only, symbols stripped → harder to analyze
- Exploitation: Accessible trước iOS 16 restrictions
AppleSPU
- Vai trò: Signal Processing Unit
- Newer target: Less analyzed, potentially less hardened
Reverse Engineering IOKit Drivers
1. Find UserClient Classes
# Từ kernelcache trong IDA/Ghidra:
# Search for strings containing "UserClient"
# Hoặc search cho ::externalMethod references
# Dùng jtool2
jtool2 -d __DATA.__objc_classlist kernelcache | grep UserClient
2. Find External Method Table
Trong IDA:
1. Find class's externalMethod() implementation
2. Look for dispatch table reference (usually in __DATA_CONST.__const)
3. Table entries are IOExternalMethodDispatch structs:
struct IOExternalMethodDispatch {
IOExternalMethodAction function; // 8 bytes (function pointer)
uint32_t checkScalarInputCount; // 4 bytes
uint32_t checkStructureInputSize; // 4 bytes
uint32_t checkScalarOutputCount; // 4 bytes
uint32_t checkStructureOutputSize; // 4 bytes
};
3. Map Method Table
Từ dispatch table, build map:
Selector 0 → create_surface(0 scalar, var struct, 0 scalar out, 0 struct out)
Selector 1 → release_surface(1 scalar, 0 struct, 0 scalar out, 0 struct out)
Selector 2 → ...
Mỗi method = potential attack vector
4. Phrack Methodology
- Phrack #72 — Mapping IOKit Methods
- Systematic approach: enumerate tất cả UserClients → map mọi external methods → prioritize targets
iOS 16+ Restrictions
Apple đã restrict nhiều IOKit UserClients:
Trước iOS 16:
App sandbox → IOSurfaceRootUserClient (full method table)
App sandbox → IOGPUDeviceUserClient (full)
Sau iOS 16:
App sandbox → IOSurfaceRootUserClient_Restricted (limited methods)
App sandbox → IOGPUDeviceUserClient_Restricted (limited methods)
Restricted UserClients:
- Duplicate class inheriting from original
- Separate method dispatch table với fewer methods
- Sensitive methods (e.g., set_value, get_value) removed
Fuzzing IOKit
Manual Fuzzing
// Brute-force selectors với random input
for (uint32_t sel = 0; sel < 256; sel++) {
uint64_t scalar[16];
char structbuf[4096];
arc4random_buf(scalar, sizeof(scalar));
arc4random_buf(structbuf, sizeof(structbuf));
IOConnectCallMethod(conn, sel,
scalar, 16,
structbuf, sizeof(structbuf),
NULL, NULL, NULL, NULL);
}
Intelligent Fuzzing
- Parse method dispatch table → biết đúng input sizes
- Dùng Corellium kernel hooks để monitor crashes
- Coverage-guided fuzzing (phức tạp hơn nhưng hiệu quả)
Vulnerability Patterns Trong IOKit
| Pattern | Mô tả | Prevention |
|---|---|---|
| Race condition | clientClose() concurrent với externalMethod() |
Locking, sequencing |
| UAF | Object freed nhưng pointer vẫn dùng | Reference counting |
| Integer overflow | Size validation bị bypass | Safe integer arithmetic |
| Missing bounds check | Buffer overread/overwrite | Input validation |
| Type confusion | Object cast sai type | OSDynamicCast() checks |
| Double free | Object freed 2 lần | Reference count tracking |