1Mach Port Guard exceptions 2========================== 3 4Mach Port Guard exceptions are used to denote various misuses of Mach IPC. 5This document covers their meaning, as well as hints on how to debug issues. 6 7## Anatomy of a Mach Port Guard Exception 8 9Mach Port Guard Exception is delivered via a Mach exception. These constructs 10are described in the `<kern/exc_guard.h>` header: 11 12``` 13/* 14 * Mach port guards use the exception codes like this: 15 * 16 * code: 17 * +-----------------------------+----------------+-----------------+ 18 * |[63:61] GUARD_TYPE_MACH_PORT | [60:32] flavor | [31:0] target | 19 * +-----------------------------+----------------+-----------------+ 20 * 21 * subcode: 22 * +----------------------------------------------------------------+ 23 * |[63:0] payload | 24 * +----------------------------------------------------------------+ 25 */ 26 27#define GUARD_TYPE_MACH_PORT 0x1 /* guarded mach port */ 28``` 29 30This description is mostly useful to implementors of a Mach exception handler, 31most clients will instead receive a crash log where ReportCrash tried its best 32to decode the message above, however sometimes it lags behind the introduction 33of new guards, and this document helps decoding the matrix. 34 35A properly decoded crashlog will contain information like this: 36 37``` 38Exception Type: EXC_GUARD (SIGKILL) 39Exception Subtype: GUARD_TYPE_MACH_PORT 40Exception Message: INVALID_NAME on mach port 9987 (guarded with 0x0000000000000000) 41Exception Codes: 0x0000000000002703, 0x0000000000000000 42Termination Reason: GUARD 2305845208236959491 43``` 44 45However, in some cases, the decoding is partial and one needs to decode 46these by hand. In all cases, ReportCrash will always recognize Mach Port Guards, 47and the `Exception Codes` and `Termination Reason` are the lines we need, 48in terms of the kernel defined fields, they follow this template: 49 50``` 51Exception Codes: $(code.target), $(subcode.payload) 52Termination Reason: GUARD $(code) 53``` 54 55When applying it to the example above, we can see that: 56 57- the code is `2305845208236959491 == 0x2000020000002703` which decodes into 58 `{ guard_type: GUARD_TYPE_MACH_PORT, flavor: 0x200, target: 0x2703 }` 59- the payload is `0`. 60 61 62## Typical Mach Port bugs, and how to reason about them 63 64In this section, we will describe the most common cases of Mach IPC issues 65that are reported by Mach Port Guard exceptions, and how to reason about them. 66 67### Port right mismanagement 68 69This is by far the most common source of issues with Mach IPC. Unlike file 70descriptors which have a really simple lifecycle (you destroy them with 71`close()`), Mach ports have several associated rights that must be managed 72properly. 73 74Port right mismanagement usually happens when some subsystem has a dangling 75reference to a Mach port name that it has already destroyed, and keeps using it. 76This is the analogous to a use-after-free for allocated memory. 77 78The most common sources of issues are: 79 80- confusions in accounting of the receive right and send rights, due to the 81 arcane `mach_port_mod_refs` API being misused. We recommend using 82 `mach_port_destruct()` for receive rights, and `mach_port_deallocate()` 83 for send or send-once rights. 84 85- dangling port names: the port name management was correct, but the reference 86 to the port wasn't reset to `MACH_PORT_NULL`, leading to eventual over-releases. 87 88- threading safety related issues where the port management isn't properly 89 synchronized. 90 91 92## List of fatal Mach Port Guard Exceptions 93 94Some of the exceptions are always fatal (hitting them will cause the process to 95be terminated) regardless of the process kind. 96 97 98### `kGUARD_EXC_DESTROY` 0x00000001 99 100- **ReportCrash Name**: DESTROY, 101- **Target meaning**: the mach port name the incorrect operation targets, 102- **Payload meaning**: the correct value of the context guarding the Mach Port. 103 104This exception is thrown when a guarded receive right is being destroyed 105with an incorrect or missing context presented by the caller. 106 107Receive rights can be guarded with a caller chosen context via mechanisms such 108as: 109 110- `mach_port_guard()` being called, 111- the right being made using the `MPO_CONTEXT_AS_GUARD` flag of 112 `mach_port_construct()`, 113- the usage of a guarded port descriptor in a Mach message. 114 115 116Examples of such ports are the receive rights used for XPC Connections, 117hitting such a bug usually is a sign of port right mismanagement. 118 119 120### `kGUARD_EXC_MOD_REFS` 0x00000002 121 122- **ReportCrash Name**: `OVER_DEALLOC` or `MOD_REFS`, 123- **Target meaning**: the mach port name the incorrect operation targets, 124- **Payload meaning**: 125 - `0x0100000000000000`: a `deallocate` function, 126 - `0x0200000000000000`: a `destroy` function, 127 - `0x0300000000000000`: via the side effect of a message send (port copyin). 128 129This exception is thrown when the last send right of a pinned mach port is being 130destroyed. Pinned ports must never have a send right count going to zero in a 131given IPC space. 132 133Examples of such ports are thread and task control ports. This is usually a 134sign of port-right mismanagement. 135 136 137### `kGUARD_EXC_INVALID_OPTIONS` 0x00000003 138 139- **ReportCrash Name**: `INVALID_OPTIONS`, 140- **Target meaning**: the message ID of a rejected message via the legacy 141 `mach_msg_trap()` or zero, 142- **Payload meaning**: the kernel sanitized (see `ipc_current_user_policy()`) 143 for the rejected `mach_msg2()` call. 144 145There are several policies dictating the shape of options passed to calls of the 146`mach_msg()` family. These correspond to programming mistakes. 147 148 149### `kGUARD_EXC_SET_CONTEXT` 0x00000004 150 151- **ReportCrash Name**: `SET_CONTEXT`, 152- **Target meaning**: the mach port name the incorrect operation targets, 153- **Payload meaning**: the value of the context guarding the Mach Port. 154 155This exception is thrown when `mach_port_set_context()` or 156`mach_port_swap_guard()` is used against a Mach Port using a strict guard (a 157Mach Port constructed with the `MPO_STRICT | MPO_CONTEXT_AS_GUARD` flags). 158 159Examples of such ports are the client-side receive right for XPC connections. 160This is usually a sign of port right mismanagement. 161 162 163### `kGUARD_EXC_THREAD_SET_STATE` 0x00000005 164 165- **ReportCrash Name**: N/A, 166- **Target meaning**: exception flavor, 167- **Payload meaning**: 168 - `0x0100000000000000`: tss called from userspace exception handler, 169 - `0x0200000000000000`: tss with flavor that modifies cpu registers, 170 - `0x0300000000000000`: tss called from fatal PAC exception. 171 172This exception is thrown when a process is trying to use the 173`thread_set_state()` interface, or any interface leading to it (such as trying 174to change thread state via replying to a Mach exception message), and that this 175is disallowed by policy for this process. 176 177 178### `kGUARD_EXC_EXCEPTION_BEHAVIOR_ENFORCE` 0x00000006 179 180- **ReportCrash Name**: N/A, 181- **Target meaning**: the new exception behavior, 182- **Payload meaning**: the exception mask. 183 184This exception is thrown when a process is trying to register an exception port 185for a behavior not using a task identity port, and that this is disallowed by 186policy for this process. 187 188 189### `kGUARD_EXC_SERVICE_PORT_VIOLATION_FATAL` 0x00000007 190 191- **ReportCrash Name**: N/A, 192- **Target meaning**: the type of service port defense violation, 193- **Payload meaning**: violator port name if we have it, zero otherwise. 194 195This exception is thrown when the `service_port_defense_enabled` bootarg is set and a 196process violates service port defense policy, which includes copyin a service port receive 197right from process other than launchd, arming pd notification on a service port if the 198process is not launchd, and setting a service port as exception port. 199 200### `kGUARD_EXC_UNGUARDED` 0x00000008 201 202- **ReportCrash Name**: UNGUARDED, 203- **Target meaning**: the mach port name the incorrect operation targets, 204- **Payload meaning**: always zero. 205 206This exception is thrown when a process is trying to perform an operation (such 207as `mach_port_unguard()` on a port that isn't guarded. 208 209This is usually a sign of port right mismanagement. 210 211### `kGUARD_EXC_KOBJECT_REPLY_PORT_SEMANTICS` 0x00000009 212 213- **ReportCrash Name**: KOBJECT\_REPLY\_PORT\_SEMANTICS, 214- **Target meaning**: the mach port name the incorrect operation targets, 215- **Payload meaning**: always zero. 216 217This exception is thrown when a hardened process is trying to send a message 218to a kobject port without using an `IOT_REPLY_PORT` to receive the reply. 219 220### `kGUARD_EXC_REQUIRE_REPLY_PORT_SEMANTICS` 0x0000000a 221 222- **ReportCrash Name**: `REQUIRE_REPLY_PORT_SEMANTICS`, 223- **Target meaning**: the mach port name the incorrect operation targets, 224- **Payload meaning**: 1 if the port is a bootstrap port, 0 otherwise. 225 226This exception is thrown when a caller is violating the reply port semantics in 227a process where this is disallowed by policy. This is used to gather telemetry 228around violators pending enforcement in a future release. 229 230This is usually a sign of a programming mistake (violation of the reply port 231semantics rules). 232 233### `kGUARD_EXC_INCORRECT_GUARD` 0x00000010 234 235- **ReportCrash Name**: `INCORRECT_GUARD`, 236- **Target meaning**: the mach port name the incorrect operation targets, 237- **Payload meaning**: the value of the context guarding the Mach Port. 238 239This exception is thrown when a process is attemtping a guarded operation but 240passed a context to the call that doesn't match the context actually guarding 241this port. 242 243This is usually a sign of port right mismanagement. 244 245 246### `kGUARD_EXC_IMMOVABLE` 0x00000020 247 248- **ReportCrash Name**: `ILLEGAL_MOVE`, 249- **Target meaning**: the mach port name the incorrect operation targets, 250- **Payload meaning**: (target port type << 32) | disposition. 251 252This exception is thrown when a process is attempting to move a port right, 253and this has been disallowed by policy for this port type and process. 254 255This is usually a programming mistake (or legacy code that hasn't been updated 256to the most recent Mach IPC policies). 257 258 259### `kGUARD_EXC_STRICT_REPLY` 0x00000040 260 261This exception is thrown for reply port semantics mistakes, if the 262`enforce_strict_reply` boot-arg is set. As this is not a default config at this 263point, and that this is likely going to be phased out in favor of tracking reply 264ports at the port type level, this is left mostly undocumented on purpose. 265 266 267### `kGUARD_EXC_INVALID_NOTIFICATION_REQ` 0x00000041 268 269- **ReportCrash Name**: INVALID\_NOTIFICATION\_REQ, 270- **Target meaning**: IOT_ port type that you are trying to arm the notification on 271- **Payload meaning**: The type of notification you were registering for 272 273This exception is thrown when a process is trying to arm a notification 274on a port type that disallows such requests. 275 276 277### `kGUARD_EXC_INVALID_MPO_ENTITLEMENT` 0x00000042 278 279- **ReportCrash Name**: `INVALID_MPO_ENTITLEMENT`, 280- **Target meaning**: The `mpo_flags_t` that were passed into `mach_port_construct` 281 282This exception is thrown when you try to construct a mach port type that is disallowed 283for your process based on entitlements. 284 285### `kGUARD_EXC_DESCRIPTOR_VIOLATION` 0x00000043 286 287- **ReportCrash Name**: `DESCRIPTOR_VIOLATION`, 288- **Target meaning**: The IPC space policy. 289- **Payload meaning**: 290 - `(violation_type << 56) | aux` : the violation's type, among with associated metadata 291 292This exception is thrown when a process attempts to violate any 293Mach message descriptor policies. 294 295### `kGUARD_EXC_MSG_FILTERED` 0x00000080 296 297- **ReportCrash Name**: `MSG_FILTERED`, 298- **Target meaning**: the mach port name the incorrect operation targets, 299- **Payload meaning**: the message ID of the filtered message. 300 301This exception is thrown when a process is not allowed to send the specified 302message due to sandboxing, and that a hard failure has been requested by either 303the client or the Sandbox. 304 305 306## List of optionally fatal Mach Port Guard Exceptions 307 308Some of the exceptions are optionally fatal. Hitting them will only terminate 309the process when it is opted for a hardened Mach IPC environment. Such processes 310are: 311 312- platform binaries, 313- processes with a browser entitlement (`com.apple.developer.web-browser-engine.*`). 314 315The `task_exc_guard_default` boot-arg can be used to change these defaults. 316 317Note: using the `amfi=-1` or similar boot-args will make all processes appear to 318be platform binaries, which in turn will turn a lot of bugs in 3p software into 319hard crashes. Most notably at this time, electron apps cause several guard 320exceptions in the Mach IPC and VM world. This is not a supported configuration. 321 322 323### `kGUARD_EXC_INVALID_RIGHT` 0x00000100 324 325- **ReportCrash Name**: `INVALID_RIGHT`, 326- **Target meaning**: the mach port name the incorrect operation targets, 327- **Payload meaning**: 328 - `0x01 << 56` : `ipc_port_translate_receive` failed, 329 - `(0x02 << 56) | (right << 32) | ie_bits` : `ipc_right_delta` failed, 330 - `(0x03 << 56) | ie_bits` : `ipc_right_destruct` failed, 331 - `(0x04 << 56) | (reason << 32) | ie_bits` : `ipc_right_copyin` failed, 332 - `(0x05 << 56) | ie_bits` : `ipc_right_dealloc` failed, 333 - `(0x06 << 56) | (otype << 32) | io_type` : `ipc_right_deallocate_kernel` failed, 334 - `(0x07 << 56) | ie_bits` : invalid port in `ipc_object_translate_port_pset`, 335 - `(0x08 << 56) | ie_bits` : invalid pset in `ipc_object_translate_port_pset`. 336 337This exception is thrown when an operation is targetting a port which rights do 338not match the caller's expectations. Examples of such mistakes are: 339 340- performing an operation expecting a port-set name, but passing a port name 341 instead, 342- trying to receive a message and not owning the receive right for it. 343 344These correspond to cases leading to the `KERN_INVALID_RIGHT` or 345`KERN_INVALID_CAPABILITY` error codes of most Mach IPC interfaces. 346 347This is usually a sign of port right mismanagement. 348 349 350### `kGUARD_EXC_INVALID_NAME` 0x00000200 351 352- **ReportCrash Name**: `INVALID_NAME`, 353- **Target meaning**: the mach port name the incorrect operation targets, 354- **Payload meaning**: always zero. 355 356This exception is thrown when an operation is targetting a name for which 357the caller holds no right. 358 359These correspond to cases leading to the `KERN_INVALID_NAME` error code of most 360Mach IPC interfaces. 361 362This is usually a sign of port right mismanagement. 363 364 365### `kGUARD_EXC_INVALID_VALUE` 0x00000400 366 367- **ReportCrash Name**: `INVALID_VALUE`, 368- **Target meaning**: the mach port name the incorrect operation targets, 369- **Payload meaning**: 370 - `(0x01 << 56) | (type << 32) | size` : invalid trailer in `mach_port_peek`, 371 - `(0x02 << 56) | (right << 32) | (delta << 16) | ie_bits` : `ipc_right_delta` failed, 372 - `(0x03 << 56) | (srdelta << 32) | ie_bits` : `ipc_right_destruct` failed, 373 374This exception is thrown when: 375 376- the caller is trying to apply a delta to the number of send rights of a port 377 name, and this would overflow the send right count, which is usually a sign of 378 port right mismanagement, 379 380- the trailer related arguments to `mach_port_peek()` are invalid, which is 381 typicaly a programming mistake. 382 383These correspond to cases leading to the `KERN_INVALID_VALUE` error code of most 384Mach IPC interfaces. 385 386 387### `kGUARD_EXC_INVALID_ARGUMENT` 0x00000800 388 389- **ReportCrash Name**: `INVALID_ARGUMENT`, 390- **Target meaning**: the mach port name the incorrect operation targets, 391- **Payload meaning**: the correct value of the context guarding the Mach Port. 392 393This exception is thrown when a caller is trying to guard an already guarded 394port. This should really have been named `kGUARD_EXC_ALREADY_GUARDED`. 395 396This is usually a sign of port right mismanagement. 397 398 399### `kGUARD_EXC_KERN_FAILURE` 0x00004000 400 401- **ReportCrash Name**: `KERN_FAILURE`, 402- **Target meaning**: always zero, 403- **Payload meaning**: 404 - `0x0100000000000000`: task other than launchd arm pd on service ports, 405 - `0x0200000000000000`: not using IOT_NOTIFICATION_PORT for pd notification, 406 - `0x0300000000000000`: notification port not owned by launchd, 407 - `0x0400000000000000`: register multiple pd notification. 408 409This exception is thrown when a caller is trying to request a port-destroyed 410notification that is disallowed by system policy. This should really have been 411named `kGUARD_EXC_INVALID_PDREQUEST`. 412 413This is usually a sign of port right mismanagement. 414 415 416### `kGUARD_EXC_SEND_INVALID_REPLY` 0x00010000 417 418- **ReportCrash Name**: `SEND_INVALID_REPLY`, 419- **Target meaning**: the mach port name the incorrect operation targets, 420- **Payload meaning**: (reply port ie bits << 32) | disposition. 421 422This exception is thrown when a caller is trying to send a message whose reply 423port (the `msgh_local_port` field of a Mach message) violates policies around 424reply ports or its disposition. 425 426This is usually a sign of port right mismanagement. 427 428 429### `kGUARD_EXC_SEND_INVALID_RIGHT` 0x00020000 430 431- **ReportCrash Name**: `SEND_INVALID_RIGHT`, 432- **Target meaning**: the mach port name the incorrect operation targets, 433- **Payload meaning**: 434 - `(0x01 << 56) | disposition`: copyin port descriptor failed, 435 - `(0x02 << 56) | disposition`: copyin ool port descriptor failed, 436 - `(0x03 << 56) | disposition`: copyin guarded port descriptor failed, 437 438This exception is thrown when a caller is trying to send a message where one of 439the port descriptors denotes a right that doesn't match the requested 440disposition (for example, a make-send disposition for a port where the process 441doesn't own a receive right). 442 443This is usually a sign of port right mismanagement. 444 445 446### `kGUARD_EXC_SEND_INVALID_VOUCHER` 0x00040000 447 448- **ReportCrash Name**: `SEND_INVALID_VOUCHER`, 449- **Target meaning**: the mach port name the incorrect operation targets, 450- **Payload meaning**: disposition of the voucher port. 451 452This exception is thrown when a caller is trying to send a message whose voucher 453port (the `msgh_voucher_port` field of a Mach message) violates policies around 454voucher ports or its disposition. 455 456This is usually a sign of port right mismanagement. 457 458 459### `kGUARD_EXC_RCV_INVALID_NAME` 0x00080000 460 461- **ReportCrash Name**: `RCV_INVALID_NAME`, 462- **Target meaning**: the mach port name the incorrect operation targets, 463- **Payload meaning**: always zero. 464 465This exception is thrown when a caller is trying to receive a message on a mach 466port name for which it doesn't hold a port-set or receive right. 467 468This is usually a sign of port right mismanagement. 469 470 471## List of soft Mach Port Guard Exceptions 472 473Some of the exceptions are never fatal (hitting them will only emit a simulated 474crash log, and the process will keep going). 475 476 477### `kGUARD_EXC_RCV_GUARDED_DESC` 0x00100000 478 479- **ReportCrash Name**: `RCV_GUARDED_DESC`, 480- **Target meaning**: the mach port name the incorrect operation targets, 481- **Payload meaning**: always zero. 482 483This exception is thrown when a caller is trying to receive a message containing 484guarded port descriptors and it hasn't indicated that it knows how to parse them 485(by passing the `MACH_RCV_GUARDED_DESC` flag to `mach_msg()`). 486 487The usage of guarded port descriptor is a protocol agreement between the client 488and the server, and a disagreement here is a programming mistake. 489 490This guard is only enabled on development kernels at this time. 491 492### `kGUARD_EXC_SERVICE_PORT_VIOLATION_NON_FATAL` 0x00100001 493 494- **ReportCrash Name**: N/A, 495- **Target meaning**: the type of service port defense violation, 496- **Payload meaning**: violator port name if we have it, zero otherwise. 497 498This is the non fatal version of `kGUARD_EXC_SERVICE_PORT_VIOLATION_FATAL`, which is 499used when the `service_port_defense_enabled` bootarg is not set. 500 501 502### `kGUARD_EXC_PROVISIONAL_REPLY_PORT` 0x00100002 503 504- **ReportCrash Name**: N/A, 505- **Target meaning**: always zero, 506- **Payload meaning**: always zero. 507 508This exception is thrown when a 1p process is trying to create a provisional 509reply port on iOS. It is currently a soft crash to collect telemetry before 510the actual enforcement. 511 512 513### `kGUARD_EXC_OOL_PORT_ARRAY_CREATION` 0x00100003 514 515- **ReportCrash Name**: N/A, 516- **Target meaning**: always zero. 517- **Payload meaning**: always zero. 518 519This is telemetry for processes creating a port with flag 520MPO_CONNECTION_PORT_WITH_PORT_ARRAY without an entitlement 521 522 523### `kGUARD_EXC_MOVE_PROVISIONAL_REPLY_PORT` 0x00100004 524 525- **ReportCrash Name**: N/A, 526- **Target meaning**: the mach port name of the provisional reply port, 527- **Payload meaning**: always zero. 528 529This exception is thrown when a process opted for enhanced security v2 moves 530the receive right of a provisional reply port out of its ipc space. 531 532### `kGUARD_EXC_REPLY_PORT_SINGLE_SO_RIGHT` 0x00100005 533 534- **ReportCrash Name**: N/A, 535- **Target meaning**: the mach port name of the reply port, 536- **Payload meaning**: the copyin reason. 537 538This exception is thrown when a process attempts to create more than 539one single send-once right for a reply port. Reply ports are not allowed 540to extend more than one single send-once right at any given moment. 541 542 543### `kGUARD_EXC_MOD_REFS_NON_FATAL` 0x00200000 544 545- **ReportCrash Name**: `OVERDEALLOC_SOFT`, 546- **Target meaning**: the mach port name the incorrect operation targets, 547- **Payload meaning**: same as `kGUARD_EXC_MOD_REFS`. 548 549This is the same as `kGUARD_EXC_MOD_REFS`, except that this is delivered as a 550soft error. 551 552 553### `kGUARD_EXC_IMMOVABLE_NON_FATAL` 0x00400000 554 555- **ReportCrash Name**: `ILLEGALMOVE_SOFT`. 556- **Target meaning**: the mach port name the incorrect operation targets, 557- **Payload meaning**: same as `kGUARD_EXC_IMMOVABLE`. 558 559This is the same as `kGUARD_EXC_IMMOVABLE`, except that this is delivered as a 560soft error. 561 562