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