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