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
, IPC_PORT_INIT_MESSAGE_QUEUE
,
731 kr
= ipc_port_alloc(space
, IPC_PORT_INIT_MESSAGE_QUEUE
,
734 if (kr
== KERN_SUCCESS
) {
735 if (kmsg
!= IKM_NULL
) {
736 ipc_kmsg_set_prealloc(kmsg
, port
);
739 } else if (kmsg
!= IKM_NULL
) {
745 case MACH_PORT_RIGHT_PORT_SET
:
750 kr
= ipc_pset_alloc_name(space
, *namep
, &pset
);
752 kr
= ipc_pset_alloc(space
, namep
, &pset
);
754 if (kr
== KERN_SUCCESS
) {
760 case MACH_PORT_RIGHT_DEAD_NAME
:
761 kr
= ipc_object_alloc_dead(space
, namep
);
765 kr
= KERN_INVALID_VALUE
;
773 * Routine: mach_port_destroy [kernel call]
775 * Cleans up and destroys all rights denoted by a name
776 * in a space. The destruction of a receive right
777 * destroys the port, unless a port-destroyed request
778 * has been made for it; the destruction of a port-set right
779 * destroys the port set.
783 * KERN_SUCCESS The name is destroyed.
784 * KERN_INVALID_TASK The space is null.
785 * KERN_INVALID_TASK The space is dead.
786 * KERN_INVALID_NAME The name doesn't denote a right.
792 mach_port_name_t name
)
797 if (space
== IS_NULL
) {
798 return KERN_INVALID_TASK
;
801 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 and active */
812 kr
= ipc_right_destroy(space
, name
, entry
, TRUE
, 0); /* unlocks space */
817 * Routine: mach_port_deallocate [kernel call]
819 * Deallocates a user reference from a send right,
820 * send-once right, dead-name right or a port_set right.
821 * May deallocate the right, if this is the last uref,
822 * and destroy the name, if it doesn't denote
827 * KERN_SUCCESS The uref is deallocated.
828 * KERN_INVALID_TASK The space is null.
829 * KERN_INVALID_TASK The space is dead.
830 * KERN_INVALID_NAME The name doesn't denote a right.
831 * KERN_INVALID_RIGHT The right isn't correct.
835 mach_port_deallocate(
837 mach_port_name_t name
)
842 if (space
== IS_NULL
) {
843 return KERN_INVALID_TASK
;
846 if (!MACH_PORT_VALID(name
)) {
850 kr
= ipc_right_lookup_write(space
, name
, &entry
);
851 if (kr
!= KERN_SUCCESS
) {
852 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_INVALID_NAME
);
855 /* space is write-locked */
857 kr
= ipc_right_dealloc(space
, name
, entry
); /* unlocks space */
862 * Routine: mach_port_get_refs [kernel call]
864 * Retrieves the number of user references held by a right.
865 * Receive rights, port-set rights, and send-once rights
866 * always have one user reference. Returns zero if the
867 * name denotes a right, but not the queried right.
871 * KERN_SUCCESS Number of urefs returned.
872 * KERN_INVALID_TASK The space is null.
873 * KERN_INVALID_TASK The space is dead.
874 * KERN_INVALID_VALUE "right" isn't a legal value.
875 * KERN_INVALID_NAME The name doesn't denote a right.
881 mach_port_name_t name
,
882 mach_port_right_t right
,
883 mach_port_urefs_t
*urefsp
)
885 mach_port_type_t type
;
886 mach_port_urefs_t urefs
;
890 if (space
== IS_NULL
) {
891 return KERN_INVALID_TASK
;
894 if (right
>= MACH_PORT_RIGHT_NUMBER
) {
895 return KERN_INVALID_VALUE
;
898 if (!MACH_PORT_VALID(name
)) {
899 if (right
== MACH_PORT_RIGHT_SEND
||
900 right
== MACH_PORT_RIGHT_SEND_ONCE
) {
904 return KERN_INVALID_NAME
;
907 kr
= ipc_right_lookup_write(space
, name
, &entry
);
908 if (kr
!= KERN_SUCCESS
) {
912 /* space is write-locked and active */
913 kr
= ipc_right_info(space
, name
, entry
, &type
, &urefs
);
914 /* space is unlocked */
916 if (kr
!= KERN_SUCCESS
) {
920 if (type
& MACH_PORT_TYPE(right
)) {
922 case MACH_PORT_RIGHT_SEND_ONCE
:
926 case MACH_PORT_RIGHT_PORT_SET
:
927 case MACH_PORT_RIGHT_RECEIVE
:
931 case MACH_PORT_RIGHT_DEAD_NAME
:
932 case MACH_PORT_RIGHT_SEND
:
938 panic("mach_port_get_refs: strange rights");
948 * Routine: mach_port_mod_refs
950 * Modifies the number of user references held by a right.
951 * The resulting number of user references must be non-negative.
952 * If it is zero, the right is deallocated. If the name
953 * doesn't denote other rights, it is destroyed.
957 * KERN_SUCCESS Modified number of urefs.
958 * KERN_INVALID_TASK The space is null.
959 * KERN_INVALID_TASK The space is dead.
960 * KERN_INVALID_VALUE "right" isn't a legal value.
961 * KERN_INVALID_NAME The name doesn't denote a right.
962 * KERN_INVALID_RIGHT Name doesn't denote specified right.
963 * KERN_INVALID_VALUE Impossible modification to urefs.
964 * KERN_UREFS_OVERFLOW Urefs would overflow.
970 mach_port_name_t name
,
971 mach_port_right_t right
,
972 mach_port_delta_t delta
)
977 if (space
== IS_NULL
) {
978 return KERN_INVALID_TASK
;
981 if (right
>= MACH_PORT_RIGHT_NUMBER
) {
982 return KERN_INVALID_VALUE
;
985 if (!MACH_PORT_VALID(name
)) {
986 if (right
== MACH_PORT_RIGHT_SEND
||
987 right
== MACH_PORT_RIGHT_SEND_ONCE
) {
990 return KERN_INVALID_NAME
;
993 kr
= ipc_right_lookup_write(space
, name
, &entry
);
994 if (kr
!= KERN_SUCCESS
) {
995 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_INVALID_NAME
);
999 /* space is write-locked and active */
1001 kr
= ipc_right_delta(space
, name
, entry
, right
, delta
); /* unlocks */
1007 * Routine: mach_port_peek [kernel call]
1009 * Peek at the message queue for the specified receive
1010 * right and return info about a message in the queue.
1012 * On input, seqnop points to a sequence number value
1013 * to match the message being peeked. If zero is specified
1014 * as the seqno, the first message in the queue will be
1017 * Only the following trailer types are currently supported:
1018 * MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)
1020 * or'ed with one of these element types:
1021 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_NULL)
1022 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SEQNO)
1023 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER)
1024 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT)
1026 * On input, the value pointed to by trailer_sizep must be
1027 * large enough to hold the requested trailer size.
1029 * The message sequence number, id, size, requested trailer info
1030 * and requested trailer size are returned in their respective
1031 * output parameters upon success.
1036 * KERN_SUCCESS Matching message found, out parameters set.
1037 * KERN_INVALID_TASK The space is null or dead.
1038 * KERN_INVALID_NAME The name doesn't denote a right.
1039 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1040 * KERN_INVALID_VALUE The input parameter values are out of bounds.
1041 * KERN_FAILURE The requested message was not found.
1047 mach_port_name_t name
,
1048 mach_msg_trailer_type_t trailer_type
,
1049 mach_port_seqno_t
*seqnop
,
1050 mach_msg_size_t
*msg_sizep
,
1051 mach_msg_id_t
*msg_idp
,
1052 mach_msg_trailer_info_t trailer_infop
,
1053 mach_msg_type_number_t
*trailer_sizep
)
1058 mach_msg_max_trailer_t max_trailer
;
1060 if (space
== IS_NULL
) {
1061 return KERN_INVALID_TASK
;
1064 if (!MACH_PORT_VALID(name
)) {
1065 return KERN_INVALID_RIGHT
;
1069 * We don't allow anything greater than the audit trailer - to avoid
1070 * leaking the context pointer and to avoid variable-sized context issues.
1072 if (GET_RCV_ELEMENTS(trailer_type
) > MACH_RCV_TRAILER_AUDIT
||
1073 REQUESTED_TRAILER_SIZE(TRUE
, trailer_type
) > *trailer_sizep
) {
1074 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_INVALID_VALUE
);
1075 return KERN_INVALID_VALUE
;
1078 *trailer_sizep
= REQUESTED_TRAILER_SIZE(TRUE
, trailer_type
);
1080 kr
= ipc_port_translate_receive(space
, name
, &port
);
1081 if (kr
!= KERN_SUCCESS
) {
1082 mach_port_guard_exception(name
, 0, 0,
1083 ((KERN_INVALID_NAME
== kr
) ?
1084 kGUARD_EXC_INVALID_NAME
:
1085 kGUARD_EXC_INVALID_RIGHT
));
1089 /* Port locked and active */
1091 found
= ipc_mqueue_peek(&port
->ip_messages
, seqnop
,
1092 msg_sizep
, msg_idp
, &max_trailer
, NULL
);
1095 if (found
!= TRUE
) {
1096 return KERN_FAILURE
;
1099 max_trailer
.msgh_seqno
= *seqnop
;
1100 memcpy(trailer_infop
, &max_trailer
, *trailer_sizep
);
1102 return KERN_SUCCESS
;
1106 * Routine: mach_port_set_mscount [kernel call]
1108 * Changes a receive right's make-send count.
1112 * KERN_SUCCESS Set make-send count.
1113 * KERN_INVALID_TASK The space is null.
1114 * KERN_INVALID_TASK The space is dead.
1115 * KERN_INVALID_NAME The name doesn't denote a right.
1116 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1120 mach_port_set_mscount(
1122 mach_port_name_t name
,
1123 mach_port_mscount_t mscount
)
1128 if (space
== IS_NULL
) {
1129 return KERN_INVALID_TASK
;
1132 if (!MACH_PORT_VALID(name
)) {
1133 return KERN_INVALID_RIGHT
;
1136 kr
= ipc_port_translate_receive(space
, name
, &port
);
1137 if (kr
!= KERN_SUCCESS
) {
1140 /* port is locked and active */
1142 port
->ip_mscount
= mscount
;
1144 return KERN_SUCCESS
;
1148 * Routine: mach_port_set_seqno [kernel call]
1150 * Changes a receive right's sequence number.
1154 * KERN_SUCCESS Set sequence number.
1155 * KERN_INVALID_TASK The space is null.
1156 * KERN_INVALID_TASK The space is dead.
1157 * KERN_INVALID_NAME The name doesn't denote a right.
1158 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1162 mach_port_set_seqno(
1164 mach_port_name_t name
,
1165 mach_port_seqno_t seqno
)
1170 if (space
== IS_NULL
) {
1171 return KERN_INVALID_TASK
;
1174 if (!MACH_PORT_VALID(name
)) {
1175 return KERN_INVALID_RIGHT
;
1178 kr
= ipc_port_translate_receive(space
, name
, &port
);
1179 if (kr
!= KERN_SUCCESS
) {
1182 /* port is locked and active */
1184 ipc_mqueue_set_seqno(&port
->ip_messages
, seqno
);
1187 return KERN_SUCCESS
;
1191 * Routine: mach_port_get_context [kernel call]
1193 * Returns a receive right's context pointer.
1197 * KERN_SUCCESS Set context pointer.
1198 * KERN_INVALID_TASK The space is null.
1199 * KERN_INVALID_TASK The space is dead.
1200 * KERN_INVALID_NAME The name doesn't denote a right.
1201 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1205 mach_port_get_context(
1207 mach_port_name_t name
,
1208 mach_vm_address_t
*context
)
1213 if (space
== IS_NULL
) {
1214 return KERN_INVALID_TASK
;
1217 if (!MACH_PORT_VALID(name
)) {
1218 return KERN_INVALID_RIGHT
;
1221 kr
= ipc_port_translate_receive(space
, name
, &port
);
1222 if (kr
!= KERN_SUCCESS
) {
1226 /* Port locked and active */
1228 /* For strictly guarded ports, return empty context (which acts as guard) */
1229 if (port
->ip_strict_guard
) {
1232 *context
= port
->ip_context
;
1236 return KERN_SUCCESS
;
1241 * Routine: mach_port_set_context [kernel call]
1243 * Changes a receive right's context pointer.
1247 * KERN_SUCCESS Set context pointer.
1248 * KERN_INVALID_TASK The space is null.
1249 * KERN_INVALID_TASK The space is dead.
1250 * KERN_INVALID_NAME The name doesn't denote a right.
1251 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1255 mach_port_set_context(
1257 mach_port_name_t name
,
1258 mach_vm_address_t context
)
1263 if (space
== IS_NULL
) {
1264 return KERN_INVALID_TASK
;
1267 if (!MACH_PORT_VALID(name
)) {
1268 return KERN_INVALID_RIGHT
;
1271 kr
= ipc_port_translate_receive(space
, name
, &port
);
1272 if (kr
!= KERN_SUCCESS
) {
1276 /* port is locked and active */
1277 if (port
->ip_strict_guard
) {
1278 uint64_t portguard
= port
->ip_context
;
1280 /* For strictly guarded ports, disallow overwriting context; Raise Exception */
1281 mach_port_guard_exception(name
, context
, portguard
, kGUARD_EXC_SET_CONTEXT
);
1282 return KERN_INVALID_ARGUMENT
;
1285 port
->ip_context
= context
;
1288 return KERN_SUCCESS
;
1293 * Routine: mach_port_get_set_status [kernel call]
1295 * Retrieves a list of members in a port set.
1296 * Returns the space's name for each receive right member.
1300 * KERN_SUCCESS Retrieved list of members.
1301 * KERN_INVALID_TASK The space is null.
1302 * KERN_INVALID_TASK The space is dead.
1303 * KERN_INVALID_NAME The name doesn't denote a right.
1304 * KERN_INVALID_RIGHT Name doesn't denote a port set.
1305 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1309 mach_port_get_set_status(
1311 mach_port_name_t name
,
1312 mach_port_name_t
**members
,
1313 mach_msg_type_number_t
*membersCnt
)
1315 ipc_entry_num_t actual
; /* this many members */
1316 ipc_entry_num_t maxnames
; /* space for this many members */
1319 vm_size_t size
; /* size of allocated memory */
1320 vm_offset_t addr
; /* allocated memory */
1321 vm_map_copy_t memory
; /* copied-in memory */
1323 if (space
== IS_NULL
) {
1324 return KERN_INVALID_TASK
;
1327 if (!MACH_PORT_VALID(name
)) {
1328 return KERN_INVALID_RIGHT
;
1331 size
= VM_MAP_PAGE_SIZE(ipc_kernel_map
); /* initial guess */
1334 mach_port_name_t
*names
;
1338 kr
= vm_allocate_kernel(ipc_kernel_map
, &addr
, size
, VM_FLAGS_ANYWHERE
, VM_KERN_MEMORY_IPC
);
1339 if (kr
!= KERN_SUCCESS
) {
1340 return KERN_RESOURCE_SHORTAGE
;
1343 /* can't fault while we hold locks */
1345 kr
= vm_map_wire_kernel(ipc_kernel_map
, addr
, addr
+ size
,
1346 VM_PROT_READ
| VM_PROT_WRITE
, VM_KERN_MEMORY_IPC
, FALSE
);
1347 assert(kr
== KERN_SUCCESS
);
1349 kr
= ipc_object_translate(space
, name
, MACH_PORT_RIGHT_PORT_SET
, &psobj
);
1350 if (kr
!= KERN_SUCCESS
) {
1351 kmem_free(ipc_kernel_map
, addr
, size
);
1355 /* just use a portset reference from here on out */
1356 pset
= ips_object_to_pset(psobj
);
1357 ips_reference(pset
);
1360 names
= (mach_port_name_t
*) addr
;
1361 maxnames
= (ipc_entry_num_t
)(size
/ sizeof(mach_port_name_t
));
1363 ipc_mqueue_set_gather_member_names(space
, &pset
->ips_messages
, maxnames
, names
, &actual
);
1365 /* release the portset reference */
1368 if (actual
<= maxnames
) {
1372 /* didn't have enough memory; allocate more */
1373 kmem_free(ipc_kernel_map
, addr
, size
);
1374 size
= vm_map_round_page(
1375 (actual
* sizeof(mach_port_name_t
)),
1376 VM_MAP_PAGE_MASK(ipc_kernel_map
)) +
1377 VM_MAP_PAGE_SIZE(ipc_kernel_map
);
1381 memory
= VM_MAP_COPY_NULL
;
1383 kmem_free(ipc_kernel_map
, addr
, size
);
1385 vm_size_t size_used
;
1386 vm_size_t vm_size_used
;
1388 size_used
= actual
* sizeof(mach_port_name_t
);
1389 vm_size_used
= vm_map_round_page(
1391 VM_MAP_PAGE_MASK(ipc_kernel_map
));
1394 * Make used memory pageable and get it into
1395 * copied-in form. Free any unused memory.
1400 vm_map_trunc_page(addr
,
1401 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
1402 vm_map_round_page(addr
+ vm_size_used
,
1403 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
1405 assert(kr
== KERN_SUCCESS
);
1407 kr
= vm_map_copyin(ipc_kernel_map
, (vm_map_address_t
)addr
,
1408 (vm_map_size_t
)size_used
, TRUE
, &memory
);
1409 assert(kr
== KERN_SUCCESS
);
1411 if (vm_size_used
!= size
) {
1412 kmem_free(ipc_kernel_map
,
1413 addr
+ vm_size_used
, size
- vm_size_used
);
1417 *members
= (mach_port_name_t
*) memory
;
1418 *membersCnt
= actual
;
1419 return KERN_SUCCESS
;
1423 * Routine: mach_port_move_member [kernel call]
1425 * If after is MACH_PORT_NULL, removes member
1426 * from the port set it is in. Otherwise, adds
1427 * member to after, removing it from any set
1428 * it might already be in.
1432 * KERN_SUCCESS Moved the port.
1433 * KERN_INVALID_TASK The space is null.
1434 * KERN_INVALID_TASK The space is dead.
1435 * KERN_INVALID_NAME Member didn't denote a right.
1436 * KERN_INVALID_RIGHT Member didn't denote a receive right.
1437 * KERN_INVALID_NAME After didn't denote a right.
1438 * KERN_INVALID_RIGHT After didn't denote a port set right.
1440 * After is MACH_PORT_NULL and Member isn't in a port set.
1444 mach_port_move_member(
1446 mach_port_name_t member
,
1447 mach_port_name_t after
)
1449 ipc_object_t port_obj
, ps_obj
;
1451 ipc_pset_t nset
= IPS_NULL
;
1453 uint64_t wq_link_id
= 0;
1454 uint64_t wq_reserved_prepost
= 0;
1456 if (space
== IS_NULL
) {
1457 return KERN_INVALID_TASK
;
1460 if (!MACH_PORT_VALID(member
)) {
1461 return KERN_INVALID_RIGHT
;
1464 if (after
== MACH_PORT_DEAD
) {
1465 return KERN_INVALID_RIGHT
;
1466 } else if (after
== MACH_PORT_NULL
) {
1470 * We reserve both a link, and
1471 * enough prepost objects to complete
1472 * the set move atomically - we can't block
1473 * while we're holding the space lock, and
1474 * the ipc_pset_add calls ipc_mqueue_add
1475 * which may have to prepost this port onto
1478 wq_link_id
= waitq_link_reserve(NULL
);
1479 wq_reserved_prepost
= waitq_prepost_reserve(NULL
, 10,
1481 kr
= ipc_pset_lazy_allocate(space
, after
);
1482 if (kr
!= KERN_SUCCESS
) {
1487 if (after
!= MACH_PORT_NULL
) {
1488 kr
= ipc_object_translate_two(space
,
1489 member
, MACH_PORT_RIGHT_RECEIVE
, &port_obj
,
1490 after
, MACH_PORT_RIGHT_PORT_SET
, &ps_obj
);
1492 kr
= ipc_object_translate(space
,
1493 member
, MACH_PORT_RIGHT_RECEIVE
, &port_obj
);
1495 if (kr
!= KERN_SUCCESS
) {
1499 port
= ip_object_to_port(port_obj
);
1500 if (after
!= MACH_PORT_NULL
) {
1501 nset
= ips_object_to_pset(ps_obj
);
1503 /* port and nset are locked */
1505 ipc_pset_remove_from_all(port
);
1507 if (after
!= MACH_PORT_NULL
) {
1508 kr
= ipc_pset_add(nset
, port
, &wq_link_id
, &wq_reserved_prepost
);
1516 * on success the ipc_pset_add() will consume the wq_link_id
1517 * value (resetting it to 0), so this function is always safe to call.
1519 waitq_link_release(wq_link_id
);
1520 waitq_prepost_release_reserve(wq_reserved_prepost
);
1526 * Routine: mach_port_request_notification [kernel call]
1528 * Requests a notification. The caller supplies
1529 * a send-once right for the notification to use,
1530 * and the call returns the previously registered
1531 * send-once right, if any. Possible types:
1533 * MACH_NOTIFY_PORT_DESTROYED
1534 * Requests a port-destroyed notification
1535 * for a receive right. Sync should be zero.
1536 * MACH_NOTIFY_NO_SENDERS
1537 * Requests a no-senders notification for a
1538 * receive right. If there are currently no
1539 * senders, sync is less than or equal to the
1540 * current make-send count, and a send-once right
1541 * is supplied, then an immediate no-senders
1542 * notification is generated.
1543 * MACH_NOTIFY_DEAD_NAME
1544 * Requests a dead-name notification for a send
1545 * or receive right. If the name is already a
1546 * dead name, sync is non-zero, and a send-once
1547 * right is supplied, then an immediate dead-name
1548 * notification is generated.
1552 * KERN_SUCCESS Requested a notification.
1553 * KERN_INVALID_TASK The space is null.
1554 * KERN_INVALID_TASK The space is dead.
1555 * KERN_INVALID_VALUE Bad id value.
1556 * KERN_INVALID_NAME Name doesn't denote a right.
1557 * KERN_INVALID_RIGHT Name doesn't denote appropriate right.
1558 * KERN_INVALID_CAPABILITY The notify port is dead.
1559 * MACH_NOTIFY_PORT_DESTROYED:
1560 * KERN_INVALID_VALUE Sync isn't zero.
1561 * KERN_FAILURE Re-registering for this notification
1562 * MACH_NOTIFY_DEAD_NAME:
1563 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1564 * KERN_INVALID_ARGUMENT Name denotes dead name, but
1565 * sync is zero or notify is IP_NULL.
1566 * KERN_UREFS_OVERFLOW Name denotes dead name, but
1567 * generating immediate notif. would overflow urefs.
1571 mach_port_request_notification(
1573 mach_port_name_t name
,
1575 mach_port_mscount_t sync
,
1577 ipc_port_t
*previousp
)
1581 if (space
== IS_NULL
) {
1582 return KERN_INVALID_TASK
;
1585 if (notify
== IP_DEAD
) {
1586 return KERN_INVALID_CAPABILITY
;
1591 * Requesting notifications on RPC ports is an error.
1597 kr
= ipc_right_lookup_write(space
, name
, &entry
);
1598 if (kr
!= KERN_SUCCESS
) {
1602 port
= ip_object_to_port(entry
->ie_object
);
1604 if (port
->ip_subsystem
!= NULL
) {
1605 is_write_unlock(space
);
1606 panic("mach_port_request_notification: on RPC port!!");
1607 return KERN_INVALID_CAPABILITY
;
1609 is_write_unlock(space
);
1615 case MACH_NOTIFY_PORT_DESTROYED
: {
1619 return KERN_INVALID_VALUE
;
1622 if (!MACH_PORT_VALID(name
)) {
1623 return KERN_INVALID_RIGHT
;
1626 kr
= ipc_port_translate_receive(space
, name
, &port
);
1627 if (kr
!= KERN_SUCCESS
) {
1630 /* port is locked and active */
1632 /* you cannot register for port death notifications on a kobject */
1633 if (ip_kotype(port
) != IKOT_NONE
) {
1635 return KERN_INVALID_RIGHT
;
1638 /* Allow only one registeration of this notification */
1639 if (port
->ip_pdrequest
!= IP_NULL
) {
1641 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_KERN_FAILURE
);
1642 return KERN_FAILURE
;
1645 ipc_port_pdrequest(port
, notify
, previousp
);
1646 /* port is unlocked */
1647 assert(*previousp
== IP_NULL
);
1651 case MACH_NOTIFY_NO_SENDERS
: {
1654 if (!MACH_PORT_VALID(name
)) {
1655 return KERN_INVALID_RIGHT
;
1658 kr
= ipc_port_translate_receive(space
, name
, &port
);
1659 if (kr
!= KERN_SUCCESS
) {
1662 /* port is locked and active */
1664 ipc_port_nsrequest(port
, sync
, notify
, previousp
);
1665 /* port is unlocked */
1669 case MACH_NOTIFY_SEND_POSSIBLE
:
1671 if (!MACH_PORT_VALID(name
)) {
1672 return KERN_INVALID_ARGUMENT
;
1675 kr
= ipc_right_request_alloc(space
, name
, sync
!= 0,
1676 TRUE
, notify
, previousp
);
1677 if (kr
!= KERN_SUCCESS
) {
1682 case MACH_NOTIFY_DEAD_NAME
:
1684 if (!MACH_PORT_VALID(name
)) {
1687 * Should do immediate delivery check -
1688 * will do that in the near future.
1690 return KERN_INVALID_ARGUMENT
;
1693 kr
= ipc_right_request_alloc(space
, name
, sync
!= 0,
1694 FALSE
, notify
, previousp
);
1695 if (kr
!= KERN_SUCCESS
) {
1701 return KERN_INVALID_VALUE
;
1704 return KERN_SUCCESS
;
1708 * Routine: mach_port_insert_right [kernel call]
1710 * Inserts a right into a space, as if the space
1711 * voluntarily received the right in a message,
1712 * except that the right gets the specified name.
1716 * KERN_SUCCESS Inserted the right.
1717 * KERN_INVALID_TASK The space is null.
1718 * KERN_INVALID_TASK The space is dead.
1719 * KERN_INVALID_VALUE The name isn't a legal name.
1720 * KERN_NAME_EXISTS The name already denotes a right.
1721 * KERN_INVALID_VALUE Message doesn't carry a port right.
1722 * KERN_INVALID_CAPABILITY Port is null or dead.
1723 * KERN_UREFS_OVERFLOW Urefs limit would be exceeded.
1724 * KERN_RIGHT_EXISTS Space has rights under another name.
1725 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1729 mach_port_insert_right(
1731 mach_port_name_t name
,
1733 mach_msg_type_name_t polyPoly
)
1735 if (space
== IS_NULL
) {
1736 return KERN_INVALID_TASK
;
1739 if (!MACH_PORT_VALID(name
) ||
1740 !MACH_MSG_TYPE_PORT_ANY_RIGHT(polyPoly
)) {
1741 return KERN_INVALID_VALUE
;
1744 if (!IP_VALID(poly
)) {
1745 return KERN_INVALID_CAPABILITY
;
1748 return ipc_object_copyout_name(space
, ip_to_object(poly
),
1753 * Routine: mach_port_extract_right [kernel call]
1755 * Extracts a right from a space, as if the space
1756 * voluntarily sent the right to the caller.
1760 * KERN_SUCCESS Extracted the right.
1761 * KERN_INVALID_TASK The space is null.
1762 * KERN_INVALID_TASK The space is dead.
1763 * KERN_INVALID_VALUE Requested type isn't a port right.
1764 * KERN_INVALID_NAME Name doesn't denote a right.
1765 * KERN_INVALID_RIGHT Name doesn't denote appropriate right.
1769 mach_port_extract_right(
1771 mach_port_name_t name
,
1772 mach_msg_type_name_t msgt_name
,
1774 mach_msg_type_name_t
*polyPoly
)
1778 if (space
== IS_NULL
) {
1779 return KERN_INVALID_TASK
;
1782 if (!MACH_MSG_TYPE_PORT_ANY(msgt_name
)) {
1783 return KERN_INVALID_VALUE
;
1786 if (!MACH_PORT_VALID(name
)) {
1788 * really should copy out a dead name, if it is a send or
1789 * send-once right being copied, but instead return an
1792 return KERN_INVALID_RIGHT
;
1795 kr
= ipc_object_copyin(space
, name
, msgt_name
, (ipc_object_t
*) poly
, 0, NULL
,
1796 IPC_KMSG_FLAGS_ALLOW_IMMOVABLE_SEND
);
1798 if (kr
== KERN_SUCCESS
) {
1799 *polyPoly
= ipc_object_copyin_type(msgt_name
);
1805 * Routine: mach_port_get_status_helper [helper]
1807 * Populates a mach_port_status_t structure with
1810 * Port needs to be locked
1815 mach_port_get_status_helper(
1817 mach_port_status_t
*statusp
)
1819 imq_lock(&port
->ip_messages
);
1820 /* don't leak set IDs, just indicate that the port is in one or not */
1821 statusp
->mps_pset
= !!(port
->ip_in_pset
);
1822 statusp
->mps_seqno
= port
->ip_messages
.imq_seqno
;
1823 statusp
->mps_qlimit
= port
->ip_messages
.imq_qlimit
;
1824 statusp
->mps_msgcount
= port
->ip_messages
.imq_msgcount
;
1825 imq_unlock(&port
->ip_messages
);
1827 statusp
->mps_mscount
= port
->ip_mscount
;
1828 statusp
->mps_sorights
= port
->ip_sorights
;
1829 statusp
->mps_srights
= port
->ip_srights
> 0;
1830 statusp
->mps_pdrequest
= port
->ip_pdrequest
!= IP_NULL
;
1831 statusp
->mps_nsrequest
= port
->ip_nsrequest
!= IP_NULL
;
1832 statusp
->mps_flags
= 0;
1833 if (port
->ip_impdonation
) {
1834 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_IMP_DONATION
;
1835 if (port
->ip_tempowner
) {
1836 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_TEMPOWNER
;
1837 if (IIT_NULL
!= port
->ip_imp_task
) {
1838 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_TASKPTR
;
1842 if (port
->ip_guarded
) {
1843 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_GUARDED
;
1844 if (port
->ip_strict_guard
) {
1845 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_STRICT_GUARD
;
1847 if (port
->ip_immovable_receive
) {
1848 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_GUARD_IMMOVABLE_RECEIVE
;
1851 if (port
->ip_no_grant
) {
1852 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_NO_GRANT
;
1860 mach_port_get_attributes(
1862 mach_port_name_t name
,
1864 mach_port_info_t info
,
1865 mach_msg_type_number_t
*count
)
1870 if (space
== IS_NULL
) {
1871 return KERN_INVALID_TASK
;
1875 case MACH_PORT_LIMITS_INFO
: {
1876 mach_port_limits_t
*lp
= (mach_port_limits_t
*)info
;
1878 if (*count
< MACH_PORT_LIMITS_INFO_COUNT
) {
1879 return KERN_FAILURE
;
1882 if (!MACH_PORT_VALID(name
)) {
1887 kr
= ipc_port_translate_receive(space
, name
, &port
);
1888 if (kr
!= KERN_SUCCESS
) {
1891 /* port is locked and active */
1893 lp
->mpl_qlimit
= port
->ip_messages
.imq_qlimit
;
1894 *count
= MACH_PORT_LIMITS_INFO_COUNT
;
1899 case MACH_PORT_RECEIVE_STATUS
: {
1900 mach_port_status_t
*statusp
= (mach_port_status_t
*)info
;
1902 if (*count
< MACH_PORT_RECEIVE_STATUS_COUNT
) {
1903 return KERN_FAILURE
;
1906 if (!MACH_PORT_VALID(name
)) {
1907 return KERN_INVALID_RIGHT
;
1910 kr
= ipc_port_translate_receive(space
, name
, &port
);
1911 if (kr
!= KERN_SUCCESS
) {
1914 /* port is locked and active */
1915 mach_port_get_status_helper(port
, statusp
);
1916 *count
= MACH_PORT_RECEIVE_STATUS_COUNT
;
1921 case MACH_PORT_DNREQUESTS_SIZE
: {
1922 ipc_port_request_t table
;
1924 if (*count
< MACH_PORT_DNREQUESTS_SIZE_COUNT
) {
1925 return KERN_FAILURE
;
1928 if (!MACH_PORT_VALID(name
)) {
1933 kr
= ipc_port_translate_receive(space
, name
, &port
);
1934 if (kr
!= KERN_SUCCESS
) {
1937 /* port is locked and active */
1939 table
= port
->ip_requests
;
1940 if (table
== IPR_NULL
) {
1943 *(int *)info
= table
->ipr_size
->its_size
;
1945 *count
= MACH_PORT_DNREQUESTS_SIZE_COUNT
;
1950 case MACH_PORT_INFO_EXT
: {
1951 mach_port_info_ext_t
*mp_info
= (mach_port_info_ext_t
*)info
;
1952 if (*count
< MACH_PORT_INFO_EXT_COUNT
) {
1953 return KERN_FAILURE
;
1956 if (!MACH_PORT_VALID(name
)) {
1957 return KERN_INVALID_RIGHT
;
1960 kr
= ipc_port_translate_receive(space
, name
, &port
);
1961 if (kr
!= KERN_SUCCESS
) {
1964 /* port is locked and active */
1965 mach_port_get_status_helper(port
, &mp_info
->mpie_status
);
1966 mp_info
->mpie_boost_cnt
= port
->ip_impcount
;
1967 *count
= MACH_PORT_INFO_EXT_COUNT
;
1973 return KERN_INVALID_ARGUMENT
;
1977 return KERN_SUCCESS
;
1981 mach_port_set_attributes(
1983 mach_port_name_t name
,
1985 mach_port_info_t info
,
1986 mach_msg_type_number_t count
)
1991 if (space
== IS_NULL
) {
1992 return KERN_INVALID_TASK
;
1996 case MACH_PORT_LIMITS_INFO
: {
1997 mach_port_limits_t
*mplp
= (mach_port_limits_t
*)info
;
1999 if (count
< MACH_PORT_LIMITS_INFO_COUNT
) {
2000 return KERN_FAILURE
;
2003 if (mplp
->mpl_qlimit
> MACH_PORT_QLIMIT_MAX
) {
2004 return KERN_INVALID_VALUE
;
2007 if (!MACH_PORT_VALID(name
)) {
2008 return KERN_INVALID_RIGHT
;
2011 kr
= ipc_port_translate_receive(space
, name
, &port
);
2012 if (kr
!= KERN_SUCCESS
) {
2015 /* port is locked and active */
2017 ipc_mqueue_set_qlimit(&port
->ip_messages
, mplp
->mpl_qlimit
);
2021 case MACH_PORT_DNREQUESTS_SIZE
: {
2022 if (count
< MACH_PORT_DNREQUESTS_SIZE_COUNT
) {
2023 return KERN_FAILURE
;
2026 if (!MACH_PORT_VALID(name
)) {
2027 return KERN_INVALID_RIGHT
;
2030 kr
= ipc_port_translate_receive(space
, name
, &port
);
2031 if (kr
!= KERN_SUCCESS
) {
2034 /* port is locked and active */
2036 kr
= ipc_port_request_grow(port
, *(int *)info
);
2037 if (kr
!= KERN_SUCCESS
) {
2042 case MACH_PORT_TEMPOWNER
:
2043 if (!MACH_PORT_VALID(name
)) {
2044 return KERN_INVALID_RIGHT
;
2047 ipc_importance_task_t release_imp_task
= IIT_NULL
;
2048 natural_t assertcnt
= 0;
2050 kr
= ipc_port_translate_receive(space
, name
, &port
);
2051 if (kr
!= KERN_SUCCESS
) {
2054 /* port is locked and active */
2057 * don't allow temp-owner importance donation if user
2058 * associated it with a kobject already (timer, host_notify target),
2059 * or is a special reply port.
2061 if (ip_is_kobject(port
) || port
->ip_specialreply
) {
2063 return KERN_INVALID_ARGUMENT
;
2066 if (port
->ip_tempowner
!= 0) {
2067 if (IIT_NULL
!= port
->ip_imp_task
) {
2068 release_imp_task
= port
->ip_imp_task
;
2069 port
->ip_imp_task
= IIT_NULL
;
2070 assertcnt
= port
->ip_impcount
;
2073 assertcnt
= port
->ip_impcount
;
2076 port
->ip_impdonation
= 1;
2077 port
->ip_tempowner
= 1;
2080 #if IMPORTANCE_INHERITANCE
2081 /* drop assertions from previous destination task */
2082 if (release_imp_task
!= IIT_NULL
) {
2083 assert(ipc_importance_task_is_any_receiver_type(release_imp_task
));
2084 if (assertcnt
> 0) {
2085 ipc_importance_task_drop_internal_assertion(release_imp_task
, assertcnt
);
2087 ipc_importance_task_release(release_imp_task
);
2088 } else if (assertcnt
> 0) {
2089 release_imp_task
= current_task()->task_imp_base
;
2090 if (release_imp_task
!= IIT_NULL
&&
2091 ipc_importance_task_is_any_receiver_type(release_imp_task
)) {
2092 ipc_importance_task_drop_internal_assertion(release_imp_task
, assertcnt
);
2096 if (release_imp_task
!= IIT_NULL
) {
2097 ipc_importance_task_release(release_imp_task
);
2099 #endif /* IMPORTANCE_INHERITANCE */
2103 #if IMPORTANCE_INHERITANCE
2104 case MACH_PORT_DENAP_RECEIVER
:
2105 case MACH_PORT_IMPORTANCE_RECEIVER
:
2106 if (!MACH_PORT_VALID(name
)) {
2107 return KERN_INVALID_RIGHT
;
2110 kr
= ipc_port_translate_receive(space
, name
, &port
);
2111 if (kr
!= KERN_SUCCESS
) {
2116 * don't allow importance donation if user associated
2117 * it with a kobject already (timer, host_notify target),
2118 * or is a special reply port.
2120 if (ip_is_kobject(port
) || port
->ip_specialreply
) {
2122 return KERN_INVALID_ARGUMENT
;
2125 /* port is locked and active */
2126 port
->ip_impdonation
= 1;
2130 #endif /* IMPORTANCE_INHERITANCE */
2133 return KERN_INVALID_ARGUMENT
;
2136 return KERN_SUCCESS
;
2140 * Routine: mach_port_insert_member [kernel call]
2142 * Add the receive right, specified by name, to
2144 * The port cannot already be a member of the set.
2148 * KERN_SUCCESS Moved the port.
2149 * KERN_INVALID_TASK The space is null.
2150 * KERN_INVALID_TASK The space is dead.
2151 * KERN_INVALID_NAME name didn't denote a right.
2152 * KERN_INVALID_RIGHT name didn't denote a receive right.
2153 * KERN_INVALID_NAME pset_name didn't denote a right.
2154 * KERN_INVALID_RIGHT pset_name didn't denote a portset right.
2155 * KERN_ALREADY_IN_SET name was already a member of pset.
2159 mach_port_insert_member(
2161 mach_port_name_t name
,
2162 mach_port_name_t psname
)
2167 uint64_t wq_link_id
;
2168 uint64_t wq_reserved_prepost
;
2170 if (space
== IS_NULL
) {
2171 return KERN_INVALID_TASK
;
2174 if (!MACH_PORT_VALID(name
) || !MACH_PORT_VALID(psname
)) {
2175 return KERN_INVALID_RIGHT
;
2178 wq_link_id
= waitq_link_reserve(NULL
);
2179 wq_reserved_prepost
= waitq_prepost_reserve(NULL
, 10,
2181 kr
= ipc_pset_lazy_allocate(space
, psname
);
2182 if (kr
!= KERN_SUCCESS
) {
2187 kr
= ipc_object_translate_two(space
,
2188 name
, MACH_PORT_RIGHT_RECEIVE
, &obj
,
2189 psname
, MACH_PORT_RIGHT_PORT_SET
, &psobj
);
2190 if (kr
!= KERN_SUCCESS
) {
2194 /* obj and psobj are locked (and were locked in that order) */
2195 assert(psobj
!= IO_NULL
);
2196 assert(obj
!= IO_NULL
);
2198 kr
= ipc_pset_add(ips_object_to_pset(psobj
), ip_object_to_port(obj
),
2199 &wq_link_id
, &wq_reserved_prepost
);
2205 /* on success, wq_link_id is reset to 0, so this is always safe */
2206 waitq_link_release(wq_link_id
);
2207 waitq_prepost_release_reserve(wq_reserved_prepost
);
2213 * Routine: mach_port_extract_member [kernel call]
2215 * Remove a port from one portset that it is a member of.
2219 * KERN_SUCCESS Moved the port.
2220 * KERN_INVALID_TASK The space is null.
2221 * KERN_INVALID_TASK The space is dead.
2222 * KERN_INVALID_NAME Member didn't denote a right.
2223 * KERN_INVALID_RIGHT Member didn't denote a receive right.
2224 * KERN_INVALID_NAME After didn't denote a right.
2225 * KERN_INVALID_RIGHT After didn't denote a port set right.
2227 * After is MACH_PORT_NULL and Member isn't in a port set.
2231 mach_port_extract_member(
2233 mach_port_name_t name
,
2234 mach_port_name_t psname
)
2240 if (space
== IS_NULL
) {
2241 return KERN_INVALID_TASK
;
2244 if (!MACH_PORT_VALID(name
) || !MACH_PORT_VALID(psname
)) {
2245 return KERN_INVALID_RIGHT
;
2248 kr
= ipc_object_translate_two(space
,
2249 name
, MACH_PORT_RIGHT_RECEIVE
, &obj
,
2250 psname
, MACH_PORT_RIGHT_PORT_SET
, &psobj
);
2251 if (kr
!= KERN_SUCCESS
) {
2255 /* obj and psobj are both locked (and were locked in that order) */
2256 assert(psobj
!= IO_NULL
);
2257 assert(obj
!= IO_NULL
);
2259 kr
= ipc_pset_remove(ips_object_to_pset(psobj
), ip_object_to_port(obj
));
2268 * task_set_port_space:
2270 * Set port name space of task to specified size.
2273 task_set_port_space(
2279 if (space
== IS_NULL
) {
2280 return KERN_INVALID_TASK
;
2283 is_write_lock(space
);
2285 if (!is_active(space
)) {
2286 is_write_unlock(space
);
2287 return KERN_INVALID_TASK
;
2290 kr
= ipc_entry_grow_table(space
, table_entries
);
2291 if (kr
== KERN_SUCCESS
) {
2292 is_write_unlock(space
);
2298 * Routine: mach_port_guard_locked [helper routine]
2300 * Sets a new guard for a locked port.
2304 * KERN_SUCCESS Port Guarded.
2305 * KERN_INVALID_ARGUMENT Port already contains a context/guard.
2307 static kern_return_t
2308 mach_port_guard_locked(
2313 if (port
->ip_context
) {
2314 return KERN_INVALID_ARGUMENT
;
2317 int strict
= (flags
& MPG_STRICT
)? 1 : 0;
2318 int immovable_receive
= (flags
& MPG_IMMOVABLE_RECEIVE
)? 1 : 0;
2320 imq_lock(&port
->ip_messages
);
2321 port
->ip_context
= guard
;
2322 port
->ip_guarded
= 1;
2323 port
->ip_strict_guard
= strict
;
2324 /* ip_immovable_receive bit is sticky and can't be un-guarded */
2325 if (!port
->ip_immovable_receive
) {
2326 port
->ip_immovable_receive
= immovable_receive
;
2328 imq_unlock(&port
->ip_messages
);
2330 return KERN_SUCCESS
;
2334 * Routine: mach_port_unguard_locked [helper routine]
2336 * Removes guard for a locked port.
2340 * KERN_SUCCESS Port Unguarded.
2341 * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch.
2342 * This also raises a EXC_GUARD exception.
2344 static kern_return_t
2345 mach_port_unguard_locked(
2347 mach_port_name_t name
,
2350 /* Port locked and active */
2351 if (!port
->ip_guarded
) {
2352 /* Port already unguarded; Raise exception */
2353 mach_port_guard_exception(name
, guard
, 0, kGUARD_EXC_UNGUARDED
);
2354 return KERN_INVALID_ARGUMENT
;
2357 if (port
->ip_context
!= guard
) {
2358 /* Incorrect guard; Raise exception */
2359 mach_port_guard_exception(name
, guard
, port
->ip_context
, kGUARD_EXC_INCORRECT_GUARD
);
2360 return KERN_INVALID_ARGUMENT
;
2363 imq_lock(&port
->ip_messages
);
2364 port
->ip_context
= 0;
2365 port
->ip_guarded
= port
->ip_strict_guard
= 0;
2366 /* Don't clear the ip_immovable_receive bit */
2367 imq_unlock(&port
->ip_messages
);
2369 return KERN_SUCCESS
;
2374 * Routine: mach_port_guard_exception [helper routine]
2376 * Marks the thread with AST_GUARD for mach port guard violation.
2377 * Also saves exception info in thread structure.
2381 * KERN_FAILURE Thread marked with AST_GUARD.
2384 mach_port_guard_exception(
2385 mach_port_name_t name
,
2386 __unused
uint64_t inguard
,
2390 mach_exception_code_t code
= 0;
2391 EXC_GUARD_ENCODE_TYPE(code
, GUARD_TYPE_MACH_PORT
);
2392 EXC_GUARD_ENCODE_FLAVOR(code
, reason
);
2393 EXC_GUARD_ENCODE_TARGET(code
, name
);
2394 mach_exception_subcode_t subcode
= (uint64_t)portguard
;
2395 thread_t t
= current_thread();
2396 boolean_t fatal
= FALSE
;
2397 if (t
->task
->task_exc_guard
& TASK_EXC_GUARD_MP_FATAL
) {
2399 } else if (reason
<= MAX_FATAL_kGUARD_EXC_CODE
) {
2402 thread_guard_violation(t
, code
, subcode
, fatal
);
2407 * Routine: mach_port_guard_ast
2409 * Raises an exception for mach port guard violation.
2417 mach_port_guard_ast(thread_t t
,
2418 mach_exception_data_type_t code
, mach_exception_data_type_t subcode
)
2420 unsigned int reason
= EXC_GUARD_DECODE_GUARD_FLAVOR(code
);
2421 task_t task
= t
->task
;
2422 unsigned int behavior
= task
->task_exc_guard
;
2423 assert(task
== current_task());
2424 assert(task
!= kernel_task
);
2428 * Fatal Mach port guards - always delivered synchronously
2430 case kGUARD_EXC_DESTROY
:
2431 case kGUARD_EXC_MOD_REFS
:
2432 case kGUARD_EXC_SET_CONTEXT
:
2433 case kGUARD_EXC_UNGUARDED
:
2434 case kGUARD_EXC_INCORRECT_GUARD
:
2435 case kGUARD_EXC_IMMOVABLE
:
2436 case kGUARD_EXC_STRICT_REPLY
:
2437 task_exception_notify(EXC_GUARD
, code
, subcode
);
2438 task_bsdtask_kill(task
);
2443 * Mach port guards controlled by task settings.
2446 /* Is delivery enabled */
2447 if ((behavior
& TASK_EXC_GUARD_MP_DELIVER
) == 0) {
2451 /* If only once, make sure we're that once */
2452 while (behavior
& TASK_EXC_GUARD_MP_ONCE
) {
2453 uint32_t new_behavior
= behavior
& ~TASK_EXC_GUARD_MP_DELIVER
;
2455 if (OSCompareAndSwap(behavior
, new_behavior
, &task
->task_exc_guard
)) {
2458 behavior
= task
->task_exc_guard
;
2459 if ((behavior
& TASK_EXC_GUARD_MP_DELIVER
) == 0) {
2464 /* Raise exception via corpse fork or synchronously */
2465 if ((task
->task_exc_guard
& TASK_EXC_GUARD_MP_CORPSE
) &&
2466 (task
->task_exc_guard
& TASK_EXC_GUARD_MP_FATAL
) == 0) {
2467 task_violated_guard(code
, subcode
, NULL
);
2469 task_exception_notify(EXC_GUARD
, code
, subcode
);
2472 /* Terminate the task if desired */
2473 if (task
->task_exc_guard
& TASK_EXC_GUARD_MP_FATAL
) {
2474 task_bsdtask_kill(task
);
2481 * Routine: mach_port_construct [kernel call]
2483 * Constructs a mach port with the provided set of options.
2487 * KERN_SUCCESS The right is allocated.
2488 * KERN_INVALID_TASK The space is null.
2489 * KERN_INVALID_TASK The space is dead.
2490 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
2491 * KERN_NO_SPACE No room in space for another right.
2492 * KERN_FAILURE Illegal option values requested.
2496 mach_port_construct(
2498 mach_port_options_t
*options
,
2500 mach_port_name_t
*name
)
2504 ipc_port_init_flags_t init_flags
= IPC_PORT_INIT_MESSAGE_QUEUE
;
2506 if (space
== IS_NULL
) {
2507 return KERN_INVALID_TASK
;
2510 if (options
->flags
& MPO_INSERT_SEND_RIGHT
) {
2511 init_flags
|= IPC_PORT_INIT_MAKE_SEND_RIGHT
;
2514 /* Allocate a new port in the IPC space */
2515 kr
= ipc_port_alloc(space
, init_flags
, name
, &port
);
2516 if (kr
!= KERN_SUCCESS
) {
2520 /* Port locked and active */
2521 if (options
->flags
& MPO_CONTEXT_AS_GUARD
) {
2523 if (options
->flags
& MPO_STRICT
) {
2524 flags
|= MPG_STRICT
;
2526 if (options
->flags
& MPO_IMMOVABLE_RECEIVE
) {
2527 flags
|= MPG_IMMOVABLE_RECEIVE
;
2529 kr
= mach_port_guard_locked(port
, (uint64_t) context
, flags
);
2530 /* A newly allocated and locked port should always be guarded successfully */
2531 assert(kr
== KERN_SUCCESS
);
2533 port
->ip_context
= context
;
2539 /* Set port attributes as requested */
2541 if (options
->flags
& MPO_QLIMIT
) {
2542 kr
= mach_port_set_attributes(space
, *name
, MACH_PORT_LIMITS_INFO
,
2543 (mach_port_info_t
)&options
->mpl
, sizeof(options
->mpl
) / sizeof(int));
2544 if (kr
!= KERN_SUCCESS
) {
2549 if (options
->flags
& MPO_TEMPOWNER
) {
2550 kr
= mach_port_set_attributes(space
, *name
, MACH_PORT_TEMPOWNER
, NULL
, 0);
2551 if (kr
!= KERN_SUCCESS
) {
2556 if (options
->flags
& MPO_IMPORTANCE_RECEIVER
) {
2557 kr
= mach_port_set_attributes(space
, *name
, MACH_PORT_IMPORTANCE_RECEIVER
, NULL
, 0);
2558 if (kr
!= KERN_SUCCESS
) {
2563 if (options
->flags
& MPO_DENAP_RECEIVER
) {
2564 kr
= mach_port_set_attributes(space
, *name
, MACH_PORT_DENAP_RECEIVER
, NULL
, 0);
2565 if (kr
!= KERN_SUCCESS
) {
2570 return KERN_SUCCESS
;
2573 /* Attempt to destroy port. If its already destroyed by some other thread, we're done */
2574 (void) mach_port_destruct(space
, *name
,
2575 (options
->flags
& MPO_INSERT_SEND_RIGHT
) ? -1 : 0, context
);
2580 * Routine: mach_port_destruct [kernel call]
2582 * Destroys a mach port with appropriate guard
2586 * KERN_SUCCESS The name is destroyed.
2587 * KERN_INVALID_TASK The space is null.
2588 * KERN_INVALID_TASK The space is dead.
2589 * KERN_INVALID_NAME The name doesn't denote a right.
2590 * KERN_INVALID_RIGHT The right isn't correct.
2591 * KERN_INVALID_VALUE The delta for send right is incorrect.
2592 * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch.
2593 * This also raises a EXC_GUARD exception.
2599 mach_port_name_t name
,
2600 mach_port_delta_t srdelta
,
2606 if (space
== IS_NULL
) {
2607 return KERN_INVALID_TASK
;
2610 if (!MACH_PORT_VALID(name
)) {
2611 return KERN_INVALID_NAME
;
2614 /* Remove reference for receive right */
2615 kr
= ipc_right_lookup_write(space
, name
, &entry
);
2616 if (kr
!= KERN_SUCCESS
) {
2617 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_INVALID_NAME
);
2620 /* space is write-locked and active */
2621 kr
= ipc_right_destruct(space
, name
, entry
, srdelta
, guard
); /* unlocks */
2627 * Routine: mach_port_guard [kernel call]
2629 * Guard a mach port with specified guard value.
2630 * The context field of the port is used as the guard.
2634 * KERN_SUCCESS The name is destroyed.
2635 * KERN_INVALID_TASK The space is null.
2636 * KERN_INVALID_TASK The space is dead.
2637 * KERN_INVALID_NAME The name doesn't denote a right.
2638 * KERN_INVALID_RIGHT The right isn't correct.
2639 * KERN_INVALID_ARGUMENT Port already contains a context/guard.
2644 mach_port_name_t name
,
2652 if (space
== IS_NULL
) {
2653 return KERN_INVALID_TASK
;
2656 if (!MACH_PORT_VALID(name
)) {
2657 return KERN_INVALID_NAME
;
2660 /* Guard can be applied only to receive rights */
2661 kr
= ipc_port_translate_receive(space
, name
, &port
);
2662 if (kr
!= KERN_SUCCESS
) {
2663 mach_port_guard_exception(name
, 0, 0,
2664 ((KERN_INVALID_NAME
== kr
) ?
2665 kGUARD_EXC_INVALID_NAME
:
2666 kGUARD_EXC_INVALID_RIGHT
));
2670 /* Port locked and active */
2675 kr
= mach_port_guard_locked(port
, guard
, flags
);
2678 if (KERN_INVALID_ARGUMENT
== kr
) {
2679 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_INVALID_ARGUMENT
);
2686 * Routine: mach_port_unguard [kernel call]
2688 * Unguard a mach port with specified guard value.
2692 * KERN_SUCCESS The name is destroyed.
2693 * KERN_INVALID_TASK The space is null.
2694 * KERN_INVALID_TASK The space is dead.
2695 * KERN_INVALID_NAME The name doesn't denote a right.
2696 * KERN_INVALID_RIGHT The right isn't correct.
2697 * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch.
2698 * This also raises a EXC_GUARD exception.
2703 mach_port_name_t name
,
2709 if (space
== IS_NULL
) {
2710 return KERN_INVALID_TASK
;
2713 if (!MACH_PORT_VALID(name
)) {
2714 return KERN_INVALID_NAME
;
2717 kr
= ipc_port_translate_receive(space
, name
, &port
);
2718 if (kr
!= KERN_SUCCESS
) {
2719 mach_port_guard_exception(name
, 0, 0,
2720 ((KERN_INVALID_NAME
== kr
) ?
2721 kGUARD_EXC_INVALID_NAME
:
2722 kGUARD_EXC_INVALID_RIGHT
));
2726 /* Port locked and active */
2727 kr
= mach_port_unguard_locked(port
, name
, guard
);
2734 * Routine: mach_port_guard_with_flags [kernel call]
2736 * Guard a mach port with specified guard value and guard flags.
2737 * The context field of the port is used as the guard.
2739 * Should hold receive right for that port
2741 * KERN_SUCCESS The name is destroyed.
2742 * KERN_INVALID_TASK The space is null.
2743 * KERN_INVALID_TASK The space is dead.
2744 * KERN_INVALID_NAME The name doesn't denote a right.
2745 * KERN_INVALID_RIGHT The right isn't correct.
2746 * KERN_INVALID_ARGUMENT Port already contains a context/guard.
2747 * KERN_INVALID_CAPABILITY Cannot set MPG_IMMOVABLE_RECEIVE flag for a port with
2748 * a movable port-destroyed notification port
2751 mach_port_guard_with_flags(
2753 mach_port_name_t name
,
2760 if (space
== IS_NULL
) {
2761 return KERN_INVALID_TASK
;
2764 if (!MACH_PORT_VALID(name
)) {
2765 return KERN_INVALID_NAME
;
2768 kr
= ipc_port_translate_receive(space
, name
, &port
);
2769 if (kr
!= KERN_SUCCESS
) {
2770 mach_port_guard_exception(name
, 0, 0,
2771 ((KERN_INVALID_NAME
== kr
) ?
2772 kGUARD_EXC_INVALID_NAME
:
2773 kGUARD_EXC_INVALID_RIGHT
));
2777 /* Port locked and active */
2778 kr
= mach_port_guard_locked(port
, guard
, flags
);
2781 if (KERN_INVALID_ARGUMENT
== kr
) {
2782 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_INVALID_ARGUMENT
);
2789 * Routine: mach_port_swap_guard [kernel call]
2793 * Port should already be guarded.
2795 * KERN_SUCCESS The name is destroyed.
2796 * KERN_INVALID_TASK The space is null.
2797 * KERN_INVALID_TASK The space is dead.
2798 * KERN_INVALID_NAME The name doesn't denote a right.
2799 * KERN_INVALID_RIGHT The right isn't correct.
2800 * KERN_INVALID_ARGUMENT Port doesn't contain a guard; is strictly guarded
2801 * or the old_guard doesnt match the context
2804 mach_port_swap_guard(
2806 mach_port_name_t name
,
2813 if (space
== IS_NULL
) {
2814 return KERN_INVALID_TASK
;
2817 if (!MACH_PORT_VALID(name
)) {
2818 return KERN_INVALID_NAME
;
2821 kr
= ipc_port_translate_receive(space
, name
, &port
);
2822 if (kr
!= KERN_SUCCESS
) {
2823 mach_port_guard_exception(name
, 0, 0,
2824 ((KERN_INVALID_NAME
== kr
) ?
2825 kGUARD_EXC_INVALID_NAME
:
2826 kGUARD_EXC_INVALID_RIGHT
));
2830 /* Port locked and active */
2831 if (!port
->ip_guarded
) {
2833 mach_port_guard_exception(name
, old_guard
, 0, kGUARD_EXC_UNGUARDED
);
2834 return KERN_INVALID_ARGUMENT
;
2837 if (port
->ip_strict_guard
) {
2838 uint64_t portguard
= port
->ip_context
;
2840 /* For strictly guarded ports, disallow overwriting context; Raise Exception */
2841 mach_port_guard_exception(name
, old_guard
, portguard
, kGUARD_EXC_SET_CONTEXT
);
2842 return KERN_INVALID_ARGUMENT
;
2845 if (port
->ip_context
!= old_guard
) {
2846 uint64_t portguard
= port
->ip_context
;
2848 mach_port_guard_exception(name
, old_guard
, portguard
, kGUARD_EXC_INCORRECT_GUARD
);
2849 return KERN_INVALID_ARGUMENT
;
2852 imq_lock(&port
->ip_messages
);
2853 port
->ip_context
= new_guard
;
2854 imq_unlock(&port
->ip_messages
);
2858 return KERN_SUCCESS
;