1/*
2 * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*
29 * @OSF_COPYRIGHT@
30 */
31/*
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
34 * All Rights Reserved.
35 *
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
41 *
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56/*
57 * NOTICE: This file was modified by McAfee Research in 2004 to introduce
58 * support for mandatory and extensible security protections. This notice
59 * is included in support of clause 2.2 (b) of the Apple Public License,
60 * Version 2.0.
61 * Copyright (c) 2005-2006 SPARTA, Inc.
62 */
63/*
64 */
65/*
66 * File: ipc/mach_port.c
67 * Author: Rich Draves
68 * Date: 1989
69 *
70 * Exported kernel calls. See mach/mach_port.defs.
71 */
72
73#include <mach/port.h>
74#include <mach/kern_return.h>
75#include <mach/notify.h>
76#include <mach/mach_param.h>
77#include <mach/vm_param.h>
78#include <mach/vm_prot.h>
79#include <mach/vm_map.h>
80#include <kern/task.h>
81#include <kern/thread.h>
82#include <kern/exc_guard.h>
83#include <mach/mach_port_server.h>
84#include <vm/vm_map.h>
85#include <vm/vm_kern.h>
86#include <ipc/port.h>
87#include <ipc/ipc_entry.h>
88#include <ipc/ipc_space.h>
89#include <ipc/ipc_object.h>
90#include <ipc/ipc_notify.h>
91#include <ipc/ipc_port.h>
92#include <ipc/ipc_pset.h>
93#include <ipc/ipc_right.h>
94#include <ipc/ipc_kmsg.h>
95#include <ipc/ipc_service_port.h>
96#include <kern/misc_protos.h>
97#include <security/mac_mach_internal.h>
98#include <kern/work_interval.h>
99#include <kern/policy_internal.h>
100#include <kern/coalition.h>
101#include <ipc/ipc_service_port.h>
102#include <kern/mach_filter.h>
103
104
105#if IMPORTANCE_INHERITANCE
106#include <ipc/ipc_importance.h>
107#endif
108
109static TUNABLE(bool, provisional_reply_port_enforced, "-provisional_reply_port_enforced", false);
110
111extern void qsort(void *a, size_t n, size_t es, int (*cmp)(const void *, const void *));
112extern int proc_isinitproc(struct proc *p);
113
114static int
115mach_port_name_cmp(const void *_n1, const void *_n2)
116{
117 mach_port_name_t n1 = *(const mach_port_name_t *)_n1;
118 mach_port_name_t n2 = *(const mach_port_name_t *)_n2;
119
120 if (n1 == n2) {
121 return 0;
122 }
123
124 return n1 < n2 ? -1 : 1;
125}
126
127kern_return_t mach_port_get_attributes(ipc_space_t space, mach_port_name_t name,
128 int flavor, mach_port_info_t info, mach_msg_type_number_t *count);
129kern_return_t mach_port_get_context(ipc_space_t space, mach_port_name_t name,
130 mach_vm_address_t *context);
131kern_return_t mach_port_get_set_status(ipc_space_t space, mach_port_name_t name,
132 mach_port_name_t **members, mach_msg_type_number_t *membersCnt);
133extern int exit_with_guard_exception(void *p, mach_exception_data_type_t code,
134 mach_exception_data_type_t subcode);
135
136/*
137 * Routine: mach_port_names_helper
138 * Purpose:
139 * A helper function for mach_port_names.
140 *
141 * Conditions:
142 * Space containing entry is [at least] read-locked.
143 */
144static void
145mach_port_names_helper(
146 ipc_port_timestamp_t timestamp,
147 ipc_entry_t entry,
148 mach_port_name_t name,
149 mach_port_name_t *names,
150 mach_port_type_t *types,
151 ipc_entry_num_t *actualp)
152{
153 ipc_entry_bits_t bits;
154 ipc_port_request_index_t request;
155 mach_port_type_t type = 0;
156 ipc_entry_num_t actual;
157 ipc_port_t port;
158
159 bits = entry->ie_bits;
160 request = entry->ie_request;
161 port = ip_object_to_port(entry->ie_object);
162
163 if (bits & MACH_PORT_TYPE_RECEIVE) {
164 assert(IP_VALID(port));
165
166 if (request != IE_REQ_NONE) {
167 ip_mq_lock(port);
168 require_ip_active(port);
169 type |= ipc_port_request_type(port, name, index: request);
170 ip_mq_unlock(port);
171 }
172 } else if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
173 mach_port_type_t reqtype;
174
175 assert(IP_VALID(port));
176 ip_mq_lock(port);
177
178 reqtype = (request != IE_REQ_NONE) ?
179 ipc_port_request_type(port, name, index: request) : 0;
180
181 /*
182 * If the port is alive, or was alive when the mach_port_names
183 * started, then return that fact. Otherwise, pretend we found
184 * a dead name entry.
185 */
186 if (ip_active(port) || IP_TIMESTAMP_ORDER(timestamp, ip_get_death_time(port))) {
187 type |= reqtype;
188 } else {
189 bits &= ~(IE_BITS_TYPE_MASK);
190 bits |= MACH_PORT_TYPE_DEAD_NAME;
191 /* account for additional reference for dead-name notification */
192 if (reqtype != 0) {
193 bits++;
194 }
195 }
196 ip_mq_unlock(port);
197 }
198
199 type |= IE_BITS_TYPE(bits);
200
201 actual = *actualp;
202 names[actual] = name;
203 types[actual] = type;
204 *actualp = actual + 1;
205}
206
207/*
208 * Routine: mach_port_names [kernel call]
209 * Purpose:
210 * Retrieves a list of the rights present in the space,
211 * along with type information. (Same as returned
212 * by mach_port_type.) The names are returned in
213 * no particular order, but they (and the type info)
214 * are an accurate snapshot of the space.
215 * Conditions:
216 * Nothing locked.
217 * Returns:
218 * KERN_SUCCESS Arrays of names and types returned.
219 * KERN_INVALID_TASK The space is null.
220 * KERN_INVALID_TASK The space is dead.
221 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
222 */
223
224kern_return_t
225mach_port_names(
226 ipc_space_t space,
227 mach_port_name_t **namesp,
228 mach_msg_type_number_t *namesCnt,
229 mach_port_type_t **typesp,
230 mach_msg_type_number_t *typesCnt)
231{
232 ipc_entry_table_t table;
233 ipc_entry_num_t tsize;
234 mach_port_index_t index;
235 ipc_entry_num_t actual; /* this many names */
236 ipc_port_timestamp_t timestamp; /* logical time of this operation */
237 mach_port_name_t *names;
238 mach_port_type_t *types;
239 kern_return_t kr;
240
241 vm_size_t size; /* size of allocated memory */
242 vm_offset_t addr1 = 0; /* allocated memory, for names */
243 vm_offset_t addr2 = 0; /* allocated memory, for types */
244 vm_map_copy_t memory1; /* copied-in memory, for names */
245 vm_map_copy_t memory2; /* copied-in memory, for types */
246
247 /* safe simplifying assumption */
248 static_assert(sizeof(mach_port_name_t) == sizeof(mach_port_type_t));
249
250 if (space == IS_NULL) {
251 return KERN_INVALID_TASK;
252 }
253
254 size = 0;
255
256 for (;;) {
257 ipc_entry_num_t bound;
258 vm_size_t size_needed;
259
260 is_read_lock(space);
261 if (!is_active(space)) {
262 is_read_unlock(space);
263 if (size != 0) {
264 kmem_free(map: ipc_kernel_map, addr: addr1, size);
265 kmem_free(map: ipc_kernel_map, addr: addr2, size);
266 }
267 return KERN_INVALID_TASK;
268 }
269
270 /* upper bound on number of names in the space */
271 bound = ipc_entry_table_count(array: is_active_table(space));
272 size_needed = vm_map_round_page(
273 (bound * sizeof(mach_port_name_t)),
274 VM_MAP_PAGE_MASK(ipc_kernel_map));
275
276 if (size_needed <= size) {
277 break;
278 }
279
280 is_read_unlock(space);
281
282 if (size != 0) {
283 kmem_free(map: ipc_kernel_map, addr: addr1, size);
284 kmem_free(map: ipc_kernel_map, addr: addr2, size);
285 }
286 size = size_needed;
287
288 kr = kmem_alloc(map: ipc_kernel_map, addrp: &addr1, size,
289 flags: KMA_DATA, VM_KERN_MEMORY_IPC);
290 if (kr != KERN_SUCCESS) {
291 return KERN_RESOURCE_SHORTAGE;
292 }
293
294 kr = kmem_alloc(map: ipc_kernel_map, addrp: &addr2, size,
295 flags: KMA_DATA, VM_KERN_MEMORY_IPC);
296 if (kr != KERN_SUCCESS) {
297 kmem_free(map: ipc_kernel_map, addr: addr1, size);
298 return KERN_RESOURCE_SHORTAGE;
299 }
300 }
301 /* space is read-locked and active */
302
303 names = (mach_port_name_t *) addr1;
304 types = (mach_port_type_t *) addr2;
305 actual = 0;
306
307 timestamp = ipc_port_timestamp();
308
309 table = is_active_table(space);
310 tsize = ipc_entry_table_count(array: table);
311
312 for (index = 1; index < tsize; index++) {
313 ipc_entry_t entry = ipc_entry_table_get_nocheck(array: table, i: index);
314 ipc_entry_bits_t bits = entry->ie_bits;
315
316 if (IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE) {
317 mach_port_name_t name;
318
319 name = MACH_PORT_MAKE(index, IE_BITS_GEN(bits));
320 mach_port_names_helper(timestamp, entry, name, names,
321 types, actualp: &actual);
322 }
323 }
324
325 is_read_unlock(space);
326
327 if (actual == 0) {
328 memory1 = VM_MAP_COPY_NULL;
329 memory2 = VM_MAP_COPY_NULL;
330
331 if (size != 0) {
332 kmem_free(map: ipc_kernel_map, addr: addr1, size);
333 kmem_free(map: ipc_kernel_map, addr: addr2, size);
334 }
335 } else {
336 vm_size_t size_used;
337 vm_size_t vm_size_used;
338
339 size_used = actual * sizeof(mach_port_name_t);
340 vm_size_used =
341 vm_map_round_page(size_used,
342 VM_MAP_PAGE_MASK(ipc_kernel_map));
343
344 /*
345 * Make used memory pageable and get it into
346 * copied-in form. Free any unused memory.
347 */
348
349 if (size_used < vm_size_used) {
350 bzero(s: (char *)addr1 + size_used, n: vm_size_used - size_used);
351 bzero(s: (char *)addr2 + size_used, n: vm_size_used - size_used);
352 }
353
354 kr = vm_map_unwire(map: ipc_kernel_map, start: addr1, end: addr1 + vm_size_used, FALSE);
355 assert(kr == KERN_SUCCESS);
356
357 kr = vm_map_unwire(map: ipc_kernel_map, start: addr2, end: addr2 + vm_size_used, FALSE);
358 assert(kr == KERN_SUCCESS);
359
360 kr = vm_map_copyin(src_map: ipc_kernel_map, src_addr: (vm_map_address_t)addr1,
361 len: (vm_map_size_t)size_used, TRUE, copy_result: &memory1);
362 assert(kr == KERN_SUCCESS);
363
364 kr = vm_map_copyin(src_map: ipc_kernel_map, src_addr: (vm_map_address_t)addr2,
365 len: (vm_map_size_t)size_used, TRUE, copy_result: &memory2);
366 assert(kr == KERN_SUCCESS);
367
368 if (vm_size_used != size) {
369 kmem_free(map: ipc_kernel_map,
370 addr: addr1 + vm_size_used, size: size - vm_size_used);
371 kmem_free(map: ipc_kernel_map,
372 addr: addr2 + vm_size_used, size: size - vm_size_used);
373 }
374 }
375
376 *namesp = (mach_port_name_t *) memory1;
377 *namesCnt = actual;
378 *typesp = (mach_port_type_t *) memory2;
379 *typesCnt = actual;
380 return KERN_SUCCESS;
381}
382
383/*
384 * Routine: mach_port_type [kernel call]
385 * Purpose:
386 * Retrieves the type of a right in the space.
387 * The type is a bitwise combination of one or more
388 * of the following type bits:
389 * MACH_PORT_TYPE_SEND
390 * MACH_PORT_TYPE_RECEIVE
391 * MACH_PORT_TYPE_SEND_ONCE
392 * MACH_PORT_TYPE_PORT_SET
393 * MACH_PORT_TYPE_DEAD_NAME
394 * In addition, the following pseudo-type bits may be present:
395 * MACH_PORT_TYPE_DNREQUEST
396 * A dead-name notification is requested.
397 * Conditions:
398 * Nothing locked.
399 * Returns:
400 * KERN_SUCCESS Type is returned.
401 * KERN_INVALID_TASK The space is null.
402 * KERN_INVALID_TASK The space is dead.
403 * KERN_INVALID_NAME The name doesn't denote a right.
404 */
405
406kern_return_t
407mach_port_type(
408 ipc_space_t space,
409 mach_port_name_t name,
410 mach_port_type_t *typep)
411{
412 mach_port_urefs_t urefs;
413 ipc_entry_t entry;
414 kern_return_t kr;
415
416 if (space == IS_NULL) {
417 return KERN_INVALID_TASK;
418 }
419
420 if (name == MACH_PORT_NULL) {
421 return KERN_INVALID_NAME;
422 }
423
424 if (name == MACH_PORT_DEAD) {
425 *typep = MACH_PORT_TYPE_DEAD_NAME;
426 return KERN_SUCCESS;
427 }
428
429 kr = ipc_right_lookup_write(space, name, entryp: &entry);
430 if (kr != KERN_SUCCESS) {
431 return kr;
432 }
433
434 /* space is write-locked and active */
435 kr = ipc_right_info(space, name, entry, typep, urefsp: &urefs);
436 /* space is unlocked */
437
438#if 1
439 /* JMM - workaround rdar://problem/9121297 (CF being too picky on these bits). */
440 *typep &= ~(MACH_PORT_TYPE_SPREQUEST | MACH_PORT_TYPE_SPREQUEST_DELAYED);
441#endif
442
443 return kr;
444}
445
446
447/*
448 * Routine: mach_port_allocate_name [kernel call]
449 * Purpose:
450 * Allocates a right in a space, using a specific name
451 * for the new right. Possible rights:
452 * MACH_PORT_RIGHT_RECEIVE
453 * MACH_PORT_RIGHT_PORT_SET
454 * MACH_PORT_RIGHT_DEAD_NAME
455 *
456 * A new port (allocated with MACH_PORT_RIGHT_RECEIVE)
457 * has no extant send or send-once rights and no queued
458 * messages. Its queue limit is MACH_PORT_QLIMIT_DEFAULT
459 * and its make-send count is 0. It is not a member of
460 * a port set. It has no registered no-senders or
461 * port-destroyed notification requests.
462 *
463 * A new port set has no members.
464 *
465 * A new dead name has one user reference.
466 * Conditions:
467 * Nothing locked.
468 * Returns:
469 * KERN_SUCCESS The right is allocated.
470 * KERN_INVALID_TASK The space is null.
471 * KERN_INVALID_TASK The space is dead.
472 * KERN_INVALID_VALUE The name isn't a legal name.
473 * KERN_INVALID_VALUE "right" isn't a legal kind of right.
474 * KERN_NAME_EXISTS The name already denotes a right.
475 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
476 *
477 * Restrictions on name allocation: NT bits are reserved by kernel,
478 * must be set on any chosen name. Can't do this at all in kernel
479 * loaded server.
480 */
481
482kern_return_t
483mach_port_allocate_name(
484 ipc_space_t space,
485 mach_port_right_t right,
486 mach_port_name_t name)
487{
488 kern_return_t kr;
489 mach_port_qos_t qos = { .name = TRUE };
490
491 if (!MACH_PORT_VALID(name)) {
492 return KERN_INVALID_VALUE;
493 }
494
495 kr = mach_port_allocate_full(task: space, right, MACH_PORT_NULL,
496 qos: &qos, name: &name);
497 return kr;
498}
499
500/*
501 * Routine: mach_port_allocate [kernel call]
502 * Purpose:
503 * Allocates a right in a space. Like mach_port_allocate_name,
504 * except that the implementation picks a name for the right.
505 * The name may be any legal name in the space that doesn't
506 * currently denote a right.
507 * Conditions:
508 * Nothing locked.
509 * Returns:
510 * KERN_SUCCESS The right is allocated.
511 * KERN_INVALID_TASK The space is null.
512 * KERN_INVALID_TASK The space is dead.
513 * KERN_INVALID_VALUE "right" isn't a legal kind of right.
514 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
515 * KERN_NO_SPACE No room in space for another right.
516 */
517
518kern_return_t
519mach_port_allocate(
520 ipc_space_t space,
521 mach_port_right_t right,
522 mach_port_name_t *namep)
523{
524 kern_return_t kr;
525 mach_port_qos_t qos = { };
526
527 kr = mach_port_allocate_full(task: space, right, MACH_PORT_NULL,
528 qos: &qos, name: namep);
529 return kr;
530}
531
532/*
533 * Routine: mach_port_allocate_qos [kernel call]
534 * Purpose:
535 * Allocates a right, with qos options, in a space. Like
536 * mach_port_allocate_name, except that the implementation
537 * picks a name for the right. The name may be any legal name
538 * in the space that doesn't currently denote a right.
539 * Conditions:
540 * Nothing locked.
541 * Returns:
542 * KERN_SUCCESS The right is allocated.
543 * KERN_INVALID_TASK The space is null.
544 * KERN_INVALID_TASK The space is dead.
545 * KERN_INVALID_VALUE "right" isn't a legal kind of right.
546 * KERN_INVALID_ARGUMENT The qos request was invalid.
547 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
548 * KERN_NO_SPACE No room in space for another right.
549 */
550
551kern_return_t
552mach_port_allocate_qos(
553 ipc_space_t space,
554 mach_port_right_t right,
555 mach_port_qos_t *qosp,
556 mach_port_name_t *namep)
557{
558 kern_return_t kr;
559
560 if (qosp->name) {
561 return KERN_INVALID_ARGUMENT;
562 }
563 kr = mach_port_allocate_full(task: space, right, MACH_PORT_NULL,
564 qos: qosp, name: namep);
565 return kr;
566}
567
568/*
569 * Routine: mach_port_allocate_full [kernel call]
570 * Purpose:
571 * Allocates a right in a space. Supports the
572 * special case of specifying a name. The name may
573 * be any legal name in the space that doesn't
574 * currently denote a right.
575 *
576 * While we no longer support users requesting
577 * preallocated message for the port, we still
578 * check for errors in such requests and then
579 * just clear the request.
580 * Conditions:
581 * Nothing locked.
582 * Returns:
583 * KERN_SUCCESS The right is allocated.
584 * KERN_INVALID_TASK The space is null.
585 * KERN_INVALID_TASK The space is dead.
586 * KERN_INVALID_VALUE "right" isn't a legal kind of right, or supplied port
587 * name is invalid.
588 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
589 * KERN_NO_SPACE No room in space for another right.
590 */
591
592kern_return_t
593mach_port_allocate_full(
594 ipc_space_t space,
595 mach_port_right_t right,
596 mach_port_t proto,
597 mach_port_qos_t *qosp,
598 mach_port_name_t *namep)
599{
600 kern_return_t kr;
601
602 if (space == IS_NULL) {
603 return KERN_INVALID_TASK;
604 }
605
606 if (proto != MACH_PORT_NULL) {
607 return KERN_INVALID_VALUE;
608 }
609
610 if (qosp->name) {
611 if (!MACH_PORT_VALID(*namep)) {
612 return KERN_INVALID_VALUE;
613 }
614 }
615
616 /*
617 * Don't actually honor prealloc requests anymore,
618 * (only mk_timer still uses IP_PREALLOC messages, by hand).
619 *
620 * (for security reasons, and because it isn't guaranteed anyway).
621 * Keep old errors for legacy reasons.
622 */
623 if (qosp->prealloc) {
624 if (qosp->len > MACH_MSG_SIZE_MAX - MAX_TRAILER_SIZE) {
625 return KERN_RESOURCE_SHORTAGE;
626 }
627 if (right != MACH_PORT_RIGHT_RECEIVE) {
628 return KERN_INVALID_VALUE;
629 }
630 qosp->prealloc = 0;
631 }
632
633 switch (right) {
634 case MACH_PORT_RIGHT_RECEIVE:
635 {
636 ipc_port_t port;
637
638 if (qosp->name) {
639 kr = ipc_port_alloc_name(space, flags: IPC_PORT_INIT_MESSAGE_QUEUE,
640 name: *namep, portp: &port);
641 } else {
642 kr = ipc_port_alloc(space, flags: IPC_PORT_INIT_MESSAGE_QUEUE,
643 namep, portp: &port);
644 }
645 if (kr == KERN_SUCCESS) {
646 ip_mq_unlock(port);
647 }
648 break;
649 }
650
651 case MACH_PORT_RIGHT_PORT_SET:
652 {
653 ipc_pset_t pset;
654
655 if (qosp->name) {
656 kr = ipc_pset_alloc_name(space, name: *namep, psetp: &pset);
657 } else {
658 kr = ipc_pset_alloc(space, namep, psetp: &pset);
659 }
660 if (kr == KERN_SUCCESS) {
661 ips_mq_unlock(pset);
662 }
663 break;
664 }
665
666 case MACH_PORT_RIGHT_DEAD_NAME:
667 kr = ipc_object_alloc_dead(space, namep);
668 break;
669
670 default:
671 kr = KERN_INVALID_VALUE;
672 break;
673 }
674
675 return kr;
676}
677
678/*
679 * Routine: mach_port_destroy [kernel call]
680 * Purpose:
681 * Cleans up and destroys all rights denoted by a name
682 * in a space. The destruction of a receive right
683 * destroys the port, unless a port-destroyed request
684 * has been made for it; the destruction of a port-set right
685 * destroys the port set.
686 * Conditions:
687 * Nothing locked.
688 * Returns:
689 * KERN_SUCCESS The name is destroyed.
690 * KERN_INVALID_TASK The space is null.
691 * KERN_INVALID_TASK The space is dead.
692 * KERN_INVALID_NAME The name doesn't denote a right.
693 */
694
695kern_return_t
696mach_port_destroy(
697 ipc_space_t space,
698 mach_port_name_t name)
699{
700 ipc_entry_t entry;
701 kern_return_t kr;
702
703 if (space == IS_NULL) {
704 return KERN_INVALID_TASK;
705 }
706
707 if (!MACH_PORT_VALID(name)) {
708 return KERN_SUCCESS;
709 }
710
711 kr = ipc_right_lookup_write(space, name, entryp: &entry);
712 if (kr != KERN_SUCCESS) {
713 mach_port_guard_exception(name, inguard: 0, portguard: 0, reason: kGUARD_EXC_INVALID_NAME);
714 return kr;
715 }
716 /* space is write-locked and active */
717
718 kr = ipc_right_destroy(space, name, entry, TRUE, guard: 0); /* unlocks space */
719 return kr;
720}
721
722/*
723 * Routine: mach_port_deallocate [kernel call]
724 * Purpose:
725 * Deallocates a user reference from a send right,
726 * send-once right, dead-name right or a port_set right.
727 * May deallocate the right, if this is the last uref,
728 * and destroy the name, if it doesn't denote
729 * other rights.
730 * Conditions:
731 * Nothing locked.
732 * Returns:
733 * KERN_SUCCESS The uref is deallocated.
734 * KERN_INVALID_TASK The space is null.
735 * KERN_INVALID_TASK The space is dead.
736 * KERN_INVALID_NAME The name doesn't denote a right.
737 * KERN_INVALID_RIGHT The right isn't correct.
738 */
739
740kern_return_t
741mach_port_deallocate(
742 ipc_space_t space,
743 mach_port_name_t name)
744{
745 ipc_entry_t entry;
746 kern_return_t kr;
747
748 if (space == IS_NULL) {
749 return KERN_INVALID_TASK;
750 }
751
752 if (!MACH_PORT_VALID(name)) {
753 return KERN_SUCCESS;
754 }
755
756 kr = ipc_right_lookup_write(space, name, entryp: &entry);
757 if (kr != KERN_SUCCESS) {
758 mach_port_guard_exception(name, inguard: 0, portguard: 0, reason: kGUARD_EXC_INVALID_NAME);
759 return kr;
760 }
761 /* space is write-locked */
762
763 kr = ipc_right_dealloc(space, name, entry); /* unlocks space */
764 return kr;
765}
766
767/*
768 * Routine: mach_port_get_refs [kernel call]
769 * Purpose:
770 * Retrieves the number of user references held by a right.
771 * Receive rights, port-set rights, and send-once rights
772 * always have one user reference. Returns zero if the
773 * name denotes a right, but not the queried right.
774 * Conditions:
775 * Nothing locked.
776 * Returns:
777 * KERN_SUCCESS Number of urefs returned.
778 * KERN_INVALID_TASK The space is null.
779 * KERN_INVALID_TASK The space is dead.
780 * KERN_INVALID_VALUE "right" isn't a legal value.
781 * KERN_INVALID_NAME The name doesn't denote a right.
782 */
783
784kern_return_t
785mach_port_get_refs(
786 ipc_space_t space,
787 mach_port_name_t name,
788 mach_port_right_t right,
789 mach_port_urefs_t *urefsp)
790{
791 mach_port_type_t type;
792 mach_port_urefs_t urefs;
793 ipc_entry_t entry;
794 kern_return_t kr;
795
796 if (space == IS_NULL) {
797 return KERN_INVALID_TASK;
798 }
799
800 if (right >= MACH_PORT_RIGHT_NUMBER) {
801 return KERN_INVALID_VALUE;
802 }
803
804 if (!MACH_PORT_VALID(name)) {
805 if (right == MACH_PORT_RIGHT_SEND ||
806 right == MACH_PORT_RIGHT_SEND_ONCE) {
807 *urefsp = 1;
808 return KERN_SUCCESS;
809 }
810 return KERN_INVALID_NAME;
811 }
812
813 kr = ipc_right_lookup_write(space, name, entryp: &entry);
814 if (kr != KERN_SUCCESS) {
815 return kr;
816 }
817
818 /* space is write-locked and active */
819 kr = ipc_right_info(space, name, entry, typep: &type, urefsp: &urefs);
820 /* space is unlocked */
821
822 if (kr != KERN_SUCCESS) {
823 return kr;
824 }
825
826 if (type & MACH_PORT_TYPE(right)) {
827 switch (right) {
828 case MACH_PORT_RIGHT_SEND_ONCE:
829 assert(urefs == 1);
830 OS_FALLTHROUGH;
831
832 case MACH_PORT_RIGHT_PORT_SET:
833 case MACH_PORT_RIGHT_RECEIVE:
834 *urefsp = 1;
835 break;
836
837 case MACH_PORT_RIGHT_DEAD_NAME:
838 case MACH_PORT_RIGHT_SEND:
839 assert(urefs > 0);
840 *urefsp = urefs;
841 break;
842
843 default:
844 panic("mach_port_get_refs: strange rights");
845 }
846 } else {
847 *urefsp = 0;
848 }
849
850 return kr;
851}
852
853/*
854 * Routine: mach_port_mod_refs
855 * Purpose:
856 * Modifies the number of user references held by a right.
857 * The resulting number of user references must be non-negative.
858 * If it is zero, the right is deallocated. If the name
859 * doesn't denote other rights, it is destroyed.
860 * Conditions:
861 * Nothing locked.
862 * Returns:
863 * KERN_SUCCESS Modified number of urefs.
864 * KERN_INVALID_TASK The space is null.
865 * KERN_INVALID_TASK The space is dead.
866 * KERN_INVALID_VALUE "right" isn't a legal value.
867 * KERN_INVALID_NAME The name doesn't denote a right.
868 * KERN_INVALID_RIGHT Name doesn't denote specified right.
869 * KERN_INVALID_VALUE Impossible modification to urefs.
870 * KERN_UREFS_OVERFLOW Urefs would overflow.
871 */
872
873kern_return_t
874mach_port_mod_refs(
875 ipc_space_t space,
876 mach_port_name_t name,
877 mach_port_right_t right,
878 mach_port_delta_t delta)
879{
880 ipc_entry_t entry;
881 kern_return_t kr;
882
883 if (space == IS_NULL) {
884 return KERN_INVALID_TASK;
885 }
886
887 if (right >= MACH_PORT_RIGHT_NUMBER) {
888 return KERN_INVALID_VALUE;
889 }
890
891 if (!MACH_PORT_VALID(name)) {
892 if (right == MACH_PORT_RIGHT_SEND ||
893 right == MACH_PORT_RIGHT_SEND_ONCE) {
894 return KERN_SUCCESS;
895 }
896 return KERN_INVALID_NAME;
897 }
898
899 kr = ipc_right_lookup_write(space, name, entryp: &entry);
900 if (kr != KERN_SUCCESS) {
901 mach_port_guard_exception(name, inguard: 0, portguard: 0, reason: kGUARD_EXC_INVALID_NAME);
902 return kr;
903 }
904
905 /* space is write-locked and active */
906
907 kr = ipc_right_delta(space, name, entry, right, delta); /* unlocks */
908 return kr;
909}
910
911
912/*
913 * Routine: mach_port_peek [kernel call]
914 * Purpose:
915 * Peek at the message queue for the specified receive
916 * right and return info about a message in the queue.
917 *
918 * On input, seqnop points to a sequence number value
919 * to match the message being peeked. If zero is specified
920 * as the seqno, the first message in the queue will be
921 * peeked.
922 *
923 * Only the following trailer types are currently supported:
924 * MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)
925 *
926 * or'ed with one of these element types:
927 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_NULL)
928 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SEQNO)
929 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER)
930 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT)
931 *
932 * On input, the value pointed to by trailer_sizep must be
933 * large enough to hold the requested trailer size.
934 *
935 * The message sequence number, id, size, requested trailer info
936 * and requested trailer size are returned in their respective
937 * output parameters upon success.
938 *
939 * Conditions:
940 * Nothing locked.
941 * Returns:
942 * KERN_SUCCESS Matching message found, out parameters set.
943 * KERN_INVALID_TASK The space is null or dead.
944 * KERN_INVALID_NAME The name doesn't denote a right.
945 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
946 * KERN_INVALID_VALUE The input parameter values are out of bounds.
947 * KERN_FAILURE The requested message was not found.
948 */
949
950kern_return_t
951mach_port_peek(
952 ipc_space_t space,
953 mach_port_name_t name,
954 mach_msg_trailer_type_t trailer_type,
955 mach_port_seqno_t *seqnop,
956 mach_msg_size_t *msg_sizep,
957 mach_msg_id_t *msg_idp,
958 mach_msg_trailer_info_t trailer_infop,
959 mach_msg_type_number_t *trailer_sizep)
960{
961 ipc_port_t port;
962 kern_return_t kr;
963 boolean_t found;
964 mach_msg_max_trailer_t max_trailer;
965
966 if (space == IS_NULL) {
967 return KERN_INVALID_TASK;
968 }
969
970 if (!MACH_PORT_VALID(name)) {
971 return KERN_INVALID_RIGHT;
972 }
973
974 /*
975 * We don't allow anything greater than the audit trailer - to avoid
976 * leaking the context pointer and to avoid variable-sized context issues.
977 */
978 if (GET_RCV_ELEMENTS(trailer_type) > MACH_RCV_TRAILER_AUDIT ||
979 REQUESTED_TRAILER_SIZE(TRUE, trailer_type) > *trailer_sizep) {
980 mach_port_guard_exception(name, inguard: 0, portguard: 0, reason: kGUARD_EXC_INVALID_VALUE);
981 return KERN_INVALID_VALUE;
982 }
983
984 *trailer_sizep = REQUESTED_TRAILER_SIZE(TRUE, trailer_type);
985
986 kr = ipc_port_translate_receive(space, name, portp: &port);
987 if (kr != KERN_SUCCESS) {
988 mach_port_guard_exception(name, inguard: 0, portguard: 0,
989 reason: ((KERN_INVALID_NAME == kr) ?
990 kGUARD_EXC_INVALID_NAME :
991 kGUARD_EXC_INVALID_RIGHT));
992 return kr;
993 }
994
995 /* Port locked and active */
996 found = ipc_mqueue_peek_locked(mqueue: &port->ip_messages, msg_seqnop: seqnop,
997 msg_sizep, msg_idp, msg_trailerp: &max_trailer, NULL);
998 ip_mq_unlock(port);
999
1000 if (found != TRUE) {
1001 return KERN_FAILURE;
1002 }
1003
1004 max_trailer.msgh_seqno = *seqnop;
1005 memcpy(dst: trailer_infop, src: &max_trailer, n: *trailer_sizep);
1006
1007 return KERN_SUCCESS;
1008}
1009
1010/*
1011 * Routine: mach_port_set_mscount [kernel call]
1012 * Purpose:
1013 * Changes a receive right's make-send count.
1014 * Conditions:
1015 * Nothing locked.
1016 * Returns:
1017 * KERN_SUCCESS Set make-send count.
1018 * KERN_INVALID_TASK The space is null.
1019 * KERN_INVALID_TASK The space is dead.
1020 * KERN_INVALID_NAME The name doesn't denote a right.
1021 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1022 */
1023
1024kern_return_t
1025mach_port_set_mscount(
1026 ipc_space_t space,
1027 mach_port_name_t name,
1028 mach_port_mscount_t mscount)
1029{
1030 ipc_port_t port;
1031 kern_return_t kr;
1032
1033 if (space == IS_NULL) {
1034 return KERN_INVALID_TASK;
1035 }
1036
1037 if (!MACH_PORT_VALID(name)) {
1038 return KERN_INVALID_RIGHT;
1039 }
1040
1041 kr = ipc_port_translate_receive(space, name, portp: &port);
1042 if (kr != KERN_SUCCESS) {
1043 return kr;
1044 }
1045 /* port is locked and active */
1046
1047 port->ip_mscount = mscount;
1048 ip_mq_unlock(port);
1049 return KERN_SUCCESS;
1050}
1051
1052/*
1053 * Routine: mach_port_set_seqno [kernel call]
1054 * Purpose:
1055 * Changes a receive right's sequence number.
1056 * Conditions:
1057 * Nothing locked.
1058 * Returns:
1059 * KERN_SUCCESS Set sequence number.
1060 * KERN_INVALID_TASK The space is null.
1061 * KERN_INVALID_TASK The space is dead.
1062 * KERN_INVALID_NAME The name doesn't denote a right.
1063 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1064 */
1065
1066kern_return_t
1067mach_port_set_seqno(
1068 ipc_space_t space,
1069 mach_port_name_t name,
1070 mach_port_seqno_t seqno)
1071{
1072 ipc_port_t port;
1073 kern_return_t kr;
1074
1075 if (space == IS_NULL) {
1076 return KERN_INVALID_TASK;
1077 }
1078
1079 if (!MACH_PORT_VALID(name)) {
1080 return KERN_INVALID_RIGHT;
1081 }
1082
1083 kr = ipc_port_translate_receive(space, name, portp: &port);
1084 if (kr != KERN_SUCCESS) {
1085 return kr;
1086 }
1087 /* port is locked and active */
1088
1089 ipc_mqueue_set_seqno_locked(mqueue: &port->ip_messages, seqno);
1090
1091 ip_mq_unlock(port);
1092 return KERN_SUCCESS;
1093}
1094
1095/*
1096 * Routine: mach_port_get_context [kernel call]
1097 * Purpose:
1098 * Returns a receive right's context pointer.
1099 * Conditions:
1100 * Nothing locked.
1101 * Returns:
1102 * KERN_SUCCESS Set context pointer.
1103 * KERN_INVALID_TASK The space is null.
1104 * KERN_INVALID_TASK The space is dead.
1105 * KERN_INVALID_NAME The name doesn't denote a right.
1106 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1107 */
1108
1109kern_return_t
1110mach_port_get_context(
1111 ipc_space_t space,
1112 mach_port_name_t name,
1113 mach_vm_address_t *context)
1114{
1115 ipc_port_t port;
1116 kern_return_t kr;
1117
1118 if (space == IS_NULL) {
1119 return KERN_INVALID_TASK;
1120 }
1121
1122 if (!MACH_PORT_VALID(name)) {
1123 return KERN_INVALID_RIGHT;
1124 }
1125
1126 kr = ipc_port_translate_receive(space, name, portp: &port);
1127 if (kr != KERN_SUCCESS) {
1128 return kr;
1129 }
1130
1131 /* Port locked and active */
1132
1133 /* For strictly guarded ports, return empty context (which acts as guard) */
1134 if (port->ip_strict_guard) {
1135 *context = 0;
1136 } else {
1137 *context = port->ip_context;
1138 }
1139
1140 ip_mq_unlock(port);
1141 return KERN_SUCCESS;
1142}
1143
1144kern_return_t
1145mach_port_get_context_from_user(
1146 mach_port_t port,
1147 mach_port_name_t name,
1148 mach_vm_address_t *context)
1149{
1150 kern_return_t kr;
1151
1152 ipc_space_t space = convert_port_to_space_read_no_eval(port);
1153
1154 if (space == IPC_SPACE_NULL) {
1155 return KERN_INVALID_ARGUMENT;
1156 }
1157
1158 kr = mach_port_get_context(space, name, context);
1159
1160 ipc_space_release(space);
1161 return kr;
1162}
1163
1164/*
1165 * Routine: mach_port_set_context [kernel call]
1166 * Purpose:
1167 * Changes a receive right's context pointer.
1168 * Conditions:
1169 * Nothing locked.
1170 * Returns:
1171 * KERN_SUCCESS Set context pointer.
1172 * KERN_INVALID_TASK The space is null.
1173 * KERN_INVALID_TASK The space is dead.
1174 * KERN_INVALID_NAME The name doesn't denote a right.
1175 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1176 */
1177
1178kern_return_t
1179mach_port_set_context(
1180 ipc_space_t space,
1181 mach_port_name_t name,
1182 mach_vm_address_t context)
1183{
1184 ipc_port_t port;
1185 kern_return_t kr;
1186
1187 if (space == IS_NULL) {
1188 return KERN_INVALID_TASK;
1189 }
1190
1191 if (!MACH_PORT_VALID(name)) {
1192 return KERN_INVALID_RIGHT;
1193 }
1194
1195 kr = ipc_port_translate_receive(space, name, portp: &port);
1196 if (kr != KERN_SUCCESS) {
1197 return kr;
1198 }
1199
1200 /* port is locked and active */
1201 if (port->ip_strict_guard) {
1202 uint64_t portguard = port->ip_context;
1203 ip_mq_unlock(port);
1204 /* For strictly guarded ports, disallow overwriting context; Raise Exception */
1205 mach_port_guard_exception(name, inguard: context, portguard, reason: kGUARD_EXC_SET_CONTEXT);
1206 return KERN_INVALID_ARGUMENT;
1207 }
1208
1209 port->ip_context = context;
1210
1211 ip_mq_unlock(port);
1212 return KERN_SUCCESS;
1213}
1214
1215
1216/*
1217 * Routine: mach_port_get_set_status [kernel call]
1218 * Purpose:
1219 * Retrieves a list of members in a port set.
1220 * Returns the space's name for each receive right member.
1221 * Conditions:
1222 * Nothing locked.
1223 * Returns:
1224 * KERN_SUCCESS Retrieved list of members.
1225 * KERN_INVALID_TASK The space is null.
1226 * KERN_INVALID_TASK The space is dead.
1227 * KERN_INVALID_NAME The name doesn't denote a right.
1228 * KERN_INVALID_RIGHT Name doesn't denote a port set.
1229 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1230 */
1231
1232kern_return_t
1233mach_port_get_set_status(
1234 ipc_space_t space,
1235 mach_port_name_t name,
1236 mach_port_name_t **members,
1237 mach_msg_type_number_t *membersCnt)
1238{
1239 __block ipc_entry_num_t actual; /* this many members */
1240 ipc_entry_num_t maxnames; /* space for this many members */
1241 kern_return_t kr;
1242
1243 vm_size_t size; /* size of allocated memory */
1244 vm_offset_t addr; /* allocated memory */
1245 vm_map_copy_t memory; /* copied-in memory */
1246
1247 if (space == IS_NULL) {
1248 return KERN_INVALID_TASK;
1249 }
1250
1251 if (!MACH_PORT_VALID(name)) {
1252 return KERN_INVALID_RIGHT;
1253 }
1254
1255 size = VM_MAP_PAGE_SIZE(ipc_kernel_map); /* initial guess */
1256
1257 for (;;) {
1258 mach_port_name_t *names;
1259 ipc_object_t psobj;
1260 ipc_pset_t pset;
1261
1262 kr = kmem_alloc(map: ipc_kernel_map, addrp: &addr, size,
1263 flags: KMA_DATA, VM_KERN_MEMORY_IPC);
1264 if (kr != KERN_SUCCESS) {
1265 return KERN_RESOURCE_SHORTAGE;
1266 }
1267
1268 kr = ipc_object_translate(space, name, MACH_PORT_RIGHT_PORT_SET, objectp: &psobj);
1269 if (kr != KERN_SUCCESS) {
1270 kmem_free(map: ipc_kernel_map, addr, size);
1271 return kr;
1272 }
1273
1274 /* just use a portset reference from here on out */
1275 pset = ips_object_to_pset(psobj);
1276 names = (mach_port_name_t *)addr;
1277 maxnames = (ipc_entry_num_t)(size / sizeof(mach_port_name_t));
1278
1279 waitq_set_foreach_member_locked(wqset: &pset->ips_wqset, cb: ^(struct waitq *wq){
1280 if (actual < maxnames) {
1281 names[actual] = ip_get_receiver_name(ip_from_waitq(wq));
1282 }
1283 actual++;
1284 });
1285
1286 /* release the portset reference */
1287 ips_mq_unlock(pset);
1288
1289 if (actual <= maxnames) {
1290 break;
1291 }
1292
1293 /* didn't have enough memory; allocate more */
1294 kmem_free(map: ipc_kernel_map, addr, size);
1295 size = vm_map_round_page(actual * sizeof(mach_port_name_t),
1296 VM_MAP_PAGE_MASK(ipc_kernel_map)) +
1297 VM_MAP_PAGE_SIZE(ipc_kernel_map);
1298 }
1299
1300 if (actual == 0) {
1301 memory = VM_MAP_COPY_NULL;
1302
1303 kmem_free(map: ipc_kernel_map, addr, size);
1304 } else {
1305 vm_size_t size_used;
1306 vm_size_t vm_size_used;
1307
1308 qsort(a: (void *)addr, n: actual, es: sizeof(mach_port_name_t),
1309 cmp: mach_port_name_cmp);
1310
1311 size_used = actual * sizeof(mach_port_name_t);
1312 vm_size_used = vm_map_round_page(size_used,
1313 VM_MAP_PAGE_MASK(ipc_kernel_map));
1314
1315 if (size_used < vm_size_used) {
1316 bzero(s: (char *)addr + size_used, n: vm_size_used - size_used);
1317 }
1318
1319 /*
1320 * Make used memory pageable and get it into
1321 * copied-in form. Free any unused memory.
1322 */
1323
1324 kr = vm_map_unwire(map: ipc_kernel_map, start: addr, end: addr + vm_size_used, FALSE);
1325 assert(kr == KERN_SUCCESS);
1326
1327 kr = vm_map_copyin(src_map: ipc_kernel_map, src_addr: (vm_map_address_t)addr,
1328 len: (vm_map_size_t)size_used, TRUE, copy_result: &memory);
1329 assert(kr == KERN_SUCCESS);
1330
1331 if (vm_size_used != size) {
1332 kmem_free(map: ipc_kernel_map,
1333 addr: addr + vm_size_used, size: size - vm_size_used);
1334 }
1335 }
1336
1337 *members = (mach_port_name_t *) memory;
1338 *membersCnt = actual;
1339 return KERN_SUCCESS;
1340}
1341
1342kern_return_t
1343mach_port_get_set_status_from_user(
1344 mach_port_t port,
1345 mach_port_name_t name,
1346 mach_port_name_t **members,
1347 mach_msg_type_number_t *membersCnt)
1348{
1349 kern_return_t kr;
1350
1351 ipc_space_t space = convert_port_to_space_read_no_eval(port);
1352
1353 if (space == IPC_SPACE_NULL) {
1354 return KERN_INVALID_ARGUMENT;
1355 }
1356
1357 kr = mach_port_get_set_status(space, name, members, membersCnt);
1358
1359 ipc_space_release(space);
1360 return kr;
1361}
1362
1363/*
1364 * Routine: mach_port_move_member [kernel call]
1365 * Purpose:
1366 * If after is MACH_PORT_NULL, removes member
1367 * from the port set it is in. Otherwise, adds
1368 * member to after, removing it from any set
1369 * it might already be in.
1370 * Conditions:
1371 * Nothing locked.
1372 * Returns:
1373 * KERN_SUCCESS Moved the port.
1374 * KERN_INVALID_TASK The space is null.
1375 * KERN_INVALID_TASK The space is dead.
1376 * KERN_INVALID_NAME Member didn't denote a right.
1377 * KERN_INVALID_RIGHT Member didn't denote a receive right.
1378 * KERN_INVALID_NAME After didn't denote a right.
1379 * KERN_INVALID_RIGHT After didn't denote a port set right.
1380 * KERN_NOT_IN_SET
1381 * After is MACH_PORT_NULL and Member isn't in a port set.
1382 */
1383
1384kern_return_t
1385mach_port_move_member(
1386 ipc_space_t space,
1387 mach_port_name_t member,
1388 mach_port_name_t after)
1389{
1390 ipc_object_t port_obj, ps_obj;
1391 ipc_port_t port = IP_NULL;
1392 kern_return_t kr;
1393 waitq_link_list_t free_l = { };
1394 waitq_link_t link = WQL_NULL;
1395 struct waitq_set *keep_waitq_set = NULL;
1396
1397 if (space == IS_NULL) {
1398 return KERN_INVALID_TASK;
1399 }
1400
1401 if (!MACH_PORT_VALID(member)) {
1402 return KERN_INVALID_RIGHT;
1403 }
1404
1405 if (after == MACH_PORT_DEAD) {
1406 return KERN_INVALID_RIGHT;
1407 }
1408
1409 if (after != MACH_PORT_NULL) {
1410 link = waitq_link_alloc(type: WQT_PORT_SET);
1411 kr = ipc_object_translate_two(space,
1412 name1: member, MACH_PORT_RIGHT_RECEIVE, objectp1: &port_obj,
1413 name2: after, MACH_PORT_RIGHT_PORT_SET, objectp2: &ps_obj);
1414 } else {
1415 kr = ipc_object_translate(space,
1416 name: member, MACH_PORT_RIGHT_RECEIVE, objectp: &port_obj);
1417 }
1418 if (kr != KERN_SUCCESS) {
1419 goto done;
1420 }
1421
1422 port = ip_object_to_port(port_obj);
1423
1424 if (after != MACH_PORT_NULL) {
1425 ipc_pset_t nset = ips_object_to_pset(ps_obj);
1426
1427 ipc_mqueue_add_locked(mqueue: &port->ip_messages, pset: nset, linkp: &link);
1428 ips_mq_unlock(nset);
1429
1430 keep_waitq_set = &nset->ips_wqset;
1431 } else if (!ip_in_pset(port)) {
1432 kr = KERN_NOT_IN_SET;
1433 }
1434
1435 /*
1436 * waitq_unlink_all_locked() doesn't dereference `keep_waitq_set,
1437 * but we wouldn't want an ABA issue. Fortunately, while `port`
1438 * is locked and linked to `nset`, then `nset` can't be reused/freed.
1439 */
1440 waitq_unlink_all_locked(waitq: &port->ip_waitq, except_wqset: keep_waitq_set, free_l: &free_l);
1441
1442 ip_mq_unlock(port);
1443
1444 waitq_link_free_list(type: WQT_PORT_SET, list: &free_l);
1445done:
1446 if (link.wqlh) {
1447 waitq_link_free(type: WQT_PORT_SET, link);
1448 }
1449
1450 return kr;
1451}
1452
1453/*
1454 * Routine: mach_service_pd_request_notification_check
1455 * Purpose:
1456 * Check if requesting port destroyed notification on a service port is allowed.
1457 * Conditions:
1458 * Assumes service_port is locked and active.
1459 */
1460static bool
1461mach_service_pd_request_notification_check(
1462 ipc_port_t service_port,
1463 ipc_port_t notify_port
1464 )
1465{
1466#ifdef MACH_BSD
1467
1468 uintptr_t task;
1469
1470 /* Only launchd should be able to register for port destroyed notification on a service port. */
1471 (void)ipc_port_get_receiver_task_locked(port: service_port, task: &task);
1472 if (task && !proc_isinitproc(p: get_bsdtask_info((task_t)task))) {
1473 return false;
1474 }
1475
1476 /* Notify port should indicate immovable receive right owned by launchd. */
1477 if (IP_VALID(notify_port)) {
1478 ip_mq_lock(notify_port);
1479 (void)ipc_port_get_receiver_task_locked(port: notify_port, task: &task);
1480 if (task && !proc_isinitproc(p: get_bsdtask_info((task_t)task))) {
1481 ip_mq_unlock(notify_port);
1482 return false;
1483 }
1484 if (!notify_port->ip_immovable_receive) {
1485 ip_mq_unlock(notify_port);
1486 return false;
1487 }
1488 ip_mq_unlock(notify_port);
1489 }
1490#endif
1491
1492 return true;
1493}
1494
1495/*
1496 * Routine: mach_port_request_notification [kernel call]
1497 * Purpose:
1498 * Requests a notification. The caller supplies
1499 * a send-once right for the notification to use,
1500 * and the call returns the previously registered
1501 * send-once right, if any. Possible types:
1502 *
1503 * MACH_NOTIFY_PORT_DESTROYED
1504 * Requests a port-destroyed notification
1505 * for a receive right. Sync should be zero.
1506 * MACH_NOTIFY_SERVICE_PORT_DESTROYED
1507 * Special port destroyed notifications to be
1508 * used by launchd for service ports only.
1509 * MACH_NOTIFY_NO_SENDERS
1510 * Requests a no-senders notification for a
1511 * receive right. If there are currently no
1512 * senders, sync is less than or equal to the
1513 * current make-send count, and a send-once right
1514 * is supplied, then an immediate no-senders
1515 * notification is generated.
1516 * MACH_NOTIFY_DEAD_NAME
1517 * Requests a dead-name notification for a send
1518 * or receive right. If the name is already a
1519 * dead name, sync is non-zero, and a send-once
1520 * right is supplied, then an immediate dead-name
1521 * notification is generated.
1522 * Conditions:
1523 * Nothing locked.
1524 * Returns:
1525 * KERN_SUCCESS Requested a notification.
1526 * KERN_INVALID_TASK The space is null.
1527 * KERN_INVALID_TASK The space is dead.
1528 * KERN_INVALID_VALUE Bad id value.
1529 * KERN_INVALID_NAME Name doesn't denote a right.
1530 * KERN_INVALID_RIGHT Name doesn't denote appropriate right.
1531 * KERN_INVALID_CAPABILITY The notify port is dead.
1532 * MACH_NOTIFY_PORT_DESTROYED:
1533 * KERN_INVALID_VALUE Sync isn't zero.
1534 * KERN_FAILURE Re-registering for this notification or registering for a reply port.
1535 * If registering for this notification is not allowed on a service port.
1536 * MACH_NOTIFY_NO_SENDERS:
1537 * KERN_FAILURE Registering for a reply port.
1538 * MACH_NOTIFY_SERVICE_PORT_DESTROYED
1539 * KERN_INVALID_CAPABILITY Name is not a service port
1540 * KERN_DENIED Only launchd can set this notification or
1541 * Launchd tried to register the old port
1542 * destroyed notification
1543 * MACH_NOTIFY_DEAD_NAME:
1544 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1545 * KERN_INVALID_ARGUMENT Name denotes dead name, but
1546 * sync is zero or notify is IP_NULL.
1547 * KERN_UREFS_OVERFLOW Name denotes dead name, but
1548 * generating immediate notif. would overflow urefs.
1549 */
1550
1551kern_return_t
1552mach_port_request_notification(
1553 ipc_space_t space,
1554 mach_port_name_t name,
1555 mach_msg_id_t id,
1556 mach_port_mscount_t sync,
1557 ipc_port_t notify,
1558 ipc_port_t *previousp)
1559{
1560 kern_return_t kr;
1561
1562 if (space == IS_NULL) {
1563 return KERN_INVALID_TASK;
1564 }
1565
1566 if (notify == IP_DEAD) {
1567 return KERN_INVALID_CAPABILITY;
1568 }
1569
1570 switch (id) {
1571 case MACH_NOTIFY_PORT_DESTROYED: {
1572 ipc_port_t port;
1573
1574 if (sync != 0) {
1575 return KERN_INVALID_VALUE;
1576 }
1577
1578 if (!MACH_PORT_VALID(name)) {
1579 return KERN_INVALID_RIGHT;
1580 }
1581
1582 kr = ipc_port_translate_receive(space, name, portp: &port);
1583 if (kr != KERN_SUCCESS) {
1584 return kr;
1585 }
1586 /* port is locked and active */
1587
1588 /*
1589 * you cannot register for port death notifications on a kobject,
1590 * kolabel or special reply port.
1591 */
1592 if (ip_is_kobject(port) || ip_is_kolabeled(port) ||
1593 port->ip_specialreply || ip_is_reply_port(port)) {
1594 ip_mq_unlock(port);
1595 mach_port_guard_exception(name, inguard: 0, portguard: 0, reason: kGUARD_EXC_INVALID_RIGHT);
1596 return KERN_INVALID_RIGHT;
1597 }
1598
1599 if (service_port_defense_enabled && port->ip_service_port &&
1600 !mach_service_pd_request_notification_check(service_port: port, notify_port: notify)) {
1601 ip_mq_unlock(port);
1602 mach_port_guard_exception(name, inguard: 0, portguard: 0, reason: kGUARD_EXC_KERN_FAILURE);
1603 return KERN_FAILURE;
1604 }
1605
1606 /* Allow only one registeration of this notification */
1607 if (ipc_port_has_prdrequest(port)) {
1608 ip_mq_unlock(port);
1609 mach_port_guard_exception(name, inguard: 0, portguard: 0, reason: kGUARD_EXC_KERN_FAILURE);
1610 return KERN_FAILURE;
1611 }
1612
1613 if (port->ip_has_watchport) {
1614 port->ip_twe->twe_pdrequest = notify;
1615 } else {
1616 port->ip_pdrequest = notify;
1617 }
1618 ip_mq_unlock(port);
1619 *previousp = IP_NULL;
1620 break;
1621 }
1622
1623 case MACH_NOTIFY_NO_SENDERS: {
1624 ipc_port_t port;
1625
1626 if (!MACH_PORT_VALID(name)) {
1627 return KERN_INVALID_RIGHT;
1628 }
1629
1630 kr = ipc_port_translate_receive(space, name, portp: &port);
1631 if (kr != KERN_SUCCESS) {
1632 return kr;
1633 }
1634 /* port is locked and active */
1635
1636 if (ip_is_reply_port(port)) {
1637 ip_mq_unlock(port);
1638 mach_port_guard_exception(name, inguard: 0, portguard: 0, reason: kGUARD_EXC_INVALID_RIGHT);
1639 return KERN_INVALID_RIGHT;
1640 }
1641
1642 ipc_port_nsrequest(port, sync, notify, previousp);
1643 /* port is unlocked */
1644 break;
1645 }
1646
1647 case MACH_NOTIFY_SEND_POSSIBLE:
1648 case MACH_NOTIFY_DEAD_NAME: {
1649 ipc_port_request_opts_t opts = 0;
1650
1651 if (!MACH_PORT_VALID(name)) {
1652 return KERN_INVALID_ARGUMENT;
1653 }
1654
1655 if (id == MACH_NOTIFY_SEND_POSSIBLE) {
1656 opts |= IPR_SOR_SPREQ_MASK;
1657 if (sync) {
1658 opts |= IPR_SOR_SPARM_MASK;
1659 }
1660 }
1661
1662 kr = ipc_right_request_alloc(space, name, options: opts, notify, previousp);
1663 if (kr != KERN_SUCCESS) {
1664 return kr;
1665 }
1666 break;
1667 }
1668
1669 default:
1670 return KERN_INVALID_VALUE;
1671 }
1672
1673 return KERN_SUCCESS;
1674}
1675
1676/*
1677 * Routine: mach_port_insert_right [kernel call]
1678 * Purpose:
1679 * Inserts a right into a space, as if the space
1680 * voluntarily received the right in a message,
1681 * except that the right gets the specified name.
1682 * Conditions:
1683 * Nothing locked.
1684 * Returns:
1685 * KERN_SUCCESS Inserted the right.
1686 * KERN_INVALID_TASK The space is null.
1687 * KERN_INVALID_TASK The space is dead.
1688 * KERN_INVALID_VALUE The name isn't a legal name.
1689 * KERN_NAME_EXISTS The name already denotes a right.
1690 * KERN_INVALID_VALUE Message doesn't carry a port right.
1691 * KERN_INVALID_CAPABILITY Port is null or dead.
1692 * KERN_UREFS_OVERFLOW Urefs limit would be exceeded.
1693 * KERN_RIGHT_EXISTS Space has rights under another name.
1694 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1695 */
1696
1697kern_return_t
1698mach_port_insert_right(
1699 ipc_space_t space,
1700 mach_port_name_t name,
1701 ipc_port_t poly,
1702 mach_msg_type_name_t polyPoly)
1703{
1704 if (space == IS_NULL) {
1705 return KERN_INVALID_TASK;
1706 }
1707
1708 if (!MACH_PORT_VALID(name) ||
1709 !MACH_MSG_TYPE_PORT_ANY_RIGHT(polyPoly)) {
1710 return KERN_INVALID_VALUE;
1711 }
1712
1713 if (!IP_VALID(poly)) {
1714 return KERN_INVALID_CAPABILITY;
1715 }
1716
1717 return ipc_object_copyout_name(space, ip_to_object(poly),
1718 msgt_name: polyPoly, name);
1719}
1720
1721/*
1722 * Routine: mach_port_extract_right [kernel call]
1723 * Purpose:
1724 * Extracts a right from a space, as if the space
1725 * voluntarily sent the right to the caller.
1726 * Conditions:
1727 * Nothing locked.
1728 * Returns:
1729 * KERN_SUCCESS Extracted the right.
1730 * KERN_INVALID_TASK The space is null.
1731 * KERN_INVALID_TASK The space is dead.
1732 * KERN_INVALID_VALUE Requested type isn't a port right.
1733 * KERN_INVALID_NAME Name doesn't denote a right.
1734 * KERN_INVALID_RIGHT Name doesn't denote appropriate right.
1735 */
1736
1737kern_return_t
1738mach_port_extract_right(
1739 ipc_space_t space,
1740 mach_port_name_t name,
1741 mach_msg_type_name_t msgt_name,
1742 ipc_port_t *poly,
1743 mach_msg_type_name_t *polyPoly)
1744{
1745 kern_return_t kr;
1746
1747 if (space == IS_NULL) {
1748 return KERN_INVALID_TASK;
1749 }
1750
1751 if (!MACH_MSG_TYPE_PORT_ANY(msgt_name)) {
1752 return KERN_INVALID_VALUE;
1753 }
1754
1755 if (!MACH_PORT_VALID(name)) {
1756 /*
1757 * really should copy out a dead name, if it is a send or
1758 * send-once right being copied, but instead return an
1759 * error for now.
1760 */
1761 return KERN_INVALID_RIGHT;
1762 }
1763
1764 kr = ipc_object_copyin(space, name, msgt_name, objectp: (ipc_object_t *) poly, context: 0, NULL,
1765 copyin_flags: (space == current_space() && msgt_name == MACH_MSG_TYPE_COPY_SEND) ?
1766 IPC_OBJECT_COPYIN_FLAGS_ALLOW_IMMOVABLE_SEND : IPC_OBJECT_COPYIN_FLAGS_NONE);
1767
1768 if (kr == KERN_SUCCESS) {
1769 *polyPoly = ipc_object_copyin_type(msgt_name);
1770 }
1771 return kr;
1772}
1773
1774/*
1775 * Routine: mach_port_get_status_helper [helper]
1776 * Purpose:
1777 * Populates a mach_port_status_t structure with
1778 * port information.
1779 * Conditions:
1780 * Port needs to be locked
1781 * Returns:
1782 * None.
1783 */
1784static void
1785mach_port_get_status_helper(
1786 ipc_port_t port,
1787 mach_port_status_t *statusp)
1788{
1789 /* don't leak set IDs, just indicate that the port is in one or not */
1790 statusp->mps_pset = ip_in_pset(port);
1791 statusp->mps_seqno = port->ip_messages.imq_seqno;
1792 statusp->mps_qlimit = port->ip_messages.imq_qlimit;
1793 statusp->mps_msgcount = port->ip_messages.imq_msgcount;
1794
1795 statusp->mps_mscount = port->ip_mscount;
1796 statusp->mps_sorights = port->ip_sorights;
1797 statusp->mps_srights = port->ip_srights > 0;
1798 statusp->mps_pdrequest = ipc_port_has_prdrequest(port);
1799 statusp->mps_nsrequest = port->ip_nsrequest != IP_NULL;
1800 statusp->mps_flags = 0;
1801 if (port->ip_impdonation) {
1802 statusp->mps_flags |= MACH_PORT_STATUS_FLAG_IMP_DONATION;
1803 if (port->ip_tempowner) {
1804 statusp->mps_flags |= MACH_PORT_STATUS_FLAG_TEMPOWNER;
1805 if (IIT_NULL != ip_get_imp_task(port)) {
1806 statusp->mps_flags |= MACH_PORT_STATUS_FLAG_TASKPTR;
1807 }
1808 }
1809 }
1810 if (port->ip_guarded) {
1811 statusp->mps_flags |= MACH_PORT_STATUS_FLAG_GUARDED;
1812 if (port->ip_strict_guard) {
1813 statusp->mps_flags |= MACH_PORT_STATUS_FLAG_STRICT_GUARD;
1814 }
1815 if (port->ip_immovable_receive) {
1816 statusp->mps_flags |= MACH_PORT_STATUS_FLAG_GUARD_IMMOVABLE_RECEIVE;
1817 }
1818 }
1819 if (port->ip_no_grant) {
1820 statusp->mps_flags |= MACH_PORT_STATUS_FLAG_NO_GRANT;
1821 }
1822 return;
1823}
1824
1825kern_return_t
1826mach_port_get_attributes(
1827 ipc_space_t space,
1828 mach_port_name_t name,
1829 int flavor,
1830 mach_port_info_t info,
1831 mach_msg_type_number_t *count)
1832{
1833 ipc_port_t port;
1834 kern_return_t kr;
1835
1836 if (space == IS_NULL) {
1837 return KERN_INVALID_TASK;
1838 }
1839
1840 switch (flavor) {
1841 case MACH_PORT_LIMITS_INFO: {
1842 mach_port_limits_t *lp = (mach_port_limits_t *)info;
1843
1844 if (*count < MACH_PORT_LIMITS_INFO_COUNT) {
1845 return KERN_FAILURE;
1846 }
1847
1848 if (!MACH_PORT_VALID(name)) {
1849 *count = 0;
1850 break;
1851 }
1852
1853 kr = ipc_port_translate_receive(space, name, portp: &port);
1854 if (kr != KERN_SUCCESS) {
1855 return kr;
1856 }
1857 /* port is locked and active */
1858
1859 lp->mpl_qlimit = port->ip_messages.imq_qlimit;
1860 *count = MACH_PORT_LIMITS_INFO_COUNT;
1861 ip_mq_unlock(port);
1862 break;
1863 }
1864
1865 case MACH_PORT_RECEIVE_STATUS: {
1866 mach_port_status_t *statusp = (mach_port_status_t *)info;
1867
1868 if (*count < MACH_PORT_RECEIVE_STATUS_COUNT) {
1869 return KERN_FAILURE;
1870 }
1871
1872 if (!MACH_PORT_VALID(name)) {
1873 return KERN_INVALID_RIGHT;
1874 }
1875
1876 kr = ipc_port_translate_receive(space, name, portp: &port);
1877 if (kr != KERN_SUCCESS) {
1878 return kr;
1879 }
1880 /* port is locked and active */
1881 mach_port_get_status_helper(port, statusp);
1882 *count = MACH_PORT_RECEIVE_STATUS_COUNT;
1883 ip_mq_unlock(port);
1884 break;
1885 }
1886
1887 case MACH_PORT_DNREQUESTS_SIZE: {
1888 ipc_port_request_table_t table;
1889
1890 if (*count < MACH_PORT_DNREQUESTS_SIZE_COUNT) {
1891 return KERN_FAILURE;
1892 }
1893
1894 if (!MACH_PORT_VALID(name)) {
1895 *(int *)info = 0;
1896 break;
1897 }
1898
1899 kr = ipc_port_translate_receive(space, name, portp: &port);
1900 if (kr != KERN_SUCCESS) {
1901 return kr;
1902 }
1903 /* port is locked and active */
1904
1905 table = port->ip_requests;
1906 if (table == NULL) {
1907 *(int *)info = 0;
1908 } else {
1909 *(int *)info = (int)ipc_port_request_table_count(array: table);
1910 }
1911 *count = MACH_PORT_DNREQUESTS_SIZE_COUNT;
1912 ip_mq_unlock(port);
1913 break;
1914 }
1915
1916 case MACH_PORT_INFO_EXT: {
1917 mach_port_info_ext_t *mp_info = (mach_port_info_ext_t *)info;
1918 if (*count < MACH_PORT_INFO_EXT_COUNT) {
1919 return KERN_FAILURE;
1920 }
1921
1922 if (!MACH_PORT_VALID(name)) {
1923 return KERN_INVALID_RIGHT;
1924 }
1925
1926 kr = ipc_port_translate_receive(space, name, portp: &port);
1927 if (kr != KERN_SUCCESS) {
1928 return kr;
1929 }
1930 /* port is locked and active */
1931 mach_port_get_status_helper(port, statusp: &mp_info->mpie_status);
1932 mp_info->mpie_boost_cnt = port->ip_impcount;
1933 *count = MACH_PORT_INFO_EXT_COUNT;
1934 ip_mq_unlock(port);
1935 break;
1936 }
1937
1938 case MACH_PORT_SERVICE_THROTTLED: {
1939 boolean_t *is_throttled = info;
1940
1941 if (!MACH_PORT_VALID(name)) {
1942 return KERN_INVALID_RIGHT;
1943 }
1944
1945 kr = ipc_port_translate_receive(space, name, portp: &port);
1946 if (kr != KERN_SUCCESS) {
1947 return kr;
1948 }
1949 /* port is locked and active */
1950
1951 if (!port->ip_service_port) {
1952 ip_mq_unlock(port);
1953 return KERN_INVALID_CAPABILITY;
1954 }
1955
1956 assert(port->ip_splabel != NULL);
1957 *is_throttled = ipc_service_port_label_is_throttled((ipc_service_port_label_t)port->ip_splabel);
1958 *count = MACH_PORT_SERVICE_THROTTLED_COUNT;
1959 ip_mq_unlock(port);
1960 break;
1961 }
1962
1963 default:
1964 return KERN_INVALID_ARGUMENT;
1965 /*NOTREACHED*/
1966 }
1967
1968 return KERN_SUCCESS;
1969}
1970
1971kern_return_t
1972mach_port_get_attributes_from_user(
1973 mach_port_t port,
1974 mach_port_name_t name,
1975 int flavor,
1976 mach_port_info_t info,
1977 mach_msg_type_number_t *count)
1978{
1979 kern_return_t kr;
1980
1981 ipc_space_t space = convert_port_to_space_read_no_eval(port);
1982
1983 if (space == IPC_SPACE_NULL) {
1984 return KERN_INVALID_ARGUMENT;
1985 }
1986
1987 kr = mach_port_get_attributes(space, name, flavor, info, count);
1988
1989 ipc_space_release(space);
1990 return kr;
1991}
1992
1993kern_return_t
1994mach_port_set_attributes(
1995 ipc_space_t space,
1996 mach_port_name_t name,
1997 int flavor,
1998 mach_port_info_t info,
1999 mach_msg_type_number_t count)
2000{
2001 ipc_port_t port;
2002 kern_return_t kr;
2003
2004 if (space == IS_NULL) {
2005 return KERN_INVALID_TASK;
2006 }
2007
2008 switch (flavor) {
2009 case MACH_PORT_LIMITS_INFO: {
2010 mach_port_limits_t *mplp = (mach_port_limits_t *)info;
2011
2012 if (count < MACH_PORT_LIMITS_INFO_COUNT) {
2013 return KERN_FAILURE;
2014 }
2015
2016 if (mplp->mpl_qlimit > MACH_PORT_QLIMIT_MAX) {
2017 return KERN_INVALID_VALUE;
2018 }
2019
2020 if (!MACH_PORT_VALID(name)) {
2021 return KERN_INVALID_RIGHT;
2022 }
2023
2024 kr = ipc_port_translate_receive(space, name, portp: &port);
2025 if (kr != KERN_SUCCESS) {
2026 return kr;
2027 }
2028 /* port is locked and active */
2029
2030 ipc_mqueue_set_qlimit_locked(mqueue: &port->ip_messages, qlimit: mplp->mpl_qlimit);
2031 ip_mq_unlock(port);
2032 break;
2033 }
2034 case MACH_PORT_DNREQUESTS_SIZE: {
2035 if (count < MACH_PORT_DNREQUESTS_SIZE_COUNT) {
2036 return KERN_FAILURE;
2037 }
2038
2039 if (!MACH_PORT_VALID(name)) {
2040 return KERN_INVALID_RIGHT;
2041 }
2042
2043 kr = ipc_port_translate_receive(space, name, portp: &port);
2044 if (kr != KERN_SUCCESS) {
2045 return kr;
2046 }
2047 /* port is locked and active */
2048 ip_mq_unlock(port);
2049 break;
2050 }
2051 case MACH_PORT_TEMPOWNER: {
2052 if (!MACH_PORT_VALID(name)) {
2053 return KERN_INVALID_RIGHT;
2054 }
2055
2056 ipc_importance_task_t release_imp_task = IIT_NULL;
2057 natural_t assertcnt = 0;
2058
2059 kr = ipc_port_translate_receive(space, name, portp: &port);
2060 if (kr != KERN_SUCCESS) {
2061 return kr;
2062 }
2063 /* port is locked and active */
2064
2065 /*
2066 * don't allow temp-owner importance donation if user
2067 * associated it with a kobject already (timer, host_notify target),
2068 * or is a special reply port.
2069 */
2070 if (ip_is_kobject(port) || port->ip_specialreply) {
2071 ip_mq_unlock(port);
2072 return KERN_INVALID_ARGUMENT;
2073 }
2074
2075 if (port->ip_tempowner != 0) {
2076 if (IIT_NULL != ip_get_imp_task(port)) {
2077 release_imp_task = ip_get_imp_task(port);
2078 port->ip_imp_task = IIT_NULL;
2079 assertcnt = port->ip_impcount;
2080 }
2081 } else {
2082 assertcnt = port->ip_impcount;
2083 }
2084
2085 port->ip_impdonation = 1;
2086 port->ip_tempowner = 1;
2087 ip_mq_unlock(port);
2088
2089#if IMPORTANCE_INHERITANCE
2090 /* drop assertions from previous destination task */
2091 if (release_imp_task != IIT_NULL) {
2092 assert(ipc_importance_task_is_any_receiver_type(release_imp_task));
2093 if (assertcnt > 0) {
2094 ipc_importance_task_drop_internal_assertion(task_imp: release_imp_task, count: assertcnt);
2095 }
2096 ipc_importance_task_release(task_imp: release_imp_task);
2097 } else if (assertcnt > 0) {
2098 release_imp_task = current_task()->task_imp_base;
2099 if (release_imp_task != IIT_NULL &&
2100 ipc_importance_task_is_any_receiver_type(task_imp: release_imp_task)) {
2101 ipc_importance_task_drop_internal_assertion(task_imp: release_imp_task, count: assertcnt);
2102 }
2103 }
2104#else
2105 if (release_imp_task != IIT_NULL) {
2106 ipc_importance_task_release(release_imp_task);
2107 }
2108#endif /* IMPORTANCE_INHERITANCE */
2109
2110 break;
2111
2112#if IMPORTANCE_INHERITANCE
2113 case MACH_PORT_DENAP_RECEIVER:
2114 case MACH_PORT_IMPORTANCE_RECEIVER:
2115 if (!MACH_PORT_VALID(name)) {
2116 return KERN_INVALID_RIGHT;
2117 }
2118
2119 kr = ipc_port_translate_receive(space, name, portp: &port);
2120 if (kr != KERN_SUCCESS) {
2121 return kr;
2122 }
2123
2124 /*
2125 * don't allow importance donation if user associated
2126 * it with a kobject already (timer, host_notify target),
2127 * or is a special reply port.
2128 */
2129 if (ip_is_kobject(port) || port->ip_specialreply) {
2130 ip_mq_unlock(port);
2131 return KERN_INVALID_ARGUMENT;
2132 }
2133
2134 /* port is locked and active */
2135 port->ip_impdonation = 1;
2136 ip_mq_unlock(port);
2137
2138 break;
2139#endif /* IMPORTANCE_INHERITANCE */
2140 }
2141
2142 case MACH_PORT_SERVICE_THROTTLED: {
2143 boolean_t is_throttled = *info;
2144
2145 if (!MACH_PORT_VALID(name)) {
2146 return KERN_INVALID_RIGHT;
2147 }
2148
2149 kr = ipc_port_translate_receive(space, name, portp: &port);
2150 if (kr != KERN_SUCCESS) {
2151 return kr;
2152 }
2153 /* port is locked and active */
2154
2155 if (!port->ip_service_port) {
2156 ip_mq_unlock(port);
2157 return KERN_INVALID_CAPABILITY;
2158 }
2159
2160 assert(port->ip_splabel != NULL);
2161 if (is_throttled) {
2162 ipc_service_port_label_set_flag(port_splabel: port->ip_splabel, flag: ISPL_FLAGS_THROTTLED);
2163 } else {
2164 ipc_service_port_label_clear_flag(port_splabel: port->ip_splabel, flag: ISPL_FLAGS_THROTTLED);
2165 }
2166 ip_mq_unlock(port);
2167 break;
2168 }
2169
2170 default:
2171 return KERN_INVALID_ARGUMENT;
2172 /*NOTREACHED*/
2173 }
2174 return KERN_SUCCESS;
2175}
2176
2177/*
2178 * Routine: mach_port_insert_member [kernel call]
2179 * Purpose:
2180 * Add the receive right, specified by name, to
2181 * a portset.
2182 * The port cannot already be a member of the set.
2183 * Conditions:
2184 * Nothing locked.
2185 * Returns:
2186 * KERN_SUCCESS Moved the port.
2187 * KERN_INVALID_TASK The space is null.
2188 * KERN_INVALID_TASK The space is dead.
2189 * KERN_INVALID_NAME name didn't denote a right.
2190 * KERN_INVALID_RIGHT name didn't denote a receive right.
2191 * KERN_INVALID_NAME pset_name didn't denote a right.
2192 * KERN_INVALID_RIGHT pset_name didn't denote a portset right.
2193 * KERN_ALREADY_IN_SET name was already a member of pset.
2194 */
2195
2196kern_return_t
2197mach_port_insert_member(
2198 ipc_space_t space,
2199 mach_port_name_t name,
2200 mach_port_name_t psname)
2201{
2202 ipc_object_t obj;
2203 ipc_object_t psobj;
2204 kern_return_t kr;
2205 ipc_port_t port = IP_NULL;
2206 ipc_pset_t pset = IPS_NULL;
2207 waitq_link_t link;
2208
2209 if (space == IS_NULL) {
2210 return KERN_INVALID_TASK;
2211 }
2212
2213 if (!MACH_PORT_VALID(name) || !MACH_PORT_VALID(psname)) {
2214 return KERN_INVALID_RIGHT;
2215 }
2216
2217 link = waitq_link_alloc(type: WQT_PORT_SET);
2218
2219 kr = ipc_object_translate_two(space,
2220 name1: name, MACH_PORT_RIGHT_RECEIVE, objectp1: &obj,
2221 name2: psname, MACH_PORT_RIGHT_PORT_SET, objectp2: &psobj);
2222 if (kr != KERN_SUCCESS) {
2223 goto done;
2224 }
2225
2226 /* obj and psobj are locked (and were locked in that order) */
2227 assert(psobj != IO_NULL);
2228 assert(obj != IO_NULL);
2229
2230 port = ip_object_to_port(obj);
2231 pset = ips_object_to_pset(psobj);
2232
2233 kr = ipc_mqueue_add_locked(mqueue: &port->ip_messages, pset, linkp: &link);
2234
2235 ips_mq_unlock(pset);
2236 ip_mq_unlock(port);
2237
2238done:
2239 if (link.wqlh) {
2240 waitq_link_free(type: WQT_PORT_SET, link);
2241 }
2242
2243 return kr;
2244}
2245
2246/*
2247 * Routine: mach_port_extract_member [kernel call]
2248 * Purpose:
2249 * Remove a port from one portset that it is a member of.
2250 * Conditions:
2251 * Nothing locked.
2252 * Returns:
2253 * KERN_SUCCESS Moved the port.
2254 * KERN_INVALID_TASK The space is null.
2255 * KERN_INVALID_TASK The space is dead.
2256 * KERN_INVALID_NAME Member didn't denote a right.
2257 * KERN_INVALID_RIGHT Member didn't denote a receive right.
2258 * KERN_INVALID_NAME After didn't denote a right.
2259 * KERN_INVALID_RIGHT After didn't denote a port set right.
2260 * KERN_NOT_IN_SET
2261 * After is MACH_PORT_NULL and Member isn't in a port set.
2262 */
2263
2264kern_return_t
2265mach_port_extract_member(
2266 ipc_space_t space,
2267 mach_port_name_t name,
2268 mach_port_name_t psname)
2269{
2270 ipc_object_t psobj;
2271 ipc_object_t obj;
2272 kern_return_t kr;
2273 ipc_port_t port = IP_NULL;
2274 ipc_pset_t pset = IPS_NULL;
2275 waitq_link_t link;
2276
2277 if (space == IS_NULL) {
2278 return KERN_INVALID_TASK;
2279 }
2280
2281 if (!MACH_PORT_VALID(name) || !MACH_PORT_VALID(psname)) {
2282 return KERN_INVALID_RIGHT;
2283 }
2284
2285 kr = ipc_object_translate_two(space,
2286 name1: name, MACH_PORT_RIGHT_RECEIVE, objectp1: &obj,
2287 name2: psname, MACH_PORT_RIGHT_PORT_SET, objectp2: &psobj);
2288 if (kr != KERN_SUCCESS) {
2289 return kr;
2290 }
2291
2292 /* obj and psobj are both locked (and were locked in that order) */
2293 assert(psobj != IO_NULL);
2294 assert(obj != IO_NULL);
2295
2296 port = ip_object_to_port(obj);
2297 pset = ips_object_to_pset(psobj);
2298
2299 link = waitq_unlink_locked(waitq: &port->ip_waitq, wqset: &pset->ips_wqset);
2300
2301 ips_mq_unlock(pset);
2302 ip_mq_unlock(port);
2303
2304 if (link.wqlh) {
2305 waitq_link_free(type: WQT_PORT_SET, link);
2306 return KERN_SUCCESS;
2307 }
2308
2309 return KERN_NOT_IN_SET;
2310}
2311
2312/*
2313 * task_set_port_space:
2314 *
2315 * Obsolete. Set port name space of task to specified size.
2316 */
2317kern_return_t
2318task_set_port_space(
2319 ipc_space_t space,
2320 __unused int table_entries)
2321{
2322 if (space == IS_NULL) {
2323 return KERN_INVALID_TASK;
2324 }
2325
2326 return KERN_SUCCESS;
2327}
2328
2329/*
2330 * Routine: mach_port_guard_locked [helper routine]
2331 * Purpose:
2332 * Sets a new guard for a locked port.
2333 * Conditions:
2334 * Port Locked.
2335 * Returns:
2336 * KERN_SUCCESS Port Guarded.
2337 * KERN_INVALID_ARGUMENT Port already contains a context/guard.
2338 */
2339static kern_return_t
2340mach_port_guard_locked(
2341 ipc_port_t port,
2342 uint64_t guard,
2343 uint64_t flags)
2344{
2345 if (port->ip_context) {
2346 return KERN_INVALID_ARGUMENT;
2347 }
2348
2349 int strict = (flags & MPG_STRICT)? 1 : 0;
2350 int immovable_receive = (flags & MPG_IMMOVABLE_RECEIVE)? 1 : 0;
2351
2352 port->ip_context = guard;
2353 port->ip_guarded = 1;
2354 port->ip_strict_guard = strict;
2355 /* ip_immovable_receive bit is sticky and can't be un-guarded */
2356 if (!port->ip_immovable_receive) {
2357 port->ip_immovable_receive = immovable_receive;
2358 }
2359
2360 return KERN_SUCCESS;
2361}
2362
2363/*
2364 * Routine: mach_port_unguard_locked [helper routine]
2365 * Purpose:
2366 * Removes guard for a locked port.
2367 * Conditions:
2368 * Port Locked.
2369 * Returns:
2370 * KERN_SUCCESS Port Unguarded.
2371 * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch.
2372 * This also raises a EXC_GUARD exception.
2373 */
2374static kern_return_t
2375mach_port_unguard_locked(
2376 ipc_port_t port,
2377 mach_port_name_t name,
2378 uint64_t guard)
2379{
2380 /* Port locked and active */
2381 if (!port->ip_guarded) {
2382 /* Port already unguarded; Raise exception */
2383 mach_port_guard_exception(name, inguard: guard, portguard: 0, reason: kGUARD_EXC_UNGUARDED);
2384 return KERN_INVALID_ARGUMENT;
2385 }
2386
2387 if (port->ip_context != guard) {
2388 /* Incorrect guard; Raise exception */
2389 mach_port_guard_exception(name, inguard: guard, portguard: port->ip_context, reason: kGUARD_EXC_INCORRECT_GUARD);
2390 return KERN_INVALID_ARGUMENT;
2391 }
2392
2393 port->ip_context = 0;
2394 port->ip_guarded = port->ip_strict_guard = 0;
2395 /* Don't clear the ip_immovable_receive bit */
2396
2397 return KERN_SUCCESS;
2398}
2399
2400
2401/*
2402 * Routine: mach_port_guard_exception [helper routine]
2403 * Purpose:
2404 * Marks the thread with AST_GUARD for mach port guard violation.
2405 * Also saves exception info in thread structure.
2406 * Conditions:
2407 * None.
2408 * Returns:
2409 * KERN_FAILURE Thread marked with AST_GUARD.
2410 */
2411void
2412mach_port_guard_exception(
2413 mach_port_name_t name,
2414 __unused uint64_t inguard,
2415 uint64_t portguard,
2416 unsigned reason)
2417{
2418 mach_exception_code_t code = 0;
2419 EXC_GUARD_ENCODE_TYPE(code, GUARD_TYPE_MACH_PORT);
2420 EXC_GUARD_ENCODE_FLAVOR(code, reason);
2421 EXC_GUARD_ENCODE_TARGET(code, name);
2422 mach_exception_subcode_t subcode = (uint64_t)portguard;
2423 thread_t t = current_thread();
2424 boolean_t fatal = FALSE;
2425
2426 if (reason <= MAX_OPTIONAL_kGUARD_EXC_CODE &&
2427 (get_threadtask(t)->task_exc_guard & TASK_EXC_GUARD_MP_FATAL)) {
2428 fatal = TRUE;
2429 } else if (reason <= MAX_FATAL_kGUARD_EXC_CODE) {
2430 fatal = TRUE;
2431 }
2432 thread_guard_violation(t, code, subcode, fatal);
2433}
2434
2435/*
2436 * Deliver a soft or hard immovable guard exception.
2437 *
2438 * Conditions: port is marked as immovable.
2439 */
2440void
2441mach_port_guard_exception_immovable(
2442 ipc_space_t space,
2443 mach_port_name_t name,
2444 mach_port_t port,
2445 uint64_t portguard)
2446{
2447 if (space == current_space()) {
2448 assert(ip_is_immovable_send(port));
2449
2450 boolean_t hard = task_get_control_port_options(task: current_task()) & TASK_CONTROL_PORT_IMMOVABLE_HARD;
2451
2452 if (ip_is_control(port)) {
2453 assert(task_is_immovable(current_task()));
2454 mach_port_guard_exception(name, inguard: 0, portguard,
2455 reason: hard ? kGUARD_EXC_IMMOVABLE : kGUARD_EXC_IMMOVABLE_NON_FATAL);
2456 } else {
2457 /* always fatal exception for non-control port violation */
2458 mach_port_guard_exception(name, inguard: 0, portguard, reason: kGUARD_EXC_IMMOVABLE);
2459 }
2460 }
2461}
2462
2463/*
2464 * Deliver a soft or hard immovable guard exception.
2465 *
2466 * Conditions: port is marked as immovable and pinned.
2467 */
2468void
2469mach_port_guard_exception_pinned(
2470 ipc_space_t space,
2471 mach_port_name_t name,
2472 __assert_only mach_port_t port,
2473 uint64_t portguard)
2474{
2475 if (space == current_space()) {
2476 assert(ip_is_immovable_send(port));
2477 assert(ip_is_control(port)); /* only task/thread control ports can be pinned */
2478
2479 boolean_t hard = task_get_control_port_options(task: current_task()) & TASK_CONTROL_PORT_PINNED_HARD;
2480
2481 assert(task_is_pinned(current_task()));
2482
2483 mach_port_guard_exception(name, inguard: 0, portguard,
2484 reason: hard ? kGUARD_EXC_MOD_REFS : kGUARD_EXC_MOD_REFS_NON_FATAL);
2485 }
2486}
2487
2488/*
2489 * Routine: mach_port_guard_ast
2490 * Purpose:
2491 * Raises an exception for mach port guard violation.
2492 * Conditions:
2493 * None.
2494 * Returns:
2495 * None.
2496 */
2497
2498void
2499mach_port_guard_ast(thread_t t,
2500 mach_exception_data_type_t code, mach_exception_data_type_t subcode)
2501{
2502 unsigned int reason = EXC_GUARD_DECODE_GUARD_FLAVOR(code);
2503 task_t task = get_threadtask(t);
2504 unsigned int behavior = task->task_exc_guard;
2505 bool fatal = true;
2506
2507 assert(task == current_task());
2508 assert(task != kernel_task);
2509
2510 if (reason <= MAX_FATAL_kGUARD_EXC_CODE) {
2511 /*
2512 * Fatal Mach port guards - always delivered synchronously if dev mode is on.
2513 * Check if anyone has registered for Synchronous EXC_GUARD, if yes then,
2514 * deliver it synchronously and then kill the process, else kill the process
2515 * and deliver the exception via EXC_CORPSE_NOTIFY.
2516 */
2517 if (task_exception_notify(EXC_GUARD, code, subcode, fatal) == KERN_SUCCESS) {
2518 task_bsdtask_kill(task);
2519 } else {
2520 exit_with_guard_exception(p: get_bsdtask_info(task), code, subcode);
2521 }
2522 } else {
2523 /*
2524 * Mach port guards controlled by task settings.
2525 */
2526
2527 /* Is delivery enabled */
2528 if ((behavior & TASK_EXC_GUARD_MP_DELIVER) == 0) {
2529 return;
2530 }
2531
2532 /* If only once, make sure we're that once */
2533 while (behavior & TASK_EXC_GUARD_MP_ONCE) {
2534 uint32_t new_behavior = behavior & ~TASK_EXC_GUARD_MP_DELIVER;
2535
2536 if (OSCompareAndSwap(behavior, new_behavior, &task->task_exc_guard)) {
2537 break;
2538 }
2539 behavior = task->task_exc_guard;
2540 if ((behavior & TASK_EXC_GUARD_MP_DELIVER) == 0) {
2541 return;
2542 }
2543 }
2544 fatal = (task->task_exc_guard & TASK_EXC_GUARD_MP_FATAL)
2545 && (reason <= MAX_OPTIONAL_kGUARD_EXC_CODE);
2546 kern_return_t sync_exception_result;
2547 sync_exception_result = task_exception_notify(EXC_GUARD, code, subcode, fatal);
2548
2549 if (task->task_exc_guard & TASK_EXC_GUARD_MP_FATAL) {
2550 if (reason > MAX_OPTIONAL_kGUARD_EXC_CODE) {
2551 /* generate a simulated crash if not handled synchronously */
2552 if (sync_exception_result != KERN_SUCCESS) {
2553 task_violated_guard(code, subcode, NULL, TRUE);
2554 }
2555 } else {
2556 /*
2557 * Only generate crash report if synchronous EXC_GUARD wasn't handled,
2558 * but it has to die regardless.
2559 */
2560 if (sync_exception_result == KERN_SUCCESS) {
2561 task_bsdtask_kill(task);
2562 } else {
2563 exit_with_guard_exception(p: get_bsdtask_info(task), code, subcode);
2564 }
2565 }
2566 } else if (task->task_exc_guard & TASK_EXC_GUARD_MP_CORPSE) {
2567 /* Raise exception via corpse fork if not handled synchronously */
2568 if (sync_exception_result != KERN_SUCCESS) {
2569 task_violated_guard(code, subcode, NULL, TRUE);
2570 }
2571 }
2572 }
2573}
2574
2575/*
2576 * Routine: mach_port_construct [kernel call]
2577 * Purpose:
2578 * Constructs a mach port with the provided set of options.
2579 * Conditions:
2580 * None.
2581 * Returns:
2582 * KERN_SUCCESS The right is allocated.
2583 * KERN_INVALID_TASK The space is null.
2584 * KERN_INVALID_TASK The space is dead.
2585 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
2586 * KERN_INVALID_VALUE Invalid value passed in options
2587 * KERN_INVALID_ARGUMENT Invalid arguments passed in options
2588 * KERN_NO_SPACE No room in space for another right.
2589 * KERN_FAILURE Illegal option values requested.
2590 */
2591
2592kern_return_t
2593mach_port_construct(
2594 ipc_space_t space,
2595 mach_port_options_t *options,
2596 uint64_t context,
2597 mach_port_name_t *name)
2598{
2599 kern_return_t kr;
2600 ipc_port_t port;
2601 ipc_port_init_flags_t init_flags = IPC_PORT_INIT_MESSAGE_QUEUE;
2602 void *port_splabel = NULL;
2603 bool filter_msgs = FALSE;
2604 struct mach_service_port_info sp_info = {};
2605 size_t sp_name_length = 0;
2606 user_addr_t service_port_info = 0;
2607
2608 uint32_t at_most_one_flags = options->flags & (MPO_SERVICE_PORT | MPO_CONNECTION_PORT | MPO_TG_BLOCK_TRACKING);
2609 if (at_most_one_flags & (at_most_one_flags - 1)) {
2610 /* at most one of the listed flags can be set */
2611 return KERN_INVALID_ARGUMENT;
2612 }
2613
2614 at_most_one_flags = options->flags & (MPO_REPLY_PORT | MPO_ENFORCE_REPLY_PORT_SEMANTICS |
2615 MPO_PROVISIONAL_ID_PROT_OPTOUT | MPO_PROVISIONAL_REPLY_PORT);
2616 if (at_most_one_flags & (at_most_one_flags - 1)) {
2617 /* at most one of the listed flags can be set */
2618 return KERN_INVALID_ARGUMENT;
2619 }
2620
2621 if (space == IS_NULL) {
2622 return KERN_INVALID_TASK;
2623 }
2624
2625 if (options->flags & MPO_INSERT_SEND_RIGHT) {
2626 init_flags |= IPC_PORT_INIT_MAKE_SEND_RIGHT;
2627 }
2628
2629 if (options->flags & MPO_FILTER_MSG) {
2630 init_flags |= IPC_PORT_INIT_FILTER_MESSAGE;
2631 }
2632
2633 if (options->flags & MPO_REPLY_PORT) {
2634 init_flags |= IPC_PORT_INIT_REPLY;
2635 }
2636
2637 if (options->flags & MPO_ENFORCE_REPLY_PORT_SEMANTICS) {
2638 init_flags |= IPC_PORT_ENFORCE_REPLY_PORT_SEMANTICS;
2639 }
2640
2641 if (options->flags & MPO_PROVISIONAL_ID_PROT_OPTOUT) {
2642 init_flags |= IPC_PORT_INIT_PROVISIONAL_ID_PROT_OPTOUT;
2643 }
2644
2645 if (options->flags & MPO_PROVISIONAL_REPLY_PORT) {
2646 if (provisional_reply_port_enforced) {
2647 init_flags |= IPC_PORT_INIT_REPLY;
2648 } else {
2649 init_flags |= IPC_PORT_INIT_PROVISIONAL_REPLY;
2650 }
2651 }
2652
2653 if (options->flags & MPO_TG_BLOCK_TRACKING) {
2654 /* Check the task role to allow only TASK_GRAPHICS_SERVER to set this option */
2655 if (proc_get_effective_task_policy(task: current_task(),
2656 TASK_POLICY_ROLE) != TASK_GRAPHICS_SERVER) {
2657 return KERN_DENIED;
2658 }
2659
2660 /*
2661 * Check the work interval port passed in to make sure it is the render server type.
2662 * Since the creation of the render server work interval is privileged, this check
2663 * acts as a guard to make sure only the render server is setting the thread group
2664 * blocking behavior on the port.
2665 */
2666 mach_port_name_t wi_port_name = options->work_interval_port;
2667 if (work_interval_port_type_render_server(port_name: wi_port_name) == false) {
2668 return KERN_INVALID_ARGUMENT;
2669 }
2670 init_flags |= IPC_PORT_INIT_TG_BLOCK_TRACKING;
2671 }
2672
2673 if (options->flags & MPO_SERVICE_PORT) {
2674#if !(DEVELOPMENT || DEBUG)
2675#if CONFIG_COALITIONS
2676 /*
2677 * Allow only launchd to add the service port labels
2678 * Not enforcing on development/debug kernels to
2679 * support testing
2680 */
2681 if (!task_is_in_privileged_coalition(task: current_task(), COALITION_TYPE_JETSAM)) {
2682 return KERN_DENIED;
2683 }
2684#else /* CONFIG_COALITIONS */
2685 /*
2686 * This flag is not used by launchd on simulators
2687 */
2688 if (proc_isinitproc(get_bsdtask_info(current_task()))) {
2689 return KERN_DENIED;
2690 }
2691#endif /* CONFIG_COALITIONS */
2692#endif /* !(DEVELOPMENT || DEBUG) */
2693
2694 if (task_has_64Bit_addr(current_task())) {
2695 service_port_info = CAST_USER_ADDR_T(options->service_port_info64);
2696 } else {
2697 service_port_info = CAST_USER_ADDR_T(options->service_port_info32);
2698 }
2699
2700 if (!service_port_info) {
2701 return KERN_INVALID_ARGUMENT;
2702 }
2703
2704 if (copyin(service_port_info, (void *)&sp_info, sizeof(sp_info))) {
2705 return KERN_MEMORY_ERROR;
2706 }
2707
2708 sp_name_length = strnlen(s: sp_info.mspi_string_name, MACH_SERVICE_PORT_INFO_STRING_NAME_MAX_BUF_LEN);
2709 if (sp_name_length >= (MACH_SERVICE_PORT_INFO_STRING_NAME_MAX_BUF_LEN)) {
2710 return KERN_INVALID_ARGUMENT;
2711 }
2712
2713 kr = ipc_service_port_label_alloc(sp_info: &sp_info, port_label_ptr: &port_splabel);
2714 if (kr != KERN_SUCCESS) {
2715 return kr;
2716 }
2717 /* Always filter messages on service ports */
2718 init_flags |= IPC_PORT_INIT_FILTER_MESSAGE;
2719 }
2720
2721 if (options->flags & MPO_CONNECTION_PORT) {
2722 if (!options->service_port_name) {
2723 return KERN_INVALID_ARGUMENT;
2724 }
2725
2726 kr = ipc_service_port_derive_sblabel(service_port_name: options->service_port_name, sblabel_ptr: &port_splabel, filter_msgs: &filter_msgs);
2727 if (kr != KERN_SUCCESS) {
2728 return kr;
2729 }
2730 if (filter_msgs) {
2731 init_flags |= IPC_PORT_INIT_FILTER_MESSAGE;
2732 }
2733 }
2734
2735
2736 if (options->flags & MPO_QLIMIT) {
2737 const mach_msg_type_number_t count = sizeof(options->mpl) / sizeof(int);
2738 static_assert(count >= MACH_PORT_LIMITS_INFO_COUNT);
2739
2740 if (options->mpl.mpl_qlimit > MACH_PORT_QLIMIT_MAX) {
2741 return KERN_INVALID_VALUE;
2742 }
2743 }
2744
2745 /* Allocate a new port in the IPC space */
2746 kr = ipc_port_alloc(space, flags: init_flags, namep: name, portp: &port);
2747 if (kr != KERN_SUCCESS) {
2748 if (port_splabel != NULL) {
2749 ipc_service_port_label_dealloc(ip_splabel: port_splabel,
2750 service_port: (options->flags & MPO_SERVICE_PORT));
2751 }
2752 return kr;
2753 }
2754 /* Port locked and active */
2755
2756 /* Mutate the new port based on flags - see above for error checks */
2757 if (options->flags & MPO_QLIMIT) {
2758 ipc_mqueue_set_qlimit_locked(mqueue: &port->ip_messages, qlimit: options->mpl.mpl_qlimit);
2759 }
2760
2761 if (options->flags & (MPO_IMPORTANCE_RECEIVER | MPO_DENAP_RECEIVER | MPO_TEMPOWNER)) {
2762 assert(!port->ip_specialreply);
2763
2764 port->ip_impdonation = 1;
2765 if (options->flags & MPO_TEMPOWNER) {
2766 port->ip_tempowner = 1;
2767 }
2768 }
2769
2770 if (port_splabel != NULL) {
2771 port->ip_service_port = (bool)(options->flags & MPO_SERVICE_PORT);
2772 port->ip_splabel = port_splabel;
2773
2774 /* Check if this is a service port */
2775 if (service_port_defense_enabled && port->ip_service_port) {
2776 port->ip_immovable_receive = true;
2777 }
2778
2779 /* Check if this is a libxpc connection port */
2780 if (!port->ip_service_port) {
2781 assert(options->flags & MPO_CONNECTION_PORT);
2782 port->ip_immovable_send = true;
2783 port->ip_immovable_receive = true;
2784 }
2785 }
2786
2787 if (options->flags & MPO_CONTEXT_AS_GUARD) {
2788 uint64_t flags = 0;
2789 if (options->flags & MPO_STRICT) {
2790 flags |= MPG_STRICT;
2791 }
2792 if (options->flags & MPO_IMMOVABLE_RECEIVE) {
2793 flags |= MPG_IMMOVABLE_RECEIVE;
2794 }
2795 kr = mach_port_guard_locked(port, guard: context, flags);
2796 /* A newly allocated and locked port should always be guarded successfully */
2797 assert(kr == KERN_SUCCESS);
2798 if (options->flags & MPO_SERVICE_PORT) {
2799 /*
2800 * Setting the guard on a service port triggers a special port destroyed notification
2801 * that restores the guard when the receive right moves back to launchd. This
2802 * must be a strict guard.
2803 */
2804 assert((options->flags & MPO_STRICT) == MPO_STRICT);
2805 ipc_service_port_label_set_attr(port_splabel, name: *name, context: (mach_port_context_t)context);
2806 }
2807 } else {
2808 port->ip_context = context;
2809 if (options->flags & MPO_SERVICE_PORT) {
2810 ipc_service_port_label_set_attr(port_splabel, name: *name, context: 0);
2811 }
2812 }
2813
2814 /* Unlock port */
2815 ip_mq_unlock(port);
2816
2817 return KERN_SUCCESS;
2818}
2819
2820/*
2821 * Routine: mach_port_destruct [kernel call]
2822 * Purpose:
2823 * Destroys a mach port with appropriate guard
2824 * Conditions:
2825 * None.
2826 * Returns:
2827 * KERN_SUCCESS The name is destroyed.
2828 * KERN_INVALID_TASK The space is null.
2829 * KERN_INVALID_TASK The space is dead.
2830 * KERN_INVALID_NAME The name doesn't denote a right.
2831 * KERN_INVALID_RIGHT The right isn't correct.
2832 * KERN_INVALID_VALUE The delta for send right is incorrect.
2833 * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch.
2834 * This also raises a EXC_GUARD exception.
2835 */
2836
2837kern_return_t
2838mach_port_destruct(
2839 ipc_space_t space,
2840 mach_port_name_t name,
2841 mach_port_delta_t srdelta,
2842 uint64_t guard)
2843{
2844 kern_return_t kr;
2845 ipc_entry_t entry;
2846
2847 if (space == IS_NULL) {
2848 return KERN_INVALID_TASK;
2849 }
2850
2851 if (!MACH_PORT_VALID(name)) {
2852 return KERN_INVALID_NAME;
2853 }
2854
2855 /* Remove reference for receive right */
2856 kr = ipc_right_lookup_write(space, name, entryp: &entry);
2857 if (kr != KERN_SUCCESS) {
2858 mach_port_guard_exception(name, inguard: 0, portguard: 0, reason: kGUARD_EXC_INVALID_NAME);
2859 return kr;
2860 }
2861 /* space is write-locked and active */
2862 kr = ipc_right_destruct(space, name, entry, srdelta, guard); /* unlocks */
2863
2864 return kr;
2865}
2866
2867/*
2868 * Routine: mach_port_guard [kernel call]
2869 * Purpose:
2870 * Guard a mach port with specified guard value.
2871 * The context field of the port is used as the guard.
2872 * Conditions:
2873 * None.
2874 * Returns:
2875 * KERN_SUCCESS The name is destroyed.
2876 * KERN_INVALID_TASK The space is null.
2877 * KERN_INVALID_TASK The space is dead.
2878 * KERN_INVALID_NAME The name doesn't denote a right.
2879 * KERN_INVALID_RIGHT The right isn't correct.
2880 * KERN_INVALID_ARGUMENT Port already contains a context/guard.
2881 */
2882kern_return_t
2883mach_port_guard(
2884 ipc_space_t space,
2885 mach_port_name_t name,
2886 uint64_t guard,
2887 boolean_t strict)
2888{
2889 kern_return_t kr;
2890 ipc_port_t port;
2891 uint64_t flags = 0;
2892
2893 if (space == IS_NULL) {
2894 return KERN_INVALID_TASK;
2895 }
2896
2897 if (!MACH_PORT_VALID(name)) {
2898 return KERN_INVALID_NAME;
2899 }
2900
2901 /* Guard can be applied only to receive rights */
2902 kr = ipc_port_translate_receive(space, name, portp: &port);
2903 if (kr != KERN_SUCCESS) {
2904 mach_port_guard_exception(name, inguard: 0, portguard: 0,
2905 reason: ((KERN_INVALID_NAME == kr) ?
2906 kGUARD_EXC_INVALID_NAME :
2907 kGUARD_EXC_INVALID_RIGHT));
2908 return kr;
2909 }
2910
2911 /* Port locked and active */
2912 if (strict) {
2913 flags = MPG_STRICT;
2914 }
2915
2916 kr = mach_port_guard_locked(port, guard, flags);
2917 ip_mq_unlock(port);
2918
2919 if (KERN_INVALID_ARGUMENT == kr) {
2920 mach_port_guard_exception(name, inguard: 0, portguard: 0, reason: kGUARD_EXC_INVALID_ARGUMENT);
2921 }
2922
2923 return kr;
2924}
2925
2926/*
2927 * Routine: mach_port_unguard [kernel call]
2928 * Purpose:
2929 * Unguard a mach port with specified guard value.
2930 * Conditions:
2931 * None.
2932 * Returns:
2933 * KERN_SUCCESS The name is destroyed.
2934 * KERN_INVALID_TASK The space is null.
2935 * KERN_INVALID_TASK The space is dead.
2936 * KERN_INVALID_NAME The name doesn't denote a right.
2937 * KERN_INVALID_RIGHT The right isn't correct.
2938 * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch.
2939 * This also raises a EXC_GUARD exception.
2940 */
2941kern_return_t
2942mach_port_unguard(
2943 ipc_space_t space,
2944 mach_port_name_t name,
2945 uint64_t guard)
2946{
2947 kern_return_t kr;
2948 ipc_port_t port;
2949
2950 if (space == IS_NULL) {
2951 return KERN_INVALID_TASK;
2952 }
2953
2954 if (!MACH_PORT_VALID(name)) {
2955 return KERN_INVALID_NAME;
2956 }
2957
2958 kr = ipc_port_translate_receive(space, name, portp: &port);
2959 if (kr != KERN_SUCCESS) {
2960 mach_port_guard_exception(name, inguard: 0, portguard: 0,
2961 reason: ((KERN_INVALID_NAME == kr) ?
2962 kGUARD_EXC_INVALID_NAME :
2963 kGUARD_EXC_INVALID_RIGHT));
2964 return kr;
2965 }
2966
2967 /* Port locked and active */
2968 kr = mach_port_unguard_locked(port, name, guard);
2969 ip_mq_unlock(port);
2970
2971 return kr;
2972}
2973
2974/*
2975 * Routine: mach_port_guard_with_flags [kernel call]
2976 * Purpose:
2977 * Guard a mach port with specified guard value and guard flags.
2978 * The context field of the port is used as the guard.
2979 * Conditions:
2980 * Should hold receive right for that port
2981 * Returns:
2982 * KERN_SUCCESS The name is destroyed.
2983 * KERN_INVALID_TASK The space is null.
2984 * KERN_INVALID_TASK The space is dead.
2985 * KERN_INVALID_NAME The name doesn't denote a right.
2986 * KERN_INVALID_RIGHT The right isn't correct.
2987 * KERN_INVALID_ARGUMENT Port already contains a context/guard.
2988 * KERN_INVALID_CAPABILITY Cannot set MPG_IMMOVABLE_RECEIVE flag for a port with
2989 * a movable port-destroyed notification port
2990 */
2991kern_return_t
2992mach_port_guard_with_flags(
2993 ipc_space_t space,
2994 mach_port_name_t name,
2995 uint64_t guard,
2996 uint64_t flags)
2997{
2998 kern_return_t kr;
2999 ipc_port_t port;
3000
3001 if (space == IS_NULL) {
3002 return KERN_INVALID_TASK;
3003 }
3004
3005 if (!MACH_PORT_VALID(name)) {
3006 return KERN_INVALID_NAME;
3007 }
3008
3009 kr = ipc_port_translate_receive(space, name, portp: &port);
3010 if (kr != KERN_SUCCESS) {
3011 mach_port_guard_exception(name, inguard: 0, portguard: 0,
3012 reason: ((KERN_INVALID_NAME == kr) ?
3013 kGUARD_EXC_INVALID_NAME :
3014 kGUARD_EXC_INVALID_RIGHT));
3015 return kr;
3016 }
3017
3018 /* Port locked and active */
3019 kr = mach_port_guard_locked(port, guard, flags);
3020 ip_mq_unlock(port);
3021
3022 if (KERN_INVALID_ARGUMENT == kr) {
3023 mach_port_guard_exception(name, inguard: 0, portguard: 0, reason: kGUARD_EXC_INVALID_ARGUMENT);
3024 }
3025
3026 return kr;
3027}
3028
3029/*
3030 * Routine: mach_port_swap_guard [kernel call]
3031 * Purpose:
3032 * Swap guard value.
3033 * Conditions:
3034 * Port should already be guarded.
3035 * Returns:
3036 * KERN_SUCCESS The name is destroyed.
3037 * KERN_INVALID_TASK The space is null.
3038 * KERN_INVALID_TASK The space is dead.
3039 * KERN_INVALID_NAME The name doesn't denote a right.
3040 * KERN_INVALID_RIGHT The right isn't correct.
3041 * KERN_INVALID_ARGUMENT Port doesn't contain a guard; is strictly guarded
3042 * or the old_guard doesnt match the context
3043 */
3044kern_return_t
3045mach_port_swap_guard(
3046 ipc_space_t space,
3047 mach_port_name_t name,
3048 uint64_t old_guard,
3049 uint64_t new_guard)
3050{
3051 kern_return_t kr;
3052 ipc_port_t port;
3053
3054 if (space == IS_NULL) {
3055 return KERN_INVALID_TASK;
3056 }
3057
3058 if (!MACH_PORT_VALID(name)) {
3059 return KERN_INVALID_NAME;
3060 }
3061
3062 kr = ipc_port_translate_receive(space, name, portp: &port);
3063 if (kr != KERN_SUCCESS) {
3064 mach_port_guard_exception(name, inguard: 0, portguard: 0,
3065 reason: ((KERN_INVALID_NAME == kr) ?
3066 kGUARD_EXC_INVALID_NAME :
3067 kGUARD_EXC_INVALID_RIGHT));
3068 return kr;
3069 }
3070
3071 /* Port locked and active */
3072 if (!port->ip_guarded) {
3073 ip_mq_unlock(port);
3074 mach_port_guard_exception(name, inguard: old_guard, portguard: 0, reason: kGUARD_EXC_UNGUARDED);
3075 return KERN_INVALID_ARGUMENT;
3076 }
3077
3078 if (port->ip_strict_guard) {
3079 uint64_t portguard = port->ip_context;
3080 ip_mq_unlock(port);
3081 /* For strictly guarded ports, disallow overwriting context; Raise Exception */
3082 mach_port_guard_exception(name, inguard: old_guard, portguard, reason: kGUARD_EXC_SET_CONTEXT);
3083 return KERN_INVALID_ARGUMENT;
3084 }
3085
3086 if (port->ip_context != old_guard) {
3087 uint64_t portguard = port->ip_context;
3088 ip_mq_unlock(port);
3089 mach_port_guard_exception(name, inguard: old_guard, portguard, reason: kGUARD_EXC_INCORRECT_GUARD);
3090 return KERN_INVALID_ARGUMENT;
3091 }
3092
3093 port->ip_context = new_guard;
3094
3095 ip_mq_unlock(port);
3096
3097 return KERN_SUCCESS;
3098}
3099
3100kern_return_t
3101mach_port_is_connection_for_service(
3102 ipc_space_t space,
3103 mach_port_name_t connection_port_name,
3104 mach_port_name_t service_port_name,
3105 uint64_t *filter_policy_id)
3106{
3107 mach_port_t service_port;
3108 mach_port_t connection_port;
3109 void *service_port_sblabel = NULL;
3110 void *conn_port_sblabel = NULL;
3111
3112 kern_return_t ret;
3113
3114 if (space == IS_NULL) {
3115 return KERN_INVALID_TASK;
3116 }
3117
3118 if (!MACH_PORT_VALID(connection_port_name) || !MACH_PORT_VALID(service_port_name)) {
3119 return KERN_INVALID_NAME;
3120 }
3121
3122 if (!filter_policy_id) {
3123 return KERN_INVALID_ARGUMENT;
3124 }
3125
3126 if (!mach_msg_filter_at_least(MACH_MSG_FILTER_CALLBACKS_VERSION_1)) {
3127 return KERN_NOT_SUPPORTED;
3128 }
3129
3130 ret = ipc_port_translate_receive(space, name: service_port_name, portp: &service_port);
3131 if (ret) {
3132 return ret;
3133 }
3134
3135 if (!service_port->ip_service_port) {
3136 ip_mq_unlock(service_port);
3137 return KERN_INVALID_CAPABILITY;
3138 }
3139
3140 /* Port is locked and active */
3141 service_port_sblabel = ipc_service_port_get_sblabel(port: service_port);
3142 if (service_port_sblabel) {
3143 mach_msg_filter_retain_sblabel_callback(service_port_sblabel);
3144 }
3145 ip_mq_unlock(service_port);
3146
3147 if (!service_port_sblabel) {
3148 /* Nothing to check */
3149 *filter_policy_id = 0;
3150 return KERN_SUCCESS;
3151 }
3152
3153 ret = ipc_port_translate_receive(space, name: connection_port_name, portp: &connection_port);
3154 if (ret) {
3155 mach_msg_filter_dealloc_service_port_sblabel_callback(service_port_sblabel);
3156 return ret;
3157 }
3158 /* Port is locked and active */
3159 conn_port_sblabel = ipc_service_port_get_sblabel(port: connection_port);
3160 if (conn_port_sblabel) {
3161 mach_msg_filter_retain_sblabel_callback(conn_port_sblabel);
3162 }
3163 ip_mq_unlock(connection_port);
3164
3165 /* This callback will release the sblabel references */
3166 ret = mach_msg_filter_get_connection_port_filter_policy_callback(service_port_sblabel,
3167 conn_port_sblabel, filter_policy_id);
3168
3169 return ret;
3170}
3171
3172#if CONFIG_SERVICE_PORT_INFO
3173kern_return_t
3174mach_port_get_service_port_info(
3175 ipc_space_read_t space,
3176 mach_port_name_t name,
3177 mach_service_port_info_t sp_info)
3178{
3179 ipc_port_t port;
3180 kern_return_t kr;
3181
3182 if (space == IS_NULL) {
3183 return KERN_INVALID_TASK;
3184 }
3185
3186 if (sp_info == NULL) {
3187 return KERN_INVALID_ARGUMENT;
3188 }
3189
3190 if (!MACH_PORT_VALID(name)) {
3191 return KERN_INVALID_RIGHT;
3192 }
3193
3194 kr = ipc_port_translate_receive(space, name, portp: &port);
3195 if (kr != KERN_SUCCESS) {
3196 return kr;
3197 }
3198 /* port is locked and active */
3199
3200 if (!port->ip_service_port) {
3201 ip_mq_unlock(port);
3202 return KERN_INVALID_CAPABILITY;
3203 }
3204
3205 assert(port->ip_splabel != NULL);
3206 ipc_service_port_label_get_info(port_splabel: (ipc_service_port_label_t)port->ip_splabel, info: sp_info);
3207 ip_mq_unlock(port);
3208
3209 return KERN_SUCCESS;
3210}
3211
3212#else /* CONFIG_SERVICE_PORT_INFO */
3213
3214kern_return_t
3215mach_port_get_service_port_info(
3216 __unused ipc_space_read_t space,
3217 __unused mach_port_name_t name,
3218 __unused mach_service_port_info_t sp_info)
3219{
3220 return KERN_NOT_SUPPORTED;
3221}
3222#endif /* CONFIG_SERVICE_PORT_INFO */
3223
3224kern_return_t
3225mach_port_assert_attributes(
3226 ipc_space_t space,
3227 mach_port_name_t name,
3228 int flavor,
3229 mach_port_info_t info,
3230 mach_msg_type_number_t count)
3231{
3232 ipc_port_t port;
3233 kern_return_t kr;
3234
3235 if (space == IS_NULL) {
3236 return KERN_INVALID_TASK;
3237 }
3238
3239 switch (flavor) {
3240 case MACH_PORT_GUARD_INFO: {
3241 mach_port_guard_info_t *mpgi = (mach_port_guard_info_t *)(void *)info;
3242
3243 if (count < MACH_PORT_GUARD_INFO_COUNT) {
3244 return KERN_FAILURE;
3245 }
3246
3247 if (!MACH_PORT_VALID(name)) {
3248 return KERN_INVALID_RIGHT;
3249 }
3250
3251 kr = ipc_port_translate_receive(space, name, portp: &port);
3252 if (kr != KERN_SUCCESS) {
3253 return kr;
3254 }
3255 /* port is locked and active */
3256
3257 /* Check if guard value matches else kill the process using fatal guard exception */
3258 if (!port->ip_guarded) {
3259 ip_mq_unlock(port);
3260 /* Port already unguarded; Raise exception */
3261 mach_port_guard_exception(name, inguard: mpgi->mpgi_guard, portguard: 0, reason: kGUARD_EXC_UNGUARDED);
3262 return KERN_INVALID_ARGUMENT;
3263 }
3264
3265 if (!port->ip_strict_guard || (port->ip_context != mpgi->mpgi_guard)) {
3266 ip_mq_unlock(port);
3267 /* Incorrect guard; Raise exception */
3268 mach_port_guard_exception(name, inguard: mpgi->mpgi_guard, portguard: port->ip_context, reason: kGUARD_EXC_INCORRECT_GUARD);
3269 return KERN_INVALID_ARGUMENT;
3270 }
3271
3272 ip_mq_unlock(port);
3273 break;
3274 }
3275 default:
3276 return KERN_INVALID_ARGUMENT;
3277 }
3278 return KERN_SUCCESS;
3279}
3280