Mach port exploitation primitives
TL;DR: A Mach port is a kernel-backed message queue with capability semantics; mismatched send-right counts, UAFs on
ipc_port, and OOL-port descriptor confusion give arbitrary kernel-read / kernel-write primitives that almost every public macOS / iOS LPE since 2017 has used.
What it is
Every Mach IPC endpoint is a kernel struct ipc_port referenced by user-space through opaque port names (integer handles, like file descriptors). Rights on a port (SEND, RECEIVE, SEND_ONCE, PORT_SET, DEAD_NAME) are reference-counted. Bugs in the reference-count accounting, in the lifecycle (a freed ipc_port whose name is still in the namespace), or in OOL (out-of-line) descriptor parsing reliably turn into kernel R/W:
fakeport(Pangu-era primitive): craft a fakeipc_portin user-controlled kernel memory; once the kernel treats it as real, sending a message dereferences attacker pointers.- OOL descriptor type confusion: a Mach message carries descriptors describing inline ports, OOL memory, OOL port arrays. Mismatched type tags between sender and receiver let one side hand the other a forged object.
- Mach voucher UAF: voucher reference counting has been a repeat source of kernel UAFs (e.g., Ian Beer’s
oob_timestamp).
Preconditions / where it applies
- macOS / iOS kernel. Requires the ability to call Mach traps (
mach_msg,mach_port_*) — any sandboxed userland process can. - Often paired with kernel heap shaping to position a fake port in the right zone.
Technique
Fake port primitive (classic).
- Spray a target zone with attacker-controlled bytes that mimic an
ipc_port(setip_object.io_bitstoIOT_PORT | IO_BITS_ACTIVE,ip_referencesto a high count to avoid premature free,ip_messages.imq_messagesetc.). - Trigger a vulnerability that inserts a port “name” into your task’s namespace pointing at the sprayed memory.
- Call
mach_port_kobject(task, name, &type, &addr)— kernel happily reads from your fake port and tells youaddr, which is now an arbitrary kernel-read primitive. - Upgrade to write via the same fake port’s
ip_pdrequest/ kalloc_data adjacency.
OOL port descriptor abuse.
mach_msg_ool_ports_descriptor_tcarries an array of port names that the kernel translates toipc_port *on receive. A double-receive bug where the same descriptor is processed twice double-frees the underlying port. Catch in the second free → fake-port territory.- Mismatched
disposition(e.g., sending asSENDbut the receiver expectsSEND_ONCE) once gave inconsistent ref counts.
Voucher and turnstile UAFs.
mach_voucher_attr_commandand related entry points have been a recurring UAF source.- Watch for
ipc_voucher_releasepaths where the count drops to zero while another thread holds a stale pointer (TOCTOU).
Port name reuse race.
- Port names in a task are recycled. A bug that holds a stale name reference across a
mach_port_destroyand reallocation lets you point a stale name at a brand-new port — capability confusion.
Useful Mach API for offensive code:
1
2
3
4
mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND);
mach_msg(...); // send forged OOL descriptors
mach_port_kobject(task, target, &type, &addr); // info-leak kernel pointer
Bootstrap and XPC pivot. Mach exploitation often starts from a sandboxed process that can only talk to specific bootstrap services — see mach-and-xpc for which endpoints are reachable from common sandboxes (WebContent, App Store apps). The XPC connection sits on top of a Mach port; sandbox escapes frequently use an XPC service whose Mach port is exposed.
Detection and defence
- Apple ships periodic hardening on
ipc_port(recently: PAC-signedip_kobject, randomised offsets, stricterkobject_labelchecks). - Endpoint Security has limited visibility into Mach IPC; sandbox profiles (
sandbox-exec) are the primary userspace defence. - For exploit dev: build XNU debug with
KASAN+kheap_tracesto catch port-lifecycle bugs early.
References
- Ian Beer — Mach Messages: A Guide for Exploiters — series; canonical primitive catalogue
- XNU —
osfmk/ipc/ipc_port.c— implementation - macOS and iOS Internals, Volume I — Jonathan Levin; Mach IPC chapter
- Pangu — fakeport primitive — earliest public writeup