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 [email protected]
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
109 static TUNABLE(bool, provisional_reply_port_enforced, "-provisional_reply_port_enforced", false);
110
111 extern void qsort(void *a, size_t n, size_t es, int (*cmp)(const void *, const void *));
112 extern int proc_isinitproc(struct proc *p);
113
114 static int
mach_port_name_cmp(const void * _n1,const void * _n2)115 mach_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
127 kern_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);
129 kern_return_t mach_port_get_context(ipc_space_t space, mach_port_name_t name,
130 mach_vm_address_t *context);
131 kern_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);
133 extern 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 */
144 static void
mach_port_names_helper(ipc_port_timestamp_t timestamp,ipc_entry_t entry,mach_port_name_t name,mach_port_name_t * names,mach_port_type_t * types,ipc_entry_num_t * actualp)145 mach_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, 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, 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
224 kern_return_t
mach_port_names(ipc_space_t space,mach_port_name_t ** namesp,mach_msg_type_number_t * namesCnt,mach_port_type_t ** typesp,mach_msg_type_number_t * typesCnt)225 mach_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(ipc_kernel_map, addr1, size);
265 kmem_free(ipc_kernel_map, 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(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(ipc_kernel_map, addr1, size);
284 kmem_free(ipc_kernel_map, addr2, size);
285 }
286 size = size_needed;
287
288 kr = kmem_alloc(ipc_kernel_map, &addr1, size,
289 KMA_DATA, VM_KERN_MEMORY_IPC);
290 if (kr != KERN_SUCCESS) {
291 return KERN_RESOURCE_SHORTAGE;
292 }
293
294 kr = kmem_alloc(ipc_kernel_map, &addr2, size,
295 KMA_DATA, VM_KERN_MEMORY_IPC);
296 if (kr != KERN_SUCCESS) {
297 kmem_free(ipc_kernel_map, 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(table);
311
312 for (index = 1; index < tsize; index++) {
313 ipc_entry_t entry = ipc_entry_table_get_nocheck(table, 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, &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(ipc_kernel_map, addr1, size);
333 kmem_free(ipc_kernel_map, 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((char *)addr1 + size_used, vm_size_used - size_used);
351 bzero((char *)addr2 + size_used, vm_size_used - size_used);
352 }
353
354 kr = vm_map_unwire(ipc_kernel_map, addr1, addr1 + vm_size_used, FALSE);
355 assert(kr == KERN_SUCCESS);
356
357 kr = vm_map_unwire(ipc_kernel_map, addr2, addr2 + vm_size_used, FALSE);
358 assert(kr == KERN_SUCCESS);
359
360 kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr1,
361 (vm_map_size_t)size_used, TRUE, &memory1);
362 assert(kr == KERN_SUCCESS);
363
364 kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr2,
365 (vm_map_size_t)size_used, TRUE, &memory2);
366 assert(kr == KERN_SUCCESS);
367
368 if (vm_size_used != size) {
369 kmem_free(ipc_kernel_map,
370 addr1 + vm_size_used, size - vm_size_used);
371 kmem_free(ipc_kernel_map,
372 addr2 + vm_size_used, 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
406 kern_return_t
mach_port_type(ipc_space_t space,mach_port_name_t name,mach_port_type_t * typep)407 mach_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, &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, &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
482 kern_return_t
mach_port_allocate_name(ipc_space_t space,mach_port_right_t right,mach_port_name_t name)483 mach_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(space, right, MACH_PORT_NULL,
496 &qos, &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
518 kern_return_t
mach_port_allocate(ipc_space_t space,mach_port_right_t right,mach_port_name_t * namep)519 mach_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(space, right, MACH_PORT_NULL,
528 &qos, 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
551 kern_return_t
mach_port_allocate_qos(ipc_space_t space,mach_port_right_t right,mach_port_qos_t * qosp,mach_port_name_t * namep)552 mach_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(space, right, MACH_PORT_NULL,
564 qosp, 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
592 kern_return_t
mach_port_allocate_full(ipc_space_t space,mach_port_right_t right,mach_port_t proto,mach_port_qos_t * qosp,mach_port_name_t * namep)593 mach_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, IPC_PORT_INIT_MESSAGE_QUEUE,
640 *namep, &port);
641 } else {
642 kr = ipc_port_alloc(space, IPC_PORT_INIT_MESSAGE_QUEUE,
643 namep, &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, *namep, &pset);
657 } else {
658 kr = ipc_pset_alloc(space, namep, &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
695 kern_return_t
mach_port_destroy(ipc_space_t space,mach_port_name_t name)696 mach_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, &entry);
712 if (kr != KERN_SUCCESS) {
713 mach_port_guard_exception(name, 0, 0, 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, 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
740 kern_return_t
mach_port_deallocate(ipc_space_t space,mach_port_name_t name)741 mach_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, &entry);
757 if (kr != KERN_SUCCESS) {
758 mach_port_guard_exception(name, 0, 0, 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
784 kern_return_t
mach_port_get_refs(ipc_space_t space,mach_port_name_t name,mach_port_right_t right,mach_port_urefs_t * urefsp)785 mach_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, &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, &type, &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
873 kern_return_t
mach_port_mod_refs(ipc_space_t space,mach_port_name_t name,mach_port_right_t right,mach_port_delta_t delta)874 mach_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, &entry);
900 if (kr != KERN_SUCCESS) {
901 mach_port_guard_exception(name, 0, 0, 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
950 kern_return_t
mach_port_peek(ipc_space_t space,mach_port_name_t name,mach_msg_trailer_type_t trailer_type,mach_port_seqno_t * seqnop,mach_msg_size_t * msg_sizep,mach_msg_id_t * msg_idp,mach_msg_trailer_info_t trailer_infop,mach_msg_type_number_t * trailer_sizep)951 mach_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, 0, 0, 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, &port);
987 if (kr != KERN_SUCCESS) {
988 mach_port_guard_exception(name, 0, 0,
989 ((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(&port->ip_messages, seqnop,
997 msg_sizep, msg_idp, &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(trailer_infop, &max_trailer, *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
1024 kern_return_t
mach_port_set_mscount(ipc_space_t space,mach_port_name_t name,mach_port_mscount_t mscount)1025 mach_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, &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
1066 kern_return_t
mach_port_set_seqno(ipc_space_t space,mach_port_name_t name,mach_port_seqno_t seqno)1067 mach_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, &port);
1084 if (kr != KERN_SUCCESS) {
1085 return kr;
1086 }
1087 /* port is locked and active */
1088
1089 ipc_mqueue_set_seqno_locked(&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
1109 kern_return_t
mach_port_get_context(ipc_space_t space,mach_port_name_t name,mach_vm_address_t * context)1110 mach_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, &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
1144 kern_return_t
mach_port_get_context_from_user(mach_port_t port,mach_port_name_t name,mach_vm_address_t * context)1145 mach_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
1178 kern_return_t
mach_port_set_context(ipc_space_t space,mach_port_name_t name,mach_vm_address_t context)1179 mach_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, &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, context, portguard, 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
1232 kern_return_t
mach_port_get_set_status(ipc_space_t space,mach_port_name_t name,mach_port_name_t ** members,mach_msg_type_number_t * membersCnt)1233 mach_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(ipc_kernel_map, &addr, size,
1263 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, &psobj);
1269 if (kr != KERN_SUCCESS) {
1270 kmem_free(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(&pset->ips_wqset, ^(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(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(ipc_kernel_map, addr, size);
1304 } else {
1305 vm_size_t size_used;
1306 vm_size_t vm_size_used;
1307
1308 qsort((void *)addr, actual, sizeof(mach_port_name_t),
1309 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((char *)addr + size_used, 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(ipc_kernel_map, addr, addr + vm_size_used, FALSE);
1325 assert(kr == KERN_SUCCESS);
1326
1327 kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr,
1328 (vm_map_size_t)size_used, TRUE, &memory);
1329 assert(kr == KERN_SUCCESS);
1330
1331 if (vm_size_used != size) {
1332 kmem_free(ipc_kernel_map,
1333 addr + vm_size_used, size - vm_size_used);
1334 }
1335 }
1336
1337 *members = (mach_port_name_t *) memory;
1338 *membersCnt = actual;
1339 return KERN_SUCCESS;
1340 }
1341
1342 kern_return_t
mach_port_get_set_status_from_user(mach_port_t port,mach_port_name_t name,mach_port_name_t ** members,mach_msg_type_number_t * membersCnt)1343 mach_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
1384 kern_return_t
mach_port_move_member(ipc_space_t space,mach_port_name_t member,mach_port_name_t after)1385 mach_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(WQT_PORT_SET);
1411 kr = ipc_object_translate_two(space,
1412 member, MACH_PORT_RIGHT_RECEIVE, &port_obj,
1413 after, MACH_PORT_RIGHT_PORT_SET, &ps_obj);
1414 } else {
1415 kr = ipc_object_translate(space,
1416 member, MACH_PORT_RIGHT_RECEIVE, &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(&port->ip_messages, nset, &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(&port->ip_waitq, keep_waitq_set, &free_l);
1441
1442 ip_mq_unlock(port);
1443
1444 waitq_link_free_list(WQT_PORT_SET, &free_l);
1445 done:
1446 if (link.wqlh) {
1447 waitq_link_free(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 */
1460 static bool
mach_service_pd_request_notification_check(ipc_port_t service_port,ipc_port_t notify_port)1461 mach_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(service_port, &task);
1472 if (task && !proc_isinitproc(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(notify_port, &task);
1480 if (task && !proc_isinitproc(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
1551 kern_return_t
mach_port_request_notification(ipc_space_t space,mach_port_name_t name,mach_msg_id_t id,mach_port_mscount_t sync,ipc_port_t notify,ipc_port_t * previousp)1552 mach_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, &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, 0, 0, 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(port, notify)) {
1601 ip_mq_unlock(port);
1602 mach_port_guard_exception(name, 0, 0, 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, 0, 0, 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, &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, 0, 0, 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, 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
1697 kern_return_t
mach_port_insert_right(ipc_space_t space,mach_port_name_t name,ipc_port_t poly,mach_msg_type_name_t polyPoly)1698 mach_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 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
1737 kern_return_t
mach_port_extract_right(ipc_space_t space,mach_port_name_t name,mach_msg_type_name_t msgt_name,ipc_port_t * poly,mach_msg_type_name_t * polyPoly)1738 mach_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, (ipc_object_t *) poly, 0, NULL,
1765 (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 */
1784 static void
mach_port_get_status_helper(ipc_port_t port,mach_port_status_t * statusp)1785 mach_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
1825 kern_return_t
mach_port_get_attributes(ipc_space_t space,mach_port_name_t name,int flavor,mach_port_info_t info,mach_msg_type_number_t * count)1826 mach_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, &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, &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, &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(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, &port);
1927 if (kr != KERN_SUCCESS) {
1928 return kr;
1929 }
1930 /* port is locked and active */
1931 mach_port_get_status_helper(port, &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, &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
1971 kern_return_t
mach_port_get_attributes_from_user(mach_port_t port,mach_port_name_t name,int flavor,mach_port_info_t info,mach_msg_type_number_t * count)1972 mach_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
1993 kern_return_t
mach_port_set_attributes(ipc_space_t space,mach_port_name_t name,int flavor,mach_port_info_t info,mach_msg_type_number_t count)1994 mach_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, &port);
2025 if (kr != KERN_SUCCESS) {
2026 return kr;
2027 }
2028 /* port is locked and active */
2029
2030 ipc_mqueue_set_qlimit_locked(&port->ip_messages, 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, &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, &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(release_imp_task, assertcnt);
2095 }
2096 ipc_importance_task_release(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(release_imp_task)) {
2101 ipc_importance_task_drop_internal_assertion(release_imp_task, 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, &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, &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->ip_splabel, ISPL_FLAGS_THROTTLED);
2163 } else {
2164 ipc_service_port_label_clear_flag(port->ip_splabel, 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
2196 kern_return_t
mach_port_insert_member(ipc_space_t space,mach_port_name_t name,mach_port_name_t psname)2197 mach_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(WQT_PORT_SET);
2218
2219 kr = ipc_object_translate_two(space,
2220 name, MACH_PORT_RIGHT_RECEIVE, &obj,
2221 psname, MACH_PORT_RIGHT_PORT_SET, &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(&port->ip_messages, pset, &link);
2234
2235 ips_mq_unlock(pset);
2236 ip_mq_unlock(port);
2237
2238 done:
2239 if (link.wqlh) {
2240 waitq_link_free(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
2264 kern_return_t
mach_port_extract_member(ipc_space_t space,mach_port_name_t name,mach_port_name_t psname)2265 mach_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 name, MACH_PORT_RIGHT_RECEIVE, &obj,
2287 psname, MACH_PORT_RIGHT_PORT_SET, &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(&port->ip_waitq, &pset->ips_wqset);
2300
2301 ips_mq_unlock(pset);
2302 ip_mq_unlock(port);
2303
2304 if (link.wqlh) {
2305 waitq_link_free(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 */
2317 kern_return_t
task_set_port_space(ipc_space_t space,__unused int table_entries)2318 task_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 */
2339 static kern_return_t
mach_port_guard_locked(ipc_port_t port,uint64_t guard,uint64_t flags)2340 mach_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 */
2374 static kern_return_t
mach_port_unguard_locked(ipc_port_t port,mach_port_name_t name,uint64_t guard)2375 mach_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, guard, 0, 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, guard, port->ip_context, 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 */
2411 void
mach_port_guard_exception(mach_port_name_t name,__unused uint64_t inguard,uint64_t portguard,unsigned reason)2412 mach_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 */
2440 void
mach_port_guard_exception_immovable(ipc_space_t space,mach_port_name_t name,mach_port_t port,uint64_t portguard)2441 mach_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(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, 0, portguard,
2455 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, 0, portguard, 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 */
2468 void
mach_port_guard_exception_pinned(ipc_space_t space,mach_port_name_t name,__assert_only mach_port_t port,uint64_t portguard)2469 mach_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(current_task()) & TASK_CONTROL_PORT_PINNED_HARD;
2480
2481 assert(task_is_pinned(current_task()));
2482
2483 mach_port_guard_exception(name, 0, portguard,
2484 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
2498 void
mach_port_guard_ast(thread_t t,mach_exception_data_type_t code,mach_exception_data_type_t subcode)2499 mach_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(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(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_NO_SPACE No room in space for another right.
2587 * KERN_FAILURE Illegal option values requested.
2588 */
2589
2590 kern_return_t
mach_port_construct(ipc_space_t space,mach_port_options_t * options,uint64_t context,mach_port_name_t * name)2591 mach_port_construct(
2592 ipc_space_t space,
2593 mach_port_options_t *options,
2594 uint64_t context,
2595 mach_port_name_t *name)
2596 {
2597 kern_return_t kr;
2598 ipc_port_t port;
2599 ipc_port_init_flags_t init_flags = IPC_PORT_INIT_MESSAGE_QUEUE;
2600 void *port_splabel = NULL;
2601 bool filter_msgs = FALSE;
2602 struct mach_service_port_info sp_info = {};
2603 size_t sp_name_length = 0;
2604 user_addr_t service_port_info = 0;
2605
2606 uint32_t at_most_one_flags = options->flags & (MPO_SERVICE_PORT | MPO_CONNECTION_PORT | MPO_TG_BLOCK_TRACKING);
2607 if (at_most_one_flags & (at_most_one_flags - 1)) {
2608 /* at most one of the listed flags can be set */
2609 return KERN_INVALID_ARGUMENT;
2610 }
2611
2612 at_most_one_flags = options->flags & (MPO_REPLY_PORT | MPO_ENFORCE_REPLY_PORT_SEMANTICS |
2613 MPO_PROVISIONAL_ID_PROT_OPTOUT | MPO_PROVISIONAL_REPLY_PORT);
2614 if (at_most_one_flags & (at_most_one_flags - 1)) {
2615 /* at most one of the listed flags can be set */
2616 return KERN_INVALID_ARGUMENT;
2617 }
2618
2619 if (space == IS_NULL) {
2620 return KERN_INVALID_TASK;
2621 }
2622
2623 if (options->flags & MPO_INSERT_SEND_RIGHT) {
2624 init_flags |= IPC_PORT_INIT_MAKE_SEND_RIGHT;
2625 }
2626
2627 if (options->flags & MPO_FILTER_MSG) {
2628 init_flags |= IPC_PORT_INIT_FILTER_MESSAGE;
2629 }
2630
2631 if (options->flags & MPO_REPLY_PORT) {
2632 init_flags |= IPC_PORT_INIT_REPLY;
2633 }
2634
2635 if (options->flags & MPO_ENFORCE_REPLY_PORT_SEMANTICS) {
2636 init_flags |= IPC_PORT_ENFORCE_REPLY_PORT_SEMANTICS;
2637 }
2638
2639 if (options->flags & MPO_PROVISIONAL_ID_PROT_OPTOUT) {
2640 init_flags |= IPC_PORT_INIT_PROVISIONAL_ID_PROT_OPTOUT;
2641 }
2642
2643 if (options->flags & MPO_PROVISIONAL_REPLY_PORT) {
2644 if (provisional_reply_port_enforced) {
2645 init_flags |= IPC_PORT_INIT_REPLY;
2646 } else {
2647 init_flags |= IPC_PORT_INIT_PROVISIONAL_REPLY;
2648 }
2649 }
2650
2651 if (options->flags & MPO_TG_BLOCK_TRACKING) {
2652 /* Check the task role to allow only TASK_GRAPHICS_SERVER to set this option */
2653 if (proc_get_effective_task_policy(current_task(),
2654 TASK_POLICY_ROLE) != TASK_GRAPHICS_SERVER) {
2655 return KERN_DENIED;
2656 }
2657
2658 /*
2659 * Check the work interval port passed in to make sure it is the render server type.
2660 * Since the creation of the render server work interval is privileged, this check
2661 * acts as a guard to make sure only the render server is setting the thread group
2662 * blocking behavior on the port.
2663 */
2664 mach_port_name_t wi_port_name = options->work_interval_port;
2665 if (work_interval_port_type_render_server(wi_port_name) == false) {
2666 return KERN_INVALID_ARGUMENT;
2667 }
2668 init_flags |= IPC_PORT_INIT_TG_BLOCK_TRACKING;
2669 }
2670
2671 if (options->flags & MPO_SERVICE_PORT) {
2672 #if !(DEVELOPMENT || DEBUG)
2673 #if CONFIG_COALITIONS
2674 /*
2675 * Allow only launchd to add the service port labels
2676 * Not enforcing on development/debug kernels to
2677 * support testing
2678 */
2679 if (!task_is_in_privileged_coalition(current_task(), COALITION_TYPE_JETSAM)) {
2680 return KERN_DENIED;
2681 }
2682 #else /* CONFIG_COALITIONS */
2683 /*
2684 * This flag is not used by launchd on simulators
2685 */
2686 if (proc_isinitproc(get_bsdtask_info(current_task()))) {
2687 return KERN_DENIED;
2688 }
2689 #endif /* CONFIG_COALITIONS */
2690 #endif /* !(DEVELOPMENT || DEBUG) */
2691
2692 if (task_has_64Bit_addr(current_task())) {
2693 service_port_info = CAST_USER_ADDR_T(options->service_port_info64);
2694 } else {
2695 service_port_info = CAST_USER_ADDR_T(options->service_port_info32);
2696 }
2697
2698 if (!service_port_info) {
2699 return KERN_INVALID_ARGUMENT;
2700 }
2701
2702 if (copyin(service_port_info, (void *)&sp_info, sizeof(sp_info))) {
2703 return KERN_MEMORY_ERROR;
2704 }
2705
2706 sp_name_length = strnlen(sp_info.mspi_string_name, MACH_SERVICE_PORT_INFO_STRING_NAME_MAX_BUF_LEN);
2707 if (sp_name_length >= (MACH_SERVICE_PORT_INFO_STRING_NAME_MAX_BUF_LEN)) {
2708 return KERN_INVALID_ARGUMENT;
2709 }
2710
2711 kr = ipc_service_port_label_alloc(&sp_info, &port_splabel);
2712 if (kr != KERN_SUCCESS) {
2713 return kr;
2714 }
2715 /* Always filter messages on service ports */
2716 init_flags |= IPC_PORT_INIT_FILTER_MESSAGE;
2717 }
2718
2719 if (options->flags & MPO_CONNECTION_PORT) {
2720 if (!options->service_port_name) {
2721 return KERN_INVALID_ARGUMENT;
2722 }
2723
2724 kr = ipc_service_port_derive_sblabel(options->service_port_name, &port_splabel, &filter_msgs);
2725 if (kr != KERN_SUCCESS) {
2726 return kr;
2727 }
2728 if (filter_msgs) {
2729 init_flags |= IPC_PORT_INIT_FILTER_MESSAGE;
2730 }
2731 }
2732
2733
2734 /* Allocate a new port in the IPC space */
2735 kr = ipc_port_alloc(space, init_flags, name, &port);
2736 if (kr != KERN_SUCCESS) {
2737 if (port_splabel != NULL) {
2738 ipc_service_port_label_dealloc(port_splabel,
2739 (options->flags & MPO_SERVICE_PORT));
2740 }
2741 return kr;
2742 }
2743
2744 /* Port locked and active */
2745 if (port_splabel != NULL) {
2746 port->ip_service_port = (bool)(options->flags & MPO_SERVICE_PORT);
2747 port->ip_splabel = port_splabel;
2748
2749 /* Check if this is a service port */
2750 if (service_port_defense_enabled && port->ip_service_port) {
2751 port->ip_immovable_receive = true;
2752 }
2753
2754 /* Check if this is a libxpc connection port */
2755 if (!port->ip_service_port) {
2756 assert(options->flags & MPO_CONNECTION_PORT);
2757 port->ip_immovable_send = true;
2758 port->ip_immovable_receive = true;
2759 }
2760 }
2761
2762 if (options->flags & MPO_CONTEXT_AS_GUARD) {
2763 uint64_t flags = 0;
2764 if (options->flags & MPO_STRICT) {
2765 flags |= MPG_STRICT;
2766 }
2767 if (options->flags & MPO_IMMOVABLE_RECEIVE) {
2768 flags |= MPG_IMMOVABLE_RECEIVE;
2769 }
2770 kr = mach_port_guard_locked(port, context, flags);
2771 /* A newly allocated and locked port should always be guarded successfully */
2772 assert(kr == KERN_SUCCESS);
2773 if (options->flags & MPO_SERVICE_PORT) {
2774 /*
2775 * Setting the guard on a service port triggers a special port destroyed notification
2776 * that restores the guard when the receive right moves back to launchd. This
2777 * must be a strict guard.
2778 */
2779 assert((options->flags & MPO_STRICT) == MPO_STRICT);
2780 ipc_service_port_label_set_attr(port_splabel, *name, (mach_port_context_t)context);
2781 }
2782 } else {
2783 port->ip_context = context;
2784 if (options->flags & MPO_SERVICE_PORT) {
2785 ipc_service_port_label_set_attr(port_splabel, *name, 0);
2786 }
2787 }
2788
2789 /* Unlock port */
2790 ip_mq_unlock(port);
2791
2792 /* Set port attributes as requested */
2793
2794 if (options->flags & MPO_QLIMIT) {
2795 kr = mach_port_set_attributes(space, *name, MACH_PORT_LIMITS_INFO,
2796 (mach_port_info_t)&options->mpl, sizeof(options->mpl) / sizeof(int));
2797 if (kr != KERN_SUCCESS) {
2798 goto cleanup;
2799 }
2800 }
2801
2802 if (options->flags & MPO_TEMPOWNER) {
2803 kr = mach_port_set_attributes(space, *name, MACH_PORT_TEMPOWNER, NULL, 0);
2804 if (kr != KERN_SUCCESS) {
2805 goto cleanup;
2806 }
2807 }
2808
2809 if (options->flags & MPO_IMPORTANCE_RECEIVER) {
2810 kr = mach_port_set_attributes(space, *name, MACH_PORT_IMPORTANCE_RECEIVER, NULL, 0);
2811 if (kr != KERN_SUCCESS) {
2812 goto cleanup;
2813 }
2814 }
2815
2816 if (options->flags & MPO_DENAP_RECEIVER) {
2817 kr = mach_port_set_attributes(space, *name, MACH_PORT_DENAP_RECEIVER, NULL, 0);
2818 if (kr != KERN_SUCCESS) {
2819 goto cleanup;
2820 }
2821 }
2822
2823 return KERN_SUCCESS;
2824
2825 cleanup:
2826 /* Attempt to destroy port. If its already destroyed by some other thread, we're done */
2827 (void) mach_port_destruct(space, *name,
2828 (options->flags & MPO_INSERT_SEND_RIGHT) ? -1 : 0, context);
2829 return kr;
2830 }
2831
2832 /*
2833 * Routine: mach_port_destruct [kernel call]
2834 * Purpose:
2835 * Destroys a mach port with appropriate guard
2836 * Conditions:
2837 * None.
2838 * Returns:
2839 * KERN_SUCCESS The name is destroyed.
2840 * KERN_INVALID_TASK The space is null.
2841 * KERN_INVALID_TASK The space is dead.
2842 * KERN_INVALID_NAME The name doesn't denote a right.
2843 * KERN_INVALID_RIGHT The right isn't correct.
2844 * KERN_INVALID_VALUE The delta for send right is incorrect.
2845 * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch.
2846 * This also raises a EXC_GUARD exception.
2847 */
2848
2849 kern_return_t
mach_port_destruct(ipc_space_t space,mach_port_name_t name,mach_port_delta_t srdelta,uint64_t guard)2850 mach_port_destruct(
2851 ipc_space_t space,
2852 mach_port_name_t name,
2853 mach_port_delta_t srdelta,
2854 uint64_t guard)
2855 {
2856 kern_return_t kr;
2857 ipc_entry_t entry;
2858
2859 if (space == IS_NULL) {
2860 return KERN_INVALID_TASK;
2861 }
2862
2863 if (!MACH_PORT_VALID(name)) {
2864 return KERN_INVALID_NAME;
2865 }
2866
2867 /* Remove reference for receive right */
2868 kr = ipc_right_lookup_write(space, name, &entry);
2869 if (kr != KERN_SUCCESS) {
2870 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_NAME);
2871 return kr;
2872 }
2873 /* space is write-locked and active */
2874 kr = ipc_right_destruct(space, name, entry, srdelta, guard); /* unlocks */
2875
2876 return kr;
2877 }
2878
2879 /*
2880 * Routine: mach_port_guard [kernel call]
2881 * Purpose:
2882 * Guard a mach port with specified guard value.
2883 * The context field of the port is used as the guard.
2884 * Conditions:
2885 * None.
2886 * Returns:
2887 * KERN_SUCCESS The name is destroyed.
2888 * KERN_INVALID_TASK The space is null.
2889 * KERN_INVALID_TASK The space is dead.
2890 * KERN_INVALID_NAME The name doesn't denote a right.
2891 * KERN_INVALID_RIGHT The right isn't correct.
2892 * KERN_INVALID_ARGUMENT Port already contains a context/guard.
2893 */
2894 kern_return_t
mach_port_guard(ipc_space_t space,mach_port_name_t name,uint64_t guard,boolean_t strict)2895 mach_port_guard(
2896 ipc_space_t space,
2897 mach_port_name_t name,
2898 uint64_t guard,
2899 boolean_t strict)
2900 {
2901 kern_return_t kr;
2902 ipc_port_t port;
2903 uint64_t flags = 0;
2904
2905 if (space == IS_NULL) {
2906 return KERN_INVALID_TASK;
2907 }
2908
2909 if (!MACH_PORT_VALID(name)) {
2910 return KERN_INVALID_NAME;
2911 }
2912
2913 /* Guard can be applied only to receive rights */
2914 kr = ipc_port_translate_receive(space, name, &port);
2915 if (kr != KERN_SUCCESS) {
2916 mach_port_guard_exception(name, 0, 0,
2917 ((KERN_INVALID_NAME == kr) ?
2918 kGUARD_EXC_INVALID_NAME :
2919 kGUARD_EXC_INVALID_RIGHT));
2920 return kr;
2921 }
2922
2923 /* Port locked and active */
2924 if (strict) {
2925 flags = MPG_STRICT;
2926 }
2927
2928 kr = mach_port_guard_locked(port, guard, flags);
2929 ip_mq_unlock(port);
2930
2931 if (KERN_INVALID_ARGUMENT == kr) {
2932 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_ARGUMENT);
2933 }
2934
2935 return kr;
2936 }
2937
2938 /*
2939 * Routine: mach_port_unguard [kernel call]
2940 * Purpose:
2941 * Unguard a mach port with specified guard value.
2942 * Conditions:
2943 * None.
2944 * Returns:
2945 * KERN_SUCCESS The name is destroyed.
2946 * KERN_INVALID_TASK The space is null.
2947 * KERN_INVALID_TASK The space is dead.
2948 * KERN_INVALID_NAME The name doesn't denote a right.
2949 * KERN_INVALID_RIGHT The right isn't correct.
2950 * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch.
2951 * This also raises a EXC_GUARD exception.
2952 */
2953 kern_return_t
mach_port_unguard(ipc_space_t space,mach_port_name_t name,uint64_t guard)2954 mach_port_unguard(
2955 ipc_space_t space,
2956 mach_port_name_t name,
2957 uint64_t guard)
2958 {
2959 kern_return_t kr;
2960 ipc_port_t port;
2961
2962 if (space == IS_NULL) {
2963 return KERN_INVALID_TASK;
2964 }
2965
2966 if (!MACH_PORT_VALID(name)) {
2967 return KERN_INVALID_NAME;
2968 }
2969
2970 kr = ipc_port_translate_receive(space, name, &port);
2971 if (kr != KERN_SUCCESS) {
2972 mach_port_guard_exception(name, 0, 0,
2973 ((KERN_INVALID_NAME == kr) ?
2974 kGUARD_EXC_INVALID_NAME :
2975 kGUARD_EXC_INVALID_RIGHT));
2976 return kr;
2977 }
2978
2979 /* Port locked and active */
2980 kr = mach_port_unguard_locked(port, name, guard);
2981 ip_mq_unlock(port);
2982
2983 return kr;
2984 }
2985
2986 /*
2987 * Routine: mach_port_guard_with_flags [kernel call]
2988 * Purpose:
2989 * Guard a mach port with specified guard value and guard flags.
2990 * The context field of the port is used as the guard.
2991 * Conditions:
2992 * Should hold receive right for that port
2993 * Returns:
2994 * KERN_SUCCESS The name is destroyed.
2995 * KERN_INVALID_TASK The space is null.
2996 * KERN_INVALID_TASK The space is dead.
2997 * KERN_INVALID_NAME The name doesn't denote a right.
2998 * KERN_INVALID_RIGHT The right isn't correct.
2999 * KERN_INVALID_ARGUMENT Port already contains a context/guard.
3000 * KERN_INVALID_CAPABILITY Cannot set MPG_IMMOVABLE_RECEIVE flag for a port with
3001 * a movable port-destroyed notification port
3002 */
3003 kern_return_t
mach_port_guard_with_flags(ipc_space_t space,mach_port_name_t name,uint64_t guard,uint64_t flags)3004 mach_port_guard_with_flags(
3005 ipc_space_t space,
3006 mach_port_name_t name,
3007 uint64_t guard,
3008 uint64_t flags)
3009 {
3010 kern_return_t kr;
3011 ipc_port_t port;
3012
3013 if (space == IS_NULL) {
3014 return KERN_INVALID_TASK;
3015 }
3016
3017 if (!MACH_PORT_VALID(name)) {
3018 return KERN_INVALID_NAME;
3019 }
3020
3021 kr = ipc_port_translate_receive(space, name, &port);
3022 if (kr != KERN_SUCCESS) {
3023 mach_port_guard_exception(name, 0, 0,
3024 ((KERN_INVALID_NAME == kr) ?
3025 kGUARD_EXC_INVALID_NAME :
3026 kGUARD_EXC_INVALID_RIGHT));
3027 return kr;
3028 }
3029
3030 /* Port locked and active */
3031 kr = mach_port_guard_locked(port, guard, flags);
3032 ip_mq_unlock(port);
3033
3034 if (KERN_INVALID_ARGUMENT == kr) {
3035 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_ARGUMENT);
3036 }
3037
3038 return kr;
3039 }
3040
3041 /*
3042 * Routine: mach_port_swap_guard [kernel call]
3043 * Purpose:
3044 * Swap guard value.
3045 * Conditions:
3046 * Port should already be guarded.
3047 * Returns:
3048 * KERN_SUCCESS The name is destroyed.
3049 * KERN_INVALID_TASK The space is null.
3050 * KERN_INVALID_TASK The space is dead.
3051 * KERN_INVALID_NAME The name doesn't denote a right.
3052 * KERN_INVALID_RIGHT The right isn't correct.
3053 * KERN_INVALID_ARGUMENT Port doesn't contain a guard; is strictly guarded
3054 * or the old_guard doesnt match the context
3055 */
3056 kern_return_t
mach_port_swap_guard(ipc_space_t space,mach_port_name_t name,uint64_t old_guard,uint64_t new_guard)3057 mach_port_swap_guard(
3058 ipc_space_t space,
3059 mach_port_name_t name,
3060 uint64_t old_guard,
3061 uint64_t new_guard)
3062 {
3063 kern_return_t kr;
3064 ipc_port_t port;
3065
3066 if (space == IS_NULL) {
3067 return KERN_INVALID_TASK;
3068 }
3069
3070 if (!MACH_PORT_VALID(name)) {
3071 return KERN_INVALID_NAME;
3072 }
3073
3074 kr = ipc_port_translate_receive(space, name, &port);
3075 if (kr != KERN_SUCCESS) {
3076 mach_port_guard_exception(name, 0, 0,
3077 ((KERN_INVALID_NAME == kr) ?
3078 kGUARD_EXC_INVALID_NAME :
3079 kGUARD_EXC_INVALID_RIGHT));
3080 return kr;
3081 }
3082
3083 /* Port locked and active */
3084 if (!port->ip_guarded) {
3085 ip_mq_unlock(port);
3086 mach_port_guard_exception(name, old_guard, 0, kGUARD_EXC_UNGUARDED);
3087 return KERN_INVALID_ARGUMENT;
3088 }
3089
3090 if (port->ip_strict_guard) {
3091 uint64_t portguard = port->ip_context;
3092 ip_mq_unlock(port);
3093 /* For strictly guarded ports, disallow overwriting context; Raise Exception */
3094 mach_port_guard_exception(name, old_guard, portguard, kGUARD_EXC_SET_CONTEXT);
3095 return KERN_INVALID_ARGUMENT;
3096 }
3097
3098 if (port->ip_context != old_guard) {
3099 uint64_t portguard = port->ip_context;
3100 ip_mq_unlock(port);
3101 mach_port_guard_exception(name, old_guard, portguard, kGUARD_EXC_INCORRECT_GUARD);
3102 return KERN_INVALID_ARGUMENT;
3103 }
3104
3105 port->ip_context = new_guard;
3106
3107 ip_mq_unlock(port);
3108
3109 return KERN_SUCCESS;
3110 }
3111
3112 kern_return_t
mach_port_is_connection_for_service(ipc_space_t space,mach_port_name_t connection_port_name,mach_port_name_t service_port_name,uint64_t * filter_policy_id)3113 mach_port_is_connection_for_service(
3114 ipc_space_t space,
3115 mach_port_name_t connection_port_name,
3116 mach_port_name_t service_port_name,
3117 uint64_t *filter_policy_id)
3118 {
3119 mach_port_t service_port;
3120 mach_port_t connection_port;
3121 void *service_port_sblabel = NULL;
3122 void *conn_port_sblabel = NULL;
3123
3124 kern_return_t ret;
3125
3126 if (space == IS_NULL) {
3127 return KERN_INVALID_TASK;
3128 }
3129
3130 if (!MACH_PORT_VALID(connection_port_name) || !MACH_PORT_VALID(service_port_name)) {
3131 return KERN_INVALID_NAME;
3132 }
3133
3134 if (!filter_policy_id) {
3135 return KERN_INVALID_ARGUMENT;
3136 }
3137
3138 if (!mach_msg_filter_at_least(MACH_MSG_FILTER_CALLBACKS_VERSION_1)) {
3139 return KERN_NOT_SUPPORTED;
3140 }
3141
3142 ret = ipc_port_translate_receive(space, service_port_name, &service_port);
3143 if (ret) {
3144 return ret;
3145 }
3146
3147 if (!service_port->ip_service_port) {
3148 ip_mq_unlock(service_port);
3149 return KERN_INVALID_CAPABILITY;
3150 }
3151
3152 /* Port is locked and active */
3153 service_port_sblabel = ipc_service_port_get_sblabel(service_port);
3154 if (service_port_sblabel) {
3155 mach_msg_filter_retain_sblabel_callback(service_port_sblabel);
3156 }
3157 ip_mq_unlock(service_port);
3158
3159 if (!service_port_sblabel) {
3160 /* Nothing to check */
3161 *filter_policy_id = 0;
3162 return KERN_SUCCESS;
3163 }
3164
3165 ret = ipc_port_translate_receive(space, connection_port_name, &connection_port);
3166 if (ret) {
3167 mach_msg_filter_dealloc_service_port_sblabel_callback(service_port_sblabel);
3168 return ret;
3169 }
3170 /* Port is locked and active */
3171 conn_port_sblabel = ipc_service_port_get_sblabel(connection_port);
3172 if (conn_port_sblabel) {
3173 mach_msg_filter_retain_sblabel_callback(conn_port_sblabel);
3174 }
3175 ip_mq_unlock(connection_port);
3176
3177 /* This callback will release the sblabel references */
3178 ret = mach_msg_filter_get_connection_port_filter_policy_callback(service_port_sblabel,
3179 conn_port_sblabel, filter_policy_id);
3180
3181 return ret;
3182 }
3183
3184 #if CONFIG_SERVICE_PORT_INFO
3185 kern_return_t
mach_port_get_service_port_info(ipc_space_read_t space,mach_port_name_t name,mach_service_port_info_t sp_info)3186 mach_port_get_service_port_info(
3187 ipc_space_read_t space,
3188 mach_port_name_t name,
3189 mach_service_port_info_t sp_info)
3190 {
3191 ipc_port_t port;
3192 kern_return_t kr;
3193
3194 if (space == IS_NULL) {
3195 return KERN_INVALID_TASK;
3196 }
3197
3198 if (sp_info == NULL) {
3199 return KERN_INVALID_ARGUMENT;
3200 }
3201
3202 if (!MACH_PORT_VALID(name)) {
3203 return KERN_INVALID_RIGHT;
3204 }
3205
3206 kr = ipc_port_translate_receive(space, name, &port);
3207 if (kr != KERN_SUCCESS) {
3208 return kr;
3209 }
3210 /* port is locked and active */
3211
3212 if (!port->ip_service_port) {
3213 ip_mq_unlock(port);
3214 return KERN_INVALID_CAPABILITY;
3215 }
3216
3217 assert(port->ip_splabel != NULL);
3218 ipc_service_port_label_get_info((ipc_service_port_label_t)port->ip_splabel, sp_info);
3219 ip_mq_unlock(port);
3220
3221 return KERN_SUCCESS;
3222 }
3223
3224 #else /* CONFIG_SERVICE_PORT_INFO */
3225
3226 kern_return_t
mach_port_get_service_port_info(__unused ipc_space_read_t space,__unused mach_port_name_t name,__unused mach_service_port_info_t sp_info)3227 mach_port_get_service_port_info(
3228 __unused ipc_space_read_t space,
3229 __unused mach_port_name_t name,
3230 __unused mach_service_port_info_t sp_info)
3231 {
3232 return KERN_NOT_SUPPORTED;
3233 }
3234 #endif /* CONFIG_SERVICE_PORT_INFO */
3235
3236 kern_return_t
mach_port_assert_attributes(ipc_space_t space,mach_port_name_t name,int flavor,mach_port_info_t info,mach_msg_type_number_t count)3237 mach_port_assert_attributes(
3238 ipc_space_t space,
3239 mach_port_name_t name,
3240 int flavor,
3241 mach_port_info_t info,
3242 mach_msg_type_number_t count)
3243 {
3244 ipc_port_t port;
3245 kern_return_t kr;
3246
3247 if (space == IS_NULL) {
3248 return KERN_INVALID_TASK;
3249 }
3250
3251 switch (flavor) {
3252 case MACH_PORT_GUARD_INFO: {
3253 mach_port_guard_info_t *mpgi = (mach_port_guard_info_t *)(void *)info;
3254
3255 if (count < MACH_PORT_GUARD_INFO_COUNT) {
3256 return KERN_FAILURE;
3257 }
3258
3259 if (!MACH_PORT_VALID(name)) {
3260 return KERN_INVALID_RIGHT;
3261 }
3262
3263 kr = ipc_port_translate_receive(space, name, &port);
3264 if (kr != KERN_SUCCESS) {
3265 return kr;
3266 }
3267 /* port is locked and active */
3268
3269 /* Check if guard value matches else kill the process using fatal guard exception */
3270 if (!port->ip_guarded) {
3271 ip_mq_unlock(port);
3272 /* Port already unguarded; Raise exception */
3273 mach_port_guard_exception(name, mpgi->mpgi_guard, 0, kGUARD_EXC_UNGUARDED);
3274 return KERN_INVALID_ARGUMENT;
3275 }
3276
3277 if (!port->ip_strict_guard || (port->ip_context != mpgi->mpgi_guard)) {
3278 ip_mq_unlock(port);
3279 /* Incorrect guard; Raise exception */
3280 mach_port_guard_exception(name, mpgi->mpgi_guard, port->ip_context, kGUARD_EXC_INCORRECT_GUARD);
3281 return KERN_INVALID_ARGUMENT;
3282 }
3283
3284 ip_mq_unlock(port);
3285 break;
3286 }
3287 default:
3288 return KERN_INVALID_ARGUMENT;
3289 }
3290 return KERN_SUCCESS;
3291 }
3292