Post

CVE-2025-43510 The Kernel COW Race That Gave DarkSword Its First Glimpse Into the XNU Kernel

CVE-2025-43510 The Kernel COW Race That Gave DarkSword Its First Glimpse Into the XNU Kernel

Executive Summary

CVE-2025-43510 is a kernel memory corruption vulnerability in the AppleM2ScalerCSCDriver — a hardware kernel driver handling color space conversion and scaling on Apple Silicon devices. It served as Stage 5 of the DarkSword exploit chain, providing the critical kernel arbitrary memory read/write primitive that enabled the chain to transition from user-space exploitation to kernel-level control.

The vulnerability’s root cause: improper lock state checking in the driver’s shared memory management. When the driver processes specific operations through its exposed XPC interface (selector 1), it fails to properly acquire locks around shared memory regions involved in a copy-on-write (COW) operation. This creates a race condition window where a second process (in DarkSword’s case, mediaplaybackd) can write to memory that should be protected — effectively writing into kernel-mapped shared memory.

What makes this vulnerability architecturally significant in DarkSword’s chain: it is triggered not from a direct kernel exploit, but from within mediaplaybackd (Stage 4’s target) — using the daemon’s privileged access to the driver’s XPC interface. The result: a user-space process writes to kernel memory, establishing arbitrary kernel R/W without needing a direct kernel vulnerability as the entry point.

Discovered and exploited in DarkSword campaigns since November 2025. Patched by Apple in iOS 18.7.2 and iOS 26.1. Added to CISA’s Known Exploited Vulnerabilities catalog with CISA-mandated federal patching deadline of April 3, 2026.


CVE Summary

FieldDetail
CVE IDCVE-2025-43510
ProductApple iOS/iPadOS, macOS, watchOS, tvOS, visionOS
ComponentAppleM2ScalerCSCDriver (kernel driver)
Vulnerability TypeImproper Locking / Memory Corruption (CWE-667)
CVSS v3.1 Score7.8 (High)
CVSS VectorAV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
Role in DarkSwordStage 5 — Kernel arbitrary memory R/W primitive
Triggered Frommediaplaybackd (Stage 4) via driver XPC interface
FixImproved lock state checking
Patched IniOS 18.7.2, iOS 26.1, macOS Sonoma 14.8.2, Sequoia 15.7.2, Tahoe 26.1
CISA KEVYes — Federal deadline: April 3, 2026
Active ExploitationYes — DarkSword campaign

Understanding the Attack Context: Where Stage 5 Begins

Before diving into the technical details, it’s essential to understand what state DarkSword is in when CVE-2025-43510 is triggered.

After Stage 4, DarkSword has:

  • Code execution inside mediaplaybackd (a privileged system daemon)
  • JavaScriptCore loaded into mediaplaybackd’s process space
  • pe_main.js (Stage 5’s JavaScript payload) ready to execute
  • Access to mediaplaybackd’s XPC interfaces — including access to AppleM2ScalerCSCDriver

The challenge at this point: how to get from mediaplaybackd’s user-space execution context into the kernel?

CVE-2025-43510 answers this question.


What Is AppleM2ScalerCSCDriver?

The AppleM2ScalerCSCDriver is an iOS/macOS kernel extension (kext) responsible for:

  • Color Space Conversion (CSC): Transforming pixel data between different color spaces (e.g., YCbCr → RGB, BT.709 → Display P3)
  • Scaling: Hardware-accelerated image/video upscaling and downscaling
  • Hardware bridge: Interfacing between software pipelines and Apple Silicon’s dedicated media processing hardware (the M2’s media engine)

It is used extensively in media playback — which is why mediaplaybackd has privileged access to it. When you watch a video on iPhone, this driver handles the color transformation pipeline between the video decoder and the display.

The driver exposes its functionality through an IOKit XPC interface with multiple selectors. Selector 1 — the function that DarkSword targets — handles specific shared memory operations between the driver and user-space clients.


Understanding Copy-on-Write (COW) in XNU

To understand the vulnerability, we must first understand how XNU handles copy-on-write shared memory.

COW in Operating Systems

Copy-on-Write is a memory optimization: instead of immediately copying memory when two processes need to share it, the OS maps them to the same physical pages and marks those pages read-only. If either process tries to write, only then does the kernel create a private copy.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Initial state (COW):
Process A           Process B
  VA: 0x1000          VA: 0x2000
       ↓                   ↓
  [Shared Physical Page: 0xABCD0000]
  (marked read-only for both)

Write attempt by Process A:
  → Page fault triggered
  → Kernel allocates new physical page 0xEF010000
  → Copies contents of 0xABCD0000 → 0xEF010000
  → Updates Process A's mapping: VA 0x1000 → PA 0xEF010000
  → Process B still maps VA 0x2000 → PA 0xABCD0000

After COW resolution:
Process A           Process B
  VA: 0x1000          VA: 0x2000
       ↓                   ↓
  [Private copy:       [Original:
  0xEF010000]         0xABCD0000]

The Lock Requirement

The COW copy operation is a non-atomic sequence:

  1. Detect write to read-only shared page
  2. Allocate new physical page
  3. Copy original data to new page
  4. Update page table entry (PTE) to point to new page
  5. Mark new page as writable
  6. Allow write to proceed

Between steps 1 and 4, the original shared page must be locked — no other process should be able to modify it. If the lock is missing or improperly checked, a race window opens.


The Vulnerability: Improper Lock State Checking in the Driver

Root Cause

The AppleM2ScalerCSCDriver manages shared memory regions between the kernel and user-space clients. During specific operations (triggered via selector 1 of the driver’s IOKit interface), it performs memory operations on shared regions that are marked as COW.

The bug: the driver checks the lock state of these shared regions at the wrong time or incompletely — a classic time-of-check-time-of-use (TOCTOU) pattern at the kernel level:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// CONCEPTUAL — simplified vulnerable pattern (NOT actual driver source)

// AppleM2ScalerCSCDriver selector 1 handler (simplified):
kern_return_t handleSelector1(IOMemoryDescriptor* sharedRegion) {
    
    // Step 1: Check if region is in COW-pending state
    bool isCOWPending = checkCOWState(sharedRegion);
    
    // BUG: Lock is NOT held between check and use
    // Race window opens here
    // ↓↓↓ RACE WINDOW ↓↓↓
    
    if (!isCOWPending) {
        // Step 2: Perform memory operation on shared region
        // Assumes the COW state hasn't changed since check
        writeToSharedRegion(sharedRegion, data);  
        // ← If COW state changed in the race window:
        //   This writes to the ORIGINAL shared page
        //   instead of a private copy
        //   → Write reflects in kernel's mapping too
    }
}

The race condition:

1
2
3
4
5
6
7
8
9
10
Thread 1 (mediaplaybackd via XPC):     Thread 2 (kernel / another operation):
  
  check: isCOWPending = false           ...
                                        COW transition begins (page becomes shared)
  RACE WINDOW
                                        Original page now kernel-mapped
  write to shared region (not locked!)
  ← This write goes to kernel-mapped page
                                        Kernel reads from same physical page
                                        Kernel sees attacker-written data

Exploiting the Race: Getting Kernel R/W

From mediaplaybackd, DarkSword’s exploit:

  1. Opens a connection to AppleM2ScalerCSCDriver via IOKit/XPC (legitimate — mediaplaybackd is allowed)

  2. Triggers selector 1 with crafted parameters that:
    • Set up a shared memory region in a COW-eligible state
    • Create the race window between the driver’s lock check and memory write
  3. Races a concurrent operation (using multiple threads) that causes the shared region to transition to a kernel-mapped state during the race window

  4. Wins the race: the driver writes to what it thinks is a user-space-only region, but which is now kernel-mapped → the write goes into kernel memory

  5. Establishes read primitive: by carefully controlling what gets written to kernel memory and where, the attacker can corrupt kernel structures that serve as read channels → arbitrary kernel memory read

  6. Establishes write primitive: using the read primitive to find additional kernel objects, craft a full arbitrary write primitive
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
mediaplaybackd
    │
    │ Open IOKit connection to AppleM2ScalerCSCDriver
    │ Call selector 1 with crafted parameters
    ▼
AppleM2ScalerCSCDriver (kernel space)
    │
    │ Lock check: COW state = false (no lock acquired)
    │ [RACE WINDOW]
    │ COW transition happens (page now kernel-mapped)
    │ Write operation executes (no re-check)
    │ Write goes to kernel-mapped page
    ▼
KERNEL MEMORY WRITTEN BY USER-SPACE PROCESS
    │
    │ Establishes arbitrary kernel R/W primitive
    ▼
pe_main.js executes Stage 6 setup:
  → Read kernel structures to find process credentials
  → Prepare for CVE-2025-43520 (kernel privesc)

The Full Stage 5 JavaScript Execution Flow

One of DarkSword’s most remarkable engineering choices: Stage 5 is entirely JavaScript (pe_main.js), running inside mediaplaybackd with JavaScriptCore loaded by Stage 4. This means the kernel exploit itself is written in JavaScript:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// CONCEPTUAL — pe_main.js (Stage 5) structure

// Step 1: Open AppleM2ScalerCSCDriver
let driver = IOKit.openService("AppleM2ScalerCSCDriver");

// Step 2: Set up shared memory for COW race
let sharedMem = driver.allocateSharedMemory(RACE_BUFFER_SIZE);

// Step 3: Trigger the race condition (selector 1)
// Multiple threads racing to win the COW window
let raceThread = startRaceThread(() => {
    while (!raceWon) {
        triggerCOWTransition(sharedMem);  // Thread 2: force kernel mapping
    }
});

// Main thread: try selector 1 repeatedly until race is won
while (!raceWon) {
    driver.callSelector(1, sharedMem, craftedPayload);
    // When race is won, craftedPayload is in kernel memory
}

// Step 4: Verify race was won (look for kernel artifacts)
let kernelAddr = findKernelArtifact();
if (kernelAddr) {
    raceWon = true;
    // Step 5: Build kernel R/W primitives from the foothold
    kernelRead = buildReadPrimitive(kernelAddr);
    kernelWrite = buildWritePrimitive(kernelAddr);
    // Hand off to Stage 6 (CVE-2025-43520)
}

Why This is a Particularly Dangerous Kernel Attack Class

Kernel Race Conditions Are Hard to Eliminate

Unlike memory corruption bugs that can often be fixed with bounds checks, kernel race conditions arise from fundamental concurrency challenges:

  1. Modern hardware is multi-core — real parallelism exists
  2. Kernel drivers must be high-performance — locking is expensive
  3. COW operations involve complex multi-step state machines
  4. The exact sequence depends on memory pressure, scheduling, and hardware state

This is reflected in Apple’s fix: “improved lock state checking” — not “fixed bounds check” or “added input validation.” The fix required restructuring the lock acquisition sequence in the driver.

Historical Context: COW Race Exploits in XNU

CVE-2025-43510 is part of a documented class of XNU COW race vulnerabilities:

CVEYearRoot CauseTechnique
CVE-2019-62082019Partial-page truncation COW bypassFile mutation via ftruncate
Splitting Atoms (Project Zero)2019Locking bug in VM subsystemTOCTOU via Mach message
CVE-2025-435102025Improper lock state in AppleM2ScalerCSCDriverDriver selector race

Google Project Zero’s classic 2019 research “Splitting Atoms in XNU” documented the exact class of vulnerability CVE-2025-43510 belongs to: a locking bug that violates COW preconditions, creating an unintended shared memory window between a user-space process and the kernel.


CVE-2025-43510’s Place in the Full DarkSword Architecture

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
DarkSword Full Chain:
──────────────────────────────────────────────────────

Stage 1: CVE-2025-31277 / CVE-2025-43529
  JavaScriptCore JIT/GC → R/W in WebContent process
  
Stage 2: CVE-2026-20700
  dyld → PAC/TPRO bypass → Code execution in WebContent

Stage 3: CVE-2025-14174
  ANGLE → GPU process sandbox escape

Stage 4: XPC Injection (no CVE)
  GPU → mediaplaybackd → Load JSCore + pe_main.js

★ Stage 5: CVE-2025-43510 ★
  mediaplaybackd → AppleM2ScalerCSCDriver
  COW race condition via selector 1
  → Arbitrary KERNEL memory R/W established

Stage 6: CVE-2025-43520
  Kernel memory corruption
  → Full kernel privilege escalation → ROOT

[GHOSTBLADE / GHOSTKNIFE / GHOSTSABER deployed]

Comparison With CVE-2025-43520 (Stage 6)

It’s important to understand the distinction between Stage 5 and Stage 6:

AspectCVE-2025-43510 (Stage 5)CVE-2025-43520 (Stage 6)
GoalEstablish kernel R/W primitiveFull kernel privilege escalation
MechanismCOW race condition via driverKernel memory corruption with R/W primitive
Access requiredmediaplaybackd (user-space daemon)Kernel R/W (from Stage 5)
What it providesArbitrary kernel memory read/writeRoot privileges, credential escalation
Triggered frommediaplaybackd via IOKit XPCJavaScript inside mediaplaybackd
Analogy“Pick the lock on the vault”“Take the contents of the vault”

Stage 5 opens the kernel. Stage 6 takes over the kernel.


Detection

For Security Researchers

CVE-2025-43510 exploitation leaves specific artifacts:

Kernel-level detection:

1
2
3
4
5
6
7
Look for:
- Unexpected IOKit connection from mediaplaybackd to AppleM2ScalerCSCDriver
  during non-media-playback activity (no video/audio playing)
- Unusual frequency of AppleM2ScalerCSCDriver selector 1 calls from mediaplaybackd
- Memory mapping anomalies around the driver's shared buffer regions
- Kernel panic logs with traces pointing to AppleM2ScalerCSCDriver during exploit
  (failed race conditions may cause panics)

Process behavior:

1
2
3
4
5
- mediaplaybackd CPU usage spike without active media playback
  (multithreaded race attempt causes CPU usage)
- Unusual threading patterns in mediaplaybackd
  (many short-lived threads — characteristic of race condition exploitation)
- IOKit connection opening/closing in rapid succession from mediaplaybackd

iVerify / Mobile Threat Defense:

  • Can detect post-Stage-5 kernel anomalies (unusual kernel credential structures)
  • Behavioral monitoring flags mediaplaybackd accessing kernel resources outside normal media contexts

MITRE ATT&CK Mapping

TacticTechniqueID
Privilege EscalationExploitation for Privilege EscalationT1068
Privilege EscalationAbuse Elevation Control MechanismT1548
Defense EvasionRootkitT1014
ExecutionExploitation for Client ExecutionT1203

Mitigation

Patch Table

PlatformVulnerable RangeFixed Version
iOS / iPadOS< 18.7.218.7.2
iOS / iPadOS (newer)< 26.126.1
macOS Sonoma< 14.8.214.8.2
macOS Sequoia< 15.7.215.7.2
macOS Tahoe< 26.126.1
watchOS< 26.126.1
tvOS< 26.126.1
visionOS< 26.126.1

Full DarkSword protection requires iOS 18.7.6 / iOS 26.3.1 — patching all 6 CVEs in the chain. CVE-2025-43510 specifically is patched in iOS 18.7.2, but the chain can still reach Stage 5 via earlier stages if only Stage 5 is patched — update to the latest version.

Apple’s Fix: “Improved Lock State Checking”

Apple’s description is precise: the fix restructures how AppleM2ScalerCSCDriver validates and acquires locks before operating on shared memory regions. The fix eliminates the TOCTOU window by:

  1. Acquiring the lock before checking COW state (not after)
  2. Holding the lock continuously through the entire memory operation
  3. Re-validating the state after lock acquisition (paranoid check pattern)

Conclusion

CVE-2025-43510 occupies a critical position in DarkSword’s architecture: it is the first stage that operates at the kernel level, and it provides the arbitrary kernel memory access that makes Stage 6 possible. Without it, the chain cannot progress beyond user-space.

The vulnerability’s elegance lies in its indirection. DarkSword never directly attacks the kernel — it attacks a kernel driver’s shared memory management from user space, using the driver’s own XPC interface as the attack surface. The improper lock state checking in AppleM2ScalerCSCDriver creates a small but reliable window where user-space writes reach kernel memory.

The fact that Stage 5 is executed entirely in JavaScript (pe_main.js) running inside mediaplaybackd — using Apple’s own JavaScriptCore framework — demonstrates the extraordinary engineering consistency of the DarkSword chain.

For defenders: patch to iOS 18.7.2 minimum for this CVE, but target iOS 18.7.6/26.3.1 for full chain protection. The CISA federal deadline of April 3, 2026 reflects the urgency.


References


This post is intended for security researchers, iOS kernel security engineers, and mobile threat analysts. All technical details are based on publicly disclosed research.

This post is licensed under CC BY 4.0 by the author.