Mach port exploitation primitives

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 fake ipc_port in 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).

  1. Spray a target zone with attacker-controlled bytes that mimic an ipc_port (set ip_object.io_bits to IOT_PORT | IO_BITS_ACTIVE, ip_references to a high count to avoid premature free, ip_messages.imq_messages etc.).
  2. Trigger a vulnerability that inserts a port “name” into your task’s namespace pointing at the sprayed memory.
  3. Call mach_port_kobject(task, name, &type, &addr) — kernel happily reads from your fake port and tells you addr, which is now an arbitrary kernel-read primitive.
  4. Upgrade to write via the same fake port’s ip_pdrequest / kalloc_data adjacency.

OOL port descriptor abuse.

  • mach_msg_ool_ports_descriptor_t carries an array of port names that the kernel translates to ipc_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 as SEND but the receiver expects SEND_ONCE) once gave inconsistent ref counts.

Voucher and turnstile UAFs.

  • mach_voucher_attr_command and related entry points have been a recurring UAF source.
  • Watch for ipc_voucher_release paths 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_destroy and 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-signed ip_kobject, randomised offsets, stricter kobject_label checks).
  • 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_traces to catch port-lifecycle bugs early.

References