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
| Field | Detail |
|---|---|
| CVE ID | CVE-2025-43510 |
| Product | Apple iOS/iPadOS, macOS, watchOS, tvOS, visionOS |
| Component | AppleM2ScalerCSCDriver (kernel driver) |
| Vulnerability Type | Improper Locking / Memory Corruption (CWE-667) |
| CVSS v3.1 Score | 7.8 (High) |
| CVSS Vector | AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H |
| Role in DarkSword | Stage 5 — Kernel arbitrary memory R/W primitive |
| Triggered From | mediaplaybackd (Stage 4) via driver XPC interface |
| Fix | Improved lock state checking |
| Patched In | iOS 18.7.2, iOS 26.1, macOS Sonoma 14.8.2, Sequoia 15.7.2, Tahoe 26.1 |
| CISA KEV | Yes — Federal deadline: April 3, 2026 |
| Active Exploitation | Yes — 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 toAppleM2ScalerCSCDriver
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:
- Detect write to read-only shared page
- Allocate new physical page
- Copy original data to new page
- Update page table entry (PTE) to point to new page
- Mark new page as writable
- 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:
Opens a connection to
AppleM2ScalerCSCDrivervia IOKit/XPC (legitimate —mediaplaybackdis allowed)- 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
Races a concurrent operation (using multiple threads) that causes the shared region to transition to a kernel-mapped state during the race window
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
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
- 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:
- Modern hardware is multi-core — real parallelism exists
- Kernel drivers must be high-performance — locking is expensive
- COW operations involve complex multi-step state machines
- 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:
| CVE | Year | Root Cause | Technique |
|---|---|---|---|
| CVE-2019-6208 | 2019 | Partial-page truncation COW bypass | File mutation via ftruncate |
| Splitting Atoms (Project Zero) | 2019 | Locking bug in VM subsystem | TOCTOU via Mach message |
| CVE-2025-43510 | 2025 | Improper lock state in AppleM2ScalerCSCDriver | Driver 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:
| Aspect | CVE-2025-43510 (Stage 5) | CVE-2025-43520 (Stage 6) |
|---|---|---|
| Goal | Establish kernel R/W primitive | Full kernel privilege escalation |
| Mechanism | COW race condition via driver | Kernel memory corruption with R/W primitive |
| Access required | mediaplaybackd (user-space daemon) | Kernel R/W (from Stage 5) |
| What it provides | Arbitrary kernel memory read/write | Root privileges, credential escalation |
| Triggered from | mediaplaybackd via IOKit XPC | JavaScript 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
| Tactic | Technique | ID |
|---|---|---|
| Privilege Escalation | Exploitation for Privilege Escalation | T1068 |
| Privilege Escalation | Abuse Elevation Control Mechanism | T1548 |
| Defense Evasion | Rootkit | T1014 |
| Execution | Exploitation for Client Execution | T1203 |
Mitigation
Patch Table
| Platform | Vulnerable Range | Fixed Version |
|---|---|---|
| iOS / iPadOS | < 18.7.2 | 18.7.2 |
| iOS / iPadOS (newer) | < 26.1 | 26.1 |
| macOS Sonoma | < 14.8.2 | 14.8.2 |
| macOS Sequoia | < 15.7.2 | 15.7.2 |
| macOS Tahoe | < 26.1 | 26.1 |
| watchOS | < 26.1 | 26.1 |
| tvOS | < 26.1 | 26.1 |
| visionOS | < 26.1 | 26.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:
- Acquiring the lock before checking COW state (not after)
- Holding the lock continuously through the entire memory operation
- 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
- Google Threat Intelligence — DarkSword iOS Exploit Chain
- iVerify — DarkSword Explained
- NVD — CVE-2025-43510
- CISA KEV Catalog
- Apple Security Update — iOS 18.7.2
- Google Project Zero — Splitting Atoms in XNU (2019)
- Apple — XNU Virtual Memory Overview
- Wikipedia — Copy-on-Write
- Security Week — DarkSword Coverage
This post is intended for security researchers, iOS kernel security engineers, and mobile threat analysts. All technical details are based on publicly disclosed research.