Kernel exploit development harness for the iPhone 11 series (A13, iPhone12,1) on
iOS 26.1 (23B85).
Disclosure status. Both bugs were found by patch diffing xnu 26.1 (42.6) against 26.6 (162.13) and are patched in iOS 26.6 — Apple's fix was already shipping when this harness was written, they are disclosed here after the patch, in the spirit of public exploit research. No CVE has been assigned to either bug. This code is a development harness, not a validated end-to-end jailbreak: see Status / caveats.
Targets two bugs found by patch diffing xnu 26.1 (42.6) against 26.6 (162.13):
| Stage | Bug | 26.1 symbol (unslid) | 26.6 fix |
|---|---|---|---|
| Bug 1 | Unlocked / stale-entry vm_map_clip in the CoW submap fault path |
0xfffffff0080b8820 (KSYM_COW_FAULT_FUNC) |
clip re-validates entry bounds after new-entry allocation and panics |
| Bug 2 | vm_fault_wire_object_pages has no offset + wire_size <= object->size check |
0xfffffff0080abae0 (KSYM_WIRE_OBJECT_PAGES) |
26.6 added the bounds check + panic |
The clip path locks the copy-map, releases it, then clips an entry taken from
the saved slot with the submap's own lock not held and no bounds re-check.
The wire loop walks vme_start..vme_end and decodes the object from the entry's
+0x38 upper-32 phys index into the 0xffffffdc00000000 window, storing
vm_page pointers into the object's page array with no object-size bounds check.
clipwire/
src/clipwire.h constants, entry layout, tunables, API
src/util.c init, device/version check, helpers
src/slide.c kernel slide (env/sysctl fallbacks; prim scan in krw.c)
src/trigger.c Bug 1: COW submap + two-thread clip race
src/wire.c Bug 2: wire-OOB driver + IOSurface grooming + victim detection
src/krw.c phys r/w via corrupted page array, kread/kwrite,
phys-scan slide leak, proc discovery, cred escalation
src/exploit.c orchestration
src/main.m entry point
Makefile clang (SDK) + ldid build
entitlements.plist sandbox/IOSurface/IOKit exceptions
- Bug 1
vm_remap(copy=TRUE)builds a COW submap; two threads race the unlocked clip in0xfffffff0080b8820(copy-map unlocked at0x8c2c, then clip on the saved entry with no submap lock). Detected viamach_vm_region(entry grew / region start moved). - Bug 2 wiring the corrupted range runs
0xfffffff0080abae0, which walksvme_start..vme_endwith no object-size check, writingvm_page*past the victim vm_object's page array into the kernel heap. Grooming targets heap-adjacent vm_object page arrays (COW copies of the same page count), plus an IOSurface phys-contiguous pool for the phys-window case.verify_wire_landeduses a write-through test: after the OOB, a groom whose array was overwritten maps the victim's pages, so a stamp written via the groom's user VA shows up in the victim's wired pages, that identifies the victim with no kernel read. - KRW
krw.cresolves every owned page (victim range + COW grooms + IOSurface pool) to its phys viamach_vm_page_infoand builds a(va,phys)alias cache (prim_establish). The write-through alias means the same phys is reachable through two user VAs, whichescalate()proves before anything else.prim_read64/prim_write64serve the achievable alias space; a request for kernel phys (outside our pages) is reported, not guessed. If a phys-window object is ever confirmed in the OOB path, theprim_find_kernel_in_physscan turns that into slide + kread/kwrite through the kernel linear map.find_proc_by_commself-verifiesstruct proc(p_list kernel ptrs + p_pid == getpid()), andpatch_credsself-verifies the ucred (cr_ref small, cr_uid == getuid()) before zeroing uid/gid.
make # build arm64e clipwire binary
make sign # ldid -S entitlements.plist
make deploy DEVICE_IP=1.2.3.4 # scp + run over ssh
CLIPWIRE_SLIDE=0x1234000 /var/tmp/clipwire # inject slide for pre-primitive testsTunables (COW_SRC_PAGES, RACE_ITERATIONS, GROOM_OBJECTS, ...) live in
src/clipwire.h. Log output goes to stdout.
- All sources compile clean with
clang -Wall -Wextrato object code and link without any unresolved internal symbols (Apple SDK APIs are provided by stub headers on this host); the finalmake signagainst the real iOS SDK andldidsigning are still unverified. - On-device work left: confirm the phys alias resolution reports
(the
physical_pagefield ofmach_vm_page_info), and, if kernel phys is reachable, a phys-window object in the OOB path. Thestruct proc/ucredcandidate offsets inkrw.care self-verified at runtime, so the exact values are tolerant. DEVICE_PHYS_BASE(A13) needs one on-device confirmation; the phys scan itself is base-independent.- The exact race interleaving that lands the stale clip is unverified at
runtime;
RACE_ATTEMPTS/RACE_ITERATIONStuning is expected on-device. - Sandboxed reachability of the wire path is unconfirmed;
mlockfirst,vm_wiresecond. - This project is for authorized research on devices you own. It will panic a 26.1 device when the OOB lands (that is the point).
Restricted research license, see LICENSE. Free for security research and analysis; deployment against unauthorized targets, malware, and commercial exploitation require separate written authorization.
Use at your own risk.
I am not responsible for any damage.
All A13 devices are supported (iPhone 11, 11 Pro, 11 Pro Max, SE2). "supported" here means offsets apply!
A13 iPads or other devices are NOT supported because of kernelcache mismatch. Please, do not make any issues about this