xref: /xnu-12377.81.4/doc/mach_ipc/guard_exceptions.md (revision 043036a2b3718f7f0be807e2870f8f47d3fa0796)
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