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