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>
107 /* Zeroed template of qos flags */
109 static mach_port_qos_t qos_template
;
112 * Routine: mach_port_names_helper
114 * A helper function for mach_port_names.
117 * Space containing entry is [at least] read-locked.
120 mach_port_names_helper(
121 ipc_port_timestamp_t timestamp
,
123 mach_port_name_t name
,
124 mach_port_name_t
*names
,
125 mach_port_type_t
*types
,
126 ipc_entry_num_t
*actualp
)
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
;
134 bits
= entry
->ie_bits
;
135 request
= entry
->ie_request
;
136 port
= ip_object_to_port(entry
->ie_object
);
138 if (bits
& MACH_PORT_TYPE_RECEIVE
) {
139 assert(IP_VALID(port
));
141 if (request
!= IE_REQ_NONE
) {
143 require_ip_active(port
);
144 type
|= ipc_port_request_type(port
, name
, request
);
147 } else if (bits
& MACH_PORT_TYPE_SEND_RIGHTS
) {
148 mach_port_type_t reqtype
;
150 assert(IP_VALID(port
));
153 reqtype
= (request
!= IE_REQ_NONE
) ?
154 ipc_port_request_type(port
, name
, request
) : 0;
157 * If the port is alive, or was alive when the mach_port_names
158 * started, then return that fact. Otherwise, pretend we found
161 if (ip_active(port
) || IP_TIMESTAMP_ORDER(timestamp
, port
->ip_timestamp
)) {
164 bits
&= ~(IE_BITS_TYPE_MASK
);
165 bits
|= MACH_PORT_TYPE_DEAD_NAME
;
166 /* account for additional reference for dead-name notification */
174 type
|= IE_BITS_TYPE(bits
);
177 names
[actual
] = name
;
178 types
[actual
] = type
;
179 *actualp
= actual
+ 1;
183 * Routine: mach_port_names [kernel call]
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.
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.
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
)
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
;
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 */
222 /* safe simplifying assumption */
223 static_assert(sizeof(mach_port_name_t
) == sizeof(mach_port_type_t
));
225 if (space
== IS_NULL
) {
226 return KERN_INVALID_TASK
;
232 ipc_entry_num_t bound
;
233 vm_size_t size_needed
;
236 if (!is_active(space
)) {
237 is_read_unlock(space
);
239 kmem_free(ipc_kernel_map
, addr1
, size
);
240 kmem_free(ipc_kernel_map
, addr2
, size
);
242 return KERN_INVALID_TASK
;
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
));
251 if (size_needed
<= size
) {
255 is_read_unlock(space
);
258 kmem_free(ipc_kernel_map
, addr1
, size
);
259 kmem_free(ipc_kernel_map
, addr2
, size
);
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
;
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
;
274 /* can't fault while we hold locks */
276 kr
= vm_map_wire_kernel(
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
,
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
;
290 kr
= vm_map_wire_kernel(
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
,
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
;
305 /* space is read-locked and active */
307 names
= (mach_port_name_t
*) addr1
;
308 types
= (mach_port_type_t
*) addr2
;
311 timestamp
= ipc_port_timestamp();
313 table
= space
->is_table
;
314 tsize
= space
->is_table_size
;
316 for (index
= 0; index
< tsize
; index
++) {
317 ipc_entry_t entry
= &table
[index
];
318 ipc_entry_bits_t bits
= entry
->ie_bits
;
320 if (IE_BITS_TYPE(bits
) != MACH_PORT_TYPE_NONE
) {
321 mach_port_name_t name
;
323 name
= MACH_PORT_MAKE(index
, IE_BITS_GEN(bits
));
324 mach_port_names_helper(timestamp
, entry
, name
, names
,
329 is_read_unlock(space
);
332 memory1
= VM_MAP_COPY_NULL
;
333 memory2
= VM_MAP_COPY_NULL
;
336 kmem_free(ipc_kernel_map
, addr1
, size
);
337 kmem_free(ipc_kernel_map
, addr2
, size
);
341 vm_size_t vm_size_used
;
343 size_used
= actual
* sizeof(mach_port_name_t
);
345 vm_map_round_page(size_used
,
346 VM_MAP_PAGE_MASK(ipc_kernel_map
));
349 * Make used memory pageable and get it into
350 * copied-in form. Free any unused memory.
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
)),
360 assert(kr
== KERN_SUCCESS
);
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
)),
369 assert(kr
== KERN_SUCCESS
);
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
);
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
);
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
);
387 *namesp
= (mach_port_name_t
*) memory1
;
389 *typesp
= (mach_port_type_t
*) memory2
;
395 * Routine: mach_port_type [kernel call]
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.
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.
420 mach_port_name_t name
,
421 mach_port_type_t
*typep
)
423 mach_port_urefs_t urefs
;
427 if (space
== IS_NULL
) {
428 return KERN_INVALID_TASK
;
431 if (name
== MACH_PORT_NULL
) {
432 return KERN_INVALID_NAME
;
435 if (name
== MACH_PORT_DEAD
) {
436 *typep
= MACH_PORT_TYPE_DEAD_NAME
;
440 kr
= ipc_right_lookup_write(space
, name
, &entry
);
441 if (kr
!= KERN_SUCCESS
) {
445 /* space is write-locked and active */
446 kr
= ipc_right_info(space
, name
, entry
, typep
, &urefs
);
447 /* space is unlocked */
450 /* JMM - workaround rdar://problem/9121297 (CF being too picky on these bits). */
451 *typep
&= ~(MACH_PORT_TYPE_SPREQUEST
| MACH_PORT_TYPE_SPREQUEST_DELAYED
);
458 * Routine: mach_port_rename [kernel call]
460 * Changes the name denoting a right,
461 * from oname to nname.
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.
473 * This interface is obsolete and always returns
474 * KERN_NOT_SUPPORTED.
479 __unused ipc_space_t space
,
480 __unused mach_port_name_t oname
,
481 __unused mach_port_name_t nname
)
483 return KERN_NOT_SUPPORTED
;
488 * Routine: mach_port_allocate_name [kernel call]
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
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.
503 * A new port set has no members.
505 * A new dead name has one user reference.
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.
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
523 mach_port_allocate_name(
525 mach_port_right_t right
,
526 mach_port_name_t name
)
529 mach_port_qos_t qos
= qos_template
;
533 if (!MACH_PORT_VALID(name
)) {
534 return KERN_INVALID_VALUE
;
537 kr
= mach_port_allocate_full(space
, right
, MACH_PORT_NULL
,
543 * Routine: mach_port_allocate [kernel call]
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.
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.
563 mach_port_right_t right
,
564 mach_port_name_t
*namep
)
567 mach_port_qos_t qos
= qos_template
;
569 kr
= mach_port_allocate_full(space
, right
, MACH_PORT_NULL
,
575 * Routine: mach_port_allocate_qos [kernel call]
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.
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.
594 mach_port_allocate_qos(
596 mach_port_right_t right
,
597 mach_port_qos_t
*qosp
,
598 mach_port_name_t
*namep
)
603 return KERN_INVALID_ARGUMENT
;
605 kr
= mach_port_allocate_full(space
, right
, MACH_PORT_NULL
,
611 * Routine: mach_port_allocate_full [kernel call]
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.
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.
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.
634 mach_port_allocate_full(
636 mach_port_right_t right
,
638 mach_port_qos_t
*qosp
,
639 mach_port_name_t
*namep
)
643 if (space
== IS_NULL
) {
644 return KERN_INVALID_TASK
;
647 if (proto
!= MACH_PORT_NULL
) {
648 return KERN_INVALID_VALUE
;
652 if (!MACH_PORT_VALID(*namep
)) {
653 return KERN_INVALID_VALUE
;
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.
662 if (qosp
->prealloc
) {
663 if (qosp
->len
> MACH_MSG_SIZE_MAX
- MAX_TRAILER_SIZE
) {
664 return KERN_RESOURCE_SHORTAGE
;
666 if (right
!= MACH_PORT_RIGHT_RECEIVE
) {
667 return KERN_INVALID_VALUE
;
672 kr
= mach_port_allocate_internal(space
, right
, qosp
, namep
);
678 * Routine: mach_port_allocate_internal [kernel private]
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.
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.
695 mach_port_allocate_internal(
697 mach_port_right_t right
,
698 mach_port_qos_t
*qosp
,
699 mach_port_name_t
*namep
)
703 assert(space
!= IS_NULL
);
706 case MACH_PORT_RIGHT_RECEIVE
:
708 ipc_kmsg_t kmsg
= IKM_NULL
;
712 * For in-kernel uses, only allow small (from the kmsg zone)
713 * preallocated messages for the port.
715 if (qosp
->prealloc
) {
716 mach_msg_size_t size
= qosp
->len
;
718 if (size
> IKM_SAVED_MSG_SIZE
- MAX_TRAILER_SIZE
) {
719 panic("mach_port_allocate_internal: too large a prealloc kmsg");
721 kmsg
= (ipc_kmsg_t
)ipc_kmsg_prealloc(size
+ MAX_TRAILER_SIZE
);
722 if (kmsg
== IKM_NULL
) {
723 return KERN_RESOURCE_SHORTAGE
;
728 kr
= ipc_port_alloc_name(space
, *namep
, &port
);
730 kr
= ipc_port_alloc(space
, FALSE
, namep
, &port
);
732 if (kr
== KERN_SUCCESS
) {
733 if (kmsg
!= IKM_NULL
) {
734 ipc_kmsg_set_prealloc(kmsg
, port
);
737 } else if (kmsg
!= IKM_NULL
) {
743 case MACH_PORT_RIGHT_PORT_SET
:
748 kr
= ipc_pset_alloc_name(space
, *namep
, &pset
);
750 kr
= ipc_pset_alloc(space
, namep
, &pset
);
752 if (kr
== KERN_SUCCESS
) {
758 case MACH_PORT_RIGHT_DEAD_NAME
:
759 kr
= ipc_object_alloc_dead(space
, namep
);
763 kr
= KERN_INVALID_VALUE
;
771 * Routine: mach_port_destroy [kernel call]
773 * Cleans up and destroys all rights denoted by a name
774 * in a space. The destruction of a receive right
775 * destroys the port, unless a port-destroyed request
776 * has been made for it; the destruction of a port-set right
777 * destroys the port set.
781 * KERN_SUCCESS The name is destroyed.
782 * KERN_INVALID_TASK The space is null.
783 * KERN_INVALID_TASK The space is dead.
784 * KERN_INVALID_NAME The name doesn't denote a right.
790 mach_port_name_t name
)
795 if (space
== IS_NULL
) {
796 return KERN_INVALID_TASK
;
799 if (!MACH_PORT_VALID(name
)) {
803 kr
= ipc_right_lookup_write(space
, name
, &entry
);
804 if (kr
!= KERN_SUCCESS
) {
805 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_INVALID_NAME
);
808 /* space is write-locked and active */
810 kr
= ipc_right_destroy(space
, name
, entry
, TRUE
, 0); /* unlocks space */
815 * Routine: mach_port_deallocate [kernel call]
817 * Deallocates a user reference from a send right,
818 * send-once right, dead-name right or a port_set right.
819 * May deallocate the right, if this is the last uref,
820 * and destroy the name, if it doesn't denote
825 * KERN_SUCCESS The uref is deallocated.
826 * KERN_INVALID_TASK The space is null.
827 * KERN_INVALID_TASK The space is dead.
828 * KERN_INVALID_NAME The name doesn't denote a right.
829 * KERN_INVALID_RIGHT The right isn't correct.
833 mach_port_deallocate(
835 mach_port_name_t name
)
840 if (space
== IS_NULL
) {
841 return KERN_INVALID_TASK
;
844 if (!MACH_PORT_VALID(name
)) {
848 kr
= ipc_right_lookup_write(space
, name
, &entry
);
849 if (kr
!= KERN_SUCCESS
) {
850 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_INVALID_NAME
);
853 /* space is write-locked */
855 kr
= ipc_right_dealloc(space
, name
, entry
); /* unlocks space */
860 * Routine: mach_port_get_refs [kernel call]
862 * Retrieves the number of user references held by a right.
863 * Receive rights, port-set rights, and send-once rights
864 * always have one user reference. Returns zero if the
865 * name denotes a right, but not the queried right.
869 * KERN_SUCCESS Number of urefs returned.
870 * KERN_INVALID_TASK The space is null.
871 * KERN_INVALID_TASK The space is dead.
872 * KERN_INVALID_VALUE "right" isn't a legal value.
873 * KERN_INVALID_NAME The name doesn't denote a right.
879 mach_port_name_t name
,
880 mach_port_right_t right
,
881 mach_port_urefs_t
*urefsp
)
883 mach_port_type_t type
;
884 mach_port_urefs_t urefs
;
888 if (space
== IS_NULL
) {
889 return KERN_INVALID_TASK
;
892 if (right
>= MACH_PORT_RIGHT_NUMBER
) {
893 return KERN_INVALID_VALUE
;
896 if (!MACH_PORT_VALID(name
)) {
897 if (right
== MACH_PORT_RIGHT_SEND
||
898 right
== MACH_PORT_RIGHT_SEND_ONCE
) {
902 return KERN_INVALID_NAME
;
905 kr
= ipc_right_lookup_write(space
, name
, &entry
);
906 if (kr
!= KERN_SUCCESS
) {
910 /* space is write-locked and active */
911 kr
= ipc_right_info(space
, name
, entry
, &type
, &urefs
);
912 /* space is unlocked */
914 if (kr
!= KERN_SUCCESS
) {
918 if (type
& MACH_PORT_TYPE(right
)) {
920 case MACH_PORT_RIGHT_SEND_ONCE
:
924 case MACH_PORT_RIGHT_PORT_SET
:
925 case MACH_PORT_RIGHT_RECEIVE
:
929 case MACH_PORT_RIGHT_DEAD_NAME
:
930 case MACH_PORT_RIGHT_SEND
:
936 panic("mach_port_get_refs: strange rights");
946 * Routine: mach_port_mod_refs
948 * Modifies the number of user references held by a right.
949 * The resulting number of user references must be non-negative.
950 * If it is zero, the right is deallocated. If the name
951 * doesn't denote other rights, it is destroyed.
955 * KERN_SUCCESS Modified number of urefs.
956 * KERN_INVALID_TASK The space is null.
957 * KERN_INVALID_TASK The space is dead.
958 * KERN_INVALID_VALUE "right" isn't a legal value.
959 * KERN_INVALID_NAME The name doesn't denote a right.
960 * KERN_INVALID_RIGHT Name doesn't denote specified right.
961 * KERN_INVALID_VALUE Impossible modification to urefs.
962 * KERN_UREFS_OVERFLOW Urefs would overflow.
968 mach_port_name_t name
,
969 mach_port_right_t right
,
970 mach_port_delta_t delta
)
975 if (space
== IS_NULL
) {
976 return KERN_INVALID_TASK
;
979 if (right
>= MACH_PORT_RIGHT_NUMBER
) {
980 return KERN_INVALID_VALUE
;
983 if (!MACH_PORT_VALID(name
)) {
984 if (right
== MACH_PORT_RIGHT_SEND
||
985 right
== MACH_PORT_RIGHT_SEND_ONCE
) {
988 return KERN_INVALID_NAME
;
991 kr
= ipc_right_lookup_write(space
, name
, &entry
);
992 if (kr
!= KERN_SUCCESS
) {
993 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_INVALID_NAME
);
997 /* space is write-locked and active */
999 kr
= ipc_right_delta(space
, name
, entry
, right
, delta
); /* unlocks */
1005 * Routine: mach_port_peek [kernel call]
1007 * Peek at the message queue for the specified receive
1008 * right and return info about a message in the queue.
1010 * On input, seqnop points to a sequence number value
1011 * to match the message being peeked. If zero is specified
1012 * as the seqno, the first message in the queue will be
1015 * Only the following trailer types are currently supported:
1016 * MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)
1018 * or'ed with one of these element types:
1019 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_NULL)
1020 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SEQNO)
1021 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER)
1022 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT)
1024 * On input, the value pointed to by trailer_sizep must be
1025 * large enough to hold the requested trailer size.
1027 * The message sequence number, id, size, requested trailer info
1028 * and requested trailer size are returned in their respective
1029 * output parameters upon success.
1034 * KERN_SUCCESS Matching message found, out parameters set.
1035 * KERN_INVALID_TASK The space is null or dead.
1036 * KERN_INVALID_NAME The name doesn't denote a right.
1037 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1038 * KERN_INVALID_VALUE The input parameter values are out of bounds.
1039 * KERN_FAILURE The requested message was not found.
1045 mach_port_name_t name
,
1046 mach_msg_trailer_type_t trailer_type
,
1047 mach_port_seqno_t
*seqnop
,
1048 mach_msg_size_t
*msg_sizep
,
1049 mach_msg_id_t
*msg_idp
,
1050 mach_msg_trailer_info_t trailer_infop
,
1051 mach_msg_type_number_t
*trailer_sizep
)
1056 mach_msg_max_trailer_t max_trailer
;
1058 if (space
== IS_NULL
) {
1059 return KERN_INVALID_TASK
;
1062 if (!MACH_PORT_VALID(name
)) {
1063 return KERN_INVALID_RIGHT
;
1067 * We don't allow anything greater than the audit trailer - to avoid
1068 * leaking the context pointer and to avoid variable-sized context issues.
1070 if (GET_RCV_ELEMENTS(trailer_type
) > MACH_RCV_TRAILER_AUDIT
||
1071 REQUESTED_TRAILER_SIZE(TRUE
, trailer_type
) > *trailer_sizep
) {
1072 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_INVALID_VALUE
);
1073 return KERN_INVALID_VALUE
;
1076 *trailer_sizep
= REQUESTED_TRAILER_SIZE(TRUE
, trailer_type
);
1078 kr
= ipc_port_translate_receive(space
, name
, &port
);
1079 if (kr
!= KERN_SUCCESS
) {
1080 mach_port_guard_exception(name
, 0, 0,
1081 ((KERN_INVALID_NAME
== kr
) ?
1082 kGUARD_EXC_INVALID_NAME
:
1083 kGUARD_EXC_INVALID_RIGHT
));
1087 /* Port locked and active */
1089 found
= ipc_mqueue_peek(&port
->ip_messages
, seqnop
,
1090 msg_sizep
, msg_idp
, &max_trailer
, NULL
);
1093 if (found
!= TRUE
) {
1094 return KERN_FAILURE
;
1097 max_trailer
.msgh_seqno
= *seqnop
;
1098 memcpy(trailer_infop
, &max_trailer
, *trailer_sizep
);
1100 return KERN_SUCCESS
;
1104 * Routine: mach_port_set_mscount [kernel call]
1106 * Changes a receive right's make-send count.
1110 * KERN_SUCCESS Set make-send count.
1111 * KERN_INVALID_TASK The space is null.
1112 * KERN_INVALID_TASK The space is dead.
1113 * KERN_INVALID_NAME The name doesn't denote a right.
1114 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1118 mach_port_set_mscount(
1120 mach_port_name_t name
,
1121 mach_port_mscount_t mscount
)
1126 if (space
== IS_NULL
) {
1127 return KERN_INVALID_TASK
;
1130 if (!MACH_PORT_VALID(name
)) {
1131 return KERN_INVALID_RIGHT
;
1134 kr
= ipc_port_translate_receive(space
, name
, &port
);
1135 if (kr
!= KERN_SUCCESS
) {
1138 /* port is locked and active */
1140 port
->ip_mscount
= mscount
;
1142 return KERN_SUCCESS
;
1146 * Routine: mach_port_set_seqno [kernel call]
1148 * Changes a receive right's sequence number.
1152 * KERN_SUCCESS Set sequence number.
1153 * KERN_INVALID_TASK The space is null.
1154 * KERN_INVALID_TASK The space is dead.
1155 * KERN_INVALID_NAME The name doesn't denote a right.
1156 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1160 mach_port_set_seqno(
1162 mach_port_name_t name
,
1163 mach_port_seqno_t seqno
)
1168 if (space
== IS_NULL
) {
1169 return KERN_INVALID_TASK
;
1172 if (!MACH_PORT_VALID(name
)) {
1173 return KERN_INVALID_RIGHT
;
1176 kr
= ipc_port_translate_receive(space
, name
, &port
);
1177 if (kr
!= KERN_SUCCESS
) {
1180 /* port is locked and active */
1182 ipc_mqueue_set_seqno(&port
->ip_messages
, seqno
);
1185 return KERN_SUCCESS
;
1189 * Routine: mach_port_get_context [kernel call]
1191 * Returns a receive right's context pointer.
1195 * KERN_SUCCESS Set context pointer.
1196 * KERN_INVALID_TASK The space is null.
1197 * KERN_INVALID_TASK The space is dead.
1198 * KERN_INVALID_NAME The name doesn't denote a right.
1199 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1203 mach_port_get_context(
1205 mach_port_name_t name
,
1206 mach_vm_address_t
*context
)
1211 if (space
== IS_NULL
) {
1212 return KERN_INVALID_TASK
;
1215 if (!MACH_PORT_VALID(name
)) {
1216 return KERN_INVALID_RIGHT
;
1219 kr
= ipc_port_translate_receive(space
, name
, &port
);
1220 if (kr
!= KERN_SUCCESS
) {
1224 /* Port locked and active */
1226 /* For strictly guarded ports, return empty context (which acts as guard) */
1227 if (port
->ip_strict_guard
) {
1230 *context
= port
->ip_context
;
1234 return KERN_SUCCESS
;
1239 * Routine: mach_port_set_context [kernel call]
1241 * Changes a receive right's context pointer.
1245 * KERN_SUCCESS Set context pointer.
1246 * KERN_INVALID_TASK The space is null.
1247 * KERN_INVALID_TASK The space is dead.
1248 * KERN_INVALID_NAME The name doesn't denote a right.
1249 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1253 mach_port_set_context(
1255 mach_port_name_t name
,
1256 mach_vm_address_t context
)
1261 if (space
== IS_NULL
) {
1262 return KERN_INVALID_TASK
;
1265 if (!MACH_PORT_VALID(name
)) {
1266 return KERN_INVALID_RIGHT
;
1269 kr
= ipc_port_translate_receive(space
, name
, &port
);
1270 if (kr
!= KERN_SUCCESS
) {
1274 /* port is locked and active */
1275 if (port
->ip_strict_guard
) {
1276 uint64_t portguard
= port
->ip_context
;
1278 /* For strictly guarded ports, disallow overwriting context; Raise Exception */
1279 mach_port_guard_exception(name
, context
, portguard
, kGUARD_EXC_SET_CONTEXT
);
1280 return KERN_INVALID_ARGUMENT
;
1283 port
->ip_context
= context
;
1286 return KERN_SUCCESS
;
1291 * Routine: mach_port_get_set_status [kernel call]
1293 * Retrieves a list of members in a port set.
1294 * Returns the space's name for each receive right member.
1298 * KERN_SUCCESS Retrieved list of members.
1299 * KERN_INVALID_TASK The space is null.
1300 * KERN_INVALID_TASK The space is dead.
1301 * KERN_INVALID_NAME The name doesn't denote a right.
1302 * KERN_INVALID_RIGHT Name doesn't denote a port set.
1303 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1307 mach_port_get_set_status(
1309 mach_port_name_t name
,
1310 mach_port_name_t
**members
,
1311 mach_msg_type_number_t
*membersCnt
)
1313 ipc_entry_num_t actual
; /* this many members */
1314 ipc_entry_num_t maxnames
; /* space for this many members */
1317 vm_size_t size
; /* size of allocated memory */
1318 vm_offset_t addr
; /* allocated memory */
1319 vm_map_copy_t memory
; /* copied-in memory */
1321 if (space
== IS_NULL
) {
1322 return KERN_INVALID_TASK
;
1325 if (!MACH_PORT_VALID(name
)) {
1326 return KERN_INVALID_RIGHT
;
1329 size
= VM_MAP_PAGE_SIZE(ipc_kernel_map
); /* initial guess */
1332 mach_port_name_t
*names
;
1336 kr
= vm_allocate_kernel(ipc_kernel_map
, &addr
, size
, VM_FLAGS_ANYWHERE
, VM_KERN_MEMORY_IPC
);
1337 if (kr
!= KERN_SUCCESS
) {
1338 return KERN_RESOURCE_SHORTAGE
;
1341 /* can't fault while we hold locks */
1343 kr
= vm_map_wire_kernel(ipc_kernel_map
, addr
, addr
+ size
,
1344 VM_PROT_READ
| VM_PROT_WRITE
, VM_KERN_MEMORY_IPC
, FALSE
);
1345 assert(kr
== KERN_SUCCESS
);
1347 kr
= ipc_object_translate(space
, name
, MACH_PORT_RIGHT_PORT_SET
, &psobj
);
1348 if (kr
!= KERN_SUCCESS
) {
1349 kmem_free(ipc_kernel_map
, addr
, size
);
1353 /* just use a portset reference from here on out */
1354 pset
= ips_object_to_pset(psobj
);
1355 ips_reference(pset
);
1358 names
= (mach_port_name_t
*) addr
;
1359 maxnames
= (ipc_entry_num_t
)(size
/ sizeof(mach_port_name_t
));
1361 ipc_mqueue_set_gather_member_names(space
, &pset
->ips_messages
, maxnames
, names
, &actual
);
1363 /* release the portset reference */
1366 if (actual
<= maxnames
) {
1370 /* didn't have enough memory; allocate more */
1371 kmem_free(ipc_kernel_map
, addr
, size
);
1372 size
= vm_map_round_page(
1373 (actual
* sizeof(mach_port_name_t
)),
1374 VM_MAP_PAGE_MASK(ipc_kernel_map
)) +
1375 VM_MAP_PAGE_SIZE(ipc_kernel_map
);
1379 memory
= VM_MAP_COPY_NULL
;
1381 kmem_free(ipc_kernel_map
, addr
, size
);
1383 vm_size_t size_used
;
1384 vm_size_t vm_size_used
;
1386 size_used
= actual
* sizeof(mach_port_name_t
);
1387 vm_size_used
= vm_map_round_page(
1389 VM_MAP_PAGE_MASK(ipc_kernel_map
));
1392 * Make used memory pageable and get it into
1393 * copied-in form. Free any unused memory.
1398 vm_map_trunc_page(addr
,
1399 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
1400 vm_map_round_page(addr
+ vm_size_used
,
1401 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
1403 assert(kr
== KERN_SUCCESS
);
1405 kr
= vm_map_copyin(ipc_kernel_map
, (vm_map_address_t
)addr
,
1406 (vm_map_size_t
)size_used
, TRUE
, &memory
);
1407 assert(kr
== KERN_SUCCESS
);
1409 if (vm_size_used
!= size
) {
1410 kmem_free(ipc_kernel_map
,
1411 addr
+ vm_size_used
, size
- vm_size_used
);
1415 *members
= (mach_port_name_t
*) memory
;
1416 *membersCnt
= actual
;
1417 return KERN_SUCCESS
;
1421 * Routine: mach_port_move_member [kernel call]
1423 * If after is MACH_PORT_NULL, removes member
1424 * from the port set it is in. Otherwise, adds
1425 * member to after, removing it from any set
1426 * it might already be in.
1430 * KERN_SUCCESS Moved the port.
1431 * KERN_INVALID_TASK The space is null.
1432 * KERN_INVALID_TASK The space is dead.
1433 * KERN_INVALID_NAME Member didn't denote a right.
1434 * KERN_INVALID_RIGHT Member didn't denote a receive right.
1435 * KERN_INVALID_NAME After didn't denote a right.
1436 * KERN_INVALID_RIGHT After didn't denote a port set right.
1438 * After is MACH_PORT_NULL and Member isn't in a port set.
1442 mach_port_move_member(
1444 mach_port_name_t member
,
1445 mach_port_name_t after
)
1447 ipc_object_t port_obj
, ps_obj
;
1449 ipc_pset_t nset
= IPS_NULL
;
1451 uint64_t wq_link_id
= 0;
1452 uint64_t wq_reserved_prepost
= 0;
1454 if (space
== IS_NULL
) {
1455 return KERN_INVALID_TASK
;
1458 if (!MACH_PORT_VALID(member
)) {
1459 return KERN_INVALID_RIGHT
;
1462 if (after
== MACH_PORT_DEAD
) {
1463 return KERN_INVALID_RIGHT
;
1464 } else if (after
== MACH_PORT_NULL
) {
1468 * We reserve both a link, and
1469 * enough prepost objects to complete
1470 * the set move atomically - we can't block
1471 * while we're holding the space lock, and
1472 * the ipc_pset_add calls ipc_mqueue_add
1473 * which may have to prepost this port onto
1476 wq_link_id
= waitq_link_reserve(NULL
);
1477 wq_reserved_prepost
= waitq_prepost_reserve(NULL
, 10,
1479 kr
= ipc_pset_lazy_allocate(space
, after
);
1480 if (kr
!= KERN_SUCCESS
) {
1485 if (after
!= MACH_PORT_NULL
) {
1486 kr
= ipc_object_translate_two(space
,
1487 member
, MACH_PORT_RIGHT_RECEIVE
, &port_obj
,
1488 after
, MACH_PORT_RIGHT_PORT_SET
, &ps_obj
);
1490 kr
= ipc_object_translate(space
,
1491 member
, MACH_PORT_RIGHT_RECEIVE
, &port_obj
);
1493 if (kr
!= KERN_SUCCESS
) {
1497 port
= ip_object_to_port(port_obj
);
1498 if (after
!= MACH_PORT_NULL
) {
1499 nset
= ips_object_to_pset(ps_obj
);
1501 /* port and nset are locked */
1503 ipc_pset_remove_from_all(port
);
1505 if (after
!= MACH_PORT_NULL
) {
1506 kr
= ipc_pset_add(nset
, port
, &wq_link_id
, &wq_reserved_prepost
);
1514 * on success the ipc_pset_add() will consume the wq_link_id
1515 * value (resetting it to 0), so this function is always safe to call.
1517 waitq_link_release(wq_link_id
);
1518 waitq_prepost_release_reserve(wq_reserved_prepost
);
1524 * Routine: mach_port_request_notification [kernel call]
1526 * Requests a notification. The caller supplies
1527 * a send-once right for the notification to use,
1528 * and the call returns the previously registered
1529 * send-once right, if any. Possible types:
1531 * MACH_NOTIFY_PORT_DESTROYED
1532 * Requests a port-destroyed notification
1533 * for a receive right. Sync should be zero.
1534 * MACH_NOTIFY_NO_SENDERS
1535 * Requests a no-senders notification for a
1536 * receive right. If there are currently no
1537 * senders, sync is less than or equal to the
1538 * current make-send count, and a send-once right
1539 * is supplied, then an immediate no-senders
1540 * notification is generated.
1541 * MACH_NOTIFY_DEAD_NAME
1542 * Requests a dead-name notification for a send
1543 * or receive right. If the name is already a
1544 * dead name, sync is non-zero, and a send-once
1545 * right is supplied, then an immediate dead-name
1546 * notification is generated.
1550 * KERN_SUCCESS Requested a notification.
1551 * KERN_INVALID_TASK The space is null.
1552 * KERN_INVALID_TASK The space is dead.
1553 * KERN_INVALID_VALUE Bad id value.
1554 * KERN_INVALID_NAME Name doesn't denote a right.
1555 * KERN_INVALID_RIGHT Name doesn't denote appropriate right.
1556 * KERN_INVALID_CAPABILITY The notify port is dead.
1557 * MACH_NOTIFY_PORT_DESTROYED:
1558 * KERN_INVALID_VALUE Sync isn't zero.
1559 * KERN_FAILURE Re-registering for this notification
1560 * MACH_NOTIFY_DEAD_NAME:
1561 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1562 * KERN_INVALID_ARGUMENT Name denotes dead name, but
1563 * sync is zero or notify is IP_NULL.
1564 * KERN_UREFS_OVERFLOW Name denotes dead name, but
1565 * generating immediate notif. would overflow urefs.
1569 mach_port_request_notification(
1571 mach_port_name_t name
,
1573 mach_port_mscount_t sync
,
1575 ipc_port_t
*previousp
)
1579 if (space
== IS_NULL
) {
1580 return KERN_INVALID_TASK
;
1583 if (notify
== IP_DEAD
) {
1584 return KERN_INVALID_CAPABILITY
;
1589 * Requesting notifications on RPC ports is an error.
1595 kr
= ipc_right_lookup_write(space
, name
, &entry
);
1596 if (kr
!= KERN_SUCCESS
) {
1600 port
= ip_object_to_port(entry
->ie_object
);
1602 if (port
->ip_subsystem
!= NULL
) {
1603 is_write_unlock(space
);
1604 panic("mach_port_request_notification: on RPC port!!");
1605 return KERN_INVALID_CAPABILITY
;
1607 is_write_unlock(space
);
1613 case MACH_NOTIFY_PORT_DESTROYED
: {
1617 return KERN_INVALID_VALUE
;
1620 if (!MACH_PORT_VALID(name
)) {
1621 return KERN_INVALID_RIGHT
;
1624 kr
= ipc_port_translate_receive(space
, name
, &port
);
1625 if (kr
!= KERN_SUCCESS
) {
1628 /* port is locked and active */
1630 /* you cannot register for port death notifications on a kobject */
1631 if (ip_kotype(port
) != IKOT_NONE
) {
1633 return KERN_INVALID_RIGHT
;
1636 /* Allow only one registeration of this notification */
1637 if (port
->ip_pdrequest
!= IP_NULL
) {
1639 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_KERN_FAILURE
);
1640 return KERN_FAILURE
;
1643 ipc_port_pdrequest(port
, notify
, previousp
);
1644 /* port is unlocked */
1645 assert(*previousp
== IP_NULL
);
1649 case MACH_NOTIFY_NO_SENDERS
: {
1652 if (!MACH_PORT_VALID(name
)) {
1653 return KERN_INVALID_RIGHT
;
1656 kr
= ipc_port_translate_receive(space
, name
, &port
);
1657 if (kr
!= KERN_SUCCESS
) {
1660 /* port is locked and active */
1662 ipc_port_nsrequest(port
, sync
, notify
, previousp
);
1663 /* port is unlocked */
1667 case MACH_NOTIFY_SEND_POSSIBLE
:
1669 if (!MACH_PORT_VALID(name
)) {
1670 return KERN_INVALID_ARGUMENT
;
1673 kr
= ipc_right_request_alloc(space
, name
, sync
!= 0,
1674 TRUE
, notify
, previousp
);
1675 if (kr
!= KERN_SUCCESS
) {
1680 case MACH_NOTIFY_DEAD_NAME
:
1682 if (!MACH_PORT_VALID(name
)) {
1685 * Should do immediate delivery check -
1686 * will do that in the near future.
1688 return KERN_INVALID_ARGUMENT
;
1691 kr
= ipc_right_request_alloc(space
, name
, sync
!= 0,
1692 FALSE
, notify
, previousp
);
1693 if (kr
!= KERN_SUCCESS
) {
1699 return KERN_INVALID_VALUE
;
1702 return KERN_SUCCESS
;
1706 * Routine: mach_port_insert_right [kernel call]
1708 * Inserts a right into a space, as if the space
1709 * voluntarily received the right in a message,
1710 * except that the right gets the specified name.
1714 * KERN_SUCCESS Inserted the right.
1715 * KERN_INVALID_TASK The space is null.
1716 * KERN_INVALID_TASK The space is dead.
1717 * KERN_INVALID_VALUE The name isn't a legal name.
1718 * KERN_NAME_EXISTS The name already denotes a right.
1719 * KERN_INVALID_VALUE Message doesn't carry a port right.
1720 * KERN_INVALID_CAPABILITY Port is null or dead.
1721 * KERN_UREFS_OVERFLOW Urefs limit would be exceeded.
1722 * KERN_RIGHT_EXISTS Space has rights under another name.
1723 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1727 mach_port_insert_right(
1729 mach_port_name_t name
,
1731 mach_msg_type_name_t polyPoly
)
1733 if (space
== IS_NULL
) {
1734 return KERN_INVALID_TASK
;
1737 if (!MACH_PORT_VALID(name
) ||
1738 !MACH_MSG_TYPE_PORT_ANY_RIGHT(polyPoly
)) {
1739 return KERN_INVALID_VALUE
;
1742 if (!IP_VALID(poly
)) {
1743 return KERN_INVALID_CAPABILITY
;
1746 return ipc_object_copyout_name(space
, ip_to_object(poly
),
1751 * Routine: mach_port_extract_right [kernel call]
1753 * Extracts a right from a space, as if the space
1754 * voluntarily sent the right to the caller.
1758 * KERN_SUCCESS Extracted the right.
1759 * KERN_INVALID_TASK The space is null.
1760 * KERN_INVALID_TASK The space is dead.
1761 * KERN_INVALID_VALUE Requested type isn't a port right.
1762 * KERN_INVALID_NAME Name doesn't denote a right.
1763 * KERN_INVALID_RIGHT Name doesn't denote appropriate right.
1767 mach_port_extract_right(
1769 mach_port_name_t name
,
1770 mach_msg_type_name_t msgt_name
,
1772 mach_msg_type_name_t
*polyPoly
)
1776 if (space
== IS_NULL
) {
1777 return KERN_INVALID_TASK
;
1780 if (!MACH_MSG_TYPE_PORT_ANY(msgt_name
)) {
1781 return KERN_INVALID_VALUE
;
1784 if (!MACH_PORT_VALID(name
)) {
1786 * really should copy out a dead name, if it is a send or
1787 * send-once right being copied, but instead return an
1790 return KERN_INVALID_RIGHT
;
1793 kr
= ipc_object_copyin(space
, name
, msgt_name
, (ipc_object_t
*) poly
, 0, NULL
,
1794 IPC_KMSG_FLAGS_ALLOW_IMMOVABLE_SEND
);
1796 if (kr
== KERN_SUCCESS
) {
1797 *polyPoly
= ipc_object_copyin_type(msgt_name
);
1803 * Routine: mach_port_get_status_helper [helper]
1805 * Populates a mach_port_status_t structure with
1808 * Port needs to be locked
1813 mach_port_get_status_helper(
1815 mach_port_status_t
*statusp
)
1817 imq_lock(&port
->ip_messages
);
1818 /* don't leak set IDs, just indicate that the port is in one or not */
1819 statusp
->mps_pset
= !!(port
->ip_in_pset
);
1820 statusp
->mps_seqno
= port
->ip_messages
.imq_seqno
;
1821 statusp
->mps_qlimit
= port
->ip_messages
.imq_qlimit
;
1822 statusp
->mps_msgcount
= port
->ip_messages
.imq_msgcount
;
1823 imq_unlock(&port
->ip_messages
);
1825 statusp
->mps_mscount
= port
->ip_mscount
;
1826 statusp
->mps_sorights
= port
->ip_sorights
;
1827 statusp
->mps_srights
= port
->ip_srights
> 0;
1828 statusp
->mps_pdrequest
= port
->ip_pdrequest
!= IP_NULL
;
1829 statusp
->mps_nsrequest
= port
->ip_nsrequest
!= IP_NULL
;
1830 statusp
->mps_flags
= 0;
1831 if (port
->ip_impdonation
) {
1832 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_IMP_DONATION
;
1833 if (port
->ip_tempowner
) {
1834 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_TEMPOWNER
;
1835 if (IIT_NULL
!= port
->ip_imp_task
) {
1836 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_TASKPTR
;
1840 if (port
->ip_guarded
) {
1841 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_GUARDED
;
1842 if (port
->ip_strict_guard
) {
1843 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_STRICT_GUARD
;
1845 if (port
->ip_immovable_receive
) {
1846 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_GUARD_IMMOVABLE_RECEIVE
;
1849 if (port
->ip_no_grant
) {
1850 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_NO_GRANT
;
1858 mach_port_get_attributes(
1860 mach_port_name_t name
,
1862 mach_port_info_t info
,
1863 mach_msg_type_number_t
*count
)
1868 if (space
== IS_NULL
) {
1869 return KERN_INVALID_TASK
;
1873 case MACH_PORT_LIMITS_INFO
: {
1874 mach_port_limits_t
*lp
= (mach_port_limits_t
*)info
;
1876 if (*count
< MACH_PORT_LIMITS_INFO_COUNT
) {
1877 return KERN_FAILURE
;
1880 if (!MACH_PORT_VALID(name
)) {
1885 kr
= ipc_port_translate_receive(space
, name
, &port
);
1886 if (kr
!= KERN_SUCCESS
) {
1889 /* port is locked and active */
1891 lp
->mpl_qlimit
= port
->ip_messages
.imq_qlimit
;
1892 *count
= MACH_PORT_LIMITS_INFO_COUNT
;
1897 case MACH_PORT_RECEIVE_STATUS
: {
1898 mach_port_status_t
*statusp
= (mach_port_status_t
*)info
;
1900 if (*count
< MACH_PORT_RECEIVE_STATUS_COUNT
) {
1901 return KERN_FAILURE
;
1904 if (!MACH_PORT_VALID(name
)) {
1905 return KERN_INVALID_RIGHT
;
1908 kr
= ipc_port_translate_receive(space
, name
, &port
);
1909 if (kr
!= KERN_SUCCESS
) {
1912 /* port is locked and active */
1913 mach_port_get_status_helper(port
, statusp
);
1914 *count
= MACH_PORT_RECEIVE_STATUS_COUNT
;
1919 case MACH_PORT_DNREQUESTS_SIZE
: {
1920 ipc_port_request_t table
;
1922 if (*count
< MACH_PORT_DNREQUESTS_SIZE_COUNT
) {
1923 return KERN_FAILURE
;
1926 if (!MACH_PORT_VALID(name
)) {
1931 kr
= ipc_port_translate_receive(space
, name
, &port
);
1932 if (kr
!= KERN_SUCCESS
) {
1935 /* port is locked and active */
1937 table
= port
->ip_requests
;
1938 if (table
== IPR_NULL
) {
1941 *(int *)info
= table
->ipr_size
->its_size
;
1943 *count
= MACH_PORT_DNREQUESTS_SIZE_COUNT
;
1948 case MACH_PORT_INFO_EXT
: {
1949 mach_port_info_ext_t
*mp_info
= (mach_port_info_ext_t
*)info
;
1950 if (*count
< MACH_PORT_INFO_EXT_COUNT
) {
1951 return KERN_FAILURE
;
1954 if (!MACH_PORT_VALID(name
)) {
1955 return KERN_INVALID_RIGHT
;
1958 kr
= ipc_port_translate_receive(space
, name
, &port
);
1959 if (kr
!= KERN_SUCCESS
) {
1962 /* port is locked and active */
1963 mach_port_get_status_helper(port
, &mp_info
->mpie_status
);
1964 mp_info
->mpie_boost_cnt
= port
->ip_impcount
;
1965 *count
= MACH_PORT_INFO_EXT_COUNT
;
1971 return KERN_INVALID_ARGUMENT
;
1975 return KERN_SUCCESS
;
1979 mach_port_set_attributes(
1981 mach_port_name_t name
,
1983 mach_port_info_t info
,
1984 mach_msg_type_number_t count
)
1989 if (space
== IS_NULL
) {
1990 return KERN_INVALID_TASK
;
1994 case MACH_PORT_LIMITS_INFO
: {
1995 mach_port_limits_t
*mplp
= (mach_port_limits_t
*)info
;
1997 if (count
< MACH_PORT_LIMITS_INFO_COUNT
) {
1998 return KERN_FAILURE
;
2001 if (mplp
->mpl_qlimit
> MACH_PORT_QLIMIT_MAX
) {
2002 return KERN_INVALID_VALUE
;
2005 if (!MACH_PORT_VALID(name
)) {
2006 return KERN_INVALID_RIGHT
;
2009 kr
= ipc_port_translate_receive(space
, name
, &port
);
2010 if (kr
!= KERN_SUCCESS
) {
2013 /* port is locked and active */
2015 ipc_mqueue_set_qlimit(&port
->ip_messages
, mplp
->mpl_qlimit
);
2019 case MACH_PORT_DNREQUESTS_SIZE
: {
2020 if (count
< MACH_PORT_DNREQUESTS_SIZE_COUNT
) {
2021 return KERN_FAILURE
;
2024 if (!MACH_PORT_VALID(name
)) {
2025 return KERN_INVALID_RIGHT
;
2028 kr
= ipc_port_translate_receive(space
, name
, &port
);
2029 if (kr
!= KERN_SUCCESS
) {
2032 /* port is locked and active */
2034 kr
= ipc_port_request_grow(port
, *(int *)info
);
2035 if (kr
!= KERN_SUCCESS
) {
2040 case MACH_PORT_TEMPOWNER
:
2041 if (!MACH_PORT_VALID(name
)) {
2042 return KERN_INVALID_RIGHT
;
2045 ipc_importance_task_t release_imp_task
= IIT_NULL
;
2046 natural_t assertcnt
= 0;
2048 kr
= ipc_port_translate_receive(space
, name
, &port
);
2049 if (kr
!= KERN_SUCCESS
) {
2052 /* port is locked and active */
2055 * don't allow temp-owner importance donation if user
2056 * associated it with a kobject already (timer, host_notify target),
2057 * or is a special reply port.
2059 if (ip_is_kobject(port
) || port
->ip_specialreply
) {
2061 return KERN_INVALID_ARGUMENT
;
2064 if (port
->ip_tempowner
!= 0) {
2065 if (IIT_NULL
!= port
->ip_imp_task
) {
2066 release_imp_task
= port
->ip_imp_task
;
2067 port
->ip_imp_task
= IIT_NULL
;
2068 assertcnt
= port
->ip_impcount
;
2071 assertcnt
= port
->ip_impcount
;
2074 port
->ip_impdonation
= 1;
2075 port
->ip_tempowner
= 1;
2078 #if IMPORTANCE_INHERITANCE
2079 /* drop assertions from previous destination task */
2080 if (release_imp_task
!= IIT_NULL
) {
2081 assert(ipc_importance_task_is_any_receiver_type(release_imp_task
));
2082 if (assertcnt
> 0) {
2083 ipc_importance_task_drop_internal_assertion(release_imp_task
, assertcnt
);
2085 ipc_importance_task_release(release_imp_task
);
2086 } else if (assertcnt
> 0) {
2087 release_imp_task
= current_task()->task_imp_base
;
2088 if (release_imp_task
!= IIT_NULL
&&
2089 ipc_importance_task_is_any_receiver_type(release_imp_task
)) {
2090 ipc_importance_task_drop_internal_assertion(release_imp_task
, assertcnt
);
2094 if (release_imp_task
!= IIT_NULL
) {
2095 ipc_importance_task_release(release_imp_task
);
2097 #endif /* IMPORTANCE_INHERITANCE */
2101 #if IMPORTANCE_INHERITANCE
2102 case MACH_PORT_DENAP_RECEIVER
:
2103 case MACH_PORT_IMPORTANCE_RECEIVER
:
2104 if (!MACH_PORT_VALID(name
)) {
2105 return KERN_INVALID_RIGHT
;
2108 kr
= ipc_port_translate_receive(space
, name
, &port
);
2109 if (kr
!= KERN_SUCCESS
) {
2114 * don't allow importance donation if user associated
2115 * it with a kobject already (timer, host_notify target),
2116 * or is a special reply port.
2118 if (ip_is_kobject(port
) || port
->ip_specialreply
) {
2120 return KERN_INVALID_ARGUMENT
;
2123 /* port is locked and active */
2124 port
->ip_impdonation
= 1;
2128 #endif /* IMPORTANCE_INHERITANCE */
2131 return KERN_INVALID_ARGUMENT
;
2134 return KERN_SUCCESS
;
2138 * Routine: mach_port_insert_member [kernel call]
2140 * Add the receive right, specified by name, to
2142 * The port cannot already be a member of the set.
2146 * KERN_SUCCESS Moved the port.
2147 * KERN_INVALID_TASK The space is null.
2148 * KERN_INVALID_TASK The space is dead.
2149 * KERN_INVALID_NAME name didn't denote a right.
2150 * KERN_INVALID_RIGHT name didn't denote a receive right.
2151 * KERN_INVALID_NAME pset_name didn't denote a right.
2152 * KERN_INVALID_RIGHT pset_name didn't denote a portset right.
2153 * KERN_ALREADY_IN_SET name was already a member of pset.
2157 mach_port_insert_member(
2159 mach_port_name_t name
,
2160 mach_port_name_t psname
)
2165 uint64_t wq_link_id
;
2166 uint64_t wq_reserved_prepost
;
2168 if (space
== IS_NULL
) {
2169 return KERN_INVALID_TASK
;
2172 if (!MACH_PORT_VALID(name
) || !MACH_PORT_VALID(psname
)) {
2173 return KERN_INVALID_RIGHT
;
2176 wq_link_id
= waitq_link_reserve(NULL
);
2177 wq_reserved_prepost
= waitq_prepost_reserve(NULL
, 10,
2179 kr
= ipc_pset_lazy_allocate(space
, psname
);
2180 if (kr
!= KERN_SUCCESS
) {
2185 kr
= ipc_object_translate_two(space
,
2186 name
, MACH_PORT_RIGHT_RECEIVE
, &obj
,
2187 psname
, MACH_PORT_RIGHT_PORT_SET
, &psobj
);
2188 if (kr
!= KERN_SUCCESS
) {
2192 /* obj and psobj are locked (and were locked in that order) */
2193 assert(psobj
!= IO_NULL
);
2194 assert(obj
!= IO_NULL
);
2196 kr
= ipc_pset_add(ips_object_to_pset(psobj
), ip_object_to_port(obj
),
2197 &wq_link_id
, &wq_reserved_prepost
);
2203 /* on success, wq_link_id is reset to 0, so this is always safe */
2204 waitq_link_release(wq_link_id
);
2205 waitq_prepost_release_reserve(wq_reserved_prepost
);
2211 * Routine: mach_port_extract_member [kernel call]
2213 * Remove a port from one portset that it is a member of.
2217 * KERN_SUCCESS Moved the port.
2218 * KERN_INVALID_TASK The space is null.
2219 * KERN_INVALID_TASK The space is dead.
2220 * KERN_INVALID_NAME Member didn't denote a right.
2221 * KERN_INVALID_RIGHT Member didn't denote a receive right.
2222 * KERN_INVALID_NAME After didn't denote a right.
2223 * KERN_INVALID_RIGHT After didn't denote a port set right.
2225 * After is MACH_PORT_NULL and Member isn't in a port set.
2229 mach_port_extract_member(
2231 mach_port_name_t name
,
2232 mach_port_name_t psname
)
2238 if (space
== IS_NULL
) {
2239 return KERN_INVALID_TASK
;
2242 if (!MACH_PORT_VALID(name
) || !MACH_PORT_VALID(psname
)) {
2243 return KERN_INVALID_RIGHT
;
2246 kr
= ipc_object_translate_two(space
,
2247 name
, MACH_PORT_RIGHT_RECEIVE
, &obj
,
2248 psname
, MACH_PORT_RIGHT_PORT_SET
, &psobj
);
2249 if (kr
!= KERN_SUCCESS
) {
2253 /* obj and psobj are both locked (and were locked in that order) */
2254 assert(psobj
!= IO_NULL
);
2255 assert(obj
!= IO_NULL
);
2257 kr
= ipc_pset_remove(ips_object_to_pset(psobj
), ip_object_to_port(obj
));
2266 * task_set_port_space:
2268 * Set port name space of task to specified size.
2271 task_set_port_space(
2277 if (space
== IS_NULL
) {
2278 return KERN_INVALID_TASK
;
2281 is_write_lock(space
);
2283 if (!is_active(space
)) {
2284 is_write_unlock(space
);
2285 return KERN_INVALID_TASK
;
2288 kr
= ipc_entry_grow_table(space
, table_entries
);
2289 if (kr
== KERN_SUCCESS
) {
2290 is_write_unlock(space
);
2296 * Routine: mach_port_guard_locked [helper routine]
2298 * Sets a new guard for a locked port.
2302 * KERN_SUCCESS Port Guarded.
2303 * KERN_INVALID_ARGUMENT Port already contains a context/guard.
2305 static kern_return_t
2306 mach_port_guard_locked(
2311 if (port
->ip_context
) {
2312 return KERN_INVALID_ARGUMENT
;
2315 int strict
= (flags
& MPG_STRICT
)? 1 : 0;
2316 int immovable_receive
= (flags
& MPG_IMMOVABLE_RECEIVE
)? 1 : 0;
2318 imq_lock(&port
->ip_messages
);
2319 port
->ip_context
= guard
;
2320 port
->ip_guarded
= 1;
2321 port
->ip_strict_guard
= strict
;
2322 /* ip_immovable_receive bit is sticky and can't be un-guarded */
2323 if (!port
->ip_immovable_receive
) {
2324 port
->ip_immovable_receive
= immovable_receive
;
2326 imq_unlock(&port
->ip_messages
);
2328 return KERN_SUCCESS
;
2332 * Routine: mach_port_unguard_locked [helper routine]
2334 * Removes guard for a locked port.
2338 * KERN_SUCCESS Port Unguarded.
2339 * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch.
2340 * This also raises a EXC_GUARD exception.
2342 static kern_return_t
2343 mach_port_unguard_locked(
2345 mach_port_name_t name
,
2348 /* Port locked and active */
2349 if (!port
->ip_guarded
) {
2350 /* Port already unguarded; Raise exception */
2351 mach_port_guard_exception(name
, guard
, 0, kGUARD_EXC_UNGUARDED
);
2352 return KERN_INVALID_ARGUMENT
;
2355 if (port
->ip_context
!= guard
) {
2356 /* Incorrect guard; Raise exception */
2357 mach_port_guard_exception(name
, guard
, port
->ip_context
, kGUARD_EXC_INCORRECT_GUARD
);
2358 return KERN_INVALID_ARGUMENT
;
2361 imq_lock(&port
->ip_messages
);
2362 port
->ip_context
= 0;
2363 port
->ip_guarded
= port
->ip_strict_guard
= 0;
2364 /* Don't clear the ip_immovable_receive bit */
2365 imq_unlock(&port
->ip_messages
);
2367 return KERN_SUCCESS
;
2372 * Routine: mach_port_guard_exception [helper routine]
2374 * Marks the thread with AST_GUARD for mach port guard violation.
2375 * Also saves exception info in thread structure.
2379 * KERN_FAILURE Thread marked with AST_GUARD.
2382 mach_port_guard_exception(
2383 mach_port_name_t name
,
2384 __unused
uint64_t inguard
,
2388 mach_exception_code_t code
= 0;
2389 EXC_GUARD_ENCODE_TYPE(code
, GUARD_TYPE_MACH_PORT
);
2390 EXC_GUARD_ENCODE_FLAVOR(code
, reason
);
2391 EXC_GUARD_ENCODE_TARGET(code
, name
);
2392 mach_exception_subcode_t subcode
= (uint64_t)portguard
;
2393 thread_t t
= current_thread();
2394 boolean_t fatal
= FALSE
;
2395 if (t
->task
->task_exc_guard
& TASK_EXC_GUARD_MP_FATAL
) {
2397 } else if (reason
<= MAX_FATAL_kGUARD_EXC_CODE
) {
2400 thread_guard_violation(t
, code
, subcode
, fatal
);
2405 * Routine: mach_port_guard_ast
2407 * Raises an exception for mach port guard violation.
2415 mach_port_guard_ast(thread_t t
,
2416 mach_exception_data_type_t code
, mach_exception_data_type_t subcode
)
2418 unsigned int reason
= EXC_GUARD_DECODE_GUARD_FLAVOR(code
);
2419 task_t task
= t
->task
;
2420 unsigned int behavior
= task
->task_exc_guard
;
2421 assert(task
== current_task());
2422 assert(task
!= kernel_task
);
2426 * Fatal Mach port guards - always delivered synchronously
2428 case kGUARD_EXC_DESTROY
:
2429 case kGUARD_EXC_MOD_REFS
:
2430 case kGUARD_EXC_SET_CONTEXT
:
2431 case kGUARD_EXC_UNGUARDED
:
2432 case kGUARD_EXC_INCORRECT_GUARD
:
2433 case kGUARD_EXC_IMMOVABLE
:
2434 case kGUARD_EXC_STRICT_REPLY
:
2435 task_exception_notify(EXC_GUARD
, code
, subcode
);
2436 task_bsdtask_kill(task
);
2441 * Mach port guards controlled by task settings.
2444 /* Is delivery enabled */
2445 if ((behavior
& TASK_EXC_GUARD_MP_DELIVER
) == 0) {
2449 /* If only once, make sure we're that once */
2450 while (behavior
& TASK_EXC_GUARD_MP_ONCE
) {
2451 uint32_t new_behavior
= behavior
& ~TASK_EXC_GUARD_MP_DELIVER
;
2453 if (OSCompareAndSwap(behavior
, new_behavior
, &task
->task_exc_guard
)) {
2456 behavior
= task
->task_exc_guard
;
2457 if ((behavior
& TASK_EXC_GUARD_MP_DELIVER
) == 0) {
2462 /* Raise exception via corpse fork or synchronously */
2463 if ((task
->task_exc_guard
& TASK_EXC_GUARD_MP_CORPSE
) &&
2464 (task
->task_exc_guard
& TASK_EXC_GUARD_MP_FATAL
) == 0) {
2465 task_violated_guard(code
, subcode
, NULL
);
2467 task_exception_notify(EXC_GUARD
, code
, subcode
);
2470 /* Terminate the task if desired */
2471 if (task
->task_exc_guard
& TASK_EXC_GUARD_MP_FATAL
) {
2472 task_bsdtask_kill(task
);
2479 * Routine: mach_port_construct [kernel call]
2481 * Constructs a mach port with the provided set of options.
2485 * KERN_SUCCESS The right is allocated.
2486 * KERN_INVALID_TASK The space is null.
2487 * KERN_INVALID_TASK The space is dead.
2488 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
2489 * KERN_NO_SPACE No room in space for another right.
2490 * KERN_FAILURE Illegal option values requested.
2494 mach_port_construct(
2496 mach_port_options_t
*options
,
2498 mach_port_name_t
*name
)
2503 if (space
== IS_NULL
) {
2504 return KERN_INVALID_TASK
;
2507 /* Allocate a new port in the IPC space */
2508 kr
= ipc_port_alloc(space
, (options
->flags
& MPO_INSERT_SEND_RIGHT
),
2510 if (kr
!= KERN_SUCCESS
) {
2514 /* Port locked and active */
2515 if (options
->flags
& MPO_CONTEXT_AS_GUARD
) {
2517 if (options
->flags
& MPO_STRICT
) {
2518 flags
|= MPG_STRICT
;
2520 if (options
->flags
& MPO_IMMOVABLE_RECEIVE
) {
2521 flags
|= MPG_IMMOVABLE_RECEIVE
;
2523 kr
= mach_port_guard_locked(port
, (uint64_t) context
, flags
);
2524 /* A newly allocated and locked port should always be guarded successfully */
2525 assert(kr
== KERN_SUCCESS
);
2527 port
->ip_context
= context
;
2533 /* Set port attributes as requested */
2535 if (options
->flags
& MPO_QLIMIT
) {
2536 kr
= mach_port_set_attributes(space
, *name
, MACH_PORT_LIMITS_INFO
,
2537 (mach_port_info_t
)&options
->mpl
, sizeof(options
->mpl
) / sizeof(int));
2538 if (kr
!= KERN_SUCCESS
) {
2543 if (options
->flags
& MPO_TEMPOWNER
) {
2544 kr
= mach_port_set_attributes(space
, *name
, MACH_PORT_TEMPOWNER
, NULL
, 0);
2545 if (kr
!= KERN_SUCCESS
) {
2550 if (options
->flags
& MPO_IMPORTANCE_RECEIVER
) {
2551 kr
= mach_port_set_attributes(space
, *name
, MACH_PORT_IMPORTANCE_RECEIVER
, NULL
, 0);
2552 if (kr
!= KERN_SUCCESS
) {
2557 if (options
->flags
& MPO_DENAP_RECEIVER
) {
2558 kr
= mach_port_set_attributes(space
, *name
, MACH_PORT_DENAP_RECEIVER
, NULL
, 0);
2559 if (kr
!= KERN_SUCCESS
) {
2564 return KERN_SUCCESS
;
2567 /* Attempt to destroy port. If its already destroyed by some other thread, we're done */
2568 (void) mach_port_destruct(space
, *name
,
2569 (options
->flags
& MPO_INSERT_SEND_RIGHT
) ? -1 : 0, context
);
2574 * Routine: mach_port_destruct [kernel call]
2576 * Destroys a mach port with appropriate guard
2580 * KERN_SUCCESS The name is destroyed.
2581 * KERN_INVALID_TASK The space is null.
2582 * KERN_INVALID_TASK The space is dead.
2583 * KERN_INVALID_NAME The name doesn't denote a right.
2584 * KERN_INVALID_RIGHT The right isn't correct.
2585 * KERN_INVALID_VALUE The delta for send right is incorrect.
2586 * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch.
2587 * This also raises a EXC_GUARD exception.
2593 mach_port_name_t name
,
2594 mach_port_delta_t srdelta
,
2600 if (space
== IS_NULL
) {
2601 return KERN_INVALID_TASK
;
2604 if (!MACH_PORT_VALID(name
)) {
2605 return KERN_INVALID_NAME
;
2608 /* Remove reference for receive right */
2609 kr
= ipc_right_lookup_write(space
, name
, &entry
);
2610 if (kr
!= KERN_SUCCESS
) {
2611 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_INVALID_NAME
);
2614 /* space is write-locked and active */
2615 kr
= ipc_right_destruct(space
, name
, entry
, srdelta
, guard
); /* unlocks */
2621 * Routine: mach_port_guard [kernel call]
2623 * Guard a mach port with specified guard value.
2624 * The context field of the port is used as the guard.
2628 * KERN_SUCCESS The name is destroyed.
2629 * KERN_INVALID_TASK The space is null.
2630 * KERN_INVALID_TASK The space is dead.
2631 * KERN_INVALID_NAME The name doesn't denote a right.
2632 * KERN_INVALID_RIGHT The right isn't correct.
2633 * KERN_INVALID_ARGUMENT Port already contains a context/guard.
2638 mach_port_name_t name
,
2646 if (space
== IS_NULL
) {
2647 return KERN_INVALID_TASK
;
2650 if (!MACH_PORT_VALID(name
)) {
2651 return KERN_INVALID_NAME
;
2654 /* Guard can be applied only to receive rights */
2655 kr
= ipc_port_translate_receive(space
, name
, &port
);
2656 if (kr
!= KERN_SUCCESS
) {
2657 mach_port_guard_exception(name
, 0, 0,
2658 ((KERN_INVALID_NAME
== kr
) ?
2659 kGUARD_EXC_INVALID_NAME
:
2660 kGUARD_EXC_INVALID_RIGHT
));
2664 /* Port locked and active */
2669 kr
= mach_port_guard_locked(port
, guard
, flags
);
2672 if (KERN_INVALID_ARGUMENT
== kr
) {
2673 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_INVALID_ARGUMENT
);
2680 * Routine: mach_port_unguard [kernel call]
2682 * Unguard a mach port with specified guard value.
2686 * KERN_SUCCESS The name is destroyed.
2687 * KERN_INVALID_TASK The space is null.
2688 * KERN_INVALID_TASK The space is dead.
2689 * KERN_INVALID_NAME The name doesn't denote a right.
2690 * KERN_INVALID_RIGHT The right isn't correct.
2691 * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch.
2692 * This also raises a EXC_GUARD exception.
2697 mach_port_name_t name
,
2703 if (space
== IS_NULL
) {
2704 return KERN_INVALID_TASK
;
2707 if (!MACH_PORT_VALID(name
)) {
2708 return KERN_INVALID_NAME
;
2711 kr
= ipc_port_translate_receive(space
, name
, &port
);
2712 if (kr
!= KERN_SUCCESS
) {
2713 mach_port_guard_exception(name
, 0, 0,
2714 ((KERN_INVALID_NAME
== kr
) ?
2715 kGUARD_EXC_INVALID_NAME
:
2716 kGUARD_EXC_INVALID_RIGHT
));
2720 /* Port locked and active */
2721 kr
= mach_port_unguard_locked(port
, name
, guard
);
2728 * Routine: mach_port_guard_with_flags [kernel call]
2730 * Guard a mach port with specified guard value and guard flags.
2731 * The context field of the port is used as the guard.
2733 * Should hold receive right for that port
2735 * KERN_SUCCESS The name is destroyed.
2736 * KERN_INVALID_TASK The space is null.
2737 * KERN_INVALID_TASK The space is dead.
2738 * KERN_INVALID_NAME The name doesn't denote a right.
2739 * KERN_INVALID_RIGHT The right isn't correct.
2740 * KERN_INVALID_ARGUMENT Port already contains a context/guard.
2741 * KERN_INVALID_CAPABILITY Cannot set MPG_IMMOVABLE_RECEIVE flag for a port with
2742 * a movable port-destroyed notification port
2745 mach_port_guard_with_flags(
2747 mach_port_name_t name
,
2754 if (space
== IS_NULL
) {
2755 return KERN_INVALID_TASK
;
2758 if (!MACH_PORT_VALID(name
)) {
2759 return KERN_INVALID_NAME
;
2762 kr
= ipc_port_translate_receive(space
, name
, &port
);
2763 if (kr
!= KERN_SUCCESS
) {
2764 mach_port_guard_exception(name
, 0, 0,
2765 ((KERN_INVALID_NAME
== kr
) ?
2766 kGUARD_EXC_INVALID_NAME
:
2767 kGUARD_EXC_INVALID_RIGHT
));
2771 /* Port locked and active */
2772 kr
= mach_port_guard_locked(port
, guard
, flags
);
2775 if (KERN_INVALID_ARGUMENT
== kr
) {
2776 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_INVALID_ARGUMENT
);
2783 * Routine: mach_port_swap_guard [kernel call]
2787 * Port should already be guarded.
2789 * KERN_SUCCESS The name is destroyed.
2790 * KERN_INVALID_TASK The space is null.
2791 * KERN_INVALID_TASK The space is dead.
2792 * KERN_INVALID_NAME The name doesn't denote a right.
2793 * KERN_INVALID_RIGHT The right isn't correct.
2794 * KERN_INVALID_ARGUMENT Port doesn't contain a guard; is strictly guarded
2795 * or the old_guard doesnt match the context
2798 mach_port_swap_guard(
2800 mach_port_name_t name
,
2807 if (space
== IS_NULL
) {
2808 return KERN_INVALID_TASK
;
2811 if (!MACH_PORT_VALID(name
)) {
2812 return KERN_INVALID_NAME
;
2815 kr
= ipc_port_translate_receive(space
, name
, &port
);
2816 if (kr
!= KERN_SUCCESS
) {
2817 mach_port_guard_exception(name
, 0, 0,
2818 ((KERN_INVALID_NAME
== kr
) ?
2819 kGUARD_EXC_INVALID_NAME
:
2820 kGUARD_EXC_INVALID_RIGHT
));
2824 /* Port locked and active */
2825 if (!port
->ip_guarded
) {
2827 mach_port_guard_exception(name
, old_guard
, 0, kGUARD_EXC_UNGUARDED
);
2828 return KERN_INVALID_ARGUMENT
;
2831 if (port
->ip_strict_guard
) {
2832 uint64_t portguard
= port
->ip_context
;
2834 /* For strictly guarded ports, disallow overwriting context; Raise Exception */
2835 mach_port_guard_exception(name
, old_guard
, portguard
, kGUARD_EXC_SET_CONTEXT
);
2836 return KERN_INVALID_ARGUMENT
;
2839 if (port
->ip_context
!= old_guard
) {
2840 uint64_t portguard
= port
->ip_context
;
2842 mach_port_guard_exception(name
, old_guard
, portguard
, kGUARD_EXC_INCORRECT_GUARD
);
2843 return KERN_INVALID_ARGUMENT
;
2846 imq_lock(&port
->ip_messages
);
2847 port
->ip_context
= new_guard
;
2848 imq_unlock(&port
->ip_messages
);
2852 return KERN_SUCCESS
;