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