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**: always zero, 167- **Payload meaning**: always zero. 168 169This exception is thrown when a process is trying to use the 170`thread_set_state()` interface, or any interface leading to it (such as trying 171to change thread state via replying to a Mach exception message), and that this 172is disallowed by policy for this process. 173 174 175### `kGUARD_EXC_EXCEPTION_BEHAVIOR_ENFORCE` 0x00000006 176 177- **ReportCrash Name**: N/A, 178- **Target meaning**: always zero, 179- **Payload meaning**: always zero. 180 181This exception is thrown when a process is trying to register an exception port 182for a behavior not using a task identity port, and that this is disallowed by 183policy for this process. 184 185 186### `kGUARD_EXC_SERVICE_PORT_VIOLATION_FATAL` 0x00000007 187 188- **ReportCrash Name**: N/A, 189- **Target meaning**: the type of service port defense violation, 190- **Payload meaning**: violator port name if we have it, zero otherwise. 191 192This exception is thrown when the `service_port_defense_enabled` bootarg is set and a 193process violates service port defense policy, which includes copyin a service port receive 194right from process other than launchd, arming pd notification on a service port if the 195process is not launchd, and setting a service port as exception port. 196 197### `kGUARD_EXC_UNGUARDED` 0x00000008 198 199- **ReportCrash Name**: UNGUARDED, 200- **Target meaning**: the mach port name the incorrect operation targets, 201- **Payload meaning**: always zero. 202 203This exception is thrown when a process is trying to perform an operation (such 204as `mach_port_unguard()` on a port that isn't guarded. 205 206This is usually a sign of port right mismanagement. 207 208 209### `kGUARD_EXC_INCORRECT_GUARD` 0x00000010 210 211- **ReportCrash Name**: INCORRECT\_GUARD, 212- **Target meaning**: the mach port name the incorrect operation targets, 213- **Payload meaning**: the value of the context guarding the Mach Port. 214 215This exception is thrown when a process is attemtping a guarded operation but 216passed a context to the call that doesn't match the context actually guarding 217this port. 218 219This is usually a sign of port right mismanagement. 220 221 222### `kGUARD_EXC_IMMOVABLE` 0x00000020 223 224- **ReportCrash Name**: ILLEGAL\_MOVE, 225- **Target meaning**: the mach port name the incorrect operation targets, 226- **Payload meaning**: always zero. 227 228This exception is thrown when a process is attempting to move a port right, 229and this has been disallowed by policy for this port type and process. 230 231This is usually a programming mistake (or legacy code that hasn't been updated 232to the most recent Mach IPC policies). 233 234 235### `kGUARD_EXC_STRICT_REPLY` 0x00000040 236 237This exception is thrown for reply port semantics mistakes, if the 238`enforce_strict_reply` boot-arg is set. As this is not a default config at this 239point, and that this is likely going to be phased out in favor of tracking reply 240ports at the port type level, this is left mostly undocumented on purpose. 241 242 243### `kGUARD_EXC_MSG_FILTERED` 0x00000080 244 245- **ReportCrash Name**: MSG\_FILTERED, 246- **Target meaning**: the mach port name the incorrect operation targets, 247- **Payload meaning**: the message ID of the filtered message. 248 249This exception is thrown when a process is not allowed to send the specified 250message due to sandboxing, and that a hard failure has been requested by either 251the client or the Sandbox. 252 253 254## List of optionally fatal Mach Port Guard Exceptions 255 256Some of the exceptions are optionally fatal. Hitting them will only terminate 257the process when it is opted for a hardened Mach IPC environment. Such processes 258are: 259 260- platform binaries, 261- processes with a browser entitlement (`com.apple.developer.web-browser-engine.*`). 262 263The `task_exc_guard_default` boot-arg can be used to change these defaults. 264 265Note: using the `amfi=-1` or similar boot-args will make all processes appear to 266be platform binaries, which in turn will turn a lot of bugs in 3p software into 267hard crashes. Most notably at this time, electron apps cause several guard 268exceptions in the Mach IPC and VM world. This is not a supported configuration. 269 270 271### `kGUARD_EXC_INVALID_RIGHT` 0x00000100 272 273- **ReportCrash Name**: INVALID\_RIGHT, 274- **Target meaning**: the mach port name the incorrect operation targets, 275- **Payload meaning**: always zero. 276 277This exception is thrown when an operation is targetting a port which rights do 278not match the caller's expectations. Examples of such mistakes are: 279 280- performing an operation expecting a port-set name, but passing a port name 281 instead, 282- trying to receive a message and not owning the receive right for it. 283 284These correspond to cases leading to the `KERN_INVALID_RIGHT` or 285`KERN_INVALID_CAPABILITY` error codes of most Mach IPC interfaces. 286 287This is usually a sign of port right mismanagement. 288 289 290### `kGUARD_EXC_INVALID_NAME` 0x00000200 291 292- **ReportCrash Name**: INVALID\_NAME, 293- **Target meaning**: the mach port name the incorrect operation targets, 294- **Payload meaning**: always zero. 295 296This exception is thrown when an operation is targetting a name for which 297the caller holds no right. 298 299These correspond to cases leading to the `KERN_INVALID_NAME` error code of most 300Mach IPC interfaces. 301 302This is usually a sign of port right mismanagement. 303 304 305### `kGUARD_EXC_INVALID_VALUE` 0x00000400 306 307- **ReportCrash Name**: INVALID\_VALUE, 308- **Target meaning**: the mach port name the incorrect operation targets, 309- **Payload meaning**: always zero. 310 311This exception is thrown when: 312 313- the caller is trying to apply a delta to the number of send rights of a port 314 name, and this would overflow the send right count, which is usually a sign of 315 port right mismanagement, 316 317- the trailer related arguments to `mach_port_peek()` are invalid, which is 318 typicaly a programming mistake. 319 320These correspond to cases leading to the `KERN_INVALID_VALUE` error code of most 321Mach IPC interfaces. 322 323 324### `kGUARD_EXC_INVALID_ARGUMENT` 0x00000800 325 326- **ReportCrash Name**: INVALID\_ARGUMENT, 327- **Target meaning**: the mach port name the incorrect operation targets, 328- **Payload meaning**: the correct value of the context guarding the Mach Port. 329 330This exception is thrown when a caller is trying to guard an already guarded 331port. This should really have been named `kGUARD_EXC_ALREADY_GUARDED`. 332 333This is usually a sign of port right mismanagement. 334 335 336### `kGUARD_EXC_KERN_FAILURE` 0x00004000 337 338- **ReportCrash Name**: KERN\_FAILURE, 339- **Target meaning**: the mach port name the incorrect operation targets, 340- **Payload meaning**: always zero. 341 342This exception is thrown when a caller is trying to request a port-destroyed 343notification that is disallowed by system policy. This should really have been 344named `kGUARD_EXC_INVALID_PDREQUEST`. 345 346This is usually a sign of port right mismanagement. 347 348 349### `kGUARD_EXC_SEND_INVALID_REPLY` 0x00010000 350 351- **ReportCrash Name**: SEND\_INVALID\_REPLY, 352- **Target meaning**: the mach port name the incorrect operation targets, 353- **Payload meaning**: always zero. 354 355This exception is thrown when a caller is trying to send a message whose reply 356port (the `msgh_local_port` field of a Mach message) violates policies around 357reply ports or its disposition. 358 359This is usually a sign of port right mismanagement. 360 361 362### `kGUARD_EXC_SEND_INVALID_RIGHT` 0x00020000 363 364- **ReportCrash Name**: SEND\_INVALID\_RIGHT, 365- **Target meaning**: the mach port name the incorrect operation targets, 366- **Payload meaning**: always zero. 367 368This exception is thrown when a caller is trying to send a message where one of 369the port descriptors denotes a right that doesn't match the requested 370disposition (for example, a make-send disposition for a port where the process 371doesn't own a receive right). 372 373This is usually a sign of port right mismanagement. 374 375 376### `kGUARD_EXC_SEND_INVALID_VOUCHER` 0x00040000 377 378- **ReportCrash Name**: SEND\_INVALID\_VOUCHER, 379- **Target meaning**: the mach port name the incorrect operation targets, 380- **Payload meaning**: always zero. 381 382This exception is thrown when a caller is trying to send a message whose voucher 383port (the `msgh_voucher_port` field of a Mach message) violates policies around 384voucher ports or its disposition. 385 386This is usually a sign of port right mismanagement. 387 388 389### `kGUARD_EXC_RCV_INVALID_NAME` 0x00080000 390 391- **ReportCrash Name**: RCV\_INVALID\_NAME, 392- **Target meaning**: the mach port name the incorrect operation targets, 393- **Payload meaning**: always zero. 394 395This exception is thrown when a caller is trying to receive a message on a mach 396port name for which it doesn't hold a port-set or receive right. 397 398This is usually a sign of port right mismanagement. 399 400 401## List of soft Mach Port Guard Exceptions 402 403Some of the exceptions are never fatal (hitting them will only emit a simulated 404crash log, and the process will keep going). 405 406 407### `kGUARD_EXC_RCV_GUARDED_DESC` 0x00100000 408 409- **ReportCrash Name**: RCV\_GUARDED\_DESC, 410- **Target meaning**: the mach port name the incorrect operation targets, 411- **Payload meaning**: always zero. 412 413This exception is thrown when a caller is trying to receive a message containing 414guarded port descriptors and it hasn't indicated that it knows how to parse them 415(by passing the `MACH_RCV_GUARDED_DESC` flag to `mach_msg()`). 416 417The usage of guarded port descriptor is a protocol agreement between the client 418and the server, and a disagreement here is a programming mistake. 419 420This guard is only enabled on development kernels at this time. 421 422### `kGUARD_EXC_SERVICE_PORT_VIOLATION_NON_FATAL` 0x00100001 423 424- **ReportCrash Name**: N/A, 425- **Target meaning**: the type of service port defense violation, 426- **Payload meaning**: violator port name if we have it, zero otherwise. 427 428This is the non fatal version of `kGUARD_EXC_SERVICE_PORT_VIOLATION_FATAL`, which is 429used when the `service_port_defense_enabled` bootarg is not set. 430 431 432### `kGUARD_EXC_PROVISIONAL_REPLY_PORT` 0x00100002 433 434- **ReportCrash Name**: N/A, 435- **Target meaning**: always zero, 436- **Payload meaning**: always zero. 437 438This exception is thrown when a 1p process is trying to create a provisional 439reply port on iOS. It is currently a soft crash to collect telemetry before 440the actual enforcement. 441 442 443### `kGUARD_EXC_MOD_REFS_NON_FATAL` 0x00200000 444 445- **ReportCrash Name**: OVERDEALLOC\_SOFT, 446- **Target meaning**: the mach port name the incorrect operation targets, 447- **Payload meaning**: always zero. 448 449This is the same as `kGUARD_EXC_MOD_REFS`, except that this is delivered as a 450soft error. 451 452 453### `kGUARD_EXC_IMMOVABLE_NON_FATAL` 0x00400000 454 455- **ReportCrash Name**: ILLEGALMOVE\_SOFT. 456- **Target meaning**: the mach port name the incorrect operation targets, 457- **Payload meaning**: always zero. 458 459This is the same as `kGUARD_EXC_IMMOVABLE`, except that this is delivered as a 460soft error. 461 462 463### `kGUARD_EXC_REQUIRE_REPLY_PORT_SEMANTICS` 0x00800000 464 465- **ReportCrash Name**: REQUIRE\_REPLY\_PORT\_SEMANTICS, 466- **Target meaning**: the mach port name the incorrect operation targets, 467- **Payload meaning**: always zero. 468 469This exception is thrown when a caller is violating the reply port semantics in 470a process where this is disallowed by policy. This is used to gather telemetry 471around violators pending enforcement in a future release. 472 473This is usually a sign of a programming mistake (violation of the reply port 474semantics rules). 475 476