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