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