XXNU Source Handbook Offline reading instructions
Part 06 · Chapter 06.01

Mach IPC: names, capabilities, messages, and kernel interfaces

Guide index · Architecture

Mach IPC connects a task-local name space to kernel objects and transfers messages containing data, port rights, and memory. It is also the transport for many kernel RPC interfaces and exception notifications. Start by separating a port name, a right, the port object, and a queued kernel message: these have different ownership and lifetime rules. ipc_space.h, ipc_entry.h, ipc_port.h, ipc_kmsg.h.

Mach IPC: names, capabilities, messages, and kernel interfaces diagram
Mach IPC: names, capabilities, messages, and kernel interfaces diagram · Open SVG
Mermaid source
flowchart LR
    A[Sender IPC space: name and right] --> CI[copyin: names become object rights]
    CI --> K[ipc_kmsg: owns transferred resources]
    K --> P[Destination ipc_port]
    P --> Q[Message queue or waiting receiver]
    Q --> CO[copyout: install rights and memory]
    CO --> B[Receiver IPC space and VM map]
    P --> KO[Kernel-owned destination]
    KO --> MIG[MIG dispatch and kobject operation]
    MIG --> Reply[Reply kmsg]
    Reply --> Q

Normal user destinations use ipc_mqueue_send_locked() and ipc_mqueue_post(). A destination in ipc_space_kernel is dispatched by ipc_kobject_server() directly in the sending kernel execution path; the reply then re-enters delivery. Consequently, “Mach message” does not always imply another userspace server or even another kernel server thread. ipc_kmsg_send().

Reading route

The structure route starts with spaces, entries and task-local names, then follows ports and kernel-object associations. It connects allocation and field layout to lookup, rights accounting, lock/SMR boundaries, table growth, conversion policy and final reclamation. Use it alongside the operation route below.

Continue with IPC kmsgs and message storage for allocation geometry, layout-dependent accessors, resource acquisition, representation changes and storage cleanup. Its timer-message example separates reusable allocation ownership from queue/send ownership.

  1. Names and rights: distinguish names, table entries, kernel rights, references, user-reference counts, concurrent namespace growth and resource limits. Continue with port and right lifecycle for allocation, transfer, receive-right migration, death, notifications, and namespace teardown.
  2. Message representation and the call boundary: understand the packed mach_msg2 trap ABI, user/kernel layouts, header dispositions, descriptors, and resource ownership.
  3. Message send, delivery, and receive: trace queue capacity, waiting senders, direct delivery, port sets, receiver copyout, reply messages, and phase-specific failures. Complex message conversion follows aliased header names, OOL VM/port-array acquisition, receiver death ordering, partial copyout and failed-send compensation. Port sets and persistent readiness follows two-way membership links, preposting, concurrent selection and teardown.
  4. Kernel RPC and MIG: follow the destination port, operation ID, generated conversion, synchronous kernel dispatch, and request/reply cleanup.
  5. Mach exception delivery: connect ARM faults to exception-action registration, thread/task/host fallback, exception RPC/replies, Unix signals, and validated thread-state changes.
  6. Port policy and work attribution: introduction to guarded/immovable/pinned rights, reply restrictions, vouchers, and importance. Continue with guards and policy enforcement for construction, guarded operations, deferred exceptions, persona checks, and notification policy; vouchers and importance traces immutable voucher construction, cache release races, thread adoption, and donation ownership. Bank accounts and charging follows account deduplication, role references, bill selection, quantum splitting, live reporting and release.
  7. Mach trap catalog and MIG message catalog: complete numbered trap slots and subsystem/routine declarations, with argument profiles, local receiver paths and external boundaries. The entry map separates trap selectors from message IDs and BSD calls.

Where does a message go?

Semaphores and eventlinks follows two port-backed synchronization mechanisms: semaphore credits and wait registration, paired eventlink counters and association, combined signal/wait, timeout results, scheduler handoff and teardown. Their capability lifetime is separate from queued Mach-message delivery.

Message integrity and descriptor authentication follows the selected header/count/trailer signature, acquired descriptor pointers, validation, relocation and cleanup. Concurrent-operation walkthroughs shows namespace growth meeting termination; ARM64 thread-state conversion continues exception replies into register restoration.

For the deeper dependency path, importance propagation and delayed drops follows already-queued work, inherited voucher counts, receive-right migration, lock-safe task-policy updates and delayed withdrawal. Read it alongside port circularity and backup recovery and synchronous turnstiles: moving a receive right, propagating task importance and donating a waiting thread's priority are distinct operations.

For a userspace send, the destination is the port named by the send header's msgh_remote_port, resolved in the sender's IPC space. The message does not address a process ID, function pointer, or thread ID. What happens next depends on the destination port and the available receiver:

Destination or state Delivery path
Ordinary receive right, eligible receiver already waiting Transfer the kernel message to the receiving thread's ith_kmsg and wake it; it later copies the message into its receive buffer
Ordinary receive right, no eligible receiver Enqueue the message on that port's ip_messages; an authorized receiver later dequeues it
Receive right in a port set A receive on the set can select a ready member; messages remain associated with their member ports
Kernel-object destination Dispatch in the sending thread through ipc_kobject_server; the resulting reply follows its reply-port delivery path
Reply port supplied by the caller The server sends a second message to that port, commonly using a transferred send-once right

These choices and their locking/ownership contracts are expanded in delivery and kernel dispatch. A task can have many ports and many receiving threads; possession of a receive right determines the endpoint that can be received from, while the wait/queue machinery determines which receiving operation gets a particular message.

For a first end-to-end exercise, follow a small message with COPY_SEND for the destination and MAKE_SEND_ONCE for its reply port. Then add one OOL memory descriptor. Track who owns each right after every successful call and on each error return. The actual header copyin handles aliases between destination, reply, and voucher names, so begin with distinct names before studying those cases. ipc_kmsg_copyin_header_rights().

Neighboring subsystems

Boundary Connecting operations
Runtime Message queues register waits; turnstiles propagate dependencies; continuations resume receives. ipc_mqueue_receive().
VM OOL descriptors become vm_map_copy_t objects on send and mapped addresses on receive. ipc_kmsg_copyin_ool_descriptor().
Processes Task/thread port objects expose Mach operations; BSD process identity and signal delivery remain separate layers. ipc_tt.c, exception.c.
Security Space/port policy, kobject filters, task-port conversion evaluation, and guard exceptions constrain capability use. ipc_policy.c, ipc_kobject.c.
Drivers I/O Kit and user-extension endpoints can be kernel object destinations; IKOT_UEXT_OBJECT uses a distinct server path. ipc_kobject_server().

Sources inspected and limits

The review follows selected implementation paths in this checkout. It is not a security audit, formal proof, built-kernel trace, or complete review of every IPC routine.

Depth Sources Reviewed scope and limits
Deep selected synchronization paths sync_sema.c, sync_sema.h, ipc_eventlink.c, typed-port and syscall wrappers Credit/wait ordering, combined operations, event counters/association, packed results, timeout, conditional handoff and no-senders/destroy lifetime. Not every scheduler interleaving, QoS effect or user-space synchronization algorithm.
Deep path review mach_msg.c, ipc_mqueue.c Modern trap, send/receive staging, full-queue sleep, direct receiver delivery, receive continuation, port-set readiness, result handling. Legacy trap/vector corner cases not exhausted.
Deep path review ipc_kmsg.c, ipc_kmsg.h Header/body copyin, selected descriptor conversions, OOL memory, kernel send dispatch, copyout/deflation contract, cleanup and pseudo-receive. The integrity companion adds header/count/trailer signatures and descriptor signing/relocation/stripping; every encoding, layout/interleaving combination and compiler-emitted PAC sequence remains outside review.
Deep path review ipc_right.c, ipc_entry.c, ipc_object.c, headers SMR and locked lookup, name generations, rights versus urefs/references, copyin/copyout dispositions, dead-name conversion and destruction. Live-table replacement, reverse-hash reconstruction, termination and capacity errors are traced in the names chapter; not every aliasing/race branch is audited.
Deep path review ipc_port.c, ipc_space.c, ipc_pset.c, ipc_notify.c Receiver ownership/migration, transit and circularity checks, destruction versus backup transfer, notifications, set membership and namespace teardown. The port-set companion adds waitq link ownership, readiness clearing, lock retries and set destruction. Combined importance/notification races remain outside exhaustive review.
Deep path review ipc_kobject.c, ipc_tt.c, exception.c, ipc_mig.c, mach_types.defs, ux_handler.c Typed dispatch, split request/reply layout, ownership cleanup, exception-action registration/fallback, behavior payloads, kernel reply port, Unix kobject handler and thread-state restoration. Generated MIG stubs were not built or inspected.
Deep selected paths ipc_voucher.c, ipc_voucher.h, ipc_importance.c, ipc_importance.h Voucher/cache counts, construction/deduplication, no-senders ownership, manager release races, send/receive/adoption, importance inheritance and cleanup. Graph propagation, port migration, delayed-drop scheduling and task-policy lock handoff now have a separate companion. Full manager registration, legacy/exec/watchport combinations and exhaustive interleavings remain bounded; bank lifecycle is also separate.
Deep selected bank paths bank.c, bank_internal.h, thread.c, scheduler credit sites Value derivation, account roles/deduplication, made-count release reconciliation, adoption/borrowed bill lifetime, quantum splitting, live totals and task/account teardown. External runtime policy and empirical billing accuracy remain outside this review.
Deep selected policy paths mach_port.c, ipc_policy.c, thread.c Construction, guard/context/destruction/movement, deferred guard AST policy, reply persona and notification policy. Complete product-tunable/entitlement matrix and external service behavior not reconstructed.
Focused/interface review mach_kernelrpc.c, mach_port.c, ipc_policy.c, ipc_voucher.c, ipc_importance.c Representative trap wrappers and integration entry points. Full service lifecycle and external libdispatch/XPC behavior remain outside this review; detailed voucher and guard boundaries are reviewed separately above.

The original kmsg layout guide, port types, IPC security concepts, and guard exceptions are useful companion references. Selected design sections were consulted; use source conditions for checkout-specific behavior.

Synchronous dependencies and special reply ports traces client donation, destination/workloop handoff, state-dependent references and receive reset. Label substitution, detailed trailers and per-thread destruction are expanded in the policy, representation and delivery chapters.

Search the handbook

Search every chapter, interface and code excerpt.

    Diagram

    Source preview

    Open full file