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**: always zero, 193- **Payload meaning**: violator port name. 194 195This exception is thrown when the `service_port_defense_enabled` bootarg is set and a 196process copyin a service port receive right from process other than launchd. 197 198### `kGUARD_EXC_UNGUARDED` 0x00000008 199 200- **ReportCrash Name**: UNGUARDED, 201- **Target meaning**: the mach port name the incorrect operation targets, 202- **Payload meaning**: always zero. 203 204This exception is thrown when a process is trying to perform an operation (such 205as `mach_port_unguard()` on a port that isn't guarded. 206 207This is usually a sign of port right mismanagement. 208 209### `kGUARD_EXC_KOBJECT_REPLY_PORT_SEMANTICS` 0x00000009 210 211- **ReportCrash Name**: KOBJECT\_REPLY\_PORT\_SEMANTICS, 212- **Target meaning**: the mach port name the incorrect operation targets, 213- **Payload meaning**: always zero. 214 215This exception is thrown when a hardened process is trying to send a message 216to a kobject port without using an `IOT_REPLY_PORT` to receive the reply. 217 218### `kGUARD_EXC_REQUIRE_REPLY_PORT_SEMANTICS` 0x0000000a 219 220- **ReportCrash Name**: `REQUIRE_REPLY_PORT_SEMANTICS`, 221- **Target meaning**: the mach port name the incorrect operation targets, 222- **Payload meaning**: 1 if the port is a bootstrap port, 0 otherwise. 223 224This exception is thrown when a caller is violating the reply port semantics in 225a process where this is disallowed by policy. This is used to gather telemetry 226around violators pending enforcement in a future release. 227 228This is usually a sign of a programming mistake (violation of the reply port 229semantics rules). 230 231### `kGUARD_EXC_INCORRECT_GUARD` 0x00000010 232 233- **ReportCrash Name**: `INCORRECT_GUARD`, 234- **Target meaning**: the mach port name the incorrect operation targets, 235- **Payload meaning**: the value of the context guarding the Mach Port. 236 237This exception is thrown when a process is attemtping a guarded operation but 238passed a context to the call that doesn't match the context actually guarding 239this port. 240 241This is usually a sign of port right mismanagement. 242 243 244### `kGUARD_EXC_IMMOVABLE` 0x00000020 245 246- **ReportCrash Name**: `ILLEGAL_MOVE`, 247- **Target meaning**: the mach port name the incorrect operation targets, 248- **Payload meaning**: (target port type << 32) | disposition. 249 250This exception is thrown when a process is attempting to move a port right, 251and this has been disallowed by policy for this port type and process. 252 253This is usually a programming mistake (or legacy code that hasn't been updated 254to the most recent Mach IPC policies). 255 256 257### `kGUARD_EXC_STRICT_REPLY` 0x00000040 258 259This exception is thrown for reply port semantics mistakes, if the 260`enforce_strict_reply` boot-arg is set. As this is not a default config at this 261point, and that this is likely going to be phased out in favor of tracking reply 262ports at the port type level, this is left mostly undocumented on purpose. 263 264 265### `kGUARD_EXC_INVALID_NOTIFICATION_REQ` 0x00000041 266 267- **ReportCrash Name**: INVALID\_NOTIFICATION\_REQ, 268- **Target meaning**: IOT_ port type that you are trying to arm the notification on 269- **Payload meaning**: The type of notification you were registering for 270 271This exception is thrown when a process is trying to arm a notification 272on a port type that disallows such requests. 273 274 275### `kGUARD_EXC_INVALID_MPO_ENTITLEMENT` 0x00000042 276 277- **ReportCrash Name**: `INVALID_MPO_ENTITLEMENT`, 278- **Target meaning**: The `mpo_flags_t` that were passed into `mach_port_construct` 279 280This exception is thrown when you try to construct a mach port type that is disallowed 281for your process based on entitlements. 282 283### `kGUARD_EXC_DESCRIPTOR_VIOLATION` 0x00000043 284 285- **ReportCrash Name**: `DESCRIPTOR_VIOLATION`, 286- **Target meaning**: The IPC space policy. 287- **Payload meaning**: 288 - `(violation_type << 56) | aux` : the violation's type, among with associated metadata 289 290This exception is thrown when a process attempts to violate any 291Mach message descriptor policies. 292 293### `kGUARD_EXC_MSG_FILTERED` 0x00000080 294 295- **ReportCrash Name**: `MSG_FILTERED`, 296- **Target meaning**: the mach port name the incorrect operation targets, 297- **Payload meaning**: the message ID of the filtered message. 298 299This exception is thrown when a process is not allowed to send the specified 300message due to sandboxing, and that a hard failure has been requested by either 301the client or the Sandbox. 302 303 304## List of optionally fatal Mach Port Guard Exceptions 305 306Some of the exceptions are optionally fatal. Hitting them will only terminate 307the process when it is opted for a hardened Mach IPC environment. Such processes 308are: 309 310- platform binaries, 311- processes with a browser entitlement (`com.apple.developer.web-browser-engine.*`). 312 313The `task_exc_guard_default` boot-arg can be used to change these defaults. 314 315Note: using the `amfi=-1` or similar boot-args will make all processes appear to 316be platform binaries, which in turn will turn a lot of bugs in 3p software into 317hard crashes. Most notably at this time, electron apps cause several guard 318exceptions in the Mach IPC and VM world. This is not a supported configuration. 319 320 321### `kGUARD_EXC_INVALID_RIGHT` 0x00000100 322 323- **ReportCrash Name**: `INVALID_RIGHT`, 324- **Target meaning**: the mach port name the incorrect operation targets, 325- **Payload meaning**: 326 - `0x01 << 56` : `ipc_port_translate_receive` failed, 327 - `(0x02 << 56) | (right << 32) | ie_bits` : `ipc_right_delta` failed, 328 - `(0x03 << 56) | ie_bits` : `ipc_right_destruct` failed, 329 - `(0x04 << 56) | (reason << 32) | ie_bits` : `ipc_right_copyin` failed, 330 - `(0x05 << 56) | ie_bits` : `ipc_right_dealloc` failed, 331 - `(0x06 << 56) | (otype << 32) | io_type` : `ipc_right_deallocate_kernel` failed, 332 - `(0x07 << 56) | ie_bits` : invalid port in `ipc_object_translate_port_pset`, 333 - `(0x08 << 56) | ie_bits` : invalid pset in `ipc_object_translate_port_pset`. 334 335This exception is thrown when an operation is targetting a port which rights do 336not match the caller's expectations. Examples of such mistakes are: 337 338- performing an operation expecting a port-set name, but passing a port name 339 instead, 340- trying to receive a message and not owning the receive right for it. 341 342These correspond to cases leading to the `KERN_INVALID_RIGHT` or 343`KERN_INVALID_CAPABILITY` error codes of most Mach IPC interfaces. 344 345This is usually a sign of port right mismanagement. 346 347 348### `kGUARD_EXC_INVALID_NAME` 0x00000200 349 350- **ReportCrash Name**: `INVALID_NAME`, 351- **Target meaning**: the mach port name the incorrect operation targets, 352- **Payload meaning**: always zero. 353 354This exception is thrown when an operation is targetting a name for which 355the caller holds no right. 356 357These correspond to cases leading to the `KERN_INVALID_NAME` error code of most 358Mach IPC interfaces. 359 360This is usually a sign of port right mismanagement. 361 362 363### `kGUARD_EXC_INVALID_VALUE` 0x00000400 364 365- **ReportCrash Name**: `INVALID_VALUE`, 366- **Target meaning**: the mach port name the incorrect operation targets, 367- **Payload meaning**: 368 - `(0x01 << 56) | (type << 32) | size` : invalid trailer in `mach_port_peek`, 369 - `(0x02 << 56) | (right << 32) | (delta << 16) | ie_bits` : `ipc_right_delta` failed, 370 - `(0x03 << 56) | (srdelta << 32) | ie_bits` : `ipc_right_destruct` failed, 371 372This exception is thrown when: 373 374- the caller is trying to apply a delta to the number of send rights of a port 375 name, and this would overflow the send right count, which is usually a sign of 376 port right mismanagement, 377 378- the trailer related arguments to `mach_port_peek()` are invalid, which is 379 typicaly a programming mistake. 380 381These correspond to cases leading to the `KERN_INVALID_VALUE` error code of most 382Mach IPC interfaces. 383 384 385### `kGUARD_EXC_INVALID_ARGUMENT` 0x00000800 386 387- **ReportCrash Name**: `INVALID_ARGUMENT`, 388- **Target meaning**: the mach port name the incorrect operation targets, 389- **Payload meaning**: the correct value of the context guarding the Mach Port. 390 391This exception is thrown when a caller is trying to guard an already guarded 392port. This should really have been named `kGUARD_EXC_ALREADY_GUARDED`. 393 394This is usually a sign of port right mismanagement. 395 396 397### `kGUARD_EXC_KERN_FAILURE` 0x00004000 398 399- **ReportCrash Name**: `KERN_FAILURE`, 400- **Target meaning**: always zero, 401- **Payload meaning**: 402 - `0x0100000000000000`: task other than launchd arm pd on service ports, 403 - `0x0200000000000000`: not using IOT_NOTIFICATION_PORT for pd notification, 404 - `0x0300000000000000`: notification port not owned by launchd, 405 - `0x0400000000000000`: register multiple pd notification. 406 407This exception is thrown when a caller is trying to request a port-destroyed 408notification that is disallowed by system policy. This should really have been 409named `kGUARD_EXC_INVALID_PDREQUEST`. 410 411This is usually a sign of port right mismanagement. 412 413 414### `kGUARD_EXC_SEND_INVALID_REPLY` 0x00010000 415 416- **ReportCrash Name**: `SEND_INVALID_REPLY`, 417- **Target meaning**: the mach port name the incorrect operation targets, 418- **Payload meaning**: (reply port ie bits << 32) | disposition. 419 420This exception is thrown when a caller is trying to send a message whose reply 421port (the `msgh_local_port` field of a Mach message) violates policies around 422reply ports or its disposition. 423 424This is usually a sign of port right mismanagement. 425 426 427### `kGUARD_EXC_SEND_INVALID_RIGHT` 0x00020000 428 429- **ReportCrash Name**: `SEND_INVALID_RIGHT`, 430- **Target meaning**: the mach port name the incorrect operation targets, 431- **Payload meaning**: 432 - `(0x01 << 56) | disposition`: copyin port descriptor failed, 433 - `(0x02 << 56) | disposition`: copyin ool port descriptor failed, 434 - `(0x03 << 56) | disposition`: copyin guarded port descriptor failed, 435 436This exception is thrown when a caller is trying to send a message where one of 437the port descriptors denotes a right that doesn't match the requested 438disposition (for example, a make-send disposition for a port where the process 439doesn't own a receive right). 440 441This is usually a sign of port right mismanagement. 442 443 444### `kGUARD_EXC_SEND_INVALID_VOUCHER` 0x00040000 445 446- **ReportCrash Name**: `SEND_INVALID_VOUCHER`, 447- **Target meaning**: the mach port name the incorrect operation targets, 448- **Payload meaning**: disposition of the voucher port. 449 450This exception is thrown when a caller is trying to send a message whose voucher 451port (the `msgh_voucher_port` field of a Mach message) violates policies around 452voucher ports or its disposition. 453 454This is usually a sign of port right mismanagement. 455 456 457### `kGUARD_EXC_RCV_INVALID_NAME` 0x00080000 458 459- **ReportCrash Name**: `RCV_INVALID_NAME`, 460- **Target meaning**: the mach port name the incorrect operation targets, 461- **Payload meaning**: always zero. 462 463This exception is thrown when a caller is trying to receive a message on a mach 464port name for which it doesn't hold a port-set or receive right. 465 466This is usually a sign of port right mismanagement. 467 468 469## List of soft Mach Port Guard Exceptions 470 471Some of the exceptions are never fatal (hitting them will only emit a simulated 472crash log, and the process will keep going). 473 474 475### `kGUARD_EXC_RCV_GUARDED_DESC` 0x00100000 476 477- **ReportCrash Name**: `RCV_GUARDED_DESC`, 478- **Target meaning**: the mach port name the incorrect operation targets, 479- **Payload meaning**: always zero. 480 481This exception is thrown when a caller is trying to receive a message containing 482guarded port descriptors and it hasn't indicated that it knows how to parse them 483(by passing the `MACH_RCV_GUARDED_DESC` flag to `mach_msg()`). 484 485The usage of guarded port descriptor is a protocol agreement between the client 486and the server, and a disagreement here is a programming mistake. 487 488This guard is only enabled on development kernels at this time. 489 490### `kGUARD_EXC_SERVICE_PORT_VIOLATION_NON_FATAL` 0x00100001 491 492- **ReportCrash Name**: N/A, 493- **Target meaning**: the type of service port defense violation, 494- **Payload meaning**: violator port name if we have it, zero otherwise. 495 496This is the non fatal version of `kGUARD_EXC_SERVICE_PORT_VIOLATION_FATAL`, which is 497used when the `service_port_defense_enabled` bootarg is not set. 498 499### `kGUARD_EXC_MOVE_PROVISIONAL_REPLY_PORT` 0x00100004 500 501- **ReportCrash Name**: N/A, 502- **Target meaning**: the mach port name of the provisional reply port, 503- **Payload meaning**: always zero. 504 505This exception is thrown when a process opted for enhanced security v2 moves 506the receive right of a provisional reply port out of its ipc space. 507 508### `kGUARD_EXC_REPLY_PORT_SINGLE_SO_RIGHT` 0x00100005 509 510- **ReportCrash Name**: N/A, 511- **Target meaning**: the mach port name of the reply port, 512- **Payload meaning**: the copyin reason. 513 514This exception is thrown when a process attempts to create more than 515one single send-once right for a reply port. Reply ports are not allowed 516to extend more than one single send-once right at any given moment. 517 518 519### `kGUARD_EXC_MOD_REFS_NON_FATAL` 0x00200000 520 521- **ReportCrash Name**: `OVERDEALLOC_SOFT`, 522- **Target meaning**: the mach port name the incorrect operation targets, 523- **Payload meaning**: same as `kGUARD_EXC_MOD_REFS`. 524 525This is the same as `kGUARD_EXC_MOD_REFS`, except that this is delivered as a 526soft error. 527 528 529### `kGUARD_EXC_IMMOVABLE_NON_FATAL` 0x00400000 530 531- **ReportCrash Name**: `ILLEGALMOVE_SOFT`. 532- **Target meaning**: the mach port name the incorrect operation targets, 533- **Payload meaning**: same as `kGUARD_EXC_IMMOVABLE`. 534 535This is the same as `kGUARD_EXC_IMMOVABLE`, except that this is delivered as a 536soft error. 537 538