2 * Copyright (c) 2000-2020 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/thread.h>
84 #include <kern/exc_guard.h>
85 #include <mach/mach_port_server.h>
86 #include <vm/vm_map.h>
87 #include <vm/vm_kern.h>
89 #include <ipc/ipc_entry.h>
90 #include <ipc/ipc_space.h>
91 #include <ipc/ipc_object.h>
92 #include <ipc/ipc_notify.h>
93 #include <ipc/ipc_port.h>
94 #include <ipc/ipc_pset.h>
95 #include <ipc/ipc_right.h>
96 #include <ipc/ipc_kmsg.h>
97 #include <kern/misc_protos.h>
98 #include <security/mac_mach_internal.h>
99 #include <kern/work_interval.h>
100 #include <kern/policy_internal.h>
102 #if IMPORTANCE_INHERITANCE
103 #include <ipc/ipc_importance.h>
106 kern_return_t
mach_port_get_attributes(ipc_space_t space
, mach_port_name_t name
,
107 int flavor
, mach_port_info_t info
, mach_msg_type_number_t
*count
);
108 kern_return_t
mach_port_get_context(ipc_space_t space
, mach_port_name_t name
,
109 mach_vm_address_t
*context
);
110 kern_return_t
mach_port_get_set_status(ipc_space_t space
, mach_port_name_t name
,
111 mach_port_name_t
**members
, mach_msg_type_number_t
*membersCnt
);
113 /* Zeroed template of qos flags */
115 static mach_port_qos_t qos_template
;
118 * Routine: mach_port_names_helper
120 * A helper function for mach_port_names.
123 * Space containing entry is [at least] read-locked.
126 mach_port_names_helper(
127 ipc_port_timestamp_t timestamp
,
129 mach_port_name_t name
,
130 mach_port_name_t
*names
,
131 mach_port_type_t
*types
,
132 ipc_entry_num_t
*actualp
)
134 ipc_entry_bits_t bits
;
135 ipc_port_request_index_t request
;
136 mach_port_type_t type
= 0;
137 ipc_entry_num_t actual
;
140 bits
= entry
->ie_bits
;
141 request
= entry
->ie_request
;
142 port
= ip_object_to_port(entry
->ie_object
);
144 if (bits
& MACH_PORT_TYPE_RECEIVE
) {
145 assert(IP_VALID(port
));
147 if (request
!= IE_REQ_NONE
) {
149 require_ip_active(port
);
150 type
|= ipc_port_request_type(port
, name
, request
);
153 } else if (bits
& MACH_PORT_TYPE_SEND_RIGHTS
) {
154 mach_port_type_t reqtype
;
156 assert(IP_VALID(port
));
159 reqtype
= (request
!= IE_REQ_NONE
) ?
160 ipc_port_request_type(port
, name
, request
) : 0;
163 * If the port is alive, or was alive when the mach_port_names
164 * started, then return that fact. Otherwise, pretend we found
167 if (ip_active(port
) || IP_TIMESTAMP_ORDER(timestamp
, port
->ip_timestamp
)) {
170 bits
&= ~(IE_BITS_TYPE_MASK
);
171 bits
|= MACH_PORT_TYPE_DEAD_NAME
;
172 /* account for additional reference for dead-name notification */
180 type
|= IE_BITS_TYPE(bits
);
183 names
[actual
] = name
;
184 types
[actual
] = type
;
185 *actualp
= actual
+ 1;
189 * Routine: mach_port_names [kernel call]
191 * Retrieves a list of the rights present in the space,
192 * along with type information. (Same as returned
193 * by mach_port_type.) The names are returned in
194 * no particular order, but they (and the type info)
195 * are an accurate snapshot of the space.
199 * KERN_SUCCESS Arrays of names and types returned.
200 * KERN_INVALID_TASK The space is null.
201 * KERN_INVALID_TASK The space is dead.
202 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
208 mach_port_name_t
**namesp
,
209 mach_msg_type_number_t
*namesCnt
,
210 mach_port_type_t
**typesp
,
211 mach_msg_type_number_t
*typesCnt
)
214 ipc_entry_num_t tsize
;
215 mach_port_index_t index
;
216 ipc_entry_num_t actual
; /* this many names */
217 ipc_port_timestamp_t timestamp
; /* logical time of this operation */
218 mach_port_name_t
*names
;
219 mach_port_type_t
*types
;
222 vm_size_t size
; /* size of allocated memory */
223 vm_offset_t addr1
; /* allocated memory, for names */
224 vm_offset_t addr2
; /* allocated memory, for types */
225 vm_map_copy_t memory1
; /* copied-in memory, for names */
226 vm_map_copy_t memory2
; /* copied-in memory, for types */
228 /* safe simplifying assumption */
229 static_assert(sizeof(mach_port_name_t
) == sizeof(mach_port_type_t
));
231 if (space
== IS_NULL
) {
232 return KERN_INVALID_TASK
;
238 ipc_entry_num_t bound
;
239 vm_size_t size_needed
;
242 if (!is_active(space
)) {
243 is_read_unlock(space
);
245 kmem_free(ipc_kernel_map
, addr1
, size
);
246 kmem_free(ipc_kernel_map
, addr2
, size
);
248 return KERN_INVALID_TASK
;
251 /* upper bound on number of names in the space */
252 bound
= space
->is_table_size
;
253 size_needed
= vm_map_round_page(
254 (bound
* sizeof(mach_port_name_t
)),
255 VM_MAP_PAGE_MASK(ipc_kernel_map
));
257 if (size_needed
<= size
) {
261 is_read_unlock(space
);
264 kmem_free(ipc_kernel_map
, addr1
, size
);
265 kmem_free(ipc_kernel_map
, addr2
, size
);
269 kr
= vm_allocate_kernel(ipc_kernel_map
, &addr1
, size
, VM_FLAGS_ANYWHERE
, VM_KERN_MEMORY_IPC
);
270 if (kr
!= KERN_SUCCESS
) {
271 return KERN_RESOURCE_SHORTAGE
;
274 kr
= vm_allocate_kernel(ipc_kernel_map
, &addr2
, size
, VM_FLAGS_ANYWHERE
, VM_KERN_MEMORY_IPC
);
275 if (kr
!= KERN_SUCCESS
) {
276 kmem_free(ipc_kernel_map
, addr1
, size
);
277 return KERN_RESOURCE_SHORTAGE
;
280 /* can't fault while we hold locks */
282 kr
= vm_map_wire_kernel(
284 vm_map_trunc_page(addr1
,
285 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
286 vm_map_round_page(addr1
+ size
,
287 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
288 VM_PROT_READ
| VM_PROT_WRITE
, VM_KERN_MEMORY_IPC
,
290 if (kr
!= KERN_SUCCESS
) {
291 kmem_free(ipc_kernel_map
, addr1
, size
);
292 kmem_free(ipc_kernel_map
, addr2
, size
);
293 return KERN_RESOURCE_SHORTAGE
;
296 kr
= vm_map_wire_kernel(
298 vm_map_trunc_page(addr2
,
299 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
300 vm_map_round_page(addr2
+ size
,
301 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
302 VM_PROT_READ
| VM_PROT_WRITE
,
305 if (kr
!= KERN_SUCCESS
) {
306 kmem_free(ipc_kernel_map
, addr1
, size
);
307 kmem_free(ipc_kernel_map
, addr2
, size
);
308 return KERN_RESOURCE_SHORTAGE
;
311 /* space is read-locked and active */
313 names
= (mach_port_name_t
*) addr1
;
314 types
= (mach_port_type_t
*) addr2
;
317 timestamp
= ipc_port_timestamp();
319 table
= space
->is_table
;
320 tsize
= space
->is_table_size
;
322 for (index
= 0; index
< tsize
; index
++) {
323 ipc_entry_t entry
= &table
[index
];
324 ipc_entry_bits_t bits
= entry
->ie_bits
;
326 if (IE_BITS_TYPE(bits
) != MACH_PORT_TYPE_NONE
) {
327 mach_port_name_t name
;
329 name
= MACH_PORT_MAKE(index
, IE_BITS_GEN(bits
));
330 mach_port_names_helper(timestamp
, entry
, name
, names
,
335 is_read_unlock(space
);
338 memory1
= VM_MAP_COPY_NULL
;
339 memory2
= VM_MAP_COPY_NULL
;
342 kmem_free(ipc_kernel_map
, addr1
, size
);
343 kmem_free(ipc_kernel_map
, addr2
, size
);
347 vm_size_t vm_size_used
;
349 size_used
= actual
* sizeof(mach_port_name_t
);
351 vm_map_round_page(size_used
,
352 VM_MAP_PAGE_MASK(ipc_kernel_map
));
355 * Make used memory pageable and get it into
356 * copied-in form. Free any unused memory.
361 vm_map_trunc_page(addr1
,
362 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
363 vm_map_round_page(addr1
+ vm_size_used
,
364 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
366 assert(kr
== KERN_SUCCESS
);
370 vm_map_trunc_page(addr2
,
371 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
372 vm_map_round_page(addr2
+ vm_size_used
,
373 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
375 assert(kr
== KERN_SUCCESS
);
377 kr
= vm_map_copyin(ipc_kernel_map
, (vm_map_address_t
)addr1
,
378 (vm_map_size_t
)size_used
, TRUE
, &memory1
);
379 assert(kr
== KERN_SUCCESS
);
381 kr
= vm_map_copyin(ipc_kernel_map
, (vm_map_address_t
)addr2
,
382 (vm_map_size_t
)size_used
, TRUE
, &memory2
);
383 assert(kr
== KERN_SUCCESS
);
385 if (vm_size_used
!= size
) {
386 kmem_free(ipc_kernel_map
,
387 addr1
+ vm_size_used
, size
- vm_size_used
);
388 kmem_free(ipc_kernel_map
,
389 addr2
+ vm_size_used
, size
- vm_size_used
);
393 *namesp
= (mach_port_name_t
*) memory1
;
395 *typesp
= (mach_port_type_t
*) memory2
;
401 * Routine: mach_port_type [kernel call]
403 * Retrieves the type of a right in the space.
404 * The type is a bitwise combination of one or more
405 * of the following type bits:
406 * MACH_PORT_TYPE_SEND
407 * MACH_PORT_TYPE_RECEIVE
408 * MACH_PORT_TYPE_SEND_ONCE
409 * MACH_PORT_TYPE_PORT_SET
410 * MACH_PORT_TYPE_DEAD_NAME
411 * In addition, the following pseudo-type bits may be present:
412 * MACH_PORT_TYPE_DNREQUEST
413 * A dead-name notification is requested.
417 * KERN_SUCCESS Type is returned.
418 * KERN_INVALID_TASK The space is null.
419 * KERN_INVALID_TASK The space is dead.
420 * KERN_INVALID_NAME The name doesn't denote a right.
426 mach_port_name_t name
,
427 mach_port_type_t
*typep
)
429 mach_port_urefs_t urefs
;
433 if (space
== IS_NULL
) {
434 return KERN_INVALID_TASK
;
437 if (name
== MACH_PORT_NULL
) {
438 return KERN_INVALID_NAME
;
441 if (name
== MACH_PORT_DEAD
) {
442 *typep
= MACH_PORT_TYPE_DEAD_NAME
;
446 kr
= ipc_right_lookup_write(space
, name
, &entry
);
447 if (kr
!= KERN_SUCCESS
) {
451 /* space is write-locked and active */
452 kr
= ipc_right_info(space
, name
, entry
, typep
, &urefs
);
453 /* space is unlocked */
456 /* JMM - workaround rdar://problem/9121297 (CF being too picky on these bits). */
457 *typep
&= ~(MACH_PORT_TYPE_SPREQUEST
| MACH_PORT_TYPE_SPREQUEST_DELAYED
);
464 * Routine: mach_port_rename [kernel call]
466 * Changes the name denoting a right,
467 * from oname to nname.
471 * KERN_SUCCESS The right is renamed.
472 * KERN_INVALID_TASK The space is null.
473 * KERN_INVALID_TASK The space is dead.
474 * KERN_INVALID_NAME The oname doesn't denote a right.
475 * KERN_INVALID_VALUE The nname isn't a legal name.
476 * KERN_NAME_EXISTS The nname already denotes a right.
477 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
479 * This interface is obsolete and always returns
480 * KERN_NOT_SUPPORTED.
485 __unused ipc_space_t space
,
486 __unused mach_port_name_t oname
,
487 __unused mach_port_name_t nname
)
489 return KERN_NOT_SUPPORTED
;
494 * Routine: mach_port_allocate_name [kernel call]
496 * Allocates a right in a space, using a specific name
497 * for the new right. Possible rights:
498 * MACH_PORT_RIGHT_RECEIVE
499 * MACH_PORT_RIGHT_PORT_SET
500 * MACH_PORT_RIGHT_DEAD_NAME
502 * A new port (allocated with MACH_PORT_RIGHT_RECEIVE)
503 * has no extant send or send-once rights and no queued
504 * messages. Its queue limit is MACH_PORT_QLIMIT_DEFAULT
505 * and its make-send count is 0. It is not a member of
506 * a port set. It has no registered no-senders or
507 * port-destroyed notification requests.
509 * A new port set has no members.
511 * A new dead name has one user reference.
515 * KERN_SUCCESS The right is allocated.
516 * KERN_INVALID_TASK The space is null.
517 * KERN_INVALID_TASK The space is dead.
518 * KERN_INVALID_VALUE The name isn't a legal name.
519 * KERN_INVALID_VALUE "right" isn't a legal kind of right.
520 * KERN_NAME_EXISTS The name already denotes a right.
521 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
523 * Restrictions on name allocation: NT bits are reserved by kernel,
524 * must be set on any chosen name. Can't do this at all in kernel
529 mach_port_allocate_name(
531 mach_port_right_t right
,
532 mach_port_name_t name
)
535 mach_port_qos_t qos
= qos_template
;
539 if (!MACH_PORT_VALID(name
)) {
540 return KERN_INVALID_VALUE
;
543 kr
= mach_port_allocate_full(space
, right
, MACH_PORT_NULL
,
549 * Routine: mach_port_allocate [kernel call]
551 * Allocates a right in a space. Like mach_port_allocate_name,
552 * except that the implementation picks a name for the right.
553 * The name may be any legal name in the space that doesn't
554 * currently denote a right.
558 * KERN_SUCCESS The right is allocated.
559 * KERN_INVALID_TASK The space is null.
560 * KERN_INVALID_TASK The space is dead.
561 * KERN_INVALID_VALUE "right" isn't a legal kind of right.
562 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
563 * KERN_NO_SPACE No room in space for another right.
569 mach_port_right_t right
,
570 mach_port_name_t
*namep
)
573 mach_port_qos_t qos
= qos_template
;
575 kr
= mach_port_allocate_full(space
, right
, MACH_PORT_NULL
,
581 * Routine: mach_port_allocate_qos [kernel call]
583 * Allocates a right, with qos options, in a space. Like
584 * mach_port_allocate_name, except that the implementation
585 * picks a name for the right. The name may be any legal name
586 * in the space that doesn't currently denote a right.
590 * KERN_SUCCESS The right is allocated.
591 * KERN_INVALID_TASK The space is null.
592 * KERN_INVALID_TASK The space is dead.
593 * KERN_INVALID_VALUE "right" isn't a legal kind of right.
594 * KERN_INVALID_ARGUMENT The qos request was invalid.
595 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
596 * KERN_NO_SPACE No room in space for another right.
600 mach_port_allocate_qos(
602 mach_port_right_t right
,
603 mach_port_qos_t
*qosp
,
604 mach_port_name_t
*namep
)
609 return KERN_INVALID_ARGUMENT
;
611 kr
= mach_port_allocate_full(space
, right
, MACH_PORT_NULL
,
617 * Routine: mach_port_allocate_full [kernel call]
619 * Allocates a right in a space. Supports the
620 * special case of specifying a name. The name may
621 * be any legal name in the space that doesn't
622 * currently denote a right.
624 * While we no longer support users requesting
625 * preallocated message for the port, we still
626 * check for errors in such requests and then
627 * just clear the request.
631 * KERN_SUCCESS The right is allocated.
632 * KERN_INVALID_TASK The space is null.
633 * KERN_INVALID_TASK The space is dead.
634 * KERN_INVALID_VALUE "right" isn't a legal kind of right.
635 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
636 * KERN_NO_SPACE No room in space for another right.
640 mach_port_allocate_full(
642 mach_port_right_t right
,
644 mach_port_qos_t
*qosp
,
645 mach_port_name_t
*namep
)
649 if (space
== IS_NULL
) {
650 return KERN_INVALID_TASK
;
653 if (proto
!= MACH_PORT_NULL
) {
654 return KERN_INVALID_VALUE
;
658 if (!MACH_PORT_VALID(*namep
)) {
659 return KERN_INVALID_VALUE
;
664 * Don't actually honor prealloc requests from user-space
665 * (for security reasons, and because it isn't guaranteed anyway).
666 * Keep old errors for legacy reasons.
668 if (qosp
->prealloc
) {
669 if (qosp
->len
> MACH_MSG_SIZE_MAX
- MAX_TRAILER_SIZE
) {
670 return KERN_RESOURCE_SHORTAGE
;
672 if (right
!= MACH_PORT_RIGHT_RECEIVE
) {
673 return KERN_INVALID_VALUE
;
678 kr
= mach_port_allocate_internal(space
, right
, qosp
, namep
);
684 * Routine: mach_port_allocate_internal [kernel private]
686 * Allocates a right in a space. Supports all of the
687 * special cases, a specific name, a real-time port, etc.
688 * The name may be any legal name in the space that doesn't
689 * currently denote a right.
693 * KERN_SUCCESS The right is allocated.
694 * KERN_INVALID_TASK The space is null.
695 * KERN_INVALID_TASK The space is dead.
696 * KERN_INVALID_VALUE "right" isn't a legal kind of right.
697 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
698 * KERN_NO_SPACE No room in space for another right.
701 mach_port_allocate_internal(
703 mach_port_right_t right
,
704 mach_port_qos_t
*qosp
,
705 mach_port_name_t
*namep
)
709 assert(space
!= IS_NULL
);
712 case MACH_PORT_RIGHT_RECEIVE
:
714 ipc_kmsg_t kmsg
= IKM_NULL
;
718 * For in-kernel uses, only allow small (from the kmsg zone)
719 * preallocated messages for the port.
721 if (qosp
->prealloc
) {
722 mach_msg_size_t size
= qosp
->len
;
724 if (size
> IKM_SAVED_MSG_SIZE
- MAX_TRAILER_SIZE
) {
725 panic("mach_port_allocate_internal: too large a prealloc kmsg");
727 kmsg
= (ipc_kmsg_t
)ipc_kmsg_prealloc(size
+ MAX_TRAILER_SIZE
);
728 if (kmsg
== IKM_NULL
) {
729 return KERN_RESOURCE_SHORTAGE
;
734 kr
= ipc_port_alloc_name(space
, IPC_PORT_INIT_MESSAGE_QUEUE
,
737 kr
= ipc_port_alloc(space
, IPC_PORT_INIT_MESSAGE_QUEUE
,
740 if (kr
== KERN_SUCCESS
) {
741 if (kmsg
!= IKM_NULL
) {
742 ipc_kmsg_set_prealloc(kmsg
, port
);
745 } else if (kmsg
!= IKM_NULL
) {
751 case MACH_PORT_RIGHT_PORT_SET
:
756 kr
= ipc_pset_alloc_name(space
, *namep
, &pset
);
758 kr
= ipc_pset_alloc(space
, namep
, &pset
);
760 if (kr
== KERN_SUCCESS
) {
766 case MACH_PORT_RIGHT_DEAD_NAME
:
767 kr
= ipc_object_alloc_dead(space
, namep
);
771 kr
= KERN_INVALID_VALUE
;
779 * Routine: mach_port_destroy [kernel call]
781 * Cleans up and destroys all rights denoted by a name
782 * in a space. The destruction of a receive right
783 * destroys the port, unless a port-destroyed request
784 * has been made for it; the destruction of a port-set right
785 * destroys the port set.
789 * KERN_SUCCESS The name is destroyed.
790 * KERN_INVALID_TASK The space is null.
791 * KERN_INVALID_TASK The space is dead.
792 * KERN_INVALID_NAME The name doesn't denote a right.
798 mach_port_name_t name
)
803 if (space
== IS_NULL
) {
804 return KERN_INVALID_TASK
;
807 if (!MACH_PORT_VALID(name
)) {
811 kr
= ipc_right_lookup_write(space
, name
, &entry
);
812 if (kr
!= KERN_SUCCESS
) {
813 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_INVALID_NAME
);
816 /* space is write-locked and active */
818 kr
= ipc_right_destroy(space
, name
, entry
, TRUE
, 0); /* unlocks space */
823 * Routine: mach_port_deallocate [kernel call]
825 * Deallocates a user reference from a send right,
826 * send-once right, dead-name right or a port_set right.
827 * May deallocate the right, if this is the last uref,
828 * and destroy the name, if it doesn't denote
833 * KERN_SUCCESS The uref is deallocated.
834 * KERN_INVALID_TASK The space is null.
835 * KERN_INVALID_TASK The space is dead.
836 * KERN_INVALID_NAME The name doesn't denote a right.
837 * KERN_INVALID_RIGHT The right isn't correct.
841 mach_port_deallocate(
843 mach_port_name_t name
)
848 if (space
== IS_NULL
) {
849 return KERN_INVALID_TASK
;
852 if (!MACH_PORT_VALID(name
)) {
856 kr
= ipc_right_lookup_write(space
, name
, &entry
);
857 if (kr
!= KERN_SUCCESS
) {
858 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_INVALID_NAME
);
861 /* space is write-locked */
863 kr
= ipc_right_dealloc(space
, name
, entry
); /* unlocks space */
868 * Routine: mach_port_get_refs [kernel call]
870 * Retrieves the number of user references held by a right.
871 * Receive rights, port-set rights, and send-once rights
872 * always have one user reference. Returns zero if the
873 * name denotes a right, but not the queried right.
877 * KERN_SUCCESS Number of urefs returned.
878 * KERN_INVALID_TASK The space is null.
879 * KERN_INVALID_TASK The space is dead.
880 * KERN_INVALID_VALUE "right" isn't a legal value.
881 * KERN_INVALID_NAME The name doesn't denote a right.
887 mach_port_name_t name
,
888 mach_port_right_t right
,
889 mach_port_urefs_t
*urefsp
)
891 mach_port_type_t type
;
892 mach_port_urefs_t urefs
;
896 if (space
== IS_NULL
) {
897 return KERN_INVALID_TASK
;
900 if (right
>= MACH_PORT_RIGHT_NUMBER
) {
901 return KERN_INVALID_VALUE
;
904 if (!MACH_PORT_VALID(name
)) {
905 if (right
== MACH_PORT_RIGHT_SEND
||
906 right
== MACH_PORT_RIGHT_SEND_ONCE
) {
910 return KERN_INVALID_NAME
;
913 kr
= ipc_right_lookup_write(space
, name
, &entry
);
914 if (kr
!= KERN_SUCCESS
) {
918 /* space is write-locked and active */
919 kr
= ipc_right_info(space
, name
, entry
, &type
, &urefs
);
920 /* space is unlocked */
922 if (kr
!= KERN_SUCCESS
) {
926 if (type
& MACH_PORT_TYPE(right
)) {
928 case MACH_PORT_RIGHT_SEND_ONCE
:
932 case MACH_PORT_RIGHT_PORT_SET
:
933 case MACH_PORT_RIGHT_RECEIVE
:
937 case MACH_PORT_RIGHT_DEAD_NAME
:
938 case MACH_PORT_RIGHT_SEND
:
944 panic("mach_port_get_refs: strange rights");
954 * Routine: mach_port_mod_refs
956 * Modifies the number of user references held by a right.
957 * The resulting number of user references must be non-negative.
958 * If it is zero, the right is deallocated. If the name
959 * doesn't denote other rights, it is destroyed.
963 * KERN_SUCCESS Modified number of urefs.
964 * KERN_INVALID_TASK The space is null.
965 * KERN_INVALID_TASK The space is dead.
966 * KERN_INVALID_VALUE "right" isn't a legal value.
967 * KERN_INVALID_NAME The name doesn't denote a right.
968 * KERN_INVALID_RIGHT Name doesn't denote specified right.
969 * KERN_INVALID_VALUE Impossible modification to urefs.
970 * KERN_UREFS_OVERFLOW Urefs would overflow.
976 mach_port_name_t name
,
977 mach_port_right_t right
,
978 mach_port_delta_t delta
)
983 if (space
== IS_NULL
) {
984 return KERN_INVALID_TASK
;
987 if (right
>= MACH_PORT_RIGHT_NUMBER
) {
988 return KERN_INVALID_VALUE
;
991 if (!MACH_PORT_VALID(name
)) {
992 if (right
== MACH_PORT_RIGHT_SEND
||
993 right
== MACH_PORT_RIGHT_SEND_ONCE
) {
996 return KERN_INVALID_NAME
;
999 kr
= ipc_right_lookup_write(space
, name
, &entry
);
1000 if (kr
!= KERN_SUCCESS
) {
1001 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_INVALID_NAME
);
1005 /* space is write-locked and active */
1007 kr
= ipc_right_delta(space
, name
, entry
, right
, delta
); /* unlocks */
1013 * Routine: mach_port_peek [kernel call]
1015 * Peek at the message queue for the specified receive
1016 * right and return info about a message in the queue.
1018 * On input, seqnop points to a sequence number value
1019 * to match the message being peeked. If zero is specified
1020 * as the seqno, the first message in the queue will be
1023 * Only the following trailer types are currently supported:
1024 * MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)
1026 * or'ed with one of these element types:
1027 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_NULL)
1028 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SEQNO)
1029 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER)
1030 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT)
1032 * On input, the value pointed to by trailer_sizep must be
1033 * large enough to hold the requested trailer size.
1035 * The message sequence number, id, size, requested trailer info
1036 * and requested trailer size are returned in their respective
1037 * output parameters upon success.
1042 * KERN_SUCCESS Matching message found, out parameters set.
1043 * KERN_INVALID_TASK The space is null or dead.
1044 * KERN_INVALID_NAME The name doesn't denote a right.
1045 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1046 * KERN_INVALID_VALUE The input parameter values are out of bounds.
1047 * KERN_FAILURE The requested message was not found.
1053 mach_port_name_t name
,
1054 mach_msg_trailer_type_t trailer_type
,
1055 mach_port_seqno_t
*seqnop
,
1056 mach_msg_size_t
*msg_sizep
,
1057 mach_msg_id_t
*msg_idp
,
1058 mach_msg_trailer_info_t trailer_infop
,
1059 mach_msg_type_number_t
*trailer_sizep
)
1064 mach_msg_max_trailer_t max_trailer
;
1066 if (space
== IS_NULL
) {
1067 return KERN_INVALID_TASK
;
1070 if (!MACH_PORT_VALID(name
)) {
1071 return KERN_INVALID_RIGHT
;
1075 * We don't allow anything greater than the audit trailer - to avoid
1076 * leaking the context pointer and to avoid variable-sized context issues.
1078 if (GET_RCV_ELEMENTS(trailer_type
) > MACH_RCV_TRAILER_AUDIT
||
1079 REQUESTED_TRAILER_SIZE(TRUE
, trailer_type
) > *trailer_sizep
) {
1080 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_INVALID_VALUE
);
1081 return KERN_INVALID_VALUE
;
1084 *trailer_sizep
= REQUESTED_TRAILER_SIZE(TRUE
, trailer_type
);
1086 kr
= ipc_port_translate_receive(space
, name
, &port
);
1087 if (kr
!= KERN_SUCCESS
) {
1088 mach_port_guard_exception(name
, 0, 0,
1089 ((KERN_INVALID_NAME
== kr
) ?
1090 kGUARD_EXC_INVALID_NAME
:
1091 kGUARD_EXC_INVALID_RIGHT
));
1095 /* Port locked and active */
1097 found
= ipc_mqueue_peek(&port
->ip_messages
, seqnop
,
1098 msg_sizep
, msg_idp
, &max_trailer
, NULL
);
1101 if (found
!= TRUE
) {
1102 return KERN_FAILURE
;
1105 max_trailer
.msgh_seqno
= *seqnop
;
1106 memcpy(trailer_infop
, &max_trailer
, *trailer_sizep
);
1108 return KERN_SUCCESS
;
1112 * Routine: mach_port_set_mscount [kernel call]
1114 * Changes a receive right's make-send count.
1118 * KERN_SUCCESS Set make-send count.
1119 * KERN_INVALID_TASK The space is null.
1120 * KERN_INVALID_TASK The space is dead.
1121 * KERN_INVALID_NAME The name doesn't denote a right.
1122 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1126 mach_port_set_mscount(
1128 mach_port_name_t name
,
1129 mach_port_mscount_t mscount
)
1134 if (space
== IS_NULL
) {
1135 return KERN_INVALID_TASK
;
1138 if (!MACH_PORT_VALID(name
)) {
1139 return KERN_INVALID_RIGHT
;
1142 kr
= ipc_port_translate_receive(space
, name
, &port
);
1143 if (kr
!= KERN_SUCCESS
) {
1146 /* port is locked and active */
1148 port
->ip_mscount
= mscount
;
1150 return KERN_SUCCESS
;
1154 * Routine: mach_port_set_seqno [kernel call]
1156 * Changes a receive right's sequence number.
1160 * KERN_SUCCESS Set sequence number.
1161 * KERN_INVALID_TASK The space is null.
1162 * KERN_INVALID_TASK The space is dead.
1163 * KERN_INVALID_NAME The name doesn't denote a right.
1164 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1168 mach_port_set_seqno(
1170 mach_port_name_t name
,
1171 mach_port_seqno_t seqno
)
1176 if (space
== IS_NULL
) {
1177 return KERN_INVALID_TASK
;
1180 if (!MACH_PORT_VALID(name
)) {
1181 return KERN_INVALID_RIGHT
;
1184 kr
= ipc_port_translate_receive(space
, name
, &port
);
1185 if (kr
!= KERN_SUCCESS
) {
1188 /* port is locked and active */
1190 ipc_mqueue_set_seqno(&port
->ip_messages
, seqno
);
1193 return KERN_SUCCESS
;
1197 * Routine: mach_port_get_context [kernel call]
1199 * Returns a receive right's context pointer.
1203 * KERN_SUCCESS Set context pointer.
1204 * KERN_INVALID_TASK The space is null.
1205 * KERN_INVALID_TASK The space is dead.
1206 * KERN_INVALID_NAME The name doesn't denote a right.
1207 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1211 mach_port_get_context(
1213 mach_port_name_t name
,
1214 mach_vm_address_t
*context
)
1219 if (space
== IS_NULL
) {
1220 return KERN_INVALID_TASK
;
1223 if (!MACH_PORT_VALID(name
)) {
1224 return KERN_INVALID_RIGHT
;
1227 kr
= ipc_port_translate_receive(space
, name
, &port
);
1228 if (kr
!= KERN_SUCCESS
) {
1232 /* Port locked and active */
1234 /* For strictly guarded ports, return empty context (which acts as guard) */
1235 if (port
->ip_strict_guard
) {
1238 *context
= port
->ip_context
;
1242 return KERN_SUCCESS
;
1246 mach_port_get_context_from_user(
1248 mach_port_name_t name
,
1249 mach_vm_address_t
*context
)
1253 ipc_space_t space
= convert_port_to_space_check_type(port
, NULL
, TASK_FLAVOR_READ
, FALSE
);
1255 if (space
== IPC_SPACE_NULL
) {
1256 return KERN_INVALID_ARGUMENT
;
1259 kr
= mach_port_get_context(space
, name
, context
);
1261 ipc_space_release(space
);
1266 * Routine: mach_port_set_context [kernel call]
1268 * Changes a receive right's context pointer.
1272 * KERN_SUCCESS Set context pointer.
1273 * KERN_INVALID_TASK The space is null.
1274 * KERN_INVALID_TASK The space is dead.
1275 * KERN_INVALID_NAME The name doesn't denote a right.
1276 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1280 mach_port_set_context(
1282 mach_port_name_t name
,
1283 mach_vm_address_t context
)
1288 if (space
== IS_NULL
) {
1289 return KERN_INVALID_TASK
;
1292 if (!MACH_PORT_VALID(name
)) {
1293 return KERN_INVALID_RIGHT
;
1296 kr
= ipc_port_translate_receive(space
, name
, &port
);
1297 if (kr
!= KERN_SUCCESS
) {
1301 /* port is locked and active */
1302 if (port
->ip_strict_guard
) {
1303 uint64_t portguard
= port
->ip_context
;
1305 /* For strictly guarded ports, disallow overwriting context; Raise Exception */
1306 mach_port_guard_exception(name
, context
, portguard
, kGUARD_EXC_SET_CONTEXT
);
1307 return KERN_INVALID_ARGUMENT
;
1310 port
->ip_context
= context
;
1313 return KERN_SUCCESS
;
1318 * Routine: mach_port_get_set_status [kernel call]
1320 * Retrieves a list of members in a port set.
1321 * Returns the space's name for each receive right member.
1325 * KERN_SUCCESS Retrieved list of members.
1326 * KERN_INVALID_TASK The space is null.
1327 * KERN_INVALID_TASK The space is dead.
1328 * KERN_INVALID_NAME The name doesn't denote a right.
1329 * KERN_INVALID_RIGHT Name doesn't denote a port set.
1330 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1334 mach_port_get_set_status(
1336 mach_port_name_t name
,
1337 mach_port_name_t
**members
,
1338 mach_msg_type_number_t
*membersCnt
)
1340 ipc_entry_num_t actual
; /* this many members */
1341 ipc_entry_num_t maxnames
; /* space for this many members */
1344 vm_size_t size
; /* size of allocated memory */
1345 vm_offset_t addr
; /* allocated memory */
1346 vm_map_copy_t memory
; /* copied-in memory */
1348 if (space
== IS_NULL
) {
1349 return KERN_INVALID_TASK
;
1352 if (!MACH_PORT_VALID(name
)) {
1353 return KERN_INVALID_RIGHT
;
1356 size
= VM_MAP_PAGE_SIZE(ipc_kernel_map
); /* initial guess */
1359 mach_port_name_t
*names
;
1363 kr
= vm_allocate_kernel(ipc_kernel_map
, &addr
, size
, VM_FLAGS_ANYWHERE
, VM_KERN_MEMORY_IPC
);
1364 if (kr
!= KERN_SUCCESS
) {
1365 return KERN_RESOURCE_SHORTAGE
;
1368 /* can't fault while we hold locks */
1370 kr
= vm_map_wire_kernel(ipc_kernel_map
, addr
, addr
+ size
,
1371 VM_PROT_READ
| VM_PROT_WRITE
, VM_KERN_MEMORY_IPC
, FALSE
);
1372 assert(kr
== KERN_SUCCESS
);
1374 kr
= ipc_object_translate(space
, name
, MACH_PORT_RIGHT_PORT_SET
, &psobj
);
1375 if (kr
!= KERN_SUCCESS
) {
1376 kmem_free(ipc_kernel_map
, addr
, size
);
1380 /* just use a portset reference from here on out */
1381 pset
= ips_object_to_pset(psobj
);
1382 ips_reference(pset
);
1385 names
= (mach_port_name_t
*) addr
;
1386 maxnames
= (ipc_entry_num_t
)(size
/ sizeof(mach_port_name_t
));
1388 ipc_mqueue_set_gather_member_names(space
, &pset
->ips_messages
, maxnames
, names
, &actual
);
1390 /* release the portset reference */
1393 if (actual
<= maxnames
) {
1397 /* didn't have enough memory; allocate more */
1398 kmem_free(ipc_kernel_map
, addr
, size
);
1399 size
= vm_map_round_page(
1400 (actual
* sizeof(mach_port_name_t
)),
1401 VM_MAP_PAGE_MASK(ipc_kernel_map
)) +
1402 VM_MAP_PAGE_SIZE(ipc_kernel_map
);
1406 memory
= VM_MAP_COPY_NULL
;
1408 kmem_free(ipc_kernel_map
, addr
, size
);
1410 vm_size_t size_used
;
1411 vm_size_t vm_size_used
;
1413 size_used
= actual
* sizeof(mach_port_name_t
);
1414 vm_size_used
= vm_map_round_page(
1416 VM_MAP_PAGE_MASK(ipc_kernel_map
));
1419 * Make used memory pageable and get it into
1420 * copied-in form. Free any unused memory.
1425 vm_map_trunc_page(addr
,
1426 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
1427 vm_map_round_page(addr
+ vm_size_used
,
1428 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
1430 assert(kr
== KERN_SUCCESS
);
1432 kr
= vm_map_copyin(ipc_kernel_map
, (vm_map_address_t
)addr
,
1433 (vm_map_size_t
)size_used
, TRUE
, &memory
);
1434 assert(kr
== KERN_SUCCESS
);
1436 if (vm_size_used
!= size
) {
1437 kmem_free(ipc_kernel_map
,
1438 addr
+ vm_size_used
, size
- vm_size_used
);
1442 *members
= (mach_port_name_t
*) memory
;
1443 *membersCnt
= actual
;
1444 return KERN_SUCCESS
;
1448 mach_port_get_set_status_from_user(
1450 mach_port_name_t name
,
1451 mach_port_name_t
**members
,
1452 mach_msg_type_number_t
*membersCnt
)
1456 ipc_space_t space
= convert_port_to_space_check_type(port
, NULL
, TASK_FLAVOR_READ
, FALSE
);
1458 if (space
== IPC_SPACE_NULL
) {
1459 return KERN_INVALID_ARGUMENT
;
1462 kr
= mach_port_get_set_status(space
, name
, members
, membersCnt
);
1464 ipc_space_release(space
);
1469 * Routine: mach_port_move_member [kernel call]
1471 * If after is MACH_PORT_NULL, removes member
1472 * from the port set it is in. Otherwise, adds
1473 * member to after, removing it from any set
1474 * it might already be in.
1478 * KERN_SUCCESS Moved the port.
1479 * KERN_INVALID_TASK The space is null.
1480 * KERN_INVALID_TASK The space is dead.
1481 * KERN_INVALID_NAME Member didn't denote a right.
1482 * KERN_INVALID_RIGHT Member didn't denote a receive right.
1483 * KERN_INVALID_NAME After didn't denote a right.
1484 * KERN_INVALID_RIGHT After didn't denote a port set right.
1486 * After is MACH_PORT_NULL and Member isn't in a port set.
1490 mach_port_move_member(
1492 mach_port_name_t member
,
1493 mach_port_name_t after
)
1495 ipc_object_t port_obj
, ps_obj
;
1497 ipc_pset_t nset
= IPS_NULL
;
1499 uint64_t wq_link_id
= 0;
1500 uint64_t wq_reserved_prepost
= 0;
1502 if (space
== IS_NULL
) {
1503 return KERN_INVALID_TASK
;
1506 if (!MACH_PORT_VALID(member
)) {
1507 return KERN_INVALID_RIGHT
;
1510 if (after
== MACH_PORT_DEAD
) {
1511 return KERN_INVALID_RIGHT
;
1512 } else if (after
== MACH_PORT_NULL
) {
1516 * We reserve both a link, and
1517 * enough prepost objects to complete
1518 * the set move atomically - we can't block
1519 * while we're holding the space lock, and
1520 * the ipc_pset_add calls ipc_mqueue_add
1521 * which may have to prepost this port onto
1524 wq_link_id
= waitq_link_reserve(NULL
);
1525 wq_reserved_prepost
= waitq_prepost_reserve(NULL
, 10,
1527 kr
= ipc_pset_lazy_allocate(space
, after
);
1528 if (kr
!= KERN_SUCCESS
) {
1533 if (after
!= MACH_PORT_NULL
) {
1534 kr
= ipc_object_translate_two(space
,
1535 member
, MACH_PORT_RIGHT_RECEIVE
, &port_obj
,
1536 after
, MACH_PORT_RIGHT_PORT_SET
, &ps_obj
);
1538 kr
= ipc_object_translate(space
,
1539 member
, MACH_PORT_RIGHT_RECEIVE
, &port_obj
);
1541 if (kr
!= KERN_SUCCESS
) {
1545 port
= ip_object_to_port(port_obj
);
1546 if (after
!= MACH_PORT_NULL
) {
1547 nset
= ips_object_to_pset(ps_obj
);
1549 /* port and nset are locked */
1551 ipc_pset_remove_from_all(port
);
1553 if (after
!= MACH_PORT_NULL
) {
1554 kr
= ipc_pset_add(nset
, port
, &wq_link_id
, &wq_reserved_prepost
);
1562 * on success the ipc_pset_add() will consume the wq_link_id
1563 * value (resetting it to 0), so this function is always safe to call.
1565 waitq_link_release(wq_link_id
);
1566 waitq_prepost_release_reserve(wq_reserved_prepost
);
1572 * Routine: mach_port_request_notification [kernel call]
1574 * Requests a notification. The caller supplies
1575 * a send-once right for the notification to use,
1576 * and the call returns the previously registered
1577 * send-once right, if any. Possible types:
1579 * MACH_NOTIFY_PORT_DESTROYED
1580 * Requests a port-destroyed notification
1581 * for a receive right. Sync should be zero.
1582 * MACH_NOTIFY_NO_SENDERS
1583 * Requests a no-senders notification for a
1584 * receive right. If there are currently no
1585 * senders, sync is less than or equal to the
1586 * current make-send count, and a send-once right
1587 * is supplied, then an immediate no-senders
1588 * notification is generated.
1589 * MACH_NOTIFY_DEAD_NAME
1590 * Requests a dead-name notification for a send
1591 * or receive right. If the name is already a
1592 * dead name, sync is non-zero, and a send-once
1593 * right is supplied, then an immediate dead-name
1594 * notification is generated.
1598 * KERN_SUCCESS Requested a notification.
1599 * KERN_INVALID_TASK The space is null.
1600 * KERN_INVALID_TASK The space is dead.
1601 * KERN_INVALID_VALUE Bad id value.
1602 * KERN_INVALID_NAME Name doesn't denote a right.
1603 * KERN_INVALID_RIGHT Name doesn't denote appropriate right.
1604 * KERN_INVALID_CAPABILITY The notify port is dead.
1605 * MACH_NOTIFY_PORT_DESTROYED:
1606 * KERN_INVALID_VALUE Sync isn't zero.
1607 * KERN_FAILURE Re-registering for this notification
1608 * MACH_NOTIFY_DEAD_NAME:
1609 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1610 * KERN_INVALID_ARGUMENT Name denotes dead name, but
1611 * sync is zero or notify is IP_NULL.
1612 * KERN_UREFS_OVERFLOW Name denotes dead name, but
1613 * generating immediate notif. would overflow urefs.
1617 mach_port_request_notification(
1619 mach_port_name_t name
,
1621 mach_port_mscount_t sync
,
1623 ipc_port_t
*previousp
)
1627 if (space
== IS_NULL
) {
1628 return KERN_INVALID_TASK
;
1631 if (notify
== IP_DEAD
) {
1632 return KERN_INVALID_CAPABILITY
;
1637 * Requesting notifications on RPC ports is an error.
1643 kr
= ipc_right_lookup_write(space
, name
, &entry
);
1644 if (kr
!= KERN_SUCCESS
) {
1648 port
= ip_object_to_port(entry
->ie_object
);
1650 if (port
->ip_subsystem
!= NULL
) {
1651 is_write_unlock(space
);
1652 panic("mach_port_request_notification: on RPC port!!");
1653 return KERN_INVALID_CAPABILITY
;
1655 is_write_unlock(space
);
1661 case MACH_NOTIFY_PORT_DESTROYED
: {
1665 return KERN_INVALID_VALUE
;
1668 if (!MACH_PORT_VALID(name
)) {
1669 return KERN_INVALID_RIGHT
;
1672 kr
= ipc_port_translate_receive(space
, name
, &port
);
1673 if (kr
!= KERN_SUCCESS
) {
1676 /* port is locked and active */
1679 * you cannot register for port death notifications on a kobject,
1680 * kolabel or special reply port
1682 if (ip_is_kobject(port
) || ip_is_kolabeled(port
) ||
1683 port
->ip_specialreply
) {
1685 return KERN_INVALID_RIGHT
;
1688 /* Allow only one registeration of this notification */
1689 if (port
->ip_pdrequest
!= IP_NULL
) {
1691 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_KERN_FAILURE
);
1692 return KERN_FAILURE
;
1695 ipc_port_pdrequest(port
, notify
, previousp
);
1696 /* port is unlocked */
1697 assert(*previousp
== IP_NULL
);
1701 case MACH_NOTIFY_NO_SENDERS
: {
1704 if (!MACH_PORT_VALID(name
)) {
1705 return KERN_INVALID_RIGHT
;
1708 kr
= ipc_port_translate_receive(space
, name
, &port
);
1709 if (kr
!= KERN_SUCCESS
) {
1712 /* port is locked and active */
1714 ipc_port_nsrequest(port
, sync
, notify
, previousp
);
1715 /* port is unlocked */
1719 case MACH_NOTIFY_SEND_POSSIBLE
:
1721 if (!MACH_PORT_VALID(name
)) {
1722 return KERN_INVALID_ARGUMENT
;
1725 kr
= ipc_right_request_alloc(space
, name
, sync
!= 0,
1726 TRUE
, notify
, previousp
);
1727 if (kr
!= KERN_SUCCESS
) {
1732 case MACH_NOTIFY_DEAD_NAME
:
1734 if (!MACH_PORT_VALID(name
)) {
1737 * Should do immediate delivery check -
1738 * will do that in the near future.
1740 return KERN_INVALID_ARGUMENT
;
1743 kr
= ipc_right_request_alloc(space
, name
, sync
!= 0,
1744 FALSE
, notify
, previousp
);
1745 if (kr
!= KERN_SUCCESS
) {
1751 return KERN_INVALID_VALUE
;
1754 return KERN_SUCCESS
;
1758 * Routine: mach_port_insert_right [kernel call]
1760 * Inserts a right into a space, as if the space
1761 * voluntarily received the right in a message,
1762 * except that the right gets the specified name.
1766 * KERN_SUCCESS Inserted the right.
1767 * KERN_INVALID_TASK The space is null.
1768 * KERN_INVALID_TASK The space is dead.
1769 * KERN_INVALID_VALUE The name isn't a legal name.
1770 * KERN_NAME_EXISTS The name already denotes a right.
1771 * KERN_INVALID_VALUE Message doesn't carry a port right.
1772 * KERN_INVALID_CAPABILITY Port is null or dead.
1773 * KERN_UREFS_OVERFLOW Urefs limit would be exceeded.
1774 * KERN_RIGHT_EXISTS Space has rights under another name.
1775 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1779 mach_port_insert_right(
1781 mach_port_name_t name
,
1783 mach_msg_type_name_t polyPoly
)
1785 if (space
== IS_NULL
) {
1786 return KERN_INVALID_TASK
;
1789 if (!MACH_PORT_VALID(name
) ||
1790 !MACH_MSG_TYPE_PORT_ANY_RIGHT(polyPoly
)) {
1791 return KERN_INVALID_VALUE
;
1794 if (!IP_VALID(poly
)) {
1795 return KERN_INVALID_CAPABILITY
;
1798 return ipc_object_copyout_name(space
, ip_to_object(poly
),
1803 * Routine: mach_port_extract_right [kernel call]
1805 * Extracts a right from a space, as if the space
1806 * voluntarily sent the right to the caller.
1810 * KERN_SUCCESS Extracted the right.
1811 * KERN_INVALID_TASK The space is null.
1812 * KERN_INVALID_TASK The space is dead.
1813 * KERN_INVALID_VALUE Requested type isn't a port right.
1814 * KERN_INVALID_NAME Name doesn't denote a right.
1815 * KERN_INVALID_RIGHT Name doesn't denote appropriate right.
1819 mach_port_extract_right(
1821 mach_port_name_t name
,
1822 mach_msg_type_name_t msgt_name
,
1824 mach_msg_type_name_t
*polyPoly
)
1828 if (space
== IS_NULL
) {
1829 return KERN_INVALID_TASK
;
1832 if (!MACH_MSG_TYPE_PORT_ANY(msgt_name
)) {
1833 return KERN_INVALID_VALUE
;
1836 if (!MACH_PORT_VALID(name
)) {
1838 * really should copy out a dead name, if it is a send or
1839 * send-once right being copied, but instead return an
1842 return KERN_INVALID_RIGHT
;
1845 kr
= ipc_object_copyin(space
, name
, msgt_name
, (ipc_object_t
*) poly
, 0, NULL
,
1846 (space
== current_space() && msgt_name
== MACH_MSG_TYPE_COPY_SEND
) ?
1847 IPC_OBJECT_COPYIN_FLAGS_ALLOW_IMMOVABLE_SEND
: IPC_OBJECT_COPYIN_FLAGS_SOFT_FAIL_IMMOVABLE_SEND
);
1849 if (kr
== KERN_SUCCESS
) {
1850 *polyPoly
= ipc_object_copyin_type(msgt_name
);
1856 * Routine: mach_port_get_status_helper [helper]
1858 * Populates a mach_port_status_t structure with
1861 * Port needs to be locked
1866 mach_port_get_status_helper(
1868 mach_port_status_t
*statusp
)
1870 imq_lock(&port
->ip_messages
);
1871 /* don't leak set IDs, just indicate that the port is in one or not */
1872 statusp
->mps_pset
= !!(port
->ip_in_pset
);
1873 statusp
->mps_seqno
= port
->ip_messages
.imq_seqno
;
1874 statusp
->mps_qlimit
= port
->ip_messages
.imq_qlimit
;
1875 statusp
->mps_msgcount
= port
->ip_messages
.imq_msgcount
;
1876 imq_unlock(&port
->ip_messages
);
1878 statusp
->mps_mscount
= port
->ip_mscount
;
1879 statusp
->mps_sorights
= port
->ip_sorights
;
1880 statusp
->mps_srights
= port
->ip_srights
> 0;
1881 statusp
->mps_pdrequest
= port
->ip_pdrequest
!= IP_NULL
;
1882 statusp
->mps_nsrequest
= port
->ip_nsrequest
!= IP_NULL
;
1883 statusp
->mps_flags
= 0;
1884 if (port
->ip_impdonation
) {
1885 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_IMP_DONATION
;
1886 if (port
->ip_tempowner
) {
1887 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_TEMPOWNER
;
1888 if (IIT_NULL
!= port
->ip_imp_task
) {
1889 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_TASKPTR
;
1893 if (port
->ip_guarded
) {
1894 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_GUARDED
;
1895 if (port
->ip_strict_guard
) {
1896 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_STRICT_GUARD
;
1898 if (port
->ip_immovable_receive
) {
1899 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_GUARD_IMMOVABLE_RECEIVE
;
1902 if (port
->ip_no_grant
) {
1903 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_NO_GRANT
;
1909 mach_port_get_attributes(
1911 mach_port_name_t name
,
1913 mach_port_info_t info
,
1914 mach_msg_type_number_t
*count
)
1919 if (space
== IS_NULL
) {
1920 return KERN_INVALID_TASK
;
1924 case MACH_PORT_LIMITS_INFO
: {
1925 mach_port_limits_t
*lp
= (mach_port_limits_t
*)info
;
1927 if (*count
< MACH_PORT_LIMITS_INFO_COUNT
) {
1928 return KERN_FAILURE
;
1931 if (!MACH_PORT_VALID(name
)) {
1936 kr
= ipc_port_translate_receive(space
, name
, &port
);
1937 if (kr
!= KERN_SUCCESS
) {
1940 /* port is locked and active */
1942 lp
->mpl_qlimit
= port
->ip_messages
.imq_qlimit
;
1943 *count
= MACH_PORT_LIMITS_INFO_COUNT
;
1948 case MACH_PORT_RECEIVE_STATUS
: {
1949 mach_port_status_t
*statusp
= (mach_port_status_t
*)info
;
1951 if (*count
< MACH_PORT_RECEIVE_STATUS_COUNT
) {
1952 return KERN_FAILURE
;
1955 if (!MACH_PORT_VALID(name
)) {
1956 return KERN_INVALID_RIGHT
;
1959 kr
= ipc_port_translate_receive(space
, name
, &port
);
1960 if (kr
!= KERN_SUCCESS
) {
1963 /* port is locked and active */
1964 mach_port_get_status_helper(port
, statusp
);
1965 *count
= MACH_PORT_RECEIVE_STATUS_COUNT
;
1970 case MACH_PORT_DNREQUESTS_SIZE
: {
1971 ipc_port_request_t table
;
1973 if (*count
< MACH_PORT_DNREQUESTS_SIZE_COUNT
) {
1974 return KERN_FAILURE
;
1977 if (!MACH_PORT_VALID(name
)) {
1982 kr
= ipc_port_translate_receive(space
, name
, &port
);
1983 if (kr
!= KERN_SUCCESS
) {
1986 /* port is locked and active */
1988 table
= port
->ip_requests
;
1989 if (table
== IPR_NULL
) {
1992 *(int *)info
= table
->ipr_size
->its_size
;
1994 *count
= MACH_PORT_DNREQUESTS_SIZE_COUNT
;
1999 case MACH_PORT_INFO_EXT
: {
2000 mach_port_info_ext_t
*mp_info
= (mach_port_info_ext_t
*)info
;
2001 if (*count
< MACH_PORT_INFO_EXT_COUNT
) {
2002 return KERN_FAILURE
;
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 */
2014 mach_port_get_status_helper(port
, &mp_info
->mpie_status
);
2015 mp_info
->mpie_boost_cnt
= port
->ip_impcount
;
2016 *count
= MACH_PORT_INFO_EXT_COUNT
;
2022 return KERN_INVALID_ARGUMENT
;
2026 return KERN_SUCCESS
;
2030 mach_port_get_attributes_from_user(
2032 mach_port_name_t name
,
2034 mach_port_info_t info
,
2035 mach_msg_type_number_t
*count
)
2039 ipc_space_t space
= convert_port_to_space_check_type(port
, NULL
, TASK_FLAVOR_READ
, FALSE
);
2041 if (space
== IPC_SPACE_NULL
) {
2042 return KERN_INVALID_ARGUMENT
;
2045 kr
= mach_port_get_attributes(space
, name
, flavor
, info
, count
);
2047 ipc_space_release(space
);
2052 mach_port_set_attributes(
2054 mach_port_name_t name
,
2056 mach_port_info_t info
,
2057 mach_msg_type_number_t count
)
2062 if (space
== IS_NULL
) {
2063 return KERN_INVALID_TASK
;
2067 case MACH_PORT_LIMITS_INFO
: {
2068 mach_port_limits_t
*mplp
= (mach_port_limits_t
*)info
;
2070 if (count
< MACH_PORT_LIMITS_INFO_COUNT
) {
2071 return KERN_FAILURE
;
2074 if (mplp
->mpl_qlimit
> MACH_PORT_QLIMIT_MAX
) {
2075 return KERN_INVALID_VALUE
;
2078 if (!MACH_PORT_VALID(name
)) {
2079 return KERN_INVALID_RIGHT
;
2082 kr
= ipc_port_translate_receive(space
, name
, &port
);
2083 if (kr
!= KERN_SUCCESS
) {
2086 /* port is locked and active */
2088 ipc_mqueue_set_qlimit(&port
->ip_messages
, mplp
->mpl_qlimit
);
2092 case MACH_PORT_DNREQUESTS_SIZE
: {
2093 if (count
< MACH_PORT_DNREQUESTS_SIZE_COUNT
) {
2094 return KERN_FAILURE
;
2097 if (!MACH_PORT_VALID(name
)) {
2098 return KERN_INVALID_RIGHT
;
2101 kr
= ipc_port_translate_receive(space
, name
, &port
);
2102 if (kr
!= KERN_SUCCESS
) {
2105 /* port is locked and active */
2107 kr
= ipc_port_request_grow(port
, *(int *)info
);
2108 if (kr
!= KERN_SUCCESS
) {
2113 case MACH_PORT_TEMPOWNER
:
2114 if (!MACH_PORT_VALID(name
)) {
2115 return KERN_INVALID_RIGHT
;
2118 ipc_importance_task_t release_imp_task
= IIT_NULL
;
2119 natural_t assertcnt
= 0;
2121 kr
= ipc_port_translate_receive(space
, name
, &port
);
2122 if (kr
!= KERN_SUCCESS
) {
2125 /* port is locked and active */
2128 * don't allow temp-owner importance donation if user
2129 * associated it with a kobject already (timer, host_notify target),
2130 * or is a special reply port.
2132 if (ip_is_kobject(port
) || port
->ip_specialreply
) {
2134 return KERN_INVALID_ARGUMENT
;
2137 if (port
->ip_tempowner
!= 0) {
2138 if (IIT_NULL
!= port
->ip_imp_task
) {
2139 release_imp_task
= port
->ip_imp_task
;
2140 port
->ip_imp_task
= IIT_NULL
;
2141 assertcnt
= port
->ip_impcount
;
2144 assertcnt
= port
->ip_impcount
;
2147 port
->ip_impdonation
= 1;
2148 port
->ip_tempowner
= 1;
2151 #if IMPORTANCE_INHERITANCE
2152 /* drop assertions from previous destination task */
2153 if (release_imp_task
!= IIT_NULL
) {
2154 assert(ipc_importance_task_is_any_receiver_type(release_imp_task
));
2155 if (assertcnt
> 0) {
2156 ipc_importance_task_drop_internal_assertion(release_imp_task
, assertcnt
);
2158 ipc_importance_task_release(release_imp_task
);
2159 } else if (assertcnt
> 0) {
2160 release_imp_task
= current_task()->task_imp_base
;
2161 if (release_imp_task
!= IIT_NULL
&&
2162 ipc_importance_task_is_any_receiver_type(release_imp_task
)) {
2163 ipc_importance_task_drop_internal_assertion(release_imp_task
, assertcnt
);
2167 if (release_imp_task
!= IIT_NULL
) {
2168 ipc_importance_task_release(release_imp_task
);
2170 #endif /* IMPORTANCE_INHERITANCE */
2174 #if IMPORTANCE_INHERITANCE
2175 case MACH_PORT_DENAP_RECEIVER
:
2176 case MACH_PORT_IMPORTANCE_RECEIVER
:
2177 if (!MACH_PORT_VALID(name
)) {
2178 return KERN_INVALID_RIGHT
;
2181 kr
= ipc_port_translate_receive(space
, name
, &port
);
2182 if (kr
!= KERN_SUCCESS
) {
2187 * don't allow importance donation if user associated
2188 * it with a kobject already (timer, host_notify target),
2189 * or is a special reply port.
2191 if (ip_is_kobject(port
) || port
->ip_specialreply
) {
2193 return KERN_INVALID_ARGUMENT
;
2196 /* port is locked and active */
2197 port
->ip_impdonation
= 1;
2201 #endif /* IMPORTANCE_INHERITANCE */
2204 return KERN_INVALID_ARGUMENT
;
2207 return KERN_SUCCESS
;
2211 * Routine: mach_port_insert_member [kernel call]
2213 * Add the receive right, specified by name, to
2215 * The port cannot already be a member of the set.
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 name didn't denote a right.
2223 * KERN_INVALID_RIGHT name didn't denote a receive right.
2224 * KERN_INVALID_NAME pset_name didn't denote a right.
2225 * KERN_INVALID_RIGHT pset_name didn't denote a portset right.
2226 * KERN_ALREADY_IN_SET name was already a member of pset.
2230 mach_port_insert_member(
2232 mach_port_name_t name
,
2233 mach_port_name_t psname
)
2238 uint64_t wq_link_id
;
2239 uint64_t wq_reserved_prepost
;
2241 if (space
== IS_NULL
) {
2242 return KERN_INVALID_TASK
;
2245 if (!MACH_PORT_VALID(name
) || !MACH_PORT_VALID(psname
)) {
2246 return KERN_INVALID_RIGHT
;
2249 wq_link_id
= waitq_link_reserve(NULL
);
2250 wq_reserved_prepost
= waitq_prepost_reserve(NULL
, 10,
2252 kr
= ipc_pset_lazy_allocate(space
, psname
);
2253 if (kr
!= KERN_SUCCESS
) {
2258 kr
= ipc_object_translate_two(space
,
2259 name
, MACH_PORT_RIGHT_RECEIVE
, &obj
,
2260 psname
, MACH_PORT_RIGHT_PORT_SET
, &psobj
);
2261 if (kr
!= KERN_SUCCESS
) {
2265 /* obj and psobj are locked (and were locked in that order) */
2266 assert(psobj
!= IO_NULL
);
2267 assert(obj
!= IO_NULL
);
2269 kr
= ipc_pset_add(ips_object_to_pset(psobj
), ip_object_to_port(obj
),
2270 &wq_link_id
, &wq_reserved_prepost
);
2276 /* on success, wq_link_id is reset to 0, so this is always safe */
2277 waitq_link_release(wq_link_id
);
2278 waitq_prepost_release_reserve(wq_reserved_prepost
);
2284 * Routine: mach_port_extract_member [kernel call]
2286 * Remove a port from one portset that it is a member of.
2290 * KERN_SUCCESS Moved the port.
2291 * KERN_INVALID_TASK The space is null.
2292 * KERN_INVALID_TASK The space is dead.
2293 * KERN_INVALID_NAME Member didn't denote a right.
2294 * KERN_INVALID_RIGHT Member didn't denote a receive right.
2295 * KERN_INVALID_NAME After didn't denote a right.
2296 * KERN_INVALID_RIGHT After didn't denote a port set right.
2298 * After is MACH_PORT_NULL and Member isn't in a port set.
2302 mach_port_extract_member(
2304 mach_port_name_t name
,
2305 mach_port_name_t psname
)
2311 if (space
== IS_NULL
) {
2312 return KERN_INVALID_TASK
;
2315 if (!MACH_PORT_VALID(name
) || !MACH_PORT_VALID(psname
)) {
2316 return KERN_INVALID_RIGHT
;
2319 kr
= ipc_object_translate_two(space
,
2320 name
, MACH_PORT_RIGHT_RECEIVE
, &obj
,
2321 psname
, MACH_PORT_RIGHT_PORT_SET
, &psobj
);
2322 if (kr
!= KERN_SUCCESS
) {
2326 /* obj and psobj are both locked (and were locked in that order) */
2327 assert(psobj
!= IO_NULL
);
2328 assert(obj
!= IO_NULL
);
2330 kr
= ipc_pset_remove(ips_object_to_pset(psobj
), ip_object_to_port(obj
));
2339 * task_set_port_space:
2341 * Set port name space of task to specified size.
2344 task_set_port_space(
2350 if (space
== IS_NULL
) {
2351 return KERN_INVALID_TASK
;
2354 is_write_lock(space
);
2356 if (!is_active(space
)) {
2357 is_write_unlock(space
);
2358 return KERN_INVALID_TASK
;
2361 kr
= ipc_entry_grow_table(space
, table_entries
);
2362 if (kr
== KERN_SUCCESS
) {
2363 is_write_unlock(space
);
2369 * Routine: mach_port_guard_locked [helper routine]
2371 * Sets a new guard for a locked port.
2375 * KERN_SUCCESS Port Guarded.
2376 * KERN_INVALID_ARGUMENT Port already contains a context/guard.
2378 static kern_return_t
2379 mach_port_guard_locked(
2384 if (port
->ip_context
) {
2385 return KERN_INVALID_ARGUMENT
;
2388 int strict
= (flags
& MPG_STRICT
)? 1 : 0;
2389 int immovable_receive
= (flags
& MPG_IMMOVABLE_RECEIVE
)? 1 : 0;
2391 imq_lock(&port
->ip_messages
);
2392 port
->ip_context
= guard
;
2393 port
->ip_guarded
= 1;
2394 port
->ip_strict_guard
= strict
;
2395 /* ip_immovable_receive bit is sticky and can't be un-guarded */
2396 if (!port
->ip_immovable_receive
) {
2397 port
->ip_immovable_receive
= immovable_receive
;
2399 imq_unlock(&port
->ip_messages
);
2401 return KERN_SUCCESS
;
2405 * Routine: mach_port_unguard_locked [helper routine]
2407 * Removes guard for a locked port.
2411 * KERN_SUCCESS Port Unguarded.
2412 * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch.
2413 * This also raises a EXC_GUARD exception.
2415 static kern_return_t
2416 mach_port_unguard_locked(
2418 mach_port_name_t name
,
2421 /* Port locked and active */
2422 if (!port
->ip_guarded
) {
2423 /* Port already unguarded; Raise exception */
2424 mach_port_guard_exception(name
, guard
, 0, kGUARD_EXC_UNGUARDED
);
2425 return KERN_INVALID_ARGUMENT
;
2428 if (port
->ip_context
!= guard
) {
2429 /* Incorrect guard; Raise exception */
2430 mach_port_guard_exception(name
, guard
, port
->ip_context
, kGUARD_EXC_INCORRECT_GUARD
);
2431 return KERN_INVALID_ARGUMENT
;
2434 imq_lock(&port
->ip_messages
);
2435 port
->ip_context
= 0;
2436 port
->ip_guarded
= port
->ip_strict_guard
= 0;
2437 /* Don't clear the ip_immovable_receive bit */
2438 imq_unlock(&port
->ip_messages
);
2440 return KERN_SUCCESS
;
2445 * Routine: mach_port_guard_exception [helper routine]
2447 * Marks the thread with AST_GUARD for mach port guard violation.
2448 * Also saves exception info in thread structure.
2452 * KERN_FAILURE Thread marked with AST_GUARD.
2455 mach_port_guard_exception(
2456 mach_port_name_t name
,
2457 __unused
uint64_t inguard
,
2461 mach_exception_code_t code
= 0;
2462 EXC_GUARD_ENCODE_TYPE(code
, GUARD_TYPE_MACH_PORT
);
2463 EXC_GUARD_ENCODE_FLAVOR(code
, reason
);
2464 EXC_GUARD_ENCODE_TARGET(code
, name
);
2465 mach_exception_subcode_t subcode
= (uint64_t)portguard
;
2466 thread_t t
= current_thread();
2467 boolean_t fatal
= FALSE
;
2468 if (t
->task
->task_exc_guard
& TASK_EXC_GUARD_MP_FATAL
) {
2470 } else if (reason
<= MAX_FATAL_kGUARD_EXC_CODE
) {
2473 thread_guard_violation(t
, code
, subcode
, fatal
);
2477 * Temporary wrapper for immovable mach port guard exception.
2479 * Condition: !(ip_is_control(port) && !immovable_control_port_enabled)
2482 mach_port_guard_exception_immovable(
2483 mach_port_name_t name
,
2487 if (ip_is_control(port
) && immovable_control_port_enabled
) {
2488 mach_port_guard_exception(name
, 0, portguard
,
2489 ipc_control_port_options
& IPC_CONTROL_PORT_OPTIONS_IMMOVABLE_HARD
?
2490 kGUARD_EXC_IMMOVABLE
: kGUARD_EXC_IMMOVABLE_NON_FATAL
);
2491 } else if (!ip_is_control(port
)) {
2492 /* always fatal exception for non-control port violation */
2493 mach_port_guard_exception(name
, 0, portguard
, kGUARD_EXC_IMMOVABLE
);
2495 /* ip_is_control(port) && !immovable_control_port_enabled */
2496 panic("mach_port_guard_exception_immovable: condition does not hold.");
2502 * Routine: mach_port_guard_ast
2504 * Raises an exception for mach port guard violation.
2512 mach_port_guard_ast(thread_t t
,
2513 mach_exception_data_type_t code
, mach_exception_data_type_t subcode
)
2515 unsigned int reason
= EXC_GUARD_DECODE_GUARD_FLAVOR(code
);
2516 task_t task
= t
->task
;
2517 unsigned int behavior
= task
->task_exc_guard
;
2518 assert(task
== current_task());
2519 assert(task
!= kernel_task
);
2523 * Fatal Mach port guards - always delivered synchronously
2525 case kGUARD_EXC_DESTROY
:
2526 case kGUARD_EXC_MOD_REFS
:
2527 case kGUARD_EXC_SET_CONTEXT
:
2528 case kGUARD_EXC_UNGUARDED
:
2529 case kGUARD_EXC_INCORRECT_GUARD
:
2530 case kGUARD_EXC_IMMOVABLE
:
2531 case kGUARD_EXC_STRICT_REPLY
:
2532 case kGUARD_EXC_MSG_FILTERED
:
2533 task_exception_notify(EXC_GUARD
, code
, subcode
);
2534 task_bsdtask_kill(task
);
2539 * Mach port guards controlled by task settings.
2542 /* Is delivery enabled */
2543 if ((behavior
& TASK_EXC_GUARD_MP_DELIVER
) == 0) {
2547 /* If only once, make sure we're that once */
2548 while (behavior
& TASK_EXC_GUARD_MP_ONCE
) {
2549 uint32_t new_behavior
= behavior
& ~TASK_EXC_GUARD_MP_DELIVER
;
2551 if (OSCompareAndSwap(behavior
, new_behavior
, &task
->task_exc_guard
)) {
2554 behavior
= task
->task_exc_guard
;
2555 if ((behavior
& TASK_EXC_GUARD_MP_DELIVER
) == 0) {
2560 /* Raise exception via corpse fork or synchronously */
2561 if ((task
->task_exc_guard
& TASK_EXC_GUARD_MP_CORPSE
) &&
2562 (task
->task_exc_guard
& TASK_EXC_GUARD_MP_FATAL
) == 0) {
2563 task_violated_guard(code
, subcode
, NULL
);
2565 task_exception_notify(EXC_GUARD
, code
, subcode
);
2568 /* Terminate the task if desired */
2569 if (task
->task_exc_guard
& TASK_EXC_GUARD_MP_FATAL
) {
2570 task_bsdtask_kill(task
);
2577 * Routine: mach_port_construct [kernel call]
2579 * Constructs a mach port with the provided set of options.
2583 * KERN_SUCCESS The right is allocated.
2584 * KERN_INVALID_TASK The space is null.
2585 * KERN_INVALID_TASK The space is dead.
2586 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
2587 * KERN_NO_SPACE No room in space for another right.
2588 * KERN_FAILURE Illegal option values requested.
2592 mach_port_construct(
2594 mach_port_options_t
*options
,
2596 mach_port_name_t
*name
)
2600 ipc_port_init_flags_t init_flags
= IPC_PORT_INIT_MESSAGE_QUEUE
;
2602 if (space
== IS_NULL
) {
2603 return KERN_INVALID_TASK
;
2606 if (options
->flags
& MPO_INSERT_SEND_RIGHT
) {
2607 init_flags
|= IPC_PORT_INIT_MAKE_SEND_RIGHT
;
2610 if (options
->flags
& MPO_FILTER_MSG
) {
2611 init_flags
|= IPC_PORT_INIT_FILTER_MESSAGE
;
2614 if (options
->flags
& MPO_TG_BLOCK_TRACKING
) {
2615 /* Check the task role to allow only TASK_GRAPHICS_SERVER to set this option */
2616 if (proc_get_effective_task_policy(current_task(),
2617 TASK_POLICY_ROLE
) != TASK_GRAPHICS_SERVER
) {
2622 * Check the work interval port passed in to make sure it is the render server type.
2623 * Since the creation of the render server work interval is privileged, this check
2624 * acts as a guard to make sure only the render server is setting the thread group
2625 * blocking behavior on the port.
2627 mach_port_name_t wi_port_name
= options
->work_interval_port
;
2628 if (work_interval_port_type_render_server(wi_port_name
) == false) {
2629 return KERN_INVALID_ARGUMENT
;
2631 init_flags
|= IPC_PORT_INIT_TG_BLOCK_TRACKING
;
2634 /* Allocate a new port in the IPC space */
2635 kr
= ipc_port_alloc(space
, init_flags
, name
, &port
);
2636 if (kr
!= KERN_SUCCESS
) {
2640 /* Port locked and active */
2641 if (options
->flags
& MPO_CONTEXT_AS_GUARD
) {
2643 if (options
->flags
& MPO_STRICT
) {
2644 flags
|= MPG_STRICT
;
2646 if (options
->flags
& MPO_IMMOVABLE_RECEIVE
) {
2647 flags
|= MPG_IMMOVABLE_RECEIVE
;
2649 kr
= mach_port_guard_locked(port
, (uint64_t) context
, flags
);
2650 /* A newly allocated and locked port should always be guarded successfully */
2651 assert(kr
== KERN_SUCCESS
);
2653 port
->ip_context
= context
;
2659 /* Set port attributes as requested */
2661 if (options
->flags
& MPO_QLIMIT
) {
2662 kr
= mach_port_set_attributes(space
, *name
, MACH_PORT_LIMITS_INFO
,
2663 (mach_port_info_t
)&options
->mpl
, sizeof(options
->mpl
) / sizeof(int));
2664 if (kr
!= KERN_SUCCESS
) {
2669 if (options
->flags
& MPO_TEMPOWNER
) {
2670 kr
= mach_port_set_attributes(space
, *name
, MACH_PORT_TEMPOWNER
, NULL
, 0);
2671 if (kr
!= KERN_SUCCESS
) {
2676 if (options
->flags
& MPO_IMPORTANCE_RECEIVER
) {
2677 kr
= mach_port_set_attributes(space
, *name
, MACH_PORT_IMPORTANCE_RECEIVER
, NULL
, 0);
2678 if (kr
!= KERN_SUCCESS
) {
2683 if (options
->flags
& MPO_DENAP_RECEIVER
) {
2684 kr
= mach_port_set_attributes(space
, *name
, MACH_PORT_DENAP_RECEIVER
, NULL
, 0);
2685 if (kr
!= KERN_SUCCESS
) {
2690 return KERN_SUCCESS
;
2693 /* Attempt to destroy port. If its already destroyed by some other thread, we're done */
2694 (void) mach_port_destruct(space
, *name
,
2695 (options
->flags
& MPO_INSERT_SEND_RIGHT
) ? -1 : 0, context
);
2700 * Routine: mach_port_destruct [kernel call]
2702 * Destroys a mach port with appropriate guard
2706 * KERN_SUCCESS The name is destroyed.
2707 * KERN_INVALID_TASK The space is null.
2708 * KERN_INVALID_TASK The space is dead.
2709 * KERN_INVALID_NAME The name doesn't denote a right.
2710 * KERN_INVALID_RIGHT The right isn't correct.
2711 * KERN_INVALID_VALUE The delta for send right is incorrect.
2712 * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch.
2713 * This also raises a EXC_GUARD exception.
2719 mach_port_name_t name
,
2720 mach_port_delta_t srdelta
,
2726 if (space
== IS_NULL
) {
2727 return KERN_INVALID_TASK
;
2730 if (!MACH_PORT_VALID(name
)) {
2731 return KERN_INVALID_NAME
;
2734 /* Remove reference for receive right */
2735 kr
= ipc_right_lookup_write(space
, name
, &entry
);
2736 if (kr
!= KERN_SUCCESS
) {
2737 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_INVALID_NAME
);
2740 /* space is write-locked and active */
2741 kr
= ipc_right_destruct(space
, name
, entry
, srdelta
, guard
); /* unlocks */
2747 * Routine: mach_port_guard [kernel call]
2749 * Guard a mach port with specified guard value.
2750 * The context field of the port is used as the guard.
2754 * KERN_SUCCESS The name is destroyed.
2755 * KERN_INVALID_TASK The space is null.
2756 * KERN_INVALID_TASK The space is dead.
2757 * KERN_INVALID_NAME The name doesn't denote a right.
2758 * KERN_INVALID_RIGHT The right isn't correct.
2759 * KERN_INVALID_ARGUMENT Port already contains a context/guard.
2764 mach_port_name_t name
,
2772 if (space
== IS_NULL
) {
2773 return KERN_INVALID_TASK
;
2776 if (!MACH_PORT_VALID(name
)) {
2777 return KERN_INVALID_NAME
;
2780 /* Guard can be applied only to receive rights */
2781 kr
= ipc_port_translate_receive(space
, name
, &port
);
2782 if (kr
!= KERN_SUCCESS
) {
2783 mach_port_guard_exception(name
, 0, 0,
2784 ((KERN_INVALID_NAME
== kr
) ?
2785 kGUARD_EXC_INVALID_NAME
:
2786 kGUARD_EXC_INVALID_RIGHT
));
2790 /* Port locked and active */
2795 kr
= mach_port_guard_locked(port
, guard
, flags
);
2798 if (KERN_INVALID_ARGUMENT
== kr
) {
2799 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_INVALID_ARGUMENT
);
2806 * Routine: mach_port_unguard [kernel call]
2808 * Unguard a mach port with specified guard value.
2812 * KERN_SUCCESS The name is destroyed.
2813 * KERN_INVALID_TASK The space is null.
2814 * KERN_INVALID_TASK The space is dead.
2815 * KERN_INVALID_NAME The name doesn't denote a right.
2816 * KERN_INVALID_RIGHT The right isn't correct.
2817 * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch.
2818 * This also raises a EXC_GUARD exception.
2823 mach_port_name_t name
,
2829 if (space
== IS_NULL
) {
2830 return KERN_INVALID_TASK
;
2833 if (!MACH_PORT_VALID(name
)) {
2834 return KERN_INVALID_NAME
;
2837 kr
= ipc_port_translate_receive(space
, name
, &port
);
2838 if (kr
!= KERN_SUCCESS
) {
2839 mach_port_guard_exception(name
, 0, 0,
2840 ((KERN_INVALID_NAME
== kr
) ?
2841 kGUARD_EXC_INVALID_NAME
:
2842 kGUARD_EXC_INVALID_RIGHT
));
2846 /* Port locked and active */
2847 kr
= mach_port_unguard_locked(port
, name
, guard
);
2854 * Routine: mach_port_guard_with_flags [kernel call]
2856 * Guard a mach port with specified guard value and guard flags.
2857 * The context field of the port is used as the guard.
2859 * Should hold receive right for that port
2861 * KERN_SUCCESS The name is destroyed.
2862 * KERN_INVALID_TASK The space is null.
2863 * KERN_INVALID_TASK The space is dead.
2864 * KERN_INVALID_NAME The name doesn't denote a right.
2865 * KERN_INVALID_RIGHT The right isn't correct.
2866 * KERN_INVALID_ARGUMENT Port already contains a context/guard.
2867 * KERN_INVALID_CAPABILITY Cannot set MPG_IMMOVABLE_RECEIVE flag for a port with
2868 * a movable port-destroyed notification port
2871 mach_port_guard_with_flags(
2873 mach_port_name_t name
,
2880 if (space
== IS_NULL
) {
2881 return KERN_INVALID_TASK
;
2884 if (!MACH_PORT_VALID(name
)) {
2885 return KERN_INVALID_NAME
;
2888 kr
= ipc_port_translate_receive(space
, name
, &port
);
2889 if (kr
!= KERN_SUCCESS
) {
2890 mach_port_guard_exception(name
, 0, 0,
2891 ((KERN_INVALID_NAME
== kr
) ?
2892 kGUARD_EXC_INVALID_NAME
:
2893 kGUARD_EXC_INVALID_RIGHT
));
2897 /* Port locked and active */
2898 kr
= mach_port_guard_locked(port
, guard
, flags
);
2901 if (KERN_INVALID_ARGUMENT
== kr
) {
2902 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_INVALID_ARGUMENT
);
2909 * Routine: mach_port_swap_guard [kernel call]
2913 * Port should already be guarded.
2915 * KERN_SUCCESS The name is destroyed.
2916 * KERN_INVALID_TASK The space is null.
2917 * KERN_INVALID_TASK The space is dead.
2918 * KERN_INVALID_NAME The name doesn't denote a right.
2919 * KERN_INVALID_RIGHT The right isn't correct.
2920 * KERN_INVALID_ARGUMENT Port doesn't contain a guard; is strictly guarded
2921 * or the old_guard doesnt match the context
2924 mach_port_swap_guard(
2926 mach_port_name_t name
,
2933 if (space
== IS_NULL
) {
2934 return KERN_INVALID_TASK
;
2937 if (!MACH_PORT_VALID(name
)) {
2938 return KERN_INVALID_NAME
;
2941 kr
= ipc_port_translate_receive(space
, name
, &port
);
2942 if (kr
!= KERN_SUCCESS
) {
2943 mach_port_guard_exception(name
, 0, 0,
2944 ((KERN_INVALID_NAME
== kr
) ?
2945 kGUARD_EXC_INVALID_NAME
:
2946 kGUARD_EXC_INVALID_RIGHT
));
2950 /* Port locked and active */
2951 if (!port
->ip_guarded
) {
2953 mach_port_guard_exception(name
, old_guard
, 0, kGUARD_EXC_UNGUARDED
);
2954 return KERN_INVALID_ARGUMENT
;
2957 if (port
->ip_strict_guard
) {
2958 uint64_t portguard
= port
->ip_context
;
2960 /* For strictly guarded ports, disallow overwriting context; Raise Exception */
2961 mach_port_guard_exception(name
, old_guard
, portguard
, kGUARD_EXC_SET_CONTEXT
);
2962 return KERN_INVALID_ARGUMENT
;
2965 if (port
->ip_context
!= old_guard
) {
2966 uint64_t portguard
= port
->ip_context
;
2968 mach_port_guard_exception(name
, old_guard
, portguard
, kGUARD_EXC_INCORRECT_GUARD
);
2969 return KERN_INVALID_ARGUMENT
;
2972 imq_lock(&port
->ip_messages
);
2973 port
->ip_context
= new_guard
;
2974 imq_unlock(&port
->ip_messages
);
2978 return KERN_SUCCESS
;