Mach IPC Port Types ========================== This document is not a tutorial on or encouragement to write new mach code, but serves as documentation for darwin engineers to map security policies to ports used in the lower layers of the OS. See the warning/disclaimer at https://at.apple.com/dont_write_new_mach_code and come talk to us in #help-darwin before using the knowledge contained here. # Port Types A port can have exactly one of the following types, and we describe what each port means from the userspace perspective, including what you are/aren't allowed to do with a particular port and how to construct it. The source of truth for security policies in the kernel is the `ipc_policy_array` in `ipc_policy.c` ### IOT_PORT_SET #### Creation - `mach_port_allocate(... MACH_PORT_RIGHT_PORT_SET ...)` #### Behavior/Usage - Allows you to monitor an entire set of ports for messages at once, similar to `select(2)` #### Security Restrictions - No special security restrictions on this port ### IOT_PORT #### Creation - Your standard port that you obtain through the port allocation APIs if you don't pass any special flags. #### Behavior/Usage - Sends traditional mach messages and is generally associated with "raw mach" - new code generally should not use these. #### Security Restrictions - No special security restrictions on this port ### IOT_SERVICE_PORT #### Creation - pass `MPO_SERVICE_PORT` to `mach_port_construct` #### Behavior/Usage - Used by `launchd` as the port which drives the launch-on-demand behavior of services/daemons on the system. Clients lookup the service port for some service using `bootstrap_lookup` and then can form a connection with that service. - `launchd` reclaims these ports when the process owning the service port is killed so that the service port is always active. #### Security Restrictions - This is the "hardened" version of the service port which has various security policies such as immovabile receive right and enforced reply port semantics. - `launchd` enforces that all platform binary services use this version of the service port (as opposed to the `WEAK` version below), and allows third parties to opt into this following the completion of rdar://137633308. See the `launchd` documentation for more details about how to opt into this restriction - The kernel will enforce that platform restrictions binaries receive this version of the service port following completion of rdar://133304899. ### IOT_WEAK_SERVICE_PORT #### Creation - pass `MPO_WEAK_SERVICE_PORT` to `mach_port_construct` #### Behavior/Usage - Same feature set and usage as `IOT_SERVICE_PORT` above, the only difference is the associated security policy. #### Security Restrictions - No security hardening. Launchd entirely controls which processes get the weak vs. "strong" service ports, and the kernel will eventually enforce that launchd has created the right kind of port for hardened processes. See `launchd` documentation for more info. ### IOT_CONNECTION_PORT #### Creation - pass `MPO_CONNECTION_PORT` to `mach_port_construct` #### Behavior/Usage - A connection port models an established connection between two parties, commonly between a client and a service, but it's also generalizable to peer connections. #### Security Restrictions - We assume that the handshake mechanism to create the connection between these two parties is sufficiently hardened, so the security boundary we want to protect here is that the connection and its replies are contained between the two parties. To accomplish this the connection port is marked as immovable receive and requires reply port semantics, both of which combined kills man in the middle attacks at this layer. ### IOT_CONNECTION_PORT_WITH_PORT_ARRAY #### Creation - pass `MPO_CONNECTION_PORT_WITH_PORT_ARRAY` to `mach_port_construct` #### Behavior/Usage - Serves as a connection port, however does not have the mechanics/behaviors of `IOT_CONNECTION_PORT`. Unlike other port types, this type is allowed to receive out-of-line port array descriptors (`MACH_MSG_OOL_PORTS_DESCRIPTOR`) in platform binaries. For enhanced security v2, it's the only port type that is allowed to receive `MACH_MSG_OOL_PORTS_DESCRIPTOR`. - In addition to that, we enforce the following restrictions on messages with `MACH_MSG_OOL_PORTS_DESCRIPTOR` descriptor (also, only for platform binaries): 1. a message cannot carry more than ONE single OOL port array. 2. the only allowed disposition is `MACH_MSG_TYPE_COPY_SEND`. #### Security Restrictions - Can only be created by binaries that have the `com.apple.developer.allow-connection-port-with-port-array` entitlement. ### IOT_EXCEPTION_PORT #### Creation - pass `MPO_EXCEPTION_PORT` to `mach_port_construct` #### Behavior/Usage - Used in mach exception handling, if you have the entitlement `com.apple.security.only-one-exception-port` then you must use the `task_register_hardened_exception_handler` workflow which only accepts this type of port. Otherwise the historical, non-hardened exception handling workflow using `task_set_exception_ports` accepts either a standard `IOT_PORT` or an `IOT_EXCEPTION_PORT`. #### Security Restrictions - This port must be immovable receive when using the hardened exception flow to ensure that exceptions cannot be diverted and handled/stalled outside of the process generating them. ## Reply Ports - If your port type requires reply port semantics, then you must use one of the following reply port types as the reply field (`msgh_local_port`) when sending a message to `p`. See [reply port defense](ipc_security_concepts.md#reply-port-defense) for more details. ### IOT_REPLY_PORT #### Creation - pass `MPO_REPLY_PORT` to `mach_port_construct` #### Behavior/Usage - A reply port exists in your space, and you use it to receive replies from clients in response to messages that you send them. It's intended to model synchronous IPC where you send a message to a peer and expect a single message in response. #### Security Restrictions - Reply ports guarantee that a reply comes back to you from the person you are messaging - in other words, it counters person-in-the-middle attacks. It accomplishes this by using send-once rights to ensure that *exactly* one reply from the destination will come back to your reply port, which is marked as immovable receive, and the send right must be a make-send-once so that it cannot be moved after its creation. ### IOT_SPECIAL_REPLY_PORT #### Creation - Created by the kernel: libxpc and dispatch call into `thread_get_special_reply_port` to obtain the send/receive right for this thread-specific port. #### Behavior/Usage - Has the same properties as a reply port above, but this is used by libxpc and dispatch to provide turnstile/importance inheritance capabilities. #### Security Restrictions - same as reply ports above ### IOT_PROVISIONAL_REPLY_PORT #### Creation - pass `MPO_PROVISIONAL_REPLY_PORT` to `mach_port_construct` #### Behavior/Usage - This has the mechanics of a normal `IOT_PORT` in that it has no special behaviors/usage/restrictions, but it counts as reply port for the purposes of enforced reply port semantics. #### Security Restrictions - None, this requires special entitlements in platform restrictions binaries. # Violations of Port Security Policies If you violate the security policies outlined above, expect to receive a `mach_port_exc_guard` exception, which will either emit telemetry or fatally crash your process depending on the enforcement level of the security violation. See [List of fatal Mach IPC guard exceptions](guard_exceptions.md#List-of-fatal-Mach-Port-Guard-Exceptions) or at.apple.com/exc-guard for more details.