(CVE-2024-27828) Apple IOSurfaceRoot Reference Count Leak Leading to Kernel Panic and Code Execution
CVE: CVE-2024-27828
Affected Versions: iOS and iPadOS before 17.5; tvOS before 17.5; watchOS before 10.5; visionOS before 1.2
CVSS3.1: 7.8 (High) — CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
Summary
| Product | Apple IOSurface (IOSurfaceRoot) |
|---|---|
| Vendor | Apple |
| Severity | High — an app may be able to execute arbitrary code with kernel privileges |
| Affected Versions | iOS/iPadOS < 17.5; tvOS < 17.5; watchOS < 10.5; visionOS < 1.2 |
| Tested Versions | iOS/macOS 14.1 beta (23B5056e) |
| CVE Identifier | CVE-2024-27828 |
| CVE Description | A memory handling issue may allow an app to execute arbitrary code with kernel privileges; addressed via improved memory handling |
| CWE Classification(s) | CWE-786: Access of Memory Location Before Start of Buffer; CWE-788: Access of Memory Location After End of Buffer |
CVSS3.1 Scoring System
Base Score: 7.8 (High)
Vector String: CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
| Metric | Value |
|---|---|
| Attack Vector (AV) | Local |
| Attack Complexity (AC) | Low |
| Privileges Required (PR) | None |
| User Interaction (UI) | Required |
| Scope (S) | Unchanged |
| Confidentiality (C) | High |
| Integrity (I) | High |
| Availability (A) | High |
Product Background
IOSurface.kext is a kernel extension for managing pixel buffers, controlled by the userland IOSurface framework. It provides a framebuffer object suitable for sharing across process boundaries, commonly used to offload image decompression and drawing logic into a separate process. Beyond the framework, the low-level IOKit API can be used to communicate directly with the IOSurfaceRoot IOService instance.
Technical Details
Calling IOServiceOpen(IOSurfaceRoot) creates an IOSurfaceRootUserClient connection. The vulnerability exists in IOSurfaceRootUserClient::s_create_shared_event, which delegates to create_shared_event to create an IOSurfaceSharedEvent object identified by a user-supplied string name:
__int64 __fastcall IOSurfaceRootUserClient::s_create_shared_event(
IOSurfaceRootUserClient *this,
IOSurfaceRootUserClient *a2,
IOExternalMethodArguments *a3,
IOExternalMethodArguments *a4)
{
__int64 result;
uint64_t *scalarOutput;
__int64 v7 = 0LL;
unsigned int v8 = 0;
result = IOSurfaceRootUserClient::create_shared_event(
this, *a3->scalarInput != 0, &v8, (unsigned __int64 *)&v7);
scalarOutput = a3->scalarOutput;
*scalarOutput = v8;
scalarOutput[1] = v7;
return result;
}
By manipulating the user-supplied input and calling s_create_shared_event repeatedly, a reference count leak on the IOSurfaceRoot object can be triggered. Each call leaks a retain without a corresponding release. Eventually, OSObject::taggedRelease detects that the object’s retain count has dropped below the number of collections it belongs to and triggers a kernel panic:
// OSObject.cpp
//
// This panic means that we have just attempted to release an object
// whose retain count has gone to less than the number of collections
// it is a member of.
//
if ((UInt16) actualCount < (actualCount >> 16)) {
panic("A kext releasing a(n) %s has corrupted the registry.",
getClassName(this));
}
The reference count corruption is exploitable for arbitrary code execution with kernel privileges. Running the PoC as a normal user is sufficient — no elevated privileges are required. Multiple runs may be needed to trigger the panic depending on timing:
cc poc.c -o poc -framework IOKit && ./poc
Credit
Pan Zhenpeng of STAR Labs SG Pte. Ltd.
Timeline
- 2024-05-13 — Patch released: iOS/iPadOS 17.5, tvOS 17.5, watchOS 10.5, visionOS 1.2
- 2024-05-13 — CVE-2024-27828 published by Apple