2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
34 * All Rights Reserved.
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.
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.
46 * Carnegie Mellon requests users of this software to return to
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
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,
61 * Copyright (c) 2005-2006 SPARTA, Inc.
66 * File: ipc/mach_port.c
70 * Exported kernel calls. See mach/mach_port.defs.
73 #include <mach_debug.h>
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>
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>
102 #if IMPORTANCE_INHERITANCE
103 #include <ipc/ipc_importance.h>
108 * Forward declarations
110 void mach_port_names_helper(
111 ipc_port_timestamp_t timestamp
,
113 mach_port_name_t name
,
114 mach_port_name_t
*names
,
115 mach_port_type_t
*types
,
116 ipc_entry_num_t
*actualp
);
118 void mach_port_gst_helper(
120 ipc_entry_num_t maxnames
,
121 mach_port_name_t
*names
,
122 ipc_entry_num_t
*actualp
);
124 /* Needs port locked */
125 void mach_port_get_status_helper(
127 mach_port_status_t
*status
);
129 /* Zeroed template of qos flags */
131 static mach_port_qos_t qos_template
;
134 * Routine: mach_port_names_helper
136 * A helper function for mach_port_names.
139 * Space containing entry is [at least] read-locked.
143 mach_port_names_helper(
144 ipc_port_timestamp_t timestamp
,
146 mach_port_name_t name
,
147 mach_port_name_t
*names
,
148 mach_port_type_t
*types
,
149 ipc_entry_num_t
*actualp
)
151 ipc_entry_bits_t bits
;
152 ipc_port_request_index_t request
;
153 mach_port_type_t type
= 0;
154 ipc_entry_num_t actual
;
157 bits
= entry
->ie_bits
;
158 request
= entry
->ie_request
;
159 __IGNORE_WCASTALIGN(port
= (ipc_port_t
) entry
->ie_object
);
161 if (bits
& MACH_PORT_TYPE_RECEIVE
) {
162 assert(IP_VALID(port
));
164 if (request
!= IE_REQ_NONE
) {
166 assert(ip_active(port
));
167 type
|= ipc_port_request_type(port
, name
, request
);
171 } else if (bits
& MACH_PORT_TYPE_SEND_RIGHTS
) {
172 mach_port_type_t reqtype
;
174 assert(IP_VALID(port
));
177 reqtype
= (request
!= IE_REQ_NONE
) ?
178 ipc_port_request_type(port
, name
, request
) : 0;
181 * If the port is alive, or was alive when the mach_port_names
182 * started, then return that fact. Otherwise, pretend we found
185 if (ip_active(port
) || IP_TIMESTAMP_ORDER(timestamp
, port
->ip_timestamp
)) {
188 bits
&= ~(IE_BITS_TYPE_MASK
);
189 bits
|= MACH_PORT_TYPE_DEAD_NAME
;
190 /* account for additional reference for dead-name notification */
197 type
|= IE_BITS_TYPE(bits
);
200 names
[actual
] = name
;
201 types
[actual
] = type
;
206 * Routine: mach_port_names [kernel call]
208 * Retrieves a list of the rights present in the space,
209 * along with type information. (Same as returned
210 * by mach_port_type.) The names are returned in
211 * no particular order, but they (and the type info)
212 * are an accurate snapshot of the space.
216 * KERN_SUCCESS Arrays of names and types returned.
217 * KERN_INVALID_TASK The space is null.
218 * KERN_INVALID_TASK The space is dead.
219 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
225 mach_port_name_t
**namesp
,
226 mach_msg_type_number_t
*namesCnt
,
227 mach_port_type_t
**typesp
,
228 mach_msg_type_number_t
*typesCnt
)
231 ipc_entry_num_t tsize
;
232 mach_port_index_t index
;
233 ipc_entry_num_t actual
; /* this many names */
234 ipc_port_timestamp_t timestamp
; /* logical time of this operation */
235 mach_port_name_t
*names
;
236 mach_port_type_t
*types
;
239 vm_size_t size
; /* size of allocated memory */
240 vm_offset_t addr1
; /* allocated memory, for names */
241 vm_offset_t addr2
; /* allocated memory, for types */
242 vm_map_copy_t memory1
; /* copied-in memory, for names */
243 vm_map_copy_t memory2
; /* copied-in memory, for types */
245 /* safe simplifying assumption */
246 static_assert(sizeof(mach_port_name_t
) == sizeof(mach_port_type_t
));
248 if (space
== IS_NULL
)
249 return KERN_INVALID_TASK
;
254 ipc_entry_num_t bound
;
255 vm_size_t size_needed
;
258 if (!is_active(space
)) {
259 is_read_unlock(space
);
261 kmem_free(ipc_kernel_map
, addr1
, size
);
262 kmem_free(ipc_kernel_map
, addr2
, size
);
264 return KERN_INVALID_TASK
;
267 /* upper bound on number of names in the space */
268 bound
= space
->is_table_size
;
269 size_needed
= vm_map_round_page(
270 (bound
* sizeof(mach_port_name_t
)),
271 VM_MAP_PAGE_MASK(ipc_kernel_map
));
273 if (size_needed
<= size
)
276 is_read_unlock(space
);
279 kmem_free(ipc_kernel_map
, addr1
, size
);
280 kmem_free(ipc_kernel_map
, addr2
, size
);
284 kr
= vm_allocate_kernel(ipc_kernel_map
, &addr1
, size
, VM_FLAGS_ANYWHERE
, VM_KERN_MEMORY_IPC
);
285 if (kr
!= KERN_SUCCESS
)
286 return KERN_RESOURCE_SHORTAGE
;
288 kr
= vm_allocate_kernel(ipc_kernel_map
, &addr2
, size
, VM_FLAGS_ANYWHERE
, VM_KERN_MEMORY_IPC
);
289 if (kr
!= KERN_SUCCESS
) {
290 kmem_free(ipc_kernel_map
, addr1
, size
);
291 return KERN_RESOURCE_SHORTAGE
;
294 /* can't fault while we hold locks */
296 kr
= vm_map_wire_kernel(
298 vm_map_trunc_page(addr1
,
299 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
300 vm_map_round_page(addr1
+ size
,
301 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
302 VM_PROT_READ
|VM_PROT_WRITE
, VM_KERN_MEMORY_IPC
,
304 if (kr
!= KERN_SUCCESS
) {
305 kmem_free(ipc_kernel_map
, addr1
, size
);
306 kmem_free(ipc_kernel_map
, addr2
, size
);
307 return KERN_RESOURCE_SHORTAGE
;
310 kr
= vm_map_wire_kernel(
312 vm_map_trunc_page(addr2
,
313 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
314 vm_map_round_page(addr2
+ size
,
315 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
316 VM_PROT_READ
|VM_PROT_WRITE
,
319 if (kr
!= KERN_SUCCESS
) {
320 kmem_free(ipc_kernel_map
, addr1
, size
);
321 kmem_free(ipc_kernel_map
, addr2
, size
);
322 return KERN_RESOURCE_SHORTAGE
;
326 /* space is read-locked and active */
328 names
= (mach_port_name_t
*) addr1
;
329 types
= (mach_port_type_t
*) addr2
;
332 timestamp
= ipc_port_timestamp();
334 table
= space
->is_table
;
335 tsize
= space
->is_table_size
;
337 for (index
= 0; index
< tsize
; index
++) {
338 ipc_entry_t entry
= &table
[index
];
339 ipc_entry_bits_t bits
= entry
->ie_bits
;
341 if (IE_BITS_TYPE(bits
) != MACH_PORT_TYPE_NONE
) {
342 mach_port_name_t name
;
344 name
= MACH_PORT_MAKE(index
, IE_BITS_GEN(bits
));
345 mach_port_names_helper(timestamp
, entry
, name
, names
,
350 is_read_unlock(space
);
353 memory1
= VM_MAP_COPY_NULL
;
354 memory2
= VM_MAP_COPY_NULL
;
357 kmem_free(ipc_kernel_map
, addr1
, size
);
358 kmem_free(ipc_kernel_map
, addr2
, size
);
362 vm_size_t vm_size_used
;
364 size_used
= actual
* sizeof(mach_port_name_t
);
366 vm_map_round_page(size_used
,
367 VM_MAP_PAGE_MASK(ipc_kernel_map
));
370 * Make used memory pageable and get it into
371 * copied-in form. Free any unused memory.
376 vm_map_trunc_page(addr1
,
377 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
378 vm_map_round_page(addr1
+ vm_size_used
,
379 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
381 assert(kr
== KERN_SUCCESS
);
385 vm_map_trunc_page(addr2
,
386 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
387 vm_map_round_page(addr2
+ vm_size_used
,
388 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
390 assert(kr
== KERN_SUCCESS
);
392 kr
= vm_map_copyin(ipc_kernel_map
, (vm_map_address_t
)addr1
,
393 (vm_map_size_t
)size_used
, TRUE
, &memory1
);
394 assert(kr
== KERN_SUCCESS
);
396 kr
= vm_map_copyin(ipc_kernel_map
, (vm_map_address_t
)addr2
,
397 (vm_map_size_t
)size_used
, TRUE
, &memory2
);
398 assert(kr
== KERN_SUCCESS
);
400 if (vm_size_used
!= size
) {
401 kmem_free(ipc_kernel_map
,
402 addr1
+ vm_size_used
, size
- vm_size_used
);
403 kmem_free(ipc_kernel_map
,
404 addr2
+ vm_size_used
, size
- vm_size_used
);
408 *namesp
= (mach_port_name_t
*) memory1
;
410 *typesp
= (mach_port_type_t
*) memory2
;
416 * Routine: mach_port_type [kernel call]
418 * Retrieves the type of a right in the space.
419 * The type is a bitwise combination of one or more
420 * of the following type bits:
421 * MACH_PORT_TYPE_SEND
422 * MACH_PORT_TYPE_RECEIVE
423 * MACH_PORT_TYPE_SEND_ONCE
424 * MACH_PORT_TYPE_PORT_SET
425 * MACH_PORT_TYPE_DEAD_NAME
426 * In addition, the following pseudo-type bits may be present:
427 * MACH_PORT_TYPE_DNREQUEST
428 * A dead-name notification is requested.
432 * KERN_SUCCESS Type is returned.
433 * KERN_INVALID_TASK The space is null.
434 * KERN_INVALID_TASK The space is dead.
435 * KERN_INVALID_NAME The name doesn't denote a right.
441 mach_port_name_t name
,
442 mach_port_type_t
*typep
)
444 mach_port_urefs_t urefs
;
448 if (space
== IS_NULL
)
449 return KERN_INVALID_TASK
;
451 if (name
== MACH_PORT_NULL
)
452 return KERN_INVALID_NAME
;
454 if (name
== MACH_PORT_DEAD
) {
455 *typep
= MACH_PORT_TYPE_DEAD_NAME
;
459 kr
= ipc_right_lookup_write(space
, name
, &entry
);
460 if (kr
!= KERN_SUCCESS
) {
461 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_INVALID_NAME
);
465 /* space is write-locked and active */
466 kr
= ipc_right_info(space
, name
, entry
, typep
, &urefs
);
467 /* space is unlocked */
470 /* JMM - workaround rdar://problem/9121297 (CF being too picky on these bits). */
471 *typep
&= ~(MACH_PORT_TYPE_SPREQUEST
| MACH_PORT_TYPE_SPREQUEST_DELAYED
);
478 * Routine: mach_port_rename [kernel call]
480 * Changes the name denoting a right,
481 * from oname to nname.
485 * KERN_SUCCESS The right is renamed.
486 * KERN_INVALID_TASK The space is null.
487 * KERN_INVALID_TASK The space is dead.
488 * KERN_INVALID_NAME The oname doesn't denote a right.
489 * KERN_INVALID_VALUE The nname isn't a legal name.
490 * KERN_NAME_EXISTS The nname already denotes a right.
491 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
493 * This interface is obsolete and always returns
494 * KERN_NOT_SUPPORTED.
499 __unused ipc_space_t space
,
500 __unused mach_port_name_t oname
,
501 __unused mach_port_name_t nname
)
503 return KERN_NOT_SUPPORTED
;
508 * Routine: mach_port_allocate_name [kernel call]
510 * Allocates a right in a space, using a specific name
511 * for the new right. Possible rights:
512 * MACH_PORT_RIGHT_RECEIVE
513 * MACH_PORT_RIGHT_PORT_SET
514 * MACH_PORT_RIGHT_DEAD_NAME
516 * A new port (allocated with MACH_PORT_RIGHT_RECEIVE)
517 * has no extant send or send-once rights and no queued
518 * messages. Its queue limit is MACH_PORT_QLIMIT_DEFAULT
519 * and its make-send count is 0. It is not a member of
520 * a port set. It has no registered no-senders or
521 * port-destroyed notification requests.
523 * A new port set has no members.
525 * A new dead name has one user reference.
529 * KERN_SUCCESS The right is allocated.
530 * KERN_INVALID_TASK The space is null.
531 * KERN_INVALID_TASK The space is dead.
532 * KERN_INVALID_VALUE The name isn't a legal name.
533 * KERN_INVALID_VALUE "right" isn't a legal kind of right.
534 * KERN_NAME_EXISTS The name already denotes a right.
535 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
537 * Restrictions on name allocation: NT bits are reserved by kernel,
538 * must be set on any chosen name. Can't do this at all in kernel
543 mach_port_allocate_name(
545 mach_port_right_t right
,
546 mach_port_name_t name
)
549 mach_port_qos_t qos
= qos_template
;
553 if (!MACH_PORT_VALID(name
))
554 return KERN_INVALID_VALUE
;
556 kr
= mach_port_allocate_full (space
, right
, MACH_PORT_NULL
,
562 * Routine: mach_port_allocate [kernel call]
564 * Allocates a right in a space. Like mach_port_allocate_name,
565 * except that the implementation picks a name for the right.
566 * The name may be any legal name in the space that doesn't
567 * currently denote a right.
571 * KERN_SUCCESS The right is allocated.
572 * KERN_INVALID_TASK The space is null.
573 * KERN_INVALID_TASK The space is dead.
574 * KERN_INVALID_VALUE "right" isn't a legal kind of right.
575 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
576 * KERN_NO_SPACE No room in space for another right.
582 mach_port_right_t right
,
583 mach_port_name_t
*namep
)
586 mach_port_qos_t qos
= qos_template
;
588 kr
= mach_port_allocate_full (space
, right
, MACH_PORT_NULL
,
594 * Routine: mach_port_allocate_qos [kernel call]
596 * Allocates a right, with qos options, in a space. Like
597 * mach_port_allocate_name, except that the implementation
598 * picks a name for the right. The name may be any legal name
599 * in the space that doesn't currently denote a right.
603 * KERN_SUCCESS The right is allocated.
604 * KERN_INVALID_TASK The space is null.
605 * KERN_INVALID_TASK The space is dead.
606 * KERN_INVALID_VALUE "right" isn't a legal kind of right.
607 * KERN_INVALID_ARGUMENT The qos request was invalid.
608 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
609 * KERN_NO_SPACE No room in space for another right.
613 mach_port_allocate_qos(
615 mach_port_right_t right
,
616 mach_port_qos_t
*qosp
,
617 mach_port_name_t
*namep
)
622 return KERN_INVALID_ARGUMENT
;
623 kr
= mach_port_allocate_full (space
, right
, MACH_PORT_NULL
,
629 * Routine: mach_port_allocate_full [kernel call]
631 * Allocates a right in a space. Supports all of the
632 * special cases, such as specifying a subsystem,
633 * a specific name, a real-time port, etc.
634 * The name may be any legal name in the space that doesn't
635 * currently denote a right.
639 * KERN_SUCCESS The right is allocated.
640 * KERN_INVALID_TASK The space is null.
641 * KERN_INVALID_TASK The space is dead.
642 * KERN_INVALID_VALUE "right" isn't a legal kind of right.
643 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
644 * KERN_NO_SPACE No room in space for another right.
648 mach_port_allocate_full(
650 mach_port_right_t right
,
652 mach_port_qos_t
*qosp
,
653 mach_port_name_t
*namep
)
655 ipc_kmsg_t kmsg
= IKM_NULL
;
658 if (space
== IS_NULL
)
659 return (KERN_INVALID_TASK
);
661 if (proto
!= MACH_PORT_NULL
)
662 return (KERN_INVALID_VALUE
);
665 if (!MACH_PORT_VALID (*namep
))
666 return (KERN_INVALID_VALUE
);
669 if (qosp
->prealloc
) {
670 if (qosp
->len
> MACH_MSG_SIZE_MAX
- MAX_TRAILER_SIZE
) {
671 return KERN_RESOURCE_SHORTAGE
;
673 mach_msg_size_t size
= qosp
->len
+ MAX_TRAILER_SIZE
;
675 if (right
!= MACH_PORT_RIGHT_RECEIVE
) {
676 return (KERN_INVALID_VALUE
);
679 kmsg
= (ipc_kmsg_t
)ipc_kmsg_prealloc(size
);
680 if (kmsg
== IKM_NULL
) {
681 return (KERN_RESOURCE_SHORTAGE
);
687 case MACH_PORT_RIGHT_RECEIVE
:
692 kr
= ipc_port_alloc_name(space
, *namep
, &port
);
694 kr
= ipc_port_alloc(space
, namep
, &port
);
695 if (kr
== KERN_SUCCESS
) {
696 if (kmsg
!= IKM_NULL
)
697 ipc_kmsg_set_prealloc(kmsg
, port
);
701 } else if (kmsg
!= IKM_NULL
)
706 case MACH_PORT_RIGHT_PORT_SET
:
711 kr
= ipc_pset_alloc_name(space
, *namep
, &pset
);
713 kr
= ipc_pset_alloc(space
, namep
, &pset
);
714 if (kr
== KERN_SUCCESS
)
719 case MACH_PORT_RIGHT_DEAD_NAME
:
720 kr
= ipc_object_alloc_dead(space
, namep
);
724 kr
= KERN_INVALID_VALUE
;
732 * Routine: mach_port_destroy [kernel call]
734 * Cleans up and destroys all rights denoted by a name
735 * in a space. The destruction of a receive right
736 * destroys the port, unless a port-destroyed request
737 * has been made for it; the destruction of a port-set right
738 * destroys the port set.
742 * KERN_SUCCESS The name is destroyed.
743 * KERN_INVALID_TASK The space is null.
744 * KERN_INVALID_TASK The space is dead.
745 * KERN_INVALID_NAME The name doesn't denote a right.
751 mach_port_name_t name
)
756 if (space
== IS_NULL
)
757 return KERN_INVALID_TASK
;
759 if (!MACH_PORT_VALID(name
))
762 kr
= ipc_right_lookup_write(space
, name
, &entry
);
763 if (kr
!= KERN_SUCCESS
) {
764 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_INVALID_NAME
);
767 /* space is write-locked and active */
769 kr
= ipc_right_destroy(space
, name
, entry
, TRUE
, 0); /* unlocks space */
774 * Routine: mach_port_deallocate [kernel call]
776 * Deallocates a user reference from a send right,
777 * send-once right, dead-name right or a port_set right.
778 * May deallocate the right, if this is the last uref,
779 * and destroy the name, if it doesn't denote
784 * KERN_SUCCESS The uref is deallocated.
785 * KERN_INVALID_TASK The space is null.
786 * KERN_INVALID_TASK The space is dead.
787 * KERN_INVALID_NAME The name doesn't denote a right.
788 * KERN_INVALID_RIGHT The right isn't correct.
792 mach_port_deallocate(
794 mach_port_name_t name
)
799 if (space
== IS_NULL
)
800 return KERN_INVALID_TASK
;
802 if (!MACH_PORT_VALID(name
))
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
);
810 /* space is write-locked */
812 kr
= ipc_right_dealloc(space
, name
, entry
); /* unlocks space */
817 * Routine: mach_port_get_refs [kernel call]
819 * Retrieves the number of user references held by a right.
820 * Receive rights, port-set rights, and send-once rights
821 * always have one user reference. Returns zero if the
822 * name denotes a right, but not the queried right.
826 * KERN_SUCCESS Number of urefs returned.
827 * KERN_INVALID_TASK The space is null.
828 * KERN_INVALID_TASK The space is dead.
829 * KERN_INVALID_VALUE "right" isn't a legal value.
830 * KERN_INVALID_NAME The name doesn't denote a right.
836 mach_port_name_t name
,
837 mach_port_right_t right
,
838 mach_port_urefs_t
*urefsp
)
840 mach_port_type_t type
;
841 mach_port_urefs_t urefs
;
845 if (space
== IS_NULL
)
846 return KERN_INVALID_TASK
;
848 if (right
>= MACH_PORT_RIGHT_NUMBER
)
849 return KERN_INVALID_VALUE
;
851 if (!MACH_PORT_VALID(name
)) {
852 if (right
== MACH_PORT_RIGHT_SEND
||
853 right
== MACH_PORT_RIGHT_SEND_ONCE
) {
857 return KERN_INVALID_NAME
;
860 kr
= ipc_right_lookup_write(space
, name
, &entry
);
861 if (kr
!= KERN_SUCCESS
) {
862 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_INVALID_NAME
);
866 /* space is write-locked and active */
867 kr
= ipc_right_info(space
, name
, entry
, &type
, &urefs
);
868 /* space is unlocked */
870 if (kr
!= KERN_SUCCESS
)
873 if (type
& MACH_PORT_TYPE(right
))
875 case MACH_PORT_RIGHT_SEND_ONCE
:
879 case MACH_PORT_RIGHT_PORT_SET
:
880 case MACH_PORT_RIGHT_RECEIVE
:
884 case MACH_PORT_RIGHT_DEAD_NAME
:
885 case MACH_PORT_RIGHT_SEND
:
891 panic("mach_port_get_refs: strange rights");
900 * Routine: mach_port_mod_refs
902 * Modifies the number of user references held by a right.
903 * The resulting number of user references must be non-negative.
904 * If it is zero, the right is deallocated. If the name
905 * doesn't denote other rights, it is destroyed.
909 * KERN_SUCCESS Modified number of urefs.
910 * KERN_INVALID_TASK The space is null.
911 * KERN_INVALID_TASK The space is dead.
912 * KERN_INVALID_VALUE "right" isn't a legal value.
913 * KERN_INVALID_NAME The name doesn't denote a right.
914 * KERN_INVALID_RIGHT Name doesn't denote specified right.
915 * KERN_INVALID_VALUE Impossible modification to urefs.
916 * KERN_UREFS_OVERFLOW Urefs would overflow.
922 mach_port_name_t name
,
923 mach_port_right_t right
,
924 mach_port_delta_t delta
)
929 if (space
== IS_NULL
)
930 return KERN_INVALID_TASK
;
932 if (right
>= MACH_PORT_RIGHT_NUMBER
)
933 return KERN_INVALID_VALUE
;
935 if (!MACH_PORT_VALID(name
)) {
936 if (right
== MACH_PORT_RIGHT_SEND
||
937 right
== MACH_PORT_RIGHT_SEND_ONCE
)
939 return KERN_INVALID_NAME
;
942 kr
= ipc_right_lookup_write(space
, name
, &entry
);
943 if (kr
!= KERN_SUCCESS
) {
944 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_INVALID_NAME
);
948 /* space is write-locked and active */
950 kr
= ipc_right_delta(space
, name
, entry
, right
, delta
); /* unlocks */
956 * Routine: mach_port_peek [kernel call]
958 * Peek at the message queue for the specified receive
959 * right and return info about a message in the queue.
961 * On input, seqnop points to a sequence number value
962 * to match the message being peeked. If zero is specified
963 * as the seqno, the first message in the queue will be
966 * Only the following trailer types are currently supported:
967 * MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)
969 * or'ed with one of these element types:
970 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_NULL)
971 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SEQNO)
972 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER)
973 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT)
975 * On input, the value pointed to by trailer_sizep must be
976 * large enough to hold the requested trailer size.
978 * The message sequence number, id, size, requested trailer info
979 * and requested trailer size are returned in their respective
980 * output parameters upon success.
985 * KERN_SUCCESS Matching message found, out parameters set.
986 * KERN_INVALID_TASK The space is null or dead.
987 * KERN_INVALID_NAME The name doesn't denote a right.
988 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
989 * KERN_INVALID_VALUE The input parameter values are out of bounds.
990 * KERN_FAILURE The requested message was not found.
996 mach_port_name_t name
,
997 mach_msg_trailer_type_t trailer_type
,
998 mach_port_seqno_t
*seqnop
,
999 mach_msg_size_t
*msg_sizep
,
1000 mach_msg_id_t
*msg_idp
,
1001 mach_msg_trailer_info_t trailer_infop
,
1002 mach_msg_type_number_t
*trailer_sizep
)
1007 mach_msg_max_trailer_t max_trailer
;
1009 if (space
== IS_NULL
)
1010 return KERN_INVALID_TASK
;
1012 if (!MACH_PORT_VALID(name
))
1013 return KERN_INVALID_RIGHT
;
1016 * We don't allow anything greater than the audit trailer - to avoid
1017 * leaking the context pointer and to avoid variable-sized context issues.
1019 if (GET_RCV_ELEMENTS(trailer_type
) > MACH_RCV_TRAILER_AUDIT
||
1020 REQUESTED_TRAILER_SIZE(TRUE
, trailer_type
) > *trailer_sizep
) {
1021 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_INVALID_VALUE
);
1022 return KERN_INVALID_VALUE
;
1025 *trailer_sizep
= REQUESTED_TRAILER_SIZE(TRUE
, trailer_type
);
1027 kr
= ipc_port_translate_receive(space
, name
, &port
);
1028 if (kr
!= KERN_SUCCESS
) {
1029 mach_port_guard_exception(name
, 0, 0,
1030 ((KERN_INVALID_NAME
== kr
) ?
1031 kGUARD_EXC_INVALID_NAME
:
1032 kGUARD_EXC_INVALID_RIGHT
));
1036 /* Port locked and active */
1038 found
= ipc_mqueue_peek(&port
->ip_messages
, seqnop
,
1039 msg_sizep
, msg_idp
, &max_trailer
, NULL
);
1043 return KERN_FAILURE
;
1045 max_trailer
.msgh_seqno
= *seqnop
;
1046 memcpy(trailer_infop
, &max_trailer
, *trailer_sizep
);
1048 return KERN_SUCCESS
;
1052 * Routine: mach_port_set_mscount [kernel call]
1054 * Changes a receive right's make-send count.
1058 * KERN_SUCCESS Set make-send count.
1059 * KERN_INVALID_TASK The space is null.
1060 * KERN_INVALID_TASK The space is dead.
1061 * KERN_INVALID_NAME The name doesn't denote a right.
1062 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1066 mach_port_set_mscount(
1068 mach_port_name_t name
,
1069 mach_port_mscount_t mscount
)
1074 if (space
== IS_NULL
)
1075 return KERN_INVALID_TASK
;
1077 if (!MACH_PORT_VALID(name
))
1078 return KERN_INVALID_RIGHT
;
1080 kr
= ipc_port_translate_receive(space
, name
, &port
);
1081 if (kr
!= KERN_SUCCESS
)
1083 /* port is locked and active */
1085 ipc_port_set_mscount(port
, mscount
);
1088 return KERN_SUCCESS
;
1092 * Routine: mach_port_set_seqno [kernel call]
1094 * Changes a receive right's sequence number.
1098 * KERN_SUCCESS Set sequence number.
1099 * KERN_INVALID_TASK The space is null.
1100 * KERN_INVALID_TASK The space is dead.
1101 * KERN_INVALID_NAME The name doesn't denote a right.
1102 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1106 mach_port_set_seqno(
1108 mach_port_name_t name
,
1109 mach_port_seqno_t seqno
)
1114 if (space
== IS_NULL
)
1115 return KERN_INVALID_TASK
;
1117 if (!MACH_PORT_VALID(name
))
1118 return KERN_INVALID_RIGHT
;
1120 kr
= ipc_port_translate_receive(space
, name
, &port
);
1121 if (kr
!= KERN_SUCCESS
)
1123 /* port is locked and active */
1125 ipc_mqueue_set_seqno(&port
->ip_messages
, seqno
);
1128 return KERN_SUCCESS
;
1132 * Routine: mach_port_get_context [kernel call]
1134 * Returns a receive right's context pointer.
1138 * KERN_SUCCESS Set context pointer.
1139 * KERN_INVALID_TASK The space is null.
1140 * KERN_INVALID_TASK The space is dead.
1141 * KERN_INVALID_NAME The name doesn't denote a right.
1142 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1146 mach_port_get_context(
1148 mach_port_name_t name
,
1149 mach_vm_address_t
*context
)
1154 if (space
== IS_NULL
)
1155 return KERN_INVALID_TASK
;
1157 if (!MACH_PORT_VALID(name
))
1158 return KERN_INVALID_RIGHT
;
1160 kr
= ipc_port_translate_receive(space
, name
, &port
);
1161 if (kr
!= KERN_SUCCESS
)
1164 /* Port locked and active */
1166 /* For strictly guarded ports, return empty context (which acts as guard) */
1167 if (port
->ip_strict_guard
)
1170 *context
= port
->ip_context
;
1173 return KERN_SUCCESS
;
1178 * Routine: mach_port_set_context [kernel call]
1180 * Changes a receive right's context pointer.
1184 * KERN_SUCCESS Set context pointer.
1185 * KERN_INVALID_TASK The space is null.
1186 * KERN_INVALID_TASK The space is dead.
1187 * KERN_INVALID_NAME The name doesn't denote a right.
1188 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1192 mach_port_set_context(
1194 mach_port_name_t name
,
1195 mach_vm_address_t context
)
1200 if (space
== IS_NULL
)
1201 return KERN_INVALID_TASK
;
1203 if (!MACH_PORT_VALID(name
))
1204 return KERN_INVALID_RIGHT
;
1206 kr
= ipc_port_translate_receive(space
, name
, &port
);
1207 if (kr
!= KERN_SUCCESS
)
1210 /* port is locked and active */
1211 if(port
->ip_strict_guard
) {
1212 uint64_t portguard
= port
->ip_context
;
1214 /* For strictly guarded ports, disallow overwriting context; Raise Exception */
1215 mach_port_guard_exception(name
, context
, portguard
, kGUARD_EXC_SET_CONTEXT
);
1216 return KERN_INVALID_ARGUMENT
;
1219 port
->ip_context
= context
;
1222 return KERN_SUCCESS
;
1227 * Routine: mach_port_get_set_status [kernel call]
1229 * Retrieves a list of members in a port set.
1230 * Returns the space's name for each receive right member.
1234 * KERN_SUCCESS Retrieved list of members.
1235 * KERN_INVALID_TASK The space is null.
1236 * KERN_INVALID_TASK The space is dead.
1237 * KERN_INVALID_NAME The name doesn't denote a right.
1238 * KERN_INVALID_RIGHT Name doesn't denote a port set.
1239 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1243 mach_port_get_set_status(
1245 mach_port_name_t name
,
1246 mach_port_name_t
**members
,
1247 mach_msg_type_number_t
*membersCnt
)
1249 ipc_entry_num_t actual
; /* this many members */
1250 ipc_entry_num_t maxnames
; /* space for this many members */
1253 vm_size_t size
; /* size of allocated memory */
1254 vm_offset_t addr
; /* allocated memory */
1255 vm_map_copy_t memory
; /* copied-in memory */
1257 if (space
== IS_NULL
)
1258 return KERN_INVALID_TASK
;
1260 if (!MACH_PORT_VALID(name
))
1261 return KERN_INVALID_RIGHT
;
1263 size
= VM_MAP_PAGE_SIZE(ipc_kernel_map
); /* initial guess */
1266 mach_port_name_t
*names
;
1270 kr
= vm_allocate_kernel(ipc_kernel_map
, &addr
, size
, VM_FLAGS_ANYWHERE
, VM_KERN_MEMORY_IPC
);
1271 if (kr
!= KERN_SUCCESS
)
1272 return KERN_RESOURCE_SHORTAGE
;
1274 /* can't fault while we hold locks */
1276 kr
= vm_map_wire_kernel(ipc_kernel_map
, addr
, addr
+ size
,
1277 VM_PROT_READ
|VM_PROT_WRITE
, VM_KERN_MEMORY_IPC
, FALSE
);
1278 assert(kr
== KERN_SUCCESS
);
1280 kr
= ipc_object_translate(space
, name
, MACH_PORT_RIGHT_PORT_SET
, &psobj
);
1281 if (kr
!= KERN_SUCCESS
) {
1282 kmem_free(ipc_kernel_map
, addr
, size
);
1286 /* just use a portset reference from here on out */
1287 __IGNORE_WCASTALIGN(pset
= (ipc_pset_t
) psobj
);
1288 ips_reference(pset
);
1291 names
= (mach_port_name_t
*) addr
;
1292 maxnames
= (ipc_entry_num_t
)(size
/ sizeof(mach_port_name_t
));
1294 ipc_mqueue_set_gather_member_names(space
, &pset
->ips_messages
, maxnames
, names
, &actual
);
1296 /* release the portset reference */
1299 if (actual
<= maxnames
)
1302 /* didn't have enough memory; allocate more */
1303 kmem_free(ipc_kernel_map
, addr
, size
);
1304 size
= vm_map_round_page(
1305 (actual
* sizeof(mach_port_name_t
)),
1306 VM_MAP_PAGE_MASK(ipc_kernel_map
)) +
1307 VM_MAP_PAGE_SIZE(ipc_kernel_map
);
1311 memory
= VM_MAP_COPY_NULL
;
1313 kmem_free(ipc_kernel_map
, addr
, size
);
1315 vm_size_t size_used
;
1316 vm_size_t vm_size_used
;
1318 size_used
= actual
* sizeof(mach_port_name_t
);
1319 vm_size_used
= vm_map_round_page(
1321 VM_MAP_PAGE_MASK(ipc_kernel_map
));
1324 * Make used memory pageable and get it into
1325 * copied-in form. Free any unused memory.
1330 vm_map_trunc_page(addr
,
1331 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
1332 vm_map_round_page(addr
+ vm_size_used
,
1333 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
1335 assert(kr
== KERN_SUCCESS
);
1337 kr
= vm_map_copyin(ipc_kernel_map
, (vm_map_address_t
)addr
,
1338 (vm_map_size_t
)size_used
, TRUE
, &memory
);
1339 assert(kr
== KERN_SUCCESS
);
1341 if (vm_size_used
!= size
)
1342 kmem_free(ipc_kernel_map
,
1343 addr
+ vm_size_used
, size
- vm_size_used
);
1346 *members
= (mach_port_name_t
*) memory
;
1347 *membersCnt
= actual
;
1348 return KERN_SUCCESS
;
1352 * Routine: mach_port_move_member [kernel call]
1354 * If after is MACH_PORT_NULL, removes member
1355 * from the port set it is in. Otherwise, adds
1356 * member to after, removing it from any set
1357 * it might already be in.
1361 * KERN_SUCCESS Moved the port.
1362 * KERN_INVALID_TASK The space is null.
1363 * KERN_INVALID_TASK The space is dead.
1364 * KERN_INVALID_NAME Member didn't denote a right.
1365 * KERN_INVALID_RIGHT Member didn't denote a receive right.
1366 * KERN_INVALID_NAME After didn't denote a right.
1367 * KERN_INVALID_RIGHT After didn't denote a port set right.
1369 * After is MACH_PORT_NULL and Member isn't in a port set.
1373 mach_port_move_member(
1375 mach_port_name_t member
,
1376 mach_port_name_t after
)
1382 uint64_t wq_link_id
= 0;
1383 uint64_t wq_reserved_prepost
= 0;
1385 if (space
== IS_NULL
)
1386 return KERN_INVALID_TASK
;
1388 if (!MACH_PORT_VALID(member
))
1389 return KERN_INVALID_RIGHT
;
1391 if (after
== MACH_PORT_DEAD
) {
1392 return KERN_INVALID_RIGHT
;
1393 } else if (after
== MACH_PORT_NULL
) {
1397 * We reserve both a link, and
1398 * enough prepost objects to complete
1399 * the set move atomically - we can't block
1400 * while we're holding the space lock, and
1401 * the ipc_pset_add calls ipc_mqueue_add
1402 * which may have to prepost this port onto
1405 wq_link_id
= waitq_link_reserve(NULL
);
1406 wq_reserved_prepost
= waitq_prepost_reserve(NULL
, 10,
1408 kr
= ipc_pset_lazy_allocate(space
, after
);
1409 if (kr
!= KERN_SUCCESS
)
1413 kr
= ipc_right_lookup_read(space
, member
, &entry
);
1414 if (kr
!= KERN_SUCCESS
)
1416 /* space is read-locked and active */
1418 if ((entry
->ie_bits
& MACH_PORT_TYPE_RECEIVE
) == 0) {
1419 is_read_unlock(space
);
1420 kr
= KERN_INVALID_RIGHT
;
1424 __IGNORE_WCASTALIGN(port
= (ipc_port_t
) entry
->ie_object
);
1425 assert(port
!= IP_NULL
);
1427 if (after
== MACH_PORT_NULL
)
1430 entry
= ipc_entry_lookup(space
, after
);
1431 if (entry
== IE_NULL
) {
1432 is_read_unlock(space
);
1433 kr
= KERN_INVALID_NAME
;
1437 if ((entry
->ie_bits
& MACH_PORT_TYPE_PORT_SET
) == 0) {
1438 is_read_unlock(space
);
1439 kr
= KERN_INVALID_RIGHT
;
1443 __IGNORE_WCASTALIGN(nset
= (ipc_pset_t
) entry
->ie_object
);
1444 assert(nset
!= IPS_NULL
);
1447 assert(ip_active(port
));
1448 ipc_pset_remove_from_all(port
);
1450 if (nset
!= IPS_NULL
) {
1452 kr
= ipc_pset_add(nset
, port
, &wq_link_id
, &wq_reserved_prepost
);
1456 is_read_unlock(space
);
1461 * on success the ipc_pset_add() will consume the wq_link_id
1462 * value (resetting it to 0), so this function is always safe to call.
1464 waitq_link_release(wq_link_id
);
1465 waitq_prepost_release_reserve(wq_reserved_prepost
);
1471 * Routine: mach_port_request_notification [kernel call]
1473 * Requests a notification. The caller supplies
1474 * a send-once right for the notification to use,
1475 * and the call returns the previously registered
1476 * send-once right, if any. Possible types:
1478 * MACH_NOTIFY_PORT_DESTROYED
1479 * Requests a port-destroyed notification
1480 * for a receive right. Sync should be zero.
1481 * MACH_NOTIFY_NO_SENDERS
1482 * Requests a no-senders notification for a
1483 * receive right. If there are currently no
1484 * senders, sync is less than or equal to the
1485 * current make-send count, and a send-once right
1486 * is supplied, then an immediate no-senders
1487 * notification is generated.
1488 * MACH_NOTIFY_DEAD_NAME
1489 * Requests a dead-name notification for a send
1490 * or receive right. If the name is already a
1491 * dead name, sync is non-zero, and a send-once
1492 * right is supplied, then an immediate dead-name
1493 * notification is generated.
1497 * KERN_SUCCESS Requested a notification.
1498 * KERN_INVALID_TASK The space is null.
1499 * KERN_INVALID_TASK The space is dead.
1500 * KERN_INVALID_VALUE Bad id value.
1501 * KERN_INVALID_NAME Name doesn't denote a right.
1502 * KERN_INVALID_RIGHT Name doesn't denote appropriate right.
1503 * KERN_INVALID_CAPABILITY The notify port is dead.
1504 * MACH_NOTIFY_PORT_DESTROYED:
1505 * KERN_INVALID_VALUE Sync isn't zero.
1506 * MACH_NOTIFY_DEAD_NAME:
1507 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1508 * KERN_INVALID_ARGUMENT Name denotes dead name, but
1509 * sync is zero or notify is IP_NULL.
1510 * KERN_UREFS_OVERFLOW Name denotes dead name, but
1511 * generating immediate notif. would overflow urefs.
1515 mach_port_request_notification(
1517 mach_port_name_t name
,
1519 mach_port_mscount_t sync
,
1521 ipc_port_t
*previousp
)
1525 if (space
== IS_NULL
)
1526 return KERN_INVALID_TASK
;
1528 if (notify
== IP_DEAD
)
1529 return KERN_INVALID_CAPABILITY
;
1533 * Requesting notifications on RPC ports is an error.
1539 kr
= ipc_right_lookup_write(space
, name
, &entry
);
1540 if (kr
!= KERN_SUCCESS
)
1543 port
= (ipc_port_t
) entry
->ie_object
;
1545 if (port
->ip_subsystem
!= NULL
) {
1546 is_write_unlock(space
);
1547 panic("mach_port_request_notification: on RPC port!!");
1548 return KERN_INVALID_CAPABILITY
;
1550 is_write_unlock(space
);
1556 case MACH_NOTIFY_PORT_DESTROYED
: {
1557 ipc_port_t port
, previous
;
1560 return KERN_INVALID_VALUE
;
1562 if (!MACH_PORT_VALID(name
))
1563 return KERN_INVALID_RIGHT
;
1565 kr
= ipc_port_translate_receive(space
, name
, &port
);
1566 if (kr
!= KERN_SUCCESS
)
1568 /* port is locked and active */
1570 /* you cannot register for port death notifications on a kobject */
1571 if (ip_kotype(port
) != IKOT_NONE
) {
1573 return KERN_INVALID_RIGHT
;
1576 ipc_port_pdrequest(port
, notify
, &previous
);
1577 /* port is unlocked */
1579 *previousp
= previous
;
1583 case MACH_NOTIFY_NO_SENDERS
: {
1586 if (!MACH_PORT_VALID(name
))
1587 return KERN_INVALID_RIGHT
;
1589 kr
= ipc_port_translate_receive(space
, name
, &port
);
1590 if (kr
!= KERN_SUCCESS
)
1592 /* port is locked and active */
1594 ipc_port_nsrequest(port
, sync
, notify
, previousp
);
1595 /* port is unlocked */
1599 case MACH_NOTIFY_SEND_POSSIBLE
:
1601 if (!MACH_PORT_VALID(name
)) {
1602 return KERN_INVALID_ARGUMENT
;
1605 kr
= ipc_right_request_alloc(space
, name
, sync
!= 0,
1606 TRUE
, notify
, previousp
);
1607 if (kr
!= KERN_SUCCESS
)
1611 case MACH_NOTIFY_DEAD_NAME
:
1613 if (!MACH_PORT_VALID(name
)) {
1616 * Should do immediate delivery check -
1617 * will do that in the near future.
1619 return KERN_INVALID_ARGUMENT
;
1622 kr
= ipc_right_request_alloc(space
, name
, sync
!= 0,
1623 FALSE
, notify
, previousp
);
1624 if (kr
!= KERN_SUCCESS
)
1629 return KERN_INVALID_VALUE
;
1632 return KERN_SUCCESS
;
1636 * Routine: mach_port_insert_right [kernel call]
1638 * Inserts a right into a space, as if the space
1639 * voluntarily received the right in a message,
1640 * except that the right gets the specified name.
1644 * KERN_SUCCESS Inserted the right.
1645 * KERN_INVALID_TASK The space is null.
1646 * KERN_INVALID_TASK The space is dead.
1647 * KERN_INVALID_VALUE The name isn't a legal name.
1648 * KERN_NAME_EXISTS The name already denotes a right.
1649 * KERN_INVALID_VALUE Message doesn't carry a port right.
1650 * KERN_INVALID_CAPABILITY Port is null or dead.
1651 * KERN_UREFS_OVERFLOW Urefs limit would be exceeded.
1652 * KERN_RIGHT_EXISTS Space has rights under another name.
1653 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1657 mach_port_insert_right(
1659 mach_port_name_t name
,
1661 mach_msg_type_name_t polyPoly
)
1663 if (space
== IS_NULL
)
1664 return KERN_INVALID_TASK
;
1666 if (!MACH_PORT_VALID(name
) ||
1667 !MACH_MSG_TYPE_PORT_ANY_RIGHT(polyPoly
))
1668 return KERN_INVALID_VALUE
;
1670 if (!IO_VALID((ipc_object_t
) poly
))
1671 return KERN_INVALID_CAPABILITY
;
1673 return ipc_object_copyout_name(space
, (ipc_object_t
) poly
,
1674 polyPoly
, FALSE
, name
);
1678 * Routine: mach_port_extract_right [kernel call]
1680 * Extracts a right from a space, as if the space
1681 * voluntarily sent the right to the caller.
1685 * KERN_SUCCESS Extracted the right.
1686 * KERN_INVALID_TASK The space is null.
1687 * KERN_INVALID_TASK The space is dead.
1688 * KERN_INVALID_VALUE Requested type isn't a port right.
1689 * KERN_INVALID_NAME Name doesn't denote a right.
1690 * KERN_INVALID_RIGHT Name doesn't denote appropriate right.
1694 mach_port_extract_right(
1696 mach_port_name_t name
,
1697 mach_msg_type_name_t msgt_name
,
1699 mach_msg_type_name_t
*polyPoly
)
1703 if (space
== IS_NULL
)
1704 return KERN_INVALID_TASK
;
1706 if (!MACH_MSG_TYPE_PORT_ANY(msgt_name
))
1707 return KERN_INVALID_VALUE
;
1709 if (!MACH_PORT_VALID(name
)) {
1711 * really should copy out a dead name, if it is a send or
1712 * send-once right being copied, but instead return an
1715 return KERN_INVALID_RIGHT
;
1718 kr
= ipc_object_copyin(space
, name
, msgt_name
, (ipc_object_t
*) poly
);
1720 if (kr
== KERN_SUCCESS
)
1721 *polyPoly
= ipc_object_copyin_type(msgt_name
);
1726 * Routine: mach_port_get_status_helper [helper]
1728 * Populates a mach_port_status_t structure with
1731 * Port needs to be locked
1735 void mach_port_get_status_helper(
1737 mach_port_status_t
*statusp
)
1739 imq_lock(&port
->ip_messages
);
1740 /* don't leak set IDs, just indicate that the port is in one or not */
1741 statusp
->mps_pset
= !!(port
->ip_in_pset
);
1742 statusp
->mps_seqno
= port
->ip_messages
.imq_seqno
;
1743 statusp
->mps_qlimit
= port
->ip_messages
.imq_qlimit
;
1744 statusp
->mps_msgcount
= port
->ip_messages
.imq_msgcount
;
1745 imq_unlock(&port
->ip_messages
);
1747 statusp
->mps_mscount
= port
->ip_mscount
;
1748 statusp
->mps_sorights
= port
->ip_sorights
;
1749 statusp
->mps_srights
= port
->ip_srights
> 0;
1750 statusp
->mps_pdrequest
= port
->ip_pdrequest
!= IP_NULL
;
1751 statusp
->mps_nsrequest
= port
->ip_nsrequest
!= IP_NULL
;
1752 statusp
->mps_flags
= 0;
1753 if (port
->ip_impdonation
) {
1754 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_IMP_DONATION
;
1755 if (port
->ip_tempowner
) {
1756 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_TEMPOWNER
;
1757 if (IIT_NULL
!= port
->ip_imp_task
) {
1758 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_TASKPTR
;
1762 if (port
->ip_guarded
) {
1763 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_GUARDED
;
1764 if (port
->ip_strict_guard
) {
1765 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_STRICT_GUARD
;
1774 mach_port_get_attributes(
1776 mach_port_name_t name
,
1778 mach_port_info_t info
,
1779 mach_msg_type_number_t
*count
)
1784 if (space
== IS_NULL
)
1785 return KERN_INVALID_TASK
;
1788 case MACH_PORT_LIMITS_INFO
: {
1789 mach_port_limits_t
*lp
= (mach_port_limits_t
*)info
;
1791 if (*count
< MACH_PORT_LIMITS_INFO_COUNT
)
1792 return KERN_FAILURE
;
1794 if (!MACH_PORT_VALID(name
)) {
1799 kr
= ipc_port_translate_receive(space
, name
, &port
);
1800 if (kr
!= KERN_SUCCESS
)
1802 /* port is locked and active */
1804 lp
->mpl_qlimit
= port
->ip_messages
.imq_qlimit
;
1805 *count
= MACH_PORT_LIMITS_INFO_COUNT
;
1810 case MACH_PORT_RECEIVE_STATUS
: {
1811 mach_port_status_t
*statusp
= (mach_port_status_t
*)info
;
1813 if (*count
< MACH_PORT_RECEIVE_STATUS_COUNT
)
1814 return KERN_FAILURE
;
1816 if (!MACH_PORT_VALID(name
))
1817 return KERN_INVALID_RIGHT
;
1819 kr
= ipc_port_translate_receive(space
, name
, &port
);
1820 if (kr
!= KERN_SUCCESS
)
1822 /* port is locked and active */
1823 mach_port_get_status_helper(port
, statusp
);
1824 *count
= MACH_PORT_RECEIVE_STATUS_COUNT
;
1829 case MACH_PORT_DNREQUESTS_SIZE
: {
1830 ipc_port_request_t table
;
1832 if (*count
< MACH_PORT_DNREQUESTS_SIZE_COUNT
)
1833 return KERN_FAILURE
;
1835 if (!MACH_PORT_VALID(name
)) {
1840 kr
= ipc_port_translate_receive(space
, name
, &port
);
1841 if (kr
!= KERN_SUCCESS
)
1843 /* port is locked and active */
1845 table
= port
->ip_requests
;
1846 if (table
== IPR_NULL
)
1849 *(int *)info
= table
->ipr_size
->its_size
;
1850 *count
= MACH_PORT_DNREQUESTS_SIZE_COUNT
;
1855 case MACH_PORT_INFO_EXT
: {
1856 mach_port_info_ext_t
*mp_info
= (mach_port_info_ext_t
*)info
;
1857 if (*count
< MACH_PORT_INFO_EXT_COUNT
)
1858 return KERN_FAILURE
;
1860 if (!MACH_PORT_VALID(name
))
1861 return KERN_INVALID_RIGHT
;
1863 kr
= ipc_port_translate_receive(space
, name
, &port
);
1864 if (kr
!= KERN_SUCCESS
)
1866 /* port is locked and active */
1867 mach_port_get_status_helper(port
, &mp_info
->mpie_status
);
1868 mp_info
->mpie_boost_cnt
= port
->ip_impcount
;
1869 *count
= MACH_PORT_INFO_EXT_COUNT
;
1875 return KERN_INVALID_ARGUMENT
;
1879 return KERN_SUCCESS
;
1883 mach_port_set_attributes(
1885 mach_port_name_t name
,
1887 mach_port_info_t info
,
1888 mach_msg_type_number_t count
)
1893 if (space
== IS_NULL
)
1894 return KERN_INVALID_TASK
;
1898 case MACH_PORT_LIMITS_INFO
: {
1899 mach_port_limits_t
*mplp
= (mach_port_limits_t
*)info
;
1901 if (count
< MACH_PORT_LIMITS_INFO_COUNT
)
1902 return KERN_FAILURE
;
1904 if (mplp
->mpl_qlimit
> MACH_PORT_QLIMIT_MAX
)
1905 return KERN_INVALID_VALUE
;
1907 if (!MACH_PORT_VALID(name
))
1908 return KERN_INVALID_RIGHT
;
1910 kr
= ipc_port_translate_receive(space
, name
, &port
);
1911 if (kr
!= KERN_SUCCESS
)
1913 /* port is locked and active */
1915 ipc_mqueue_set_qlimit(&port
->ip_messages
, mplp
->mpl_qlimit
);
1919 case MACH_PORT_DNREQUESTS_SIZE
: {
1920 if (count
< MACH_PORT_DNREQUESTS_SIZE_COUNT
)
1921 return KERN_FAILURE
;
1923 if (!MACH_PORT_VALID(name
))
1924 return KERN_INVALID_RIGHT
;
1926 kr
= ipc_port_translate_receive(space
, name
, &port
);
1927 if (kr
!= KERN_SUCCESS
)
1929 /* port is locked and active */
1931 kr
= ipc_port_request_grow(port
, *(int *)info
);
1932 if (kr
!= KERN_SUCCESS
)
1936 case MACH_PORT_TEMPOWNER
:
1937 if (!MACH_PORT_VALID(name
))
1938 return KERN_INVALID_RIGHT
;
1940 ipc_importance_task_t release_imp_task
= IIT_NULL
;
1941 natural_t assertcnt
= 0;
1943 kr
= ipc_port_translate_receive(space
, name
, &port
);
1944 if (kr
!= KERN_SUCCESS
)
1946 /* port is locked and active */
1949 * don't allow temp-owner importance donation if user
1950 * associated it with a kobject already (timer, host_notify target),
1951 * or is a special reply port.
1953 if (is_ipc_kobject(ip_kotype(port
)) || port
->ip_specialreply
) {
1955 return KERN_INVALID_ARGUMENT
;
1958 if (port
->ip_tempowner
!= 0) {
1959 if (IIT_NULL
!= port
->ip_imp_task
) {
1960 release_imp_task
= port
->ip_imp_task
;
1961 port
->ip_imp_task
= IIT_NULL
;
1962 assertcnt
= port
->ip_impcount
;
1965 assertcnt
= port
->ip_impcount
;
1968 port
->ip_impdonation
= 1;
1969 port
->ip_tempowner
= 1;
1972 #if IMPORTANCE_INHERITANCE
1973 /* drop assertions from previous destination task */
1974 if (release_imp_task
!= IIT_NULL
) {
1975 assert(ipc_importance_task_is_any_receiver_type(release_imp_task
));
1977 ipc_importance_task_drop_internal_assertion(release_imp_task
, assertcnt
);
1978 ipc_importance_task_release(release_imp_task
);
1979 } else if (assertcnt
> 0) {
1980 release_imp_task
= current_task()->task_imp_base
;
1981 if (release_imp_task
!= IIT_NULL
&&
1982 ipc_importance_task_is_any_receiver_type(release_imp_task
)) {
1983 ipc_importance_task_drop_internal_assertion(release_imp_task
, assertcnt
);
1987 if (release_imp_task
!= IIT_NULL
)
1988 ipc_importance_task_release(release_imp_task
);
1989 #endif /* IMPORTANCE_INHERITANCE */
1993 #if IMPORTANCE_INHERITANCE
1994 case MACH_PORT_DENAP_RECEIVER
:
1995 case MACH_PORT_IMPORTANCE_RECEIVER
:
1996 if (!MACH_PORT_VALID(name
))
1997 return KERN_INVALID_RIGHT
;
1999 kr
= ipc_port_translate_receive(space
, name
, &port
);
2000 if (kr
!= KERN_SUCCESS
)
2004 * don't allow importance donation if user associated
2005 * it with a kobject already (timer, host_notify target),
2006 * or is a special reply port.
2008 if (is_ipc_kobject(ip_kotype(port
)) || port
->ip_specialreply
) {
2010 return KERN_INVALID_ARGUMENT
;
2013 /* port is locked and active */
2014 port
->ip_impdonation
= 1;
2018 #endif /* IMPORTANCE_INHERITANCE */
2021 return KERN_INVALID_ARGUMENT
;
2024 return KERN_SUCCESS
;
2028 * Routine: mach_port_insert_member [kernel call]
2030 * Add the receive right, specified by name, to
2032 * The port cannot already be a member of the set.
2036 * KERN_SUCCESS Moved the port.
2037 * KERN_INVALID_TASK The space is null.
2038 * KERN_INVALID_TASK The space is dead.
2039 * KERN_INVALID_NAME name didn't denote a right.
2040 * KERN_INVALID_RIGHT name didn't denote a receive right.
2041 * KERN_INVALID_NAME pset_name didn't denote a right.
2042 * KERN_INVALID_RIGHT pset_name didn't denote a portset right.
2043 * KERN_ALREADY_IN_SET name was already a member of pset.
2047 mach_port_insert_member(
2049 mach_port_name_t name
,
2050 mach_port_name_t psname
)
2055 uint64_t wq_link_id
;
2056 uint64_t wq_reserved_prepost
;
2058 if (space
== IS_NULL
)
2059 return KERN_INVALID_TASK
;
2061 if (!MACH_PORT_VALID(name
) || !MACH_PORT_VALID(psname
))
2062 return KERN_INVALID_RIGHT
;
2064 wq_link_id
= waitq_link_reserve(NULL
);
2065 wq_reserved_prepost
= waitq_prepost_reserve(NULL
, 10,
2067 kr
= ipc_pset_lazy_allocate(space
, psname
);
2068 if (kr
!= KERN_SUCCESS
)
2072 kr
= ipc_object_translate_two(space
,
2073 name
, MACH_PORT_RIGHT_RECEIVE
, &obj
,
2074 psname
, MACH_PORT_RIGHT_PORT_SET
, &psobj
);
2075 if (kr
!= KERN_SUCCESS
)
2078 /* obj and psobj are locked (and were locked in that order) */
2079 assert(psobj
!= IO_NULL
);
2080 assert(obj
!= IO_NULL
);
2082 __IGNORE_WCASTALIGN(kr
= ipc_pset_add((ipc_pset_t
)psobj
, (ipc_port_t
)obj
,
2083 &wq_link_id
, &wq_reserved_prepost
));
2089 /* on success, wq_link_id is reset to 0, so this is always safe */
2090 waitq_link_release(wq_link_id
);
2091 waitq_prepost_release_reserve(wq_reserved_prepost
);
2097 * Routine: mach_port_extract_member [kernel call]
2099 * Remove a port from one portset that it is a member of.
2103 * KERN_SUCCESS Moved the port.
2104 * KERN_INVALID_TASK The space is null.
2105 * KERN_INVALID_TASK The space is dead.
2106 * KERN_INVALID_NAME Member didn't denote a right.
2107 * KERN_INVALID_RIGHT Member didn't denote a receive right.
2108 * KERN_INVALID_NAME After didn't denote a right.
2109 * KERN_INVALID_RIGHT After didn't denote a port set right.
2111 * After is MACH_PORT_NULL and Member isn't in a port set.
2115 mach_port_extract_member(
2117 mach_port_name_t name
,
2118 mach_port_name_t psname
)
2124 if (space
== IS_NULL
)
2125 return KERN_INVALID_TASK
;
2127 if (!MACH_PORT_VALID(name
) || !MACH_PORT_VALID(psname
))
2128 return KERN_INVALID_RIGHT
;
2130 kr
= ipc_object_translate_two(space
,
2131 name
, MACH_PORT_RIGHT_RECEIVE
, &obj
,
2132 psname
, MACH_PORT_RIGHT_PORT_SET
, &psobj
);
2133 if (kr
!= KERN_SUCCESS
)
2136 /* obj and psobj are both locked (and were locked in that order) */
2137 assert(psobj
!= IO_NULL
);
2138 assert(obj
!= IO_NULL
);
2140 __IGNORE_WCASTALIGN(kr
= ipc_pset_remove((ipc_pset_t
)psobj
, (ipc_port_t
)obj
));
2149 * task_set_port_space:
2151 * Set port name space of task to specified size.
2154 task_set_port_space(
2160 if (space
== IS_NULL
)
2161 return KERN_INVALID_TASK
;
2163 is_write_lock(space
);
2165 if (!is_active(space
)) {
2166 is_write_unlock(space
);
2167 return KERN_INVALID_TASK
;
2170 kr
= ipc_entry_grow_table(space
, table_entries
);
2171 if (kr
== KERN_SUCCESS
)
2172 is_write_unlock(space
);
2177 * Routine: mach_port_guard_locked [helper routine]
2179 * Sets a new guard for a locked port.
2183 * KERN_SUCCESS Port Guarded.
2184 * KERN_INVALID_ARGUMENT Port already contains a context/guard.
2186 static kern_return_t
2187 mach_port_guard_locked(
2192 if (port
->ip_context
)
2193 return KERN_INVALID_ARGUMENT
;
2195 port
->ip_context
= guard
;
2196 port
->ip_guarded
= 1;
2197 port
->ip_strict_guard
= (strict
)?1:0;
2198 return KERN_SUCCESS
;
2202 * Routine: mach_port_unguard_locked [helper routine]
2204 * Removes guard for a locked port.
2208 * KERN_SUCCESS Port Unguarded.
2209 * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch.
2210 * This also raises a EXC_GUARD exception.
2212 static kern_return_t
2213 mach_port_unguard_locked(
2215 mach_port_name_t name
,
2218 /* Port locked and active */
2219 if (!port
->ip_guarded
) {
2220 /* Port already unguarded; Raise exception */
2221 mach_port_guard_exception(name
, guard
, 0, kGUARD_EXC_UNGUARDED
);
2222 return KERN_INVALID_ARGUMENT
;
2225 if (port
->ip_context
!= guard
) {
2226 /* Incorrect guard; Raise exception */
2227 mach_port_guard_exception(name
, guard
, port
->ip_context
, kGUARD_EXC_INCORRECT_GUARD
);
2228 return KERN_INVALID_ARGUMENT
;
2231 port
->ip_context
= 0;
2232 port
->ip_guarded
= port
->ip_strict_guard
= 0;
2233 return KERN_SUCCESS
;
2238 * Routine: mach_port_guard_exception [helper routine]
2240 * Marks the thread with AST_GUARD for mach port guard violation.
2241 * Also saves exception info in thread structure.
2245 * KERN_FAILURE Thread marked with AST_GUARD.
2248 mach_port_guard_exception(
2249 mach_port_name_t name
,
2250 __unused
uint64_t inguard
,
2254 mach_exception_code_t code
= 0;
2255 EXC_GUARD_ENCODE_TYPE(code
, GUARD_TYPE_MACH_PORT
);
2256 EXC_GUARD_ENCODE_FLAVOR(code
, reason
);
2257 EXC_GUARD_ENCODE_TARGET(code
, name
);
2258 mach_exception_subcode_t subcode
= (uint64_t)portguard
;
2259 thread_t t
= current_thread();
2260 thread_guard_violation(t
, code
, subcode
);
2265 * Routine: mach_port_guard_ast
2267 * Raises an exception for mach port guard violation.
2275 mach_port_guard_ast(thread_t t
,
2276 mach_exception_data_type_t code
, mach_exception_data_type_t subcode
)
2278 unsigned int reason
= EXC_GUARD_DECODE_GUARD_FLAVOR(code
);
2279 task_t task
= t
->task
;
2280 unsigned int behavior
= task
->task_exc_guard
;
2281 assert(task
== current_task());
2282 assert(task
!= kernel_task
);
2286 * Fatal Mach port guards - always delivered synchronously
2288 case kGUARD_EXC_DESTROY
:
2289 case kGUARD_EXC_MOD_REFS
:
2290 case kGUARD_EXC_SET_CONTEXT
:
2291 case kGUARD_EXC_UNGUARDED
:
2292 case kGUARD_EXC_INCORRECT_GUARD
:
2293 task_exception_notify(EXC_GUARD
, code
, subcode
);
2294 task_bsdtask_kill(task
);
2299 * Mach port guards controlled by task settings.
2302 /* Is delivery enabled */
2303 if ((behavior
& TASK_EXC_GUARD_MP_DELIVER
) == 0) {
2307 /* If only once, make sure we're that once */
2308 while (behavior
& TASK_EXC_GUARD_MP_ONCE
) {
2309 uint32_t new_behavior
= behavior
& ~TASK_EXC_GUARD_MP_DELIVER
;
2311 if (OSCompareAndSwap(behavior
, new_behavior
, &task
->task_exc_guard
)) {
2314 behavior
= task
->task_exc_guard
;
2315 if ((behavior
& TASK_EXC_GUARD_MP_DELIVER
) == 0) {
2320 /* Raise exception via corpse fork or synchronously */
2321 if ((task
->task_exc_guard
& TASK_EXC_GUARD_MP_CORPSE
) &&
2322 (task
->task_exc_guard
& TASK_EXC_GUARD_MP_FATAL
) == 0) {
2323 task_violated_guard(code
, subcode
, NULL
);
2325 task_exception_notify(EXC_GUARD
, code
, subcode
);
2328 /* Terminate the task if desired */
2329 if (task
->task_exc_guard
& TASK_EXC_GUARD_MP_FATAL
) {
2330 task_bsdtask_kill(task
);
2337 * Routine: mach_port_construct [kernel call]
2339 * Constructs a mach port with the provided set of options.
2343 * KERN_SUCCESS The right is allocated.
2344 * KERN_INVALID_TASK The space is null.
2345 * KERN_INVALID_TASK The space is dead.
2346 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
2347 * KERN_NO_SPACE No room in space for another right.
2348 * KERN_FAILURE Illegal option values requested.
2352 mach_port_construct(
2354 mach_port_options_t
*options
,
2356 mach_port_name_t
*name
)
2361 if (space
== IS_NULL
)
2362 return (KERN_INVALID_TASK
);
2364 /* Allocate a new port in the IPC space */
2365 kr
= ipc_port_alloc(space
, name
, &port
);
2366 if (kr
!= KERN_SUCCESS
)
2369 /* Port locked and active */
2370 if (options
->flags
& MPO_CONTEXT_AS_GUARD
) {
2371 kr
= mach_port_guard_locked(port
, (uint64_t) context
, (options
->flags
& MPO_STRICT
));
2372 /* A newly allocated and locked port should always be guarded successfully */
2373 assert(kr
== KERN_SUCCESS
);
2375 port
->ip_context
= context
;
2381 /* Set port attributes as requested */
2383 if (options
->flags
& MPO_QLIMIT
) {
2384 kr
= mach_port_set_attributes(space
, *name
, MACH_PORT_LIMITS_INFO
,
2385 (mach_port_info_t
)&options
->mpl
, sizeof(options
->mpl
)/sizeof(int));
2386 if (kr
!= KERN_SUCCESS
)
2390 if (options
->flags
& MPO_TEMPOWNER
) {
2391 kr
= mach_port_set_attributes(space
, *name
, MACH_PORT_TEMPOWNER
, NULL
, 0);
2392 if (kr
!= KERN_SUCCESS
)
2396 if (options
->flags
& MPO_IMPORTANCE_RECEIVER
) {
2397 kr
= mach_port_set_attributes(space
, *name
, MACH_PORT_IMPORTANCE_RECEIVER
, NULL
, 0);
2398 if (kr
!= KERN_SUCCESS
)
2402 if (options
->flags
& MPO_DENAP_RECEIVER
) {
2403 kr
= mach_port_set_attributes(space
, *name
, MACH_PORT_DENAP_RECEIVER
, NULL
, 0);
2404 if (kr
!= KERN_SUCCESS
)
2408 if (options
->flags
& MPO_INSERT_SEND_RIGHT
) {
2409 kr
= ipc_object_copyin(space
, *name
, MACH_MSG_TYPE_MAKE_SEND
, (ipc_object_t
*)&port
);
2410 if (kr
!= KERN_SUCCESS
)
2413 kr
= mach_port_insert_right(space
, *name
, port
, MACH_MSG_TYPE_PORT_SEND
);
2414 if (kr
!= KERN_SUCCESS
)
2418 return KERN_SUCCESS
;
2421 /* Attempt to destroy port. If its already destroyed by some other thread, we're done */
2422 (void) mach_port_destruct(space
, *name
, 0, context
);
2427 * Routine: mach_port_destruct [kernel call]
2429 * Destroys a mach port with appropriate guard
2433 * KERN_SUCCESS The name is destroyed.
2434 * KERN_INVALID_TASK The space is null.
2435 * KERN_INVALID_TASK The space is dead.
2436 * KERN_INVALID_NAME The name doesn't denote a right.
2437 * KERN_INVALID_RIGHT The right isn't correct.
2438 * KERN_INVALID_VALUE The delta for send right is incorrect.
2439 * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch.
2440 * This also raises a EXC_GUARD exception.
2446 mach_port_name_t name
,
2447 mach_port_delta_t srdelta
,
2453 if (space
== IS_NULL
)
2454 return KERN_INVALID_TASK
;
2456 if (!MACH_PORT_VALID(name
))
2457 return KERN_INVALID_NAME
;
2459 /* Remove reference for receive right */
2460 kr
= ipc_right_lookup_write(space
, name
, &entry
);
2461 if (kr
!= KERN_SUCCESS
) {
2462 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_INVALID_NAME
);
2465 /* space is write-locked and active */
2466 kr
= ipc_right_destruct(space
, name
, entry
, srdelta
, guard
); /* unlocks */
2472 * Routine: mach_port_guard [kernel call]
2474 * Guard a mach port with specified guard value.
2475 * The context field of the port is used as the guard.
2479 * KERN_SUCCESS The name is destroyed.
2480 * KERN_INVALID_TASK The space is null.
2481 * KERN_INVALID_TASK The space is dead.
2482 * KERN_INVALID_NAME The name doesn't denote a right.
2483 * KERN_INVALID_RIGHT The right isn't correct.
2484 * KERN_INVALID_ARGUMENT Port already contains a context/guard.
2489 mach_port_name_t name
,
2496 if (space
== IS_NULL
)
2497 return KERN_INVALID_TASK
;
2499 if (!MACH_PORT_VALID(name
))
2500 return KERN_INVALID_NAME
;
2502 /* Guard can be applied only to receive rights */
2503 kr
= ipc_port_translate_receive(space
, name
, &port
);
2504 if (kr
!= KERN_SUCCESS
) {
2505 mach_port_guard_exception(name
, 0, 0,
2506 ((KERN_INVALID_NAME
== kr
) ?
2507 kGUARD_EXC_INVALID_NAME
:
2508 kGUARD_EXC_INVALID_RIGHT
));
2512 /* Port locked and active */
2513 kr
= mach_port_guard_locked(port
, guard
, strict
);
2516 if (KERN_INVALID_ARGUMENT
== kr
) {
2517 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_INVALID_ARGUMENT
);
2524 * Routine: mach_port_unguard [kernel call]
2526 * Unguard a mach port with specified guard value.
2530 * KERN_SUCCESS The name is destroyed.
2531 * KERN_INVALID_TASK The space is null.
2532 * KERN_INVALID_TASK The space is dead.
2533 * KERN_INVALID_NAME The name doesn't denote a right.
2534 * KERN_INVALID_RIGHT The right isn't correct.
2535 * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch.
2536 * This also raises a EXC_GUARD exception.
2541 mach_port_name_t name
,
2548 if (space
== IS_NULL
)
2549 return KERN_INVALID_TASK
;
2551 if (!MACH_PORT_VALID(name
))
2552 return KERN_INVALID_NAME
;
2554 kr
= ipc_port_translate_receive(space
, name
, &port
);
2555 if (kr
!= KERN_SUCCESS
) {
2556 mach_port_guard_exception(name
, 0, 0,
2557 ((KERN_INVALID_NAME
== kr
) ?
2558 kGUARD_EXC_INVALID_NAME
:
2559 kGUARD_EXC_INVALID_RIGHT
));
2563 /* Port locked and active */
2564 kr
= mach_port_unguard_locked(port
, name
, guard
);