]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ipc/mach_port.c
xnu-6153.61.1.tar.gz
[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, IPC_PORT_INIT_MESSAGE_QUEUE,
729 *namep, &port);
730 } else {
731 kr = ipc_port_alloc(space, IPC_PORT_INIT_MESSAGE_QUEUE,
732 namep, &port);
733 }
734 if (kr == KERN_SUCCESS) {
735 if (kmsg != IKM_NULL) {
736 ipc_kmsg_set_prealloc(kmsg, port);
737 }
738 ip_unlock(port);
739 } else if (kmsg != IKM_NULL) {
740 ipc_kmsg_free(kmsg);
741 }
742 break;
743 }
744
745 case MACH_PORT_RIGHT_PORT_SET:
746 {
747 ipc_pset_t pset;
748
749 if (qosp->name) {
750 kr = ipc_pset_alloc_name(space, *namep, &pset);
751 } else {
752 kr = ipc_pset_alloc(space, namep, &pset);
753 }
754 if (kr == KERN_SUCCESS) {
755 ips_unlock(pset);
756 }
757 break;
758 }
759
760 case MACH_PORT_RIGHT_DEAD_NAME:
761 kr = ipc_object_alloc_dead(space, namep);
762 break;
763
764 default:
765 kr = KERN_INVALID_VALUE;
766 break;
767 }
768
769 return kr;
770 }
771
772 /*
773 * Routine: mach_port_destroy [kernel call]
774 * Purpose:
775 * Cleans up and destroys all rights denoted by a name
776 * in a space. The destruction of a receive right
777 * destroys the port, unless a port-destroyed request
778 * has been made for it; the destruction of a port-set right
779 * destroys the port set.
780 * Conditions:
781 * Nothing locked.
782 * Returns:
783 * KERN_SUCCESS The name is destroyed.
784 * KERN_INVALID_TASK The space is null.
785 * KERN_INVALID_TASK The space is dead.
786 * KERN_INVALID_NAME The name doesn't denote a right.
787 */
788
789 kern_return_t
790 mach_port_destroy(
791 ipc_space_t space,
792 mach_port_name_t name)
793 {
794 ipc_entry_t entry;
795 kern_return_t kr;
796
797 if (space == IS_NULL) {
798 return KERN_INVALID_TASK;
799 }
800
801 if (!MACH_PORT_VALID(name)) {
802 return KERN_SUCCESS;
803 }
804
805 kr = ipc_right_lookup_write(space, name, &entry);
806 if (kr != KERN_SUCCESS) {
807 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_NAME);
808 return kr;
809 }
810 /* space is write-locked and active */
811
812 kr = ipc_right_destroy(space, name, entry, TRUE, 0); /* unlocks space */
813 return kr;
814 }
815
816 /*
817 * Routine: mach_port_deallocate [kernel call]
818 * Purpose:
819 * Deallocates a user reference from a send right,
820 * send-once right, dead-name right or a port_set right.
821 * May deallocate the right, if this is the last uref,
822 * and destroy the name, if it doesn't denote
823 * other rights.
824 * Conditions:
825 * Nothing locked.
826 * Returns:
827 * KERN_SUCCESS The uref is deallocated.
828 * KERN_INVALID_TASK The space is null.
829 * KERN_INVALID_TASK The space is dead.
830 * KERN_INVALID_NAME The name doesn't denote a right.
831 * KERN_INVALID_RIGHT The right isn't correct.
832 */
833
834 kern_return_t
835 mach_port_deallocate(
836 ipc_space_t space,
837 mach_port_name_t name)
838 {
839 ipc_entry_t entry;
840 kern_return_t kr;
841
842 if (space == IS_NULL) {
843 return KERN_INVALID_TASK;
844 }
845
846 if (!MACH_PORT_VALID(name)) {
847 return KERN_SUCCESS;
848 }
849
850 kr = ipc_right_lookup_write(space, name, &entry);
851 if (kr != KERN_SUCCESS) {
852 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_NAME);
853 return kr;
854 }
855 /* space is write-locked */
856
857 kr = ipc_right_dealloc(space, name, entry); /* unlocks space */
858 return kr;
859 }
860
861 /*
862 * Routine: mach_port_get_refs [kernel call]
863 * Purpose:
864 * Retrieves the number of user references held by a right.
865 * Receive rights, port-set rights, and send-once rights
866 * always have one user reference. Returns zero if the
867 * name denotes a right, but not the queried right.
868 * Conditions:
869 * Nothing locked.
870 * Returns:
871 * KERN_SUCCESS Number of urefs returned.
872 * KERN_INVALID_TASK The space is null.
873 * KERN_INVALID_TASK The space is dead.
874 * KERN_INVALID_VALUE "right" isn't a legal value.
875 * KERN_INVALID_NAME The name doesn't denote a right.
876 */
877
878 kern_return_t
879 mach_port_get_refs(
880 ipc_space_t space,
881 mach_port_name_t name,
882 mach_port_right_t right,
883 mach_port_urefs_t *urefsp)
884 {
885 mach_port_type_t type;
886 mach_port_urefs_t urefs;
887 ipc_entry_t entry;
888 kern_return_t kr;
889
890 if (space == IS_NULL) {
891 return KERN_INVALID_TASK;
892 }
893
894 if (right >= MACH_PORT_RIGHT_NUMBER) {
895 return KERN_INVALID_VALUE;
896 }
897
898 if (!MACH_PORT_VALID(name)) {
899 if (right == MACH_PORT_RIGHT_SEND ||
900 right == MACH_PORT_RIGHT_SEND_ONCE) {
901 *urefsp = 1;
902 return KERN_SUCCESS;
903 }
904 return KERN_INVALID_NAME;
905 }
906
907 kr = ipc_right_lookup_write(space, name, &entry);
908 if (kr != KERN_SUCCESS) {
909 return kr;
910 }
911
912 /* space is write-locked and active */
913 kr = ipc_right_info(space, name, entry, &type, &urefs);
914 /* space is unlocked */
915
916 if (kr != KERN_SUCCESS) {
917 return kr;
918 }
919
920 if (type & MACH_PORT_TYPE(right)) {
921 switch (right) {
922 case MACH_PORT_RIGHT_SEND_ONCE:
923 assert(urefs == 1);
924 /* fall-through */
925
926 case MACH_PORT_RIGHT_PORT_SET:
927 case MACH_PORT_RIGHT_RECEIVE:
928 *urefsp = 1;
929 break;
930
931 case MACH_PORT_RIGHT_DEAD_NAME:
932 case MACH_PORT_RIGHT_SEND:
933 assert(urefs > 0);
934 *urefsp = urefs;
935 break;
936
937 default:
938 panic("mach_port_get_refs: strange rights");
939 }
940 } else {
941 *urefsp = 0;
942 }
943
944 return kr;
945 }
946
947 /*
948 * Routine: mach_port_mod_refs
949 * Purpose:
950 * Modifies the number of user references held by a right.
951 * The resulting number of user references must be non-negative.
952 * If it is zero, the right is deallocated. If the name
953 * doesn't denote other rights, it is destroyed.
954 * Conditions:
955 * Nothing locked.
956 * Returns:
957 * KERN_SUCCESS Modified number of urefs.
958 * KERN_INVALID_TASK The space is null.
959 * KERN_INVALID_TASK The space is dead.
960 * KERN_INVALID_VALUE "right" isn't a legal value.
961 * KERN_INVALID_NAME The name doesn't denote a right.
962 * KERN_INVALID_RIGHT Name doesn't denote specified right.
963 * KERN_INVALID_VALUE Impossible modification to urefs.
964 * KERN_UREFS_OVERFLOW Urefs would overflow.
965 */
966
967 kern_return_t
968 mach_port_mod_refs(
969 ipc_space_t space,
970 mach_port_name_t name,
971 mach_port_right_t right,
972 mach_port_delta_t delta)
973 {
974 ipc_entry_t entry;
975 kern_return_t kr;
976
977 if (space == IS_NULL) {
978 return KERN_INVALID_TASK;
979 }
980
981 if (right >= MACH_PORT_RIGHT_NUMBER) {
982 return KERN_INVALID_VALUE;
983 }
984
985 if (!MACH_PORT_VALID(name)) {
986 if (right == MACH_PORT_RIGHT_SEND ||
987 right == MACH_PORT_RIGHT_SEND_ONCE) {
988 return KERN_SUCCESS;
989 }
990 return KERN_INVALID_NAME;
991 }
992
993 kr = ipc_right_lookup_write(space, name, &entry);
994 if (kr != KERN_SUCCESS) {
995 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_NAME);
996 return kr;
997 }
998
999 /* space is write-locked and active */
1000
1001 kr = ipc_right_delta(space, name, entry, right, delta); /* unlocks */
1002 return kr;
1003 }
1004
1005
1006 /*
1007 * Routine: mach_port_peek [kernel call]
1008 * Purpose:
1009 * Peek at the message queue for the specified receive
1010 * right and return info about a message in the queue.
1011 *
1012 * On input, seqnop points to a sequence number value
1013 * to match the message being peeked. If zero is specified
1014 * as the seqno, the first message in the queue will be
1015 * peeked.
1016 *
1017 * Only the following trailer types are currently supported:
1018 * MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)
1019 *
1020 * or'ed with one of these element types:
1021 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_NULL)
1022 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SEQNO)
1023 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER)
1024 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT)
1025 *
1026 * On input, the value pointed to by trailer_sizep must be
1027 * large enough to hold the requested trailer size.
1028 *
1029 * The message sequence number, id, size, requested trailer info
1030 * and requested trailer size are returned in their respective
1031 * output parameters upon success.
1032 *
1033 * Conditions:
1034 * Nothing locked.
1035 * Returns:
1036 * KERN_SUCCESS Matching message found, out parameters set.
1037 * KERN_INVALID_TASK The space is null or dead.
1038 * KERN_INVALID_NAME The name doesn't denote a right.
1039 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1040 * KERN_INVALID_VALUE The input parameter values are out of bounds.
1041 * KERN_FAILURE The requested message was not found.
1042 */
1043
1044 kern_return_t
1045 mach_port_peek(
1046 ipc_space_t space,
1047 mach_port_name_t name,
1048 mach_msg_trailer_type_t trailer_type,
1049 mach_port_seqno_t *seqnop,
1050 mach_msg_size_t *msg_sizep,
1051 mach_msg_id_t *msg_idp,
1052 mach_msg_trailer_info_t trailer_infop,
1053 mach_msg_type_number_t *trailer_sizep)
1054 {
1055 ipc_port_t port;
1056 kern_return_t kr;
1057 boolean_t found;
1058 mach_msg_max_trailer_t max_trailer;
1059
1060 if (space == IS_NULL) {
1061 return KERN_INVALID_TASK;
1062 }
1063
1064 if (!MACH_PORT_VALID(name)) {
1065 return KERN_INVALID_RIGHT;
1066 }
1067
1068 /*
1069 * We don't allow anything greater than the audit trailer - to avoid
1070 * leaking the context pointer and to avoid variable-sized context issues.
1071 */
1072 if (GET_RCV_ELEMENTS(trailer_type) > MACH_RCV_TRAILER_AUDIT ||
1073 REQUESTED_TRAILER_SIZE(TRUE, trailer_type) > *trailer_sizep) {
1074 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_VALUE);
1075 return KERN_INVALID_VALUE;
1076 }
1077
1078 *trailer_sizep = REQUESTED_TRAILER_SIZE(TRUE, trailer_type);
1079
1080 kr = ipc_port_translate_receive(space, name, &port);
1081 if (kr != KERN_SUCCESS) {
1082 mach_port_guard_exception(name, 0, 0,
1083 ((KERN_INVALID_NAME == kr) ?
1084 kGUARD_EXC_INVALID_NAME :
1085 kGUARD_EXC_INVALID_RIGHT));
1086 return kr;
1087 }
1088
1089 /* Port locked and active */
1090
1091 found = ipc_mqueue_peek(&port->ip_messages, seqnop,
1092 msg_sizep, msg_idp, &max_trailer, NULL);
1093 ip_unlock(port);
1094
1095 if (found != TRUE) {
1096 return KERN_FAILURE;
1097 }
1098
1099 max_trailer.msgh_seqno = *seqnop;
1100 memcpy(trailer_infop, &max_trailer, *trailer_sizep);
1101
1102 return KERN_SUCCESS;
1103 }
1104
1105 /*
1106 * Routine: mach_port_set_mscount [kernel call]
1107 * Purpose:
1108 * Changes a receive right's make-send count.
1109 * Conditions:
1110 * Nothing locked.
1111 * Returns:
1112 * KERN_SUCCESS Set make-send count.
1113 * KERN_INVALID_TASK The space is null.
1114 * KERN_INVALID_TASK The space is dead.
1115 * KERN_INVALID_NAME The name doesn't denote a right.
1116 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1117 */
1118
1119 kern_return_t
1120 mach_port_set_mscount(
1121 ipc_space_t space,
1122 mach_port_name_t name,
1123 mach_port_mscount_t mscount)
1124 {
1125 ipc_port_t port;
1126 kern_return_t kr;
1127
1128 if (space == IS_NULL) {
1129 return KERN_INVALID_TASK;
1130 }
1131
1132 if (!MACH_PORT_VALID(name)) {
1133 return KERN_INVALID_RIGHT;
1134 }
1135
1136 kr = ipc_port_translate_receive(space, name, &port);
1137 if (kr != KERN_SUCCESS) {
1138 return kr;
1139 }
1140 /* port is locked and active */
1141
1142 port->ip_mscount = mscount;
1143 ip_unlock(port);
1144 return KERN_SUCCESS;
1145 }
1146
1147 /*
1148 * Routine: mach_port_set_seqno [kernel call]
1149 * Purpose:
1150 * Changes a receive right's sequence number.
1151 * Conditions:
1152 * Nothing locked.
1153 * Returns:
1154 * KERN_SUCCESS Set sequence number.
1155 * KERN_INVALID_TASK The space is null.
1156 * KERN_INVALID_TASK The space is dead.
1157 * KERN_INVALID_NAME The name doesn't denote a right.
1158 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1159 */
1160
1161 kern_return_t
1162 mach_port_set_seqno(
1163 ipc_space_t space,
1164 mach_port_name_t name,
1165 mach_port_seqno_t seqno)
1166 {
1167 ipc_port_t port;
1168 kern_return_t kr;
1169
1170 if (space == IS_NULL) {
1171 return KERN_INVALID_TASK;
1172 }
1173
1174 if (!MACH_PORT_VALID(name)) {
1175 return KERN_INVALID_RIGHT;
1176 }
1177
1178 kr = ipc_port_translate_receive(space, name, &port);
1179 if (kr != KERN_SUCCESS) {
1180 return kr;
1181 }
1182 /* port is locked and active */
1183
1184 ipc_mqueue_set_seqno(&port->ip_messages, seqno);
1185
1186 ip_unlock(port);
1187 return KERN_SUCCESS;
1188 }
1189
1190 /*
1191 * Routine: mach_port_get_context [kernel call]
1192 * Purpose:
1193 * Returns a receive right's context pointer.
1194 * Conditions:
1195 * Nothing locked.
1196 * Returns:
1197 * KERN_SUCCESS Set context pointer.
1198 * KERN_INVALID_TASK The space is null.
1199 * KERN_INVALID_TASK The space is dead.
1200 * KERN_INVALID_NAME The name doesn't denote a right.
1201 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1202 */
1203
1204 kern_return_t
1205 mach_port_get_context(
1206 ipc_space_t space,
1207 mach_port_name_t name,
1208 mach_vm_address_t *context)
1209 {
1210 ipc_port_t port;
1211 kern_return_t kr;
1212
1213 if (space == IS_NULL) {
1214 return KERN_INVALID_TASK;
1215 }
1216
1217 if (!MACH_PORT_VALID(name)) {
1218 return KERN_INVALID_RIGHT;
1219 }
1220
1221 kr = ipc_port_translate_receive(space, name, &port);
1222 if (kr != KERN_SUCCESS) {
1223 return kr;
1224 }
1225
1226 /* Port locked and active */
1227
1228 /* For strictly guarded ports, return empty context (which acts as guard) */
1229 if (port->ip_strict_guard) {
1230 *context = 0;
1231 } else {
1232 *context = port->ip_context;
1233 }
1234
1235 ip_unlock(port);
1236 return KERN_SUCCESS;
1237 }
1238
1239
1240 /*
1241 * Routine: mach_port_set_context [kernel call]
1242 * Purpose:
1243 * Changes a receive right's context pointer.
1244 * Conditions:
1245 * Nothing locked.
1246 * Returns:
1247 * KERN_SUCCESS Set context pointer.
1248 * KERN_INVALID_TASK The space is null.
1249 * KERN_INVALID_TASK The space is dead.
1250 * KERN_INVALID_NAME The name doesn't denote a right.
1251 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1252 */
1253
1254 kern_return_t
1255 mach_port_set_context(
1256 ipc_space_t space,
1257 mach_port_name_t name,
1258 mach_vm_address_t context)
1259 {
1260 ipc_port_t port;
1261 kern_return_t kr;
1262
1263 if (space == IS_NULL) {
1264 return KERN_INVALID_TASK;
1265 }
1266
1267 if (!MACH_PORT_VALID(name)) {
1268 return KERN_INVALID_RIGHT;
1269 }
1270
1271 kr = ipc_port_translate_receive(space, name, &port);
1272 if (kr != KERN_SUCCESS) {
1273 return kr;
1274 }
1275
1276 /* port is locked and active */
1277 if (port->ip_strict_guard) {
1278 uint64_t portguard = port->ip_context;
1279 ip_unlock(port);
1280 /* For strictly guarded ports, disallow overwriting context; Raise Exception */
1281 mach_port_guard_exception(name, context, portguard, kGUARD_EXC_SET_CONTEXT);
1282 return KERN_INVALID_ARGUMENT;
1283 }
1284
1285 port->ip_context = context;
1286
1287 ip_unlock(port);
1288 return KERN_SUCCESS;
1289 }
1290
1291
1292 /*
1293 * Routine: mach_port_get_set_status [kernel call]
1294 * Purpose:
1295 * Retrieves a list of members in a port set.
1296 * Returns the space's name for each receive right member.
1297 * Conditions:
1298 * Nothing locked.
1299 * Returns:
1300 * KERN_SUCCESS Retrieved list of members.
1301 * KERN_INVALID_TASK The space is null.
1302 * KERN_INVALID_TASK The space is dead.
1303 * KERN_INVALID_NAME The name doesn't denote a right.
1304 * KERN_INVALID_RIGHT Name doesn't denote a port set.
1305 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1306 */
1307
1308 kern_return_t
1309 mach_port_get_set_status(
1310 ipc_space_t space,
1311 mach_port_name_t name,
1312 mach_port_name_t **members,
1313 mach_msg_type_number_t *membersCnt)
1314 {
1315 ipc_entry_num_t actual; /* this many members */
1316 ipc_entry_num_t maxnames; /* space for this many members */
1317 kern_return_t kr;
1318
1319 vm_size_t size; /* size of allocated memory */
1320 vm_offset_t addr; /* allocated memory */
1321 vm_map_copy_t memory; /* copied-in memory */
1322
1323 if (space == IS_NULL) {
1324 return KERN_INVALID_TASK;
1325 }
1326
1327 if (!MACH_PORT_VALID(name)) {
1328 return KERN_INVALID_RIGHT;
1329 }
1330
1331 size = VM_MAP_PAGE_SIZE(ipc_kernel_map); /* initial guess */
1332
1333 for (;;) {
1334 mach_port_name_t *names;
1335 ipc_object_t psobj;
1336 ipc_pset_t pset;
1337
1338 kr = vm_allocate_kernel(ipc_kernel_map, &addr, size, VM_FLAGS_ANYWHERE, VM_KERN_MEMORY_IPC);
1339 if (kr != KERN_SUCCESS) {
1340 return KERN_RESOURCE_SHORTAGE;
1341 }
1342
1343 /* can't fault while we hold locks */
1344
1345 kr = vm_map_wire_kernel(ipc_kernel_map, addr, addr + size,
1346 VM_PROT_READ | VM_PROT_WRITE, VM_KERN_MEMORY_IPC, FALSE);
1347 assert(kr == KERN_SUCCESS);
1348
1349 kr = ipc_object_translate(space, name, MACH_PORT_RIGHT_PORT_SET, &psobj);
1350 if (kr != KERN_SUCCESS) {
1351 kmem_free(ipc_kernel_map, addr, size);
1352 return kr;
1353 }
1354
1355 /* just use a portset reference from here on out */
1356 pset = ips_object_to_pset(psobj);
1357 ips_reference(pset);
1358 ips_unlock(pset);
1359
1360 names = (mach_port_name_t *) addr;
1361 maxnames = (ipc_entry_num_t)(size / sizeof(mach_port_name_t));
1362
1363 ipc_mqueue_set_gather_member_names(space, &pset->ips_messages, maxnames, names, &actual);
1364
1365 /* release the portset reference */
1366 ips_release(pset);
1367
1368 if (actual <= maxnames) {
1369 break;
1370 }
1371
1372 /* didn't have enough memory; allocate more */
1373 kmem_free(ipc_kernel_map, addr, size);
1374 size = vm_map_round_page(
1375 (actual * sizeof(mach_port_name_t)),
1376 VM_MAP_PAGE_MASK(ipc_kernel_map)) +
1377 VM_MAP_PAGE_SIZE(ipc_kernel_map);
1378 }
1379
1380 if (actual == 0) {
1381 memory = VM_MAP_COPY_NULL;
1382
1383 kmem_free(ipc_kernel_map, addr, size);
1384 } else {
1385 vm_size_t size_used;
1386 vm_size_t vm_size_used;
1387
1388 size_used = actual * sizeof(mach_port_name_t);
1389 vm_size_used = vm_map_round_page(
1390 size_used,
1391 VM_MAP_PAGE_MASK(ipc_kernel_map));
1392
1393 /*
1394 * Make used memory pageable and get it into
1395 * copied-in form. Free any unused memory.
1396 */
1397
1398 kr = vm_map_unwire(
1399 ipc_kernel_map,
1400 vm_map_trunc_page(addr,
1401 VM_MAP_PAGE_MASK(ipc_kernel_map)),
1402 vm_map_round_page(addr + vm_size_used,
1403 VM_MAP_PAGE_MASK(ipc_kernel_map)),
1404 FALSE);
1405 assert(kr == KERN_SUCCESS);
1406
1407 kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr,
1408 (vm_map_size_t)size_used, TRUE, &memory);
1409 assert(kr == KERN_SUCCESS);
1410
1411 if (vm_size_used != size) {
1412 kmem_free(ipc_kernel_map,
1413 addr + vm_size_used, size - vm_size_used);
1414 }
1415 }
1416
1417 *members = (mach_port_name_t *) memory;
1418 *membersCnt = actual;
1419 return KERN_SUCCESS;
1420 }
1421
1422 /*
1423 * Routine: mach_port_move_member [kernel call]
1424 * Purpose:
1425 * If after is MACH_PORT_NULL, removes member
1426 * from the port set it is in. Otherwise, adds
1427 * member to after, removing it from any set
1428 * it might already be in.
1429 * Conditions:
1430 * Nothing locked.
1431 * Returns:
1432 * KERN_SUCCESS Moved the port.
1433 * KERN_INVALID_TASK The space is null.
1434 * KERN_INVALID_TASK The space is dead.
1435 * KERN_INVALID_NAME Member didn't denote a right.
1436 * KERN_INVALID_RIGHT Member didn't denote a receive right.
1437 * KERN_INVALID_NAME After didn't denote a right.
1438 * KERN_INVALID_RIGHT After didn't denote a port set right.
1439 * KERN_NOT_IN_SET
1440 * After is MACH_PORT_NULL and Member isn't in a port set.
1441 */
1442
1443 kern_return_t
1444 mach_port_move_member(
1445 ipc_space_t space,
1446 mach_port_name_t member,
1447 mach_port_name_t after)
1448 {
1449 ipc_object_t port_obj, ps_obj;
1450 ipc_port_t port;
1451 ipc_pset_t nset = IPS_NULL;
1452 kern_return_t kr;
1453 uint64_t wq_link_id = 0;
1454 uint64_t wq_reserved_prepost = 0;
1455
1456 if (space == IS_NULL) {
1457 return KERN_INVALID_TASK;
1458 }
1459
1460 if (!MACH_PORT_VALID(member)) {
1461 return KERN_INVALID_RIGHT;
1462 }
1463
1464 if (after == MACH_PORT_DEAD) {
1465 return KERN_INVALID_RIGHT;
1466 } else if (after == MACH_PORT_NULL) {
1467 wq_link_id = 0;
1468 } else {
1469 /*
1470 * We reserve both a link, and
1471 * enough prepost objects to complete
1472 * the set move atomically - we can't block
1473 * while we're holding the space lock, and
1474 * the ipc_pset_add calls ipc_mqueue_add
1475 * which may have to prepost this port onto
1476 * this set.
1477 */
1478 wq_link_id = waitq_link_reserve(NULL);
1479 wq_reserved_prepost = waitq_prepost_reserve(NULL, 10,
1480 WAITQ_DONT_LOCK);
1481 kr = ipc_pset_lazy_allocate(space, after);
1482 if (kr != KERN_SUCCESS) {
1483 goto done;
1484 }
1485 }
1486
1487 if (after != MACH_PORT_NULL) {
1488 kr = ipc_object_translate_two(space,
1489 member, MACH_PORT_RIGHT_RECEIVE, &port_obj,
1490 after, MACH_PORT_RIGHT_PORT_SET, &ps_obj);
1491 } else {
1492 kr = ipc_object_translate(space,
1493 member, MACH_PORT_RIGHT_RECEIVE, &port_obj);
1494 }
1495 if (kr != KERN_SUCCESS) {
1496 goto done;
1497 }
1498
1499 port = ip_object_to_port(port_obj);
1500 if (after != MACH_PORT_NULL) {
1501 nset = ips_object_to_pset(ps_obj);
1502 }
1503 /* port and nset are locked */
1504
1505 ipc_pset_remove_from_all(port);
1506
1507 if (after != MACH_PORT_NULL) {
1508 kr = ipc_pset_add(nset, port, &wq_link_id, &wq_reserved_prepost);
1509 ips_unlock(nset);
1510 }
1511
1512 ip_unlock(port);
1513
1514 done:
1515 /*
1516 * on success the ipc_pset_add() will consume the wq_link_id
1517 * value (resetting it to 0), so this function is always safe to call.
1518 */
1519 waitq_link_release(wq_link_id);
1520 waitq_prepost_release_reserve(wq_reserved_prepost);
1521
1522 return kr;
1523 }
1524
1525 /*
1526 * Routine: mach_port_request_notification [kernel call]
1527 * Purpose:
1528 * Requests a notification. The caller supplies
1529 * a send-once right for the notification to use,
1530 * and the call returns the previously registered
1531 * send-once right, if any. Possible types:
1532 *
1533 * MACH_NOTIFY_PORT_DESTROYED
1534 * Requests a port-destroyed notification
1535 * for a receive right. Sync should be zero.
1536 * MACH_NOTIFY_NO_SENDERS
1537 * Requests a no-senders notification for a
1538 * receive right. If there are currently no
1539 * senders, sync is less than or equal to the
1540 * current make-send count, and a send-once right
1541 * is supplied, then an immediate no-senders
1542 * notification is generated.
1543 * MACH_NOTIFY_DEAD_NAME
1544 * Requests a dead-name notification for a send
1545 * or receive right. If the name is already a
1546 * dead name, sync is non-zero, and a send-once
1547 * right is supplied, then an immediate dead-name
1548 * notification is generated.
1549 * Conditions:
1550 * Nothing locked.
1551 * Returns:
1552 * KERN_SUCCESS Requested a notification.
1553 * KERN_INVALID_TASK The space is null.
1554 * KERN_INVALID_TASK The space is dead.
1555 * KERN_INVALID_VALUE Bad id value.
1556 * KERN_INVALID_NAME Name doesn't denote a right.
1557 * KERN_INVALID_RIGHT Name doesn't denote appropriate right.
1558 * KERN_INVALID_CAPABILITY The notify port is dead.
1559 * MACH_NOTIFY_PORT_DESTROYED:
1560 * KERN_INVALID_VALUE Sync isn't zero.
1561 * KERN_FAILURE Re-registering for this notification
1562 * MACH_NOTIFY_DEAD_NAME:
1563 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1564 * KERN_INVALID_ARGUMENT Name denotes dead name, but
1565 * sync is zero or notify is IP_NULL.
1566 * KERN_UREFS_OVERFLOW Name denotes dead name, but
1567 * generating immediate notif. would overflow urefs.
1568 */
1569
1570 kern_return_t
1571 mach_port_request_notification(
1572 ipc_space_t space,
1573 mach_port_name_t name,
1574 mach_msg_id_t id,
1575 mach_port_mscount_t sync,
1576 ipc_port_t notify,
1577 ipc_port_t *previousp)
1578 {
1579 kern_return_t kr;
1580
1581 if (space == IS_NULL) {
1582 return KERN_INVALID_TASK;
1583 }
1584
1585 if (notify == IP_DEAD) {
1586 return KERN_INVALID_CAPABILITY;
1587 }
1588
1589 #if NOTYET
1590 /*
1591 * Requesting notifications on RPC ports is an error.
1592 */
1593 {
1594 ipc_port_t port;
1595 ipc_entry_t entry;
1596
1597 kr = ipc_right_lookup_write(space, name, &entry);
1598 if (kr != KERN_SUCCESS) {
1599 return kr;
1600 }
1601
1602 port = ip_object_to_port(entry->ie_object);
1603
1604 if (port->ip_subsystem != NULL) {
1605 is_write_unlock(space);
1606 panic("mach_port_request_notification: on RPC port!!");
1607 return KERN_INVALID_CAPABILITY;
1608 }
1609 is_write_unlock(space);
1610 }
1611 #endif /* NOTYET */
1612
1613
1614 switch (id) {
1615 case MACH_NOTIFY_PORT_DESTROYED: {
1616 ipc_port_t port;
1617
1618 if (sync != 0) {
1619 return KERN_INVALID_VALUE;
1620 }
1621
1622 if (!MACH_PORT_VALID(name)) {
1623 return KERN_INVALID_RIGHT;
1624 }
1625
1626 kr = ipc_port_translate_receive(space, name, &port);
1627 if (kr != KERN_SUCCESS) {
1628 return kr;
1629 }
1630 /* port is locked and active */
1631
1632 /* you cannot register for port death notifications on a kobject */
1633 if (ip_kotype(port) != IKOT_NONE) {
1634 ip_unlock(port);
1635 return KERN_INVALID_RIGHT;
1636 }
1637
1638 /* Allow only one registeration of this notification */
1639 if (port->ip_pdrequest != IP_NULL) {
1640 ip_unlock(port);
1641 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_KERN_FAILURE);
1642 return KERN_FAILURE;
1643 }
1644
1645 ipc_port_pdrequest(port, notify, previousp);
1646 /* port is unlocked */
1647 assert(*previousp == IP_NULL);
1648 break;
1649 }
1650
1651 case MACH_NOTIFY_NO_SENDERS: {
1652 ipc_port_t port;
1653
1654 if (!MACH_PORT_VALID(name)) {
1655 return KERN_INVALID_RIGHT;
1656 }
1657
1658 kr = ipc_port_translate_receive(space, name, &port);
1659 if (kr != KERN_SUCCESS) {
1660 return kr;
1661 }
1662 /* port is locked and active */
1663
1664 ipc_port_nsrequest(port, sync, notify, previousp);
1665 /* port is unlocked */
1666 break;
1667 }
1668
1669 case MACH_NOTIFY_SEND_POSSIBLE:
1670
1671 if (!MACH_PORT_VALID(name)) {
1672 return KERN_INVALID_ARGUMENT;
1673 }
1674
1675 kr = ipc_right_request_alloc(space, name, sync != 0,
1676 TRUE, notify, previousp);
1677 if (kr != KERN_SUCCESS) {
1678 return kr;
1679 }
1680 break;
1681
1682 case MACH_NOTIFY_DEAD_NAME:
1683
1684 if (!MACH_PORT_VALID(name)) {
1685 /*
1686 * Already dead.
1687 * Should do immediate delivery check -
1688 * will do that in the near future.
1689 */
1690 return KERN_INVALID_ARGUMENT;
1691 }
1692
1693 kr = ipc_right_request_alloc(space, name, sync != 0,
1694 FALSE, notify, previousp);
1695 if (kr != KERN_SUCCESS) {
1696 return kr;
1697 }
1698 break;
1699
1700 default:
1701 return KERN_INVALID_VALUE;
1702 }
1703
1704 return KERN_SUCCESS;
1705 }
1706
1707 /*
1708 * Routine: mach_port_insert_right [kernel call]
1709 * Purpose:
1710 * Inserts a right into a space, as if the space
1711 * voluntarily received the right in a message,
1712 * except that the right gets the specified name.
1713 * Conditions:
1714 * Nothing locked.
1715 * Returns:
1716 * KERN_SUCCESS Inserted the right.
1717 * KERN_INVALID_TASK The space is null.
1718 * KERN_INVALID_TASK The space is dead.
1719 * KERN_INVALID_VALUE The name isn't a legal name.
1720 * KERN_NAME_EXISTS The name already denotes a right.
1721 * KERN_INVALID_VALUE Message doesn't carry a port right.
1722 * KERN_INVALID_CAPABILITY Port is null or dead.
1723 * KERN_UREFS_OVERFLOW Urefs limit would be exceeded.
1724 * KERN_RIGHT_EXISTS Space has rights under another name.
1725 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1726 */
1727
1728 kern_return_t
1729 mach_port_insert_right(
1730 ipc_space_t space,
1731 mach_port_name_t name,
1732 ipc_port_t poly,
1733 mach_msg_type_name_t polyPoly)
1734 {
1735 if (space == IS_NULL) {
1736 return KERN_INVALID_TASK;
1737 }
1738
1739 if (!MACH_PORT_VALID(name) ||
1740 !MACH_MSG_TYPE_PORT_ANY_RIGHT(polyPoly)) {
1741 return KERN_INVALID_VALUE;
1742 }
1743
1744 if (!IP_VALID(poly)) {
1745 return KERN_INVALID_CAPABILITY;
1746 }
1747
1748 return ipc_object_copyout_name(space, ip_to_object(poly),
1749 polyPoly, name);
1750 }
1751
1752 /*
1753 * Routine: mach_port_extract_right [kernel call]
1754 * Purpose:
1755 * Extracts a right from a space, as if the space
1756 * voluntarily sent the right to the caller.
1757 * Conditions:
1758 * Nothing locked.
1759 * Returns:
1760 * KERN_SUCCESS Extracted the right.
1761 * KERN_INVALID_TASK The space is null.
1762 * KERN_INVALID_TASK The space is dead.
1763 * KERN_INVALID_VALUE Requested type isn't a port right.
1764 * KERN_INVALID_NAME Name doesn't denote a right.
1765 * KERN_INVALID_RIGHT Name doesn't denote appropriate right.
1766 */
1767
1768 kern_return_t
1769 mach_port_extract_right(
1770 ipc_space_t space,
1771 mach_port_name_t name,
1772 mach_msg_type_name_t msgt_name,
1773 ipc_port_t *poly,
1774 mach_msg_type_name_t *polyPoly)
1775 {
1776 kern_return_t kr;
1777
1778 if (space == IS_NULL) {
1779 return KERN_INVALID_TASK;
1780 }
1781
1782 if (!MACH_MSG_TYPE_PORT_ANY(msgt_name)) {
1783 return KERN_INVALID_VALUE;
1784 }
1785
1786 if (!MACH_PORT_VALID(name)) {
1787 /*
1788 * really should copy out a dead name, if it is a send or
1789 * send-once right being copied, but instead return an
1790 * error for now.
1791 */
1792 return KERN_INVALID_RIGHT;
1793 }
1794
1795 kr = ipc_object_copyin(space, name, msgt_name, (ipc_object_t *) poly, 0, NULL,
1796 IPC_KMSG_FLAGS_ALLOW_IMMOVABLE_SEND);
1797
1798 if (kr == KERN_SUCCESS) {
1799 *polyPoly = ipc_object_copyin_type(msgt_name);
1800 }
1801 return kr;
1802 }
1803
1804 /*
1805 * Routine: mach_port_get_status_helper [helper]
1806 * Purpose:
1807 * Populates a mach_port_status_t structure with
1808 * port information.
1809 * Conditions:
1810 * Port needs to be locked
1811 * Returns:
1812 * None.
1813 */
1814 static void
1815 mach_port_get_status_helper(
1816 ipc_port_t port,
1817 mach_port_status_t *statusp)
1818 {
1819 imq_lock(&port->ip_messages);
1820 /* don't leak set IDs, just indicate that the port is in one or not */
1821 statusp->mps_pset = !!(port->ip_in_pset);
1822 statusp->mps_seqno = port->ip_messages.imq_seqno;
1823 statusp->mps_qlimit = port->ip_messages.imq_qlimit;
1824 statusp->mps_msgcount = port->ip_messages.imq_msgcount;
1825 imq_unlock(&port->ip_messages);
1826
1827 statusp->mps_mscount = port->ip_mscount;
1828 statusp->mps_sorights = port->ip_sorights;
1829 statusp->mps_srights = port->ip_srights > 0;
1830 statusp->mps_pdrequest = port->ip_pdrequest != IP_NULL;
1831 statusp->mps_nsrequest = port->ip_nsrequest != IP_NULL;
1832 statusp->mps_flags = 0;
1833 if (port->ip_impdonation) {
1834 statusp->mps_flags |= MACH_PORT_STATUS_FLAG_IMP_DONATION;
1835 if (port->ip_tempowner) {
1836 statusp->mps_flags |= MACH_PORT_STATUS_FLAG_TEMPOWNER;
1837 if (IIT_NULL != port->ip_imp_task) {
1838 statusp->mps_flags |= MACH_PORT_STATUS_FLAG_TASKPTR;
1839 }
1840 }
1841 }
1842 if (port->ip_guarded) {
1843 statusp->mps_flags |= MACH_PORT_STATUS_FLAG_GUARDED;
1844 if (port->ip_strict_guard) {
1845 statusp->mps_flags |= MACH_PORT_STATUS_FLAG_STRICT_GUARD;
1846 }
1847 if (port->ip_immovable_receive) {
1848 statusp->mps_flags |= MACH_PORT_STATUS_FLAG_GUARD_IMMOVABLE_RECEIVE;
1849 }
1850 }
1851 if (port->ip_no_grant) {
1852 statusp->mps_flags |= MACH_PORT_STATUS_FLAG_NO_GRANT;
1853 }
1854 return;
1855 }
1856
1857
1858
1859 kern_return_t
1860 mach_port_get_attributes(
1861 ipc_space_t space,
1862 mach_port_name_t name,
1863 int flavor,
1864 mach_port_info_t info,
1865 mach_msg_type_number_t *count)
1866 {
1867 ipc_port_t port;
1868 kern_return_t kr;
1869
1870 if (space == IS_NULL) {
1871 return KERN_INVALID_TASK;
1872 }
1873
1874 switch (flavor) {
1875 case MACH_PORT_LIMITS_INFO: {
1876 mach_port_limits_t *lp = (mach_port_limits_t *)info;
1877
1878 if (*count < MACH_PORT_LIMITS_INFO_COUNT) {
1879 return KERN_FAILURE;
1880 }
1881
1882 if (!MACH_PORT_VALID(name)) {
1883 *count = 0;
1884 break;
1885 }
1886
1887 kr = ipc_port_translate_receive(space, name, &port);
1888 if (kr != KERN_SUCCESS) {
1889 return kr;
1890 }
1891 /* port is locked and active */
1892
1893 lp->mpl_qlimit = port->ip_messages.imq_qlimit;
1894 *count = MACH_PORT_LIMITS_INFO_COUNT;
1895 ip_unlock(port);
1896 break;
1897 }
1898
1899 case MACH_PORT_RECEIVE_STATUS: {
1900 mach_port_status_t *statusp = (mach_port_status_t *)info;
1901
1902 if (*count < MACH_PORT_RECEIVE_STATUS_COUNT) {
1903 return KERN_FAILURE;
1904 }
1905
1906 if (!MACH_PORT_VALID(name)) {
1907 return KERN_INVALID_RIGHT;
1908 }
1909
1910 kr = ipc_port_translate_receive(space, name, &port);
1911 if (kr != KERN_SUCCESS) {
1912 return kr;
1913 }
1914 /* port is locked and active */
1915 mach_port_get_status_helper(port, statusp);
1916 *count = MACH_PORT_RECEIVE_STATUS_COUNT;
1917 ip_unlock(port);
1918 break;
1919 }
1920
1921 case MACH_PORT_DNREQUESTS_SIZE: {
1922 ipc_port_request_t table;
1923
1924 if (*count < MACH_PORT_DNREQUESTS_SIZE_COUNT) {
1925 return KERN_FAILURE;
1926 }
1927
1928 if (!MACH_PORT_VALID(name)) {
1929 *(int *)info = 0;
1930 break;
1931 }
1932
1933 kr = ipc_port_translate_receive(space, name, &port);
1934 if (kr != KERN_SUCCESS) {
1935 return kr;
1936 }
1937 /* port is locked and active */
1938
1939 table = port->ip_requests;
1940 if (table == IPR_NULL) {
1941 *(int *)info = 0;
1942 } else {
1943 *(int *)info = table->ipr_size->its_size;
1944 }
1945 *count = MACH_PORT_DNREQUESTS_SIZE_COUNT;
1946 ip_unlock(port);
1947 break;
1948 }
1949
1950 case MACH_PORT_INFO_EXT: {
1951 mach_port_info_ext_t *mp_info = (mach_port_info_ext_t *)info;
1952 if (*count < MACH_PORT_INFO_EXT_COUNT) {
1953 return KERN_FAILURE;
1954 }
1955
1956 if (!MACH_PORT_VALID(name)) {
1957 return KERN_INVALID_RIGHT;
1958 }
1959
1960 kr = ipc_port_translate_receive(space, name, &port);
1961 if (kr != KERN_SUCCESS) {
1962 return kr;
1963 }
1964 /* port is locked and active */
1965 mach_port_get_status_helper(port, &mp_info->mpie_status);
1966 mp_info->mpie_boost_cnt = port->ip_impcount;
1967 *count = MACH_PORT_INFO_EXT_COUNT;
1968 ip_unlock(port);
1969 break;
1970 }
1971
1972 default:
1973 return KERN_INVALID_ARGUMENT;
1974 /*NOTREACHED*/
1975 }
1976
1977 return KERN_SUCCESS;
1978 }
1979
1980 kern_return_t
1981 mach_port_set_attributes(
1982 ipc_space_t space,
1983 mach_port_name_t name,
1984 int flavor,
1985 mach_port_info_t info,
1986 mach_msg_type_number_t count)
1987 {
1988 ipc_port_t port;
1989 kern_return_t kr;
1990
1991 if (space == IS_NULL) {
1992 return KERN_INVALID_TASK;
1993 }
1994
1995 switch (flavor) {
1996 case MACH_PORT_LIMITS_INFO: {
1997 mach_port_limits_t *mplp = (mach_port_limits_t *)info;
1998
1999 if (count < MACH_PORT_LIMITS_INFO_COUNT) {
2000 return KERN_FAILURE;
2001 }
2002
2003 if (mplp->mpl_qlimit > MACH_PORT_QLIMIT_MAX) {
2004 return KERN_INVALID_VALUE;
2005 }
2006
2007 if (!MACH_PORT_VALID(name)) {
2008 return KERN_INVALID_RIGHT;
2009 }
2010
2011 kr = ipc_port_translate_receive(space, name, &port);
2012 if (kr != KERN_SUCCESS) {
2013 return kr;
2014 }
2015 /* port is locked and active */
2016
2017 ipc_mqueue_set_qlimit(&port->ip_messages, mplp->mpl_qlimit);
2018 ip_unlock(port);
2019 break;
2020 }
2021 case MACH_PORT_DNREQUESTS_SIZE: {
2022 if (count < MACH_PORT_DNREQUESTS_SIZE_COUNT) {
2023 return KERN_FAILURE;
2024 }
2025
2026 if (!MACH_PORT_VALID(name)) {
2027 return KERN_INVALID_RIGHT;
2028 }
2029
2030 kr = ipc_port_translate_receive(space, name, &port);
2031 if (kr != KERN_SUCCESS) {
2032 return kr;
2033 }
2034 /* port is locked and active */
2035
2036 kr = ipc_port_request_grow(port, *(int *)info);
2037 if (kr != KERN_SUCCESS) {
2038 return kr;
2039 }
2040 break;
2041 }
2042 case MACH_PORT_TEMPOWNER:
2043 if (!MACH_PORT_VALID(name)) {
2044 return KERN_INVALID_RIGHT;
2045 }
2046
2047 ipc_importance_task_t release_imp_task = IIT_NULL;
2048 natural_t assertcnt = 0;
2049
2050 kr = ipc_port_translate_receive(space, name, &port);
2051 if (kr != KERN_SUCCESS) {
2052 return kr;
2053 }
2054 /* port is locked and active */
2055
2056 /*
2057 * don't allow temp-owner importance donation if user
2058 * associated it with a kobject already (timer, host_notify target),
2059 * or is a special reply port.
2060 */
2061 if (ip_is_kobject(port) || port->ip_specialreply) {
2062 ip_unlock(port);
2063 return KERN_INVALID_ARGUMENT;
2064 }
2065
2066 if (port->ip_tempowner != 0) {
2067 if (IIT_NULL != port->ip_imp_task) {
2068 release_imp_task = port->ip_imp_task;
2069 port->ip_imp_task = IIT_NULL;
2070 assertcnt = port->ip_impcount;
2071 }
2072 } else {
2073 assertcnt = port->ip_impcount;
2074 }
2075
2076 port->ip_impdonation = 1;
2077 port->ip_tempowner = 1;
2078 ip_unlock(port);
2079
2080 #if IMPORTANCE_INHERITANCE
2081 /* drop assertions from previous destination task */
2082 if (release_imp_task != IIT_NULL) {
2083 assert(ipc_importance_task_is_any_receiver_type(release_imp_task));
2084 if (assertcnt > 0) {
2085 ipc_importance_task_drop_internal_assertion(release_imp_task, assertcnt);
2086 }
2087 ipc_importance_task_release(release_imp_task);
2088 } else if (assertcnt > 0) {
2089 release_imp_task = current_task()->task_imp_base;
2090 if (release_imp_task != IIT_NULL &&
2091 ipc_importance_task_is_any_receiver_type(release_imp_task)) {
2092 ipc_importance_task_drop_internal_assertion(release_imp_task, assertcnt);
2093 }
2094 }
2095 #else
2096 if (release_imp_task != IIT_NULL) {
2097 ipc_importance_task_release(release_imp_task);
2098 }
2099 #endif /* IMPORTANCE_INHERITANCE */
2100
2101 break;
2102
2103 #if IMPORTANCE_INHERITANCE
2104 case MACH_PORT_DENAP_RECEIVER:
2105 case MACH_PORT_IMPORTANCE_RECEIVER:
2106 if (!MACH_PORT_VALID(name)) {
2107 return KERN_INVALID_RIGHT;
2108 }
2109
2110 kr = ipc_port_translate_receive(space, name, &port);
2111 if (kr != KERN_SUCCESS) {
2112 return kr;
2113 }
2114
2115 /*
2116 * don't allow importance donation if user associated
2117 * it with a kobject already (timer, host_notify target),
2118 * or is a special reply port.
2119 */
2120 if (ip_is_kobject(port) || port->ip_specialreply) {
2121 ip_unlock(port);
2122 return KERN_INVALID_ARGUMENT;
2123 }
2124
2125 /* port is locked and active */
2126 port->ip_impdonation = 1;
2127 ip_unlock(port);
2128
2129 break;
2130 #endif /* IMPORTANCE_INHERITANCE */
2131
2132 default:
2133 return KERN_INVALID_ARGUMENT;
2134 /*NOTREACHED*/
2135 }
2136 return KERN_SUCCESS;
2137 }
2138
2139 /*
2140 * Routine: mach_port_insert_member [kernel call]
2141 * Purpose:
2142 * Add the receive right, specified by name, to
2143 * a portset.
2144 * The port cannot already be a member of the set.
2145 * Conditions:
2146 * Nothing locked.
2147 * Returns:
2148 * KERN_SUCCESS Moved the port.
2149 * KERN_INVALID_TASK The space is null.
2150 * KERN_INVALID_TASK The space is dead.
2151 * KERN_INVALID_NAME name didn't denote a right.
2152 * KERN_INVALID_RIGHT name didn't denote a receive right.
2153 * KERN_INVALID_NAME pset_name didn't denote a right.
2154 * KERN_INVALID_RIGHT pset_name didn't denote a portset right.
2155 * KERN_ALREADY_IN_SET name was already a member of pset.
2156 */
2157
2158 kern_return_t
2159 mach_port_insert_member(
2160 ipc_space_t space,
2161 mach_port_name_t name,
2162 mach_port_name_t psname)
2163 {
2164 ipc_object_t obj;
2165 ipc_object_t psobj;
2166 kern_return_t kr;
2167 uint64_t wq_link_id;
2168 uint64_t wq_reserved_prepost;
2169
2170 if (space == IS_NULL) {
2171 return KERN_INVALID_TASK;
2172 }
2173
2174 if (!MACH_PORT_VALID(name) || !MACH_PORT_VALID(psname)) {
2175 return KERN_INVALID_RIGHT;
2176 }
2177
2178 wq_link_id = waitq_link_reserve(NULL);
2179 wq_reserved_prepost = waitq_prepost_reserve(NULL, 10,
2180 WAITQ_DONT_LOCK);
2181 kr = ipc_pset_lazy_allocate(space, psname);
2182 if (kr != KERN_SUCCESS) {
2183 goto done;
2184 }
2185
2186
2187 kr = ipc_object_translate_two(space,
2188 name, MACH_PORT_RIGHT_RECEIVE, &obj,
2189 psname, MACH_PORT_RIGHT_PORT_SET, &psobj);
2190 if (kr != KERN_SUCCESS) {
2191 goto done;
2192 }
2193
2194 /* obj and psobj are locked (and were locked in that order) */
2195 assert(psobj != IO_NULL);
2196 assert(obj != IO_NULL);
2197
2198 kr = ipc_pset_add(ips_object_to_pset(psobj), ip_object_to_port(obj),
2199 &wq_link_id, &wq_reserved_prepost);
2200
2201 io_unlock(psobj);
2202 io_unlock(obj);
2203
2204 done:
2205 /* on success, wq_link_id is reset to 0, so this is always safe */
2206 waitq_link_release(wq_link_id);
2207 waitq_prepost_release_reserve(wq_reserved_prepost);
2208
2209 return kr;
2210 }
2211
2212 /*
2213 * Routine: mach_port_extract_member [kernel call]
2214 * Purpose:
2215 * Remove a port from one portset that it is a member of.
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 Member didn't denote a right.
2223 * KERN_INVALID_RIGHT Member didn't denote a receive right.
2224 * KERN_INVALID_NAME After didn't denote a right.
2225 * KERN_INVALID_RIGHT After didn't denote a port set right.
2226 * KERN_NOT_IN_SET
2227 * After is MACH_PORT_NULL and Member isn't in a port set.
2228 */
2229
2230 kern_return_t
2231 mach_port_extract_member(
2232 ipc_space_t space,
2233 mach_port_name_t name,
2234 mach_port_name_t psname)
2235 {
2236 ipc_object_t psobj;
2237 ipc_object_t obj;
2238 kern_return_t kr;
2239
2240 if (space == IS_NULL) {
2241 return KERN_INVALID_TASK;
2242 }
2243
2244 if (!MACH_PORT_VALID(name) || !MACH_PORT_VALID(psname)) {
2245 return KERN_INVALID_RIGHT;
2246 }
2247
2248 kr = ipc_object_translate_two(space,
2249 name, MACH_PORT_RIGHT_RECEIVE, &obj,
2250 psname, MACH_PORT_RIGHT_PORT_SET, &psobj);
2251 if (kr != KERN_SUCCESS) {
2252 return kr;
2253 }
2254
2255 /* obj and psobj are both locked (and were locked in that order) */
2256 assert(psobj != IO_NULL);
2257 assert(obj != IO_NULL);
2258
2259 kr = ipc_pset_remove(ips_object_to_pset(psobj), ip_object_to_port(obj));
2260
2261 io_unlock(psobj);
2262 io_unlock(obj);
2263
2264 return kr;
2265 }
2266
2267 /*
2268 * task_set_port_space:
2269 *
2270 * Set port name space of task to specified size.
2271 */
2272 kern_return_t
2273 task_set_port_space(
2274 ipc_space_t space,
2275 int table_entries)
2276 {
2277 kern_return_t kr;
2278
2279 if (space == IS_NULL) {
2280 return KERN_INVALID_TASK;
2281 }
2282
2283 is_write_lock(space);
2284
2285 if (!is_active(space)) {
2286 is_write_unlock(space);
2287 return KERN_INVALID_TASK;
2288 }
2289
2290 kr = ipc_entry_grow_table(space, table_entries);
2291 if (kr == KERN_SUCCESS) {
2292 is_write_unlock(space);
2293 }
2294 return kr;
2295 }
2296
2297 /*
2298 * Routine: mach_port_guard_locked [helper routine]
2299 * Purpose:
2300 * Sets a new guard for a locked port.
2301 * Conditions:
2302 * Port Locked.
2303 * Returns:
2304 * KERN_SUCCESS Port Guarded.
2305 * KERN_INVALID_ARGUMENT Port already contains a context/guard.
2306 */
2307 static kern_return_t
2308 mach_port_guard_locked(
2309 ipc_port_t port,
2310 uint64_t guard,
2311 uint64_t flags)
2312 {
2313 if (port->ip_context) {
2314 return KERN_INVALID_ARGUMENT;
2315 }
2316
2317 int strict = (flags & MPG_STRICT)? 1 : 0;
2318 int immovable_receive = (flags & MPG_IMMOVABLE_RECEIVE)? 1 : 0;
2319
2320 imq_lock(&port->ip_messages);
2321 port->ip_context = guard;
2322 port->ip_guarded = 1;
2323 port->ip_strict_guard = strict;
2324 /* ip_immovable_receive bit is sticky and can't be un-guarded */
2325 if (!port->ip_immovable_receive) {
2326 port->ip_immovable_receive = immovable_receive;
2327 }
2328 imq_unlock(&port->ip_messages);
2329
2330 return KERN_SUCCESS;
2331 }
2332
2333 /*
2334 * Routine: mach_port_unguard_locked [helper routine]
2335 * Purpose:
2336 * Removes guard for a locked port.
2337 * Conditions:
2338 * Port Locked.
2339 * Returns:
2340 * KERN_SUCCESS Port Unguarded.
2341 * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch.
2342 * This also raises a EXC_GUARD exception.
2343 */
2344 static kern_return_t
2345 mach_port_unguard_locked(
2346 ipc_port_t port,
2347 mach_port_name_t name,
2348 uint64_t guard)
2349 {
2350 /* Port locked and active */
2351 if (!port->ip_guarded) {
2352 /* Port already unguarded; Raise exception */
2353 mach_port_guard_exception(name, guard, 0, kGUARD_EXC_UNGUARDED);
2354 return KERN_INVALID_ARGUMENT;
2355 }
2356
2357 if (port->ip_context != guard) {
2358 /* Incorrect guard; Raise exception */
2359 mach_port_guard_exception(name, guard, port->ip_context, kGUARD_EXC_INCORRECT_GUARD);
2360 return KERN_INVALID_ARGUMENT;
2361 }
2362
2363 imq_lock(&port->ip_messages);
2364 port->ip_context = 0;
2365 port->ip_guarded = port->ip_strict_guard = 0;
2366 /* Don't clear the ip_immovable_receive bit */
2367 imq_unlock(&port->ip_messages);
2368
2369 return KERN_SUCCESS;
2370 }
2371
2372
2373 /*
2374 * Routine: mach_port_guard_exception [helper routine]
2375 * Purpose:
2376 * Marks the thread with AST_GUARD for mach port guard violation.
2377 * Also saves exception info in thread structure.
2378 * Conditions:
2379 * None.
2380 * Returns:
2381 * KERN_FAILURE Thread marked with AST_GUARD.
2382 */
2383 void
2384 mach_port_guard_exception(
2385 mach_port_name_t name,
2386 __unused uint64_t inguard,
2387 uint64_t portguard,
2388 unsigned reason)
2389 {
2390 mach_exception_code_t code = 0;
2391 EXC_GUARD_ENCODE_TYPE(code, GUARD_TYPE_MACH_PORT);
2392 EXC_GUARD_ENCODE_FLAVOR(code, reason);
2393 EXC_GUARD_ENCODE_TARGET(code, name);
2394 mach_exception_subcode_t subcode = (uint64_t)portguard;
2395 thread_t t = current_thread();
2396 boolean_t fatal = FALSE;
2397 if (t->task->task_exc_guard & TASK_EXC_GUARD_MP_FATAL) {
2398 fatal = TRUE;
2399 } else if (reason <= MAX_FATAL_kGUARD_EXC_CODE) {
2400 fatal = TRUE;
2401 }
2402 thread_guard_violation(t, code, subcode, fatal);
2403 }
2404
2405
2406 /*
2407 * Routine: mach_port_guard_ast
2408 * Purpose:
2409 * Raises an exception for mach port guard violation.
2410 * Conditions:
2411 * None.
2412 * Returns:
2413 * None.
2414 */
2415
2416 void
2417 mach_port_guard_ast(thread_t t,
2418 mach_exception_data_type_t code, mach_exception_data_type_t subcode)
2419 {
2420 unsigned int reason = EXC_GUARD_DECODE_GUARD_FLAVOR(code);
2421 task_t task = t->task;
2422 unsigned int behavior = task->task_exc_guard;
2423 assert(task == current_task());
2424 assert(task != kernel_task);
2425
2426 switch (reason) {
2427 /*
2428 * Fatal Mach port guards - always delivered synchronously
2429 */
2430 case kGUARD_EXC_DESTROY:
2431 case kGUARD_EXC_MOD_REFS:
2432 case kGUARD_EXC_SET_CONTEXT:
2433 case kGUARD_EXC_UNGUARDED:
2434 case kGUARD_EXC_INCORRECT_GUARD:
2435 case kGUARD_EXC_IMMOVABLE:
2436 case kGUARD_EXC_STRICT_REPLY:
2437 task_exception_notify(EXC_GUARD, code, subcode);
2438 task_bsdtask_kill(task);
2439 break;
2440
2441 default:
2442 /*
2443 * Mach port guards controlled by task settings.
2444 */
2445
2446 /* Is delivery enabled */
2447 if ((behavior & TASK_EXC_GUARD_MP_DELIVER) == 0) {
2448 return;
2449 }
2450
2451 /* If only once, make sure we're that once */
2452 while (behavior & TASK_EXC_GUARD_MP_ONCE) {
2453 uint32_t new_behavior = behavior & ~TASK_EXC_GUARD_MP_DELIVER;
2454
2455 if (OSCompareAndSwap(behavior, new_behavior, &task->task_exc_guard)) {
2456 break;
2457 }
2458 behavior = task->task_exc_guard;
2459 if ((behavior & TASK_EXC_GUARD_MP_DELIVER) == 0) {
2460 return;
2461 }
2462 }
2463
2464 /* Raise exception via corpse fork or synchronously */
2465 if ((task->task_exc_guard & TASK_EXC_GUARD_MP_CORPSE) &&
2466 (task->task_exc_guard & TASK_EXC_GUARD_MP_FATAL) == 0) {
2467 task_violated_guard(code, subcode, NULL);
2468 } else {
2469 task_exception_notify(EXC_GUARD, code, subcode);
2470 }
2471
2472 /* Terminate the task if desired */
2473 if (task->task_exc_guard & TASK_EXC_GUARD_MP_FATAL) {
2474 task_bsdtask_kill(task);
2475 }
2476 break;
2477 }
2478 }
2479
2480 /*
2481 * Routine: mach_port_construct [kernel call]
2482 * Purpose:
2483 * Constructs a mach port with the provided set of options.
2484 * Conditions:
2485 * None.
2486 * Returns:
2487 * KERN_SUCCESS The right is allocated.
2488 * KERN_INVALID_TASK The space is null.
2489 * KERN_INVALID_TASK The space is dead.
2490 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
2491 * KERN_NO_SPACE No room in space for another right.
2492 * KERN_FAILURE Illegal option values requested.
2493 */
2494
2495 kern_return_t
2496 mach_port_construct(
2497 ipc_space_t space,
2498 mach_port_options_t *options,
2499 uint64_t context,
2500 mach_port_name_t *name)
2501 {
2502 kern_return_t kr;
2503 ipc_port_t port;
2504 ipc_port_init_flags_t init_flags = IPC_PORT_INIT_MESSAGE_QUEUE;
2505
2506 if (space == IS_NULL) {
2507 return KERN_INVALID_TASK;
2508 }
2509
2510 if (options->flags & MPO_INSERT_SEND_RIGHT) {
2511 init_flags |= IPC_PORT_INIT_MAKE_SEND_RIGHT;
2512 }
2513
2514 /* Allocate a new port in the IPC space */
2515 kr = ipc_port_alloc(space, init_flags, name, &port);
2516 if (kr != KERN_SUCCESS) {
2517 return kr;
2518 }
2519
2520 /* Port locked and active */
2521 if (options->flags & MPO_CONTEXT_AS_GUARD) {
2522 uint64_t flags = 0;
2523 if (options->flags & MPO_STRICT) {
2524 flags |= MPG_STRICT;
2525 }
2526 if (options->flags & MPO_IMMOVABLE_RECEIVE) {
2527 flags |= MPG_IMMOVABLE_RECEIVE;
2528 }
2529 kr = mach_port_guard_locked(port, (uint64_t) context, flags);
2530 /* A newly allocated and locked port should always be guarded successfully */
2531 assert(kr == KERN_SUCCESS);
2532 } else {
2533 port->ip_context = context;
2534 }
2535
2536 /* Unlock port */
2537 ip_unlock(port);
2538
2539 /* Set port attributes as requested */
2540
2541 if (options->flags & MPO_QLIMIT) {
2542 kr = mach_port_set_attributes(space, *name, MACH_PORT_LIMITS_INFO,
2543 (mach_port_info_t)&options->mpl, sizeof(options->mpl) / sizeof(int));
2544 if (kr != KERN_SUCCESS) {
2545 goto cleanup;
2546 }
2547 }
2548
2549 if (options->flags & MPO_TEMPOWNER) {
2550 kr = mach_port_set_attributes(space, *name, MACH_PORT_TEMPOWNER, NULL, 0);
2551 if (kr != KERN_SUCCESS) {
2552 goto cleanup;
2553 }
2554 }
2555
2556 if (options->flags & MPO_IMPORTANCE_RECEIVER) {
2557 kr = mach_port_set_attributes(space, *name, MACH_PORT_IMPORTANCE_RECEIVER, NULL, 0);
2558 if (kr != KERN_SUCCESS) {
2559 goto cleanup;
2560 }
2561 }
2562
2563 if (options->flags & MPO_DENAP_RECEIVER) {
2564 kr = mach_port_set_attributes(space, *name, MACH_PORT_DENAP_RECEIVER, NULL, 0);
2565 if (kr != KERN_SUCCESS) {
2566 goto cleanup;
2567 }
2568 }
2569
2570 return KERN_SUCCESS;
2571
2572 cleanup:
2573 /* Attempt to destroy port. If its already destroyed by some other thread, we're done */
2574 (void) mach_port_destruct(space, *name,
2575 (options->flags & MPO_INSERT_SEND_RIGHT) ? -1 : 0, context);
2576 return kr;
2577 }
2578
2579 /*
2580 * Routine: mach_port_destruct [kernel call]
2581 * Purpose:
2582 * Destroys a mach port with appropriate guard
2583 * Conditions:
2584 * None.
2585 * Returns:
2586 * KERN_SUCCESS The name is destroyed.
2587 * KERN_INVALID_TASK The space is null.
2588 * KERN_INVALID_TASK The space is dead.
2589 * KERN_INVALID_NAME The name doesn't denote a right.
2590 * KERN_INVALID_RIGHT The right isn't correct.
2591 * KERN_INVALID_VALUE The delta for send right is incorrect.
2592 * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch.
2593 * This also raises a EXC_GUARD exception.
2594 */
2595
2596 kern_return_t
2597 mach_port_destruct(
2598 ipc_space_t space,
2599 mach_port_name_t name,
2600 mach_port_delta_t srdelta,
2601 uint64_t guard)
2602 {
2603 kern_return_t kr;
2604 ipc_entry_t entry;
2605
2606 if (space == IS_NULL) {
2607 return KERN_INVALID_TASK;
2608 }
2609
2610 if (!MACH_PORT_VALID(name)) {
2611 return KERN_INVALID_NAME;
2612 }
2613
2614 /* Remove reference for receive right */
2615 kr = ipc_right_lookup_write(space, name, &entry);
2616 if (kr != KERN_SUCCESS) {
2617 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_NAME);
2618 return kr;
2619 }
2620 /* space is write-locked and active */
2621 kr = ipc_right_destruct(space, name, entry, srdelta, guard); /* unlocks */
2622
2623 return kr;
2624 }
2625
2626 /*
2627 * Routine: mach_port_guard [kernel call]
2628 * Purpose:
2629 * Guard a mach port with specified guard value.
2630 * The context field of the port is used as the guard.
2631 * Conditions:
2632 * None.
2633 * Returns:
2634 * KERN_SUCCESS The name is destroyed.
2635 * KERN_INVALID_TASK The space is null.
2636 * KERN_INVALID_TASK The space is dead.
2637 * KERN_INVALID_NAME The name doesn't denote a right.
2638 * KERN_INVALID_RIGHT The right isn't correct.
2639 * KERN_INVALID_ARGUMENT Port already contains a context/guard.
2640 */
2641 kern_return_t
2642 mach_port_guard(
2643 ipc_space_t space,
2644 mach_port_name_t name,
2645 uint64_t guard,
2646 boolean_t strict)
2647 {
2648 kern_return_t kr;
2649 ipc_port_t port;
2650 uint64_t flags = 0;
2651
2652 if (space == IS_NULL) {
2653 return KERN_INVALID_TASK;
2654 }
2655
2656 if (!MACH_PORT_VALID(name)) {
2657 return KERN_INVALID_NAME;
2658 }
2659
2660 /* Guard can be applied only to receive rights */
2661 kr = ipc_port_translate_receive(space, name, &port);
2662 if (kr != KERN_SUCCESS) {
2663 mach_port_guard_exception(name, 0, 0,
2664 ((KERN_INVALID_NAME == kr) ?
2665 kGUARD_EXC_INVALID_NAME :
2666 kGUARD_EXC_INVALID_RIGHT));
2667 return kr;
2668 }
2669
2670 /* Port locked and active */
2671 if (strict) {
2672 flags = MPG_STRICT;
2673 }
2674
2675 kr = mach_port_guard_locked(port, guard, flags);
2676 ip_unlock(port);
2677
2678 if (KERN_INVALID_ARGUMENT == kr) {
2679 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_ARGUMENT);
2680 }
2681
2682 return kr;
2683 }
2684
2685 /*
2686 * Routine: mach_port_unguard [kernel call]
2687 * Purpose:
2688 * Unguard a mach port with specified guard value.
2689 * Conditions:
2690 * None.
2691 * Returns:
2692 * KERN_SUCCESS The name is destroyed.
2693 * KERN_INVALID_TASK The space is null.
2694 * KERN_INVALID_TASK The space is dead.
2695 * KERN_INVALID_NAME The name doesn't denote a right.
2696 * KERN_INVALID_RIGHT The right isn't correct.
2697 * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch.
2698 * This also raises a EXC_GUARD exception.
2699 */
2700 kern_return_t
2701 mach_port_unguard(
2702 ipc_space_t space,
2703 mach_port_name_t name,
2704 uint64_t guard)
2705 {
2706 kern_return_t kr;
2707 ipc_port_t port;
2708
2709 if (space == IS_NULL) {
2710 return KERN_INVALID_TASK;
2711 }
2712
2713 if (!MACH_PORT_VALID(name)) {
2714 return KERN_INVALID_NAME;
2715 }
2716
2717 kr = ipc_port_translate_receive(space, name, &port);
2718 if (kr != KERN_SUCCESS) {
2719 mach_port_guard_exception(name, 0, 0,
2720 ((KERN_INVALID_NAME == kr) ?
2721 kGUARD_EXC_INVALID_NAME :
2722 kGUARD_EXC_INVALID_RIGHT));
2723 return kr;
2724 }
2725
2726 /* Port locked and active */
2727 kr = mach_port_unguard_locked(port, name, guard);
2728 ip_unlock(port);
2729
2730 return kr;
2731 }
2732
2733 /*
2734 * Routine: mach_port_guard_with_flags [kernel call]
2735 * Purpose:
2736 * Guard a mach port with specified guard value and guard flags.
2737 * The context field of the port is used as the guard.
2738 * Conditions:
2739 * Should hold receive right for that port
2740 * Returns:
2741 * KERN_SUCCESS The name is destroyed.
2742 * KERN_INVALID_TASK The space is null.
2743 * KERN_INVALID_TASK The space is dead.
2744 * KERN_INVALID_NAME The name doesn't denote a right.
2745 * KERN_INVALID_RIGHT The right isn't correct.
2746 * KERN_INVALID_ARGUMENT Port already contains a context/guard.
2747 * KERN_INVALID_CAPABILITY Cannot set MPG_IMMOVABLE_RECEIVE flag for a port with
2748 * a movable port-destroyed notification port
2749 */
2750 kern_return_t
2751 mach_port_guard_with_flags(
2752 ipc_space_t space,
2753 mach_port_name_t name,
2754 uint64_t guard,
2755 uint64_t flags)
2756 {
2757 kern_return_t kr;
2758 ipc_port_t port;
2759
2760 if (space == IS_NULL) {
2761 return KERN_INVALID_TASK;
2762 }
2763
2764 if (!MACH_PORT_VALID(name)) {
2765 return KERN_INVALID_NAME;
2766 }
2767
2768 kr = ipc_port_translate_receive(space, name, &port);
2769 if (kr != KERN_SUCCESS) {
2770 mach_port_guard_exception(name, 0, 0,
2771 ((KERN_INVALID_NAME == kr) ?
2772 kGUARD_EXC_INVALID_NAME :
2773 kGUARD_EXC_INVALID_RIGHT));
2774 return kr;
2775 }
2776
2777 /* Port locked and active */
2778 kr = mach_port_guard_locked(port, guard, flags);
2779 ip_unlock(port);
2780
2781 if (KERN_INVALID_ARGUMENT == kr) {
2782 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_ARGUMENT);
2783 }
2784
2785 return kr;
2786 }
2787
2788 /*
2789 * Routine: mach_port_swap_guard [kernel call]
2790 * Purpose:
2791 * Swap guard value.
2792 * Conditions:
2793 * Port should already be guarded.
2794 * Returns:
2795 * KERN_SUCCESS The name is destroyed.
2796 * KERN_INVALID_TASK The space is null.
2797 * KERN_INVALID_TASK The space is dead.
2798 * KERN_INVALID_NAME The name doesn't denote a right.
2799 * KERN_INVALID_RIGHT The right isn't correct.
2800 * KERN_INVALID_ARGUMENT Port doesn't contain a guard; is strictly guarded
2801 * or the old_guard doesnt match the context
2802 */
2803 kern_return_t
2804 mach_port_swap_guard(
2805 ipc_space_t space,
2806 mach_port_name_t name,
2807 uint64_t old_guard,
2808 uint64_t new_guard)
2809 {
2810 kern_return_t kr;
2811 ipc_port_t port;
2812
2813 if (space == IS_NULL) {
2814 return KERN_INVALID_TASK;
2815 }
2816
2817 if (!MACH_PORT_VALID(name)) {
2818 return KERN_INVALID_NAME;
2819 }
2820
2821 kr = ipc_port_translate_receive(space, name, &port);
2822 if (kr != KERN_SUCCESS) {
2823 mach_port_guard_exception(name, 0, 0,
2824 ((KERN_INVALID_NAME == kr) ?
2825 kGUARD_EXC_INVALID_NAME :
2826 kGUARD_EXC_INVALID_RIGHT));
2827 return kr;
2828 }
2829
2830 /* Port locked and active */
2831 if (!port->ip_guarded) {
2832 ip_unlock(port);
2833 mach_port_guard_exception(name, old_guard, 0, kGUARD_EXC_UNGUARDED);
2834 return KERN_INVALID_ARGUMENT;
2835 }
2836
2837 if (port->ip_strict_guard) {
2838 uint64_t portguard = port->ip_context;
2839 ip_unlock(port);
2840 /* For strictly guarded ports, disallow overwriting context; Raise Exception */
2841 mach_port_guard_exception(name, old_guard, portguard, kGUARD_EXC_SET_CONTEXT);
2842 return KERN_INVALID_ARGUMENT;
2843 }
2844
2845 if (port->ip_context != old_guard) {
2846 uint64_t portguard = port->ip_context;
2847 ip_unlock(port);
2848 mach_port_guard_exception(name, old_guard, portguard, kGUARD_EXC_INCORRECT_GUARD);
2849 return KERN_INVALID_ARGUMENT;
2850 }
2851
2852 imq_lock(&port->ip_messages);
2853 port->ip_context = new_guard;
2854 imq_unlock(&port->ip_messages);
2855
2856 ip_unlock(port);
2857
2858 return KERN_SUCCESS;
2859 }