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>
76 #include <mach/port.h>
77 #include <mach/kern_return.h>
78 #include <mach/notify.h>
79 #include <mach/mach_param.h>
80 #include <mach/vm_param.h>
81 #include <mach/vm_prot.h>
82 #include <mach/vm_map.h>
83 #include <kern/task.h>
84 #include <kern/counters.h>
85 #include <kern/thread.h>
86 #include <kern/kalloc.h>
87 #include <mach/mach_port_server.h>
88 #include <vm/vm_map.h>
89 #include <vm/vm_kern.h>
90 #include <ipc/ipc_entry.h>
91 #include <ipc/ipc_space.h>
92 #include <ipc/ipc_object.h>
93 #include <ipc/ipc_notify.h>
94 #include <ipc/ipc_port.h>
95 #include <ipc/ipc_pset.h>
96 #include <ipc/ipc_right.h>
97 #include <ipc/ipc_kmsg.h>
98 #include <kern/misc_protos.h>
99 #include <security/mac_mach_internal.h>
101 #if IMPORTANCE_INHERITANCE
102 #include <ipc/ipc_importance.h>
106 * Forward declarations
108 void mach_port_names_helper(
109 ipc_port_timestamp_t timestamp
,
111 mach_port_name_t name
,
112 mach_port_name_t
*names
,
113 mach_port_type_t
*types
,
114 ipc_entry_num_t
*actualp
);
116 void mach_port_gst_helper(
118 ipc_entry_num_t maxnames
,
119 mach_port_name_t
*names
,
120 ipc_entry_num_t
*actualp
);
124 mach_port_guard_exception(
125 mach_port_name_t name
,
130 /* Needs port locked */
131 void mach_port_get_status_helper(
133 mach_port_status_t
*status
);
135 /* Zeroed template of qos flags */
137 static mach_port_qos_t qos_template
;
140 * Routine: mach_port_names_helper
142 * A helper function for mach_port_names.
145 * Space containing entry is [at least] read-locked.
149 mach_port_names_helper(
150 ipc_port_timestamp_t timestamp
,
152 mach_port_name_t name
,
153 mach_port_name_t
*names
,
154 mach_port_type_t
*types
,
155 ipc_entry_num_t
*actualp
)
157 ipc_entry_bits_t bits
;
158 ipc_port_request_index_t request
;
159 mach_port_type_t type
= 0;
160 ipc_entry_num_t actual
;
163 bits
= entry
->ie_bits
;
164 request
= entry
->ie_request
;
165 port
= (ipc_port_t
) entry
->ie_object
;
167 if (bits
& MACH_PORT_TYPE_RECEIVE
) {
168 assert(IP_VALID(port
));
170 if (request
!= IE_REQ_NONE
) {
172 assert(ip_active(port
));
173 type
|= ipc_port_request_type(port
, name
, request
);
177 } else if (bits
& MACH_PORT_TYPE_SEND_RIGHTS
) {
178 mach_port_type_t reqtype
;
180 assert(IP_VALID(port
));
183 reqtype
= (request
!= IE_REQ_NONE
) ?
184 ipc_port_request_type(port
, name
, request
) : 0;
187 * If the port is alive, or was alive when the mach_port_names
188 * started, then return that fact. Otherwise, pretend we found
191 if (ip_active(port
) || IP_TIMESTAMP_ORDER(timestamp
, port
->ip_timestamp
)) {
194 bits
&= ~(IE_BITS_TYPE_MASK
);
195 bits
|= MACH_PORT_TYPE_DEAD_NAME
;
196 /* account for additional reference for dead-name notification */
203 type
|= IE_BITS_TYPE(bits
);
206 names
[actual
] = name
;
207 types
[actual
] = type
;
212 * Routine: mach_port_names [kernel call]
214 * Retrieves a list of the rights present in the space,
215 * along with type information. (Same as returned
216 * by mach_port_type.) The names are returned in
217 * no particular order, but they (and the type info)
218 * are an accurate snapshot of the space.
222 * KERN_SUCCESS Arrays of names and types returned.
223 * KERN_INVALID_TASK The space is null.
224 * KERN_INVALID_TASK The space is dead.
225 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
231 mach_port_name_t
**namesp
,
232 mach_msg_type_number_t
*namesCnt
,
233 mach_port_type_t
**typesp
,
234 mach_msg_type_number_t
*typesCnt
)
237 ipc_entry_num_t tsize
;
238 mach_port_index_t index
;
239 ipc_entry_num_t actual
; /* this many names */
240 ipc_port_timestamp_t timestamp
; /* logical time of this operation */
241 mach_port_name_t
*names
;
242 mach_port_type_t
*types
;
245 vm_size_t size
; /* size of allocated memory */
246 vm_offset_t addr1
; /* allocated memory, for names */
247 vm_offset_t addr2
; /* allocated memory, for types */
248 vm_map_copy_t memory1
; /* copied-in memory, for names */
249 vm_map_copy_t memory2
; /* copied-in memory, for types */
251 /* safe simplifying assumption */
252 assert_static(sizeof(mach_port_name_t
) == sizeof(mach_port_type_t
));
254 if (space
== IS_NULL
)
255 return KERN_INVALID_TASK
;
260 ipc_entry_num_t bound
;
261 vm_size_t size_needed
;
264 if (!is_active(space
)) {
265 is_read_unlock(space
);
267 kmem_free(ipc_kernel_map
, addr1
, size
);
268 kmem_free(ipc_kernel_map
, addr2
, size
);
270 return KERN_INVALID_TASK
;
273 /* upper bound on number of names in the space */
274 bound
= space
->is_table_size
;
275 size_needed
= vm_map_round_page(
276 (bound
* sizeof(mach_port_name_t
)),
277 VM_MAP_PAGE_MASK(ipc_kernel_map
));
279 if (size_needed
<= size
)
282 is_read_unlock(space
);
285 kmem_free(ipc_kernel_map
, addr1
, size
);
286 kmem_free(ipc_kernel_map
, addr2
, size
);
290 kr
= vm_allocate(ipc_kernel_map
, &addr1
, size
, VM_FLAGS_ANYWHERE
);
291 if (kr
!= KERN_SUCCESS
)
292 return KERN_RESOURCE_SHORTAGE
;
294 kr
= vm_allocate(ipc_kernel_map
, &addr2
, size
, VM_FLAGS_ANYWHERE
);
295 if (kr
!= KERN_SUCCESS
) {
296 kmem_free(ipc_kernel_map
, addr1
, size
);
297 return KERN_RESOURCE_SHORTAGE
;
300 /* can't fault while we hold locks */
304 vm_map_trunc_page(addr1
,
305 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
306 vm_map_round_page(addr1
+ size
,
307 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
308 VM_PROT_READ
|VM_PROT_WRITE
,
310 if (kr
!= KERN_SUCCESS
) {
311 kmem_free(ipc_kernel_map
, addr1
, size
);
312 kmem_free(ipc_kernel_map
, addr2
, size
);
313 return KERN_RESOURCE_SHORTAGE
;
318 vm_map_trunc_page(addr2
,
319 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
320 vm_map_round_page(addr2
+ size
,
321 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
322 VM_PROT_READ
|VM_PROT_WRITE
,
324 if (kr
!= KERN_SUCCESS
) {
325 kmem_free(ipc_kernel_map
, addr1
, size
);
326 kmem_free(ipc_kernel_map
, addr2
, size
);
327 return KERN_RESOURCE_SHORTAGE
;
331 /* space is read-locked and active */
333 names
= (mach_port_name_t
*) addr1
;
334 types
= (mach_port_type_t
*) addr2
;
337 timestamp
= ipc_port_timestamp();
339 table
= space
->is_table
;
340 tsize
= space
->is_table_size
;
342 for (index
= 0; index
< tsize
; index
++) {
343 ipc_entry_t entry
= &table
[index
];
344 ipc_entry_bits_t bits
= entry
->ie_bits
;
346 if (IE_BITS_TYPE(bits
) != MACH_PORT_TYPE_NONE
) {
347 mach_port_name_t name
;
349 name
= MACH_PORT_MAKE(index
, IE_BITS_GEN(bits
));
350 mach_port_names_helper(timestamp
, entry
, name
, names
,
355 is_read_unlock(space
);
358 memory1
= VM_MAP_COPY_NULL
;
359 memory2
= VM_MAP_COPY_NULL
;
362 kmem_free(ipc_kernel_map
, addr1
, size
);
363 kmem_free(ipc_kernel_map
, addr2
, size
);
367 vm_size_t vm_size_used
;
369 size_used
= actual
* sizeof(mach_port_name_t
);
371 vm_map_round_page(size_used
,
372 VM_MAP_PAGE_MASK(ipc_kernel_map
));
375 * Make used memory pageable and get it into
376 * copied-in form. Free any unused memory.
381 vm_map_trunc_page(addr1
,
382 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
383 vm_map_round_page(addr1
+ vm_size_used
,
384 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
386 assert(kr
== KERN_SUCCESS
);
390 vm_map_trunc_page(addr2
,
391 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
392 vm_map_round_page(addr2
+ vm_size_used
,
393 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
395 assert(kr
== KERN_SUCCESS
);
397 kr
= vm_map_copyin(ipc_kernel_map
, (vm_map_address_t
)addr1
,
398 (vm_map_size_t
)size_used
, TRUE
, &memory1
);
399 assert(kr
== KERN_SUCCESS
);
401 kr
= vm_map_copyin(ipc_kernel_map
, (vm_map_address_t
)addr2
,
402 (vm_map_size_t
)size_used
, TRUE
, &memory2
);
403 assert(kr
== KERN_SUCCESS
);
405 if (vm_size_used
!= size
) {
406 kmem_free(ipc_kernel_map
,
407 addr1
+ vm_size_used
, size
- vm_size_used
);
408 kmem_free(ipc_kernel_map
,
409 addr2
+ vm_size_used
, size
- vm_size_used
);
413 *namesp
= (mach_port_name_t
*) memory1
;
415 *typesp
= (mach_port_type_t
*) memory2
;
421 * Routine: mach_port_type [kernel call]
423 * Retrieves the type of a right in the space.
424 * The type is a bitwise combination of one or more
425 * of the following type bits:
426 * MACH_PORT_TYPE_SEND
427 * MACH_PORT_TYPE_RECEIVE
428 * MACH_PORT_TYPE_SEND_ONCE
429 * MACH_PORT_TYPE_PORT_SET
430 * MACH_PORT_TYPE_DEAD_NAME
431 * In addition, the following pseudo-type bits may be present:
432 * MACH_PORT_TYPE_DNREQUEST
433 * A dead-name notification is requested.
437 * KERN_SUCCESS Type is returned.
438 * KERN_INVALID_TASK The space is null.
439 * KERN_INVALID_TASK The space is dead.
440 * KERN_INVALID_NAME The name doesn't denote a right.
446 mach_port_name_t name
,
447 mach_port_type_t
*typep
)
449 mach_port_urefs_t urefs
;
453 if (space
== IS_NULL
)
454 return KERN_INVALID_TASK
;
456 if (name
== MACH_PORT_NULL
)
457 return KERN_INVALID_NAME
;
459 if (name
== MACH_PORT_DEAD
) {
460 *typep
= MACH_PORT_TYPE_DEAD_NAME
;
464 kr
= ipc_right_lookup_write(space
, name
, &entry
);
465 if (kr
!= KERN_SUCCESS
)
468 /* space is write-locked and active */
469 kr
= ipc_right_info(space
, name
, entry
, typep
, &urefs
);
470 /* space is unlocked */
473 /* JMM - workaround rdar://problem/9121297 (CF being too picky on these bits). */
474 *typep
&= ~(MACH_PORT_TYPE_SPREQUEST
| MACH_PORT_TYPE_SPREQUEST_DELAYED
);
481 * Routine: mach_port_rename [kernel call]
483 * Changes the name denoting a right,
484 * from oname to nname.
488 * KERN_SUCCESS The right is renamed.
489 * KERN_INVALID_TASK The space is null.
490 * KERN_INVALID_TASK The space is dead.
491 * KERN_INVALID_NAME The oname doesn't denote a right.
492 * KERN_INVALID_VALUE The nname isn't a legal name.
493 * KERN_NAME_EXISTS The nname already denotes a right.
494 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
496 * This interface is obsolete and always returns
497 * KERN_NOT_SUPPORTED.
502 __unused ipc_space_t space
,
503 __unused mach_port_name_t oname
,
504 __unused mach_port_name_t nname
)
506 return KERN_NOT_SUPPORTED
;
511 * Routine: mach_port_allocate_name [kernel call]
513 * Allocates a right in a space, using a specific name
514 * for the new right. Possible rights:
515 * MACH_PORT_RIGHT_RECEIVE
516 * MACH_PORT_RIGHT_PORT_SET
517 * MACH_PORT_RIGHT_DEAD_NAME
519 * A new port (allocated with MACH_PORT_RIGHT_RECEIVE)
520 * has no extant send or send-once rights and no queued
521 * messages. Its queue limit is MACH_PORT_QLIMIT_DEFAULT
522 * and its make-send count is 0. It is not a member of
523 * a port set. It has no registered no-senders or
524 * port-destroyed notification requests.
526 * A new port set has no members.
528 * A new dead name has one user reference.
532 * KERN_SUCCESS The right is allocated.
533 * KERN_INVALID_TASK The space is null.
534 * KERN_INVALID_TASK The space is dead.
535 * KERN_INVALID_VALUE The name isn't a legal name.
536 * KERN_INVALID_VALUE "right" isn't a legal kind of right.
537 * KERN_NAME_EXISTS The name already denotes a right.
538 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
540 * Restrictions on name allocation: NT bits are reserved by kernel,
541 * must be set on any chosen name. Can't do this at all in kernel
546 mach_port_allocate_name(
548 mach_port_right_t right
,
549 mach_port_name_t name
)
552 mach_port_qos_t qos
= qos_template
;
556 if (!MACH_PORT_VALID(name
))
557 return KERN_INVALID_VALUE
;
559 kr
= mach_port_allocate_full (space
, right
, MACH_PORT_NULL
,
565 * Routine: mach_port_allocate [kernel call]
567 * Allocates a right in a space. Like mach_port_allocate_name,
568 * except that the implementation picks a name for the right.
569 * The name may be any legal name in the space that doesn't
570 * currently denote a right.
574 * KERN_SUCCESS The right is allocated.
575 * KERN_INVALID_TASK The space is null.
576 * KERN_INVALID_TASK The space is dead.
577 * KERN_INVALID_VALUE "right" isn't a legal kind of right.
578 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
579 * KERN_NO_SPACE No room in space for another right.
585 mach_port_right_t right
,
586 mach_port_name_t
*namep
)
589 mach_port_qos_t qos
= qos_template
;
591 kr
= mach_port_allocate_full (space
, right
, MACH_PORT_NULL
,
597 * Routine: mach_port_allocate_qos [kernel call]
599 * Allocates a right, with qos options, in a space. Like
600 * mach_port_allocate_name, except that the implementation
601 * picks a name for the right. The name may be any legal name
602 * in the space that doesn't currently denote a right.
606 * KERN_SUCCESS The right is allocated.
607 * KERN_INVALID_TASK The space is null.
608 * KERN_INVALID_TASK The space is dead.
609 * KERN_INVALID_VALUE "right" isn't a legal kind of right.
610 * KERN_INVALID_ARGUMENT The qos request was invalid.
611 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
612 * KERN_NO_SPACE No room in space for another right.
616 mach_port_allocate_qos(
618 mach_port_right_t right
,
619 mach_port_qos_t
*qosp
,
620 mach_port_name_t
*namep
)
625 return KERN_INVALID_ARGUMENT
;
626 kr
= mach_port_allocate_full (space
, right
, MACH_PORT_NULL
,
632 * Routine: mach_port_allocate_full [kernel call]
634 * Allocates a right in a space. Supports all of the
635 * special cases, such as specifying a subsystem,
636 * a specific name, a real-time port, etc.
637 * The name may be any legal name in the space that doesn't
638 * currently denote a right.
642 * KERN_SUCCESS The right is allocated.
643 * KERN_INVALID_TASK The space is null.
644 * KERN_INVALID_TASK The space is dead.
645 * KERN_INVALID_VALUE "right" isn't a legal kind of right.
646 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
647 * KERN_NO_SPACE No room in space for another right.
651 mach_port_allocate_full(
653 mach_port_right_t right
,
655 mach_port_qos_t
*qosp
,
656 mach_port_name_t
*namep
)
658 ipc_kmsg_t kmsg
= IKM_NULL
;
661 if (space
== IS_NULL
)
662 return (KERN_INVALID_TASK
);
664 if (proto
!= MACH_PORT_NULL
)
665 return (KERN_INVALID_VALUE
);
668 if (!MACH_PORT_VALID (*namep
))
669 return (KERN_INVALID_VALUE
);
672 if (qosp
->prealloc
) {
673 if (qosp
->len
> MACH_MSG_SIZE_MAX
- MAX_TRAILER_SIZE
) {
674 return KERN_RESOURCE_SHORTAGE
;
676 mach_msg_size_t size
= qosp
->len
+ MAX_TRAILER_SIZE
;
678 if (right
!= MACH_PORT_RIGHT_RECEIVE
)
679 return (KERN_INVALID_VALUE
);
681 kmsg
= (ipc_kmsg_t
)ipc_kmsg_prealloc(size
);
682 if (kmsg
== IKM_NULL
)
683 return (KERN_RESOURCE_SHORTAGE
);
688 case MACH_PORT_RIGHT_RECEIVE
:
693 kr
= ipc_port_alloc_name(space
, *namep
, &port
);
695 kr
= ipc_port_alloc(space
, namep
, &port
);
696 if (kr
== KERN_SUCCESS
) {
697 if (kmsg
!= IKM_NULL
)
698 ipc_kmsg_set_prealloc(kmsg
, port
);
702 } else if (kmsg
!= IKM_NULL
)
707 case MACH_PORT_RIGHT_PORT_SET
:
712 kr
= ipc_pset_alloc_name(space
, *namep
, &pset
);
714 kr
= ipc_pset_alloc(space
, namep
, &pset
);
715 if (kr
== KERN_SUCCESS
)
720 case MACH_PORT_RIGHT_DEAD_NAME
:
721 kr
= ipc_object_alloc_dead(space
, namep
);
725 kr
= KERN_INVALID_VALUE
;
733 * Routine: mach_port_destroy [kernel call]
735 * Cleans up and destroys all rights denoted by a name
736 * in a space. The destruction of a receive right
737 * destroys the port, unless a port-destroyed request
738 * has been made for it; the destruction of a port-set right
739 * destroys the port set.
743 * KERN_SUCCESS The name is destroyed.
744 * KERN_INVALID_TASK The space is null.
745 * KERN_INVALID_TASK The space is dead.
746 * KERN_INVALID_NAME The name doesn't denote a right.
752 mach_port_name_t name
)
757 if (space
== IS_NULL
)
758 return KERN_INVALID_TASK
;
760 if (!MACH_PORT_VALID(name
))
763 kr
= ipc_right_lookup_write(space
, name
, &entry
);
764 if (kr
!= KERN_SUCCESS
)
766 /* space is write-locked and active */
768 kr
= ipc_right_destroy(space
, name
, entry
, TRUE
, 0); /* unlocks space */
773 * Routine: mach_port_deallocate [kernel call]
775 * Deallocates a user reference from a send right,
776 * send-once right, or a dead-name right. May
777 * deallocate the right, if this is the last uref,
778 * and destroy the name, if it doesn't denote
783 * KERN_SUCCESS The uref is deallocated.
784 * KERN_INVALID_TASK The space is null.
785 * KERN_INVALID_TASK The space is dead.
786 * KERN_INVALID_NAME The name doesn't denote a right.
787 * KERN_INVALID_RIGHT The right isn't correct.
791 mach_port_deallocate(
793 mach_port_name_t name
)
798 if (space
== IS_NULL
)
799 return KERN_INVALID_TASK
;
801 if (!MACH_PORT_VALID(name
))
804 kr
= ipc_right_lookup_write(space
, name
, &entry
);
805 if (kr
!= KERN_SUCCESS
)
807 /* space is write-locked */
809 kr
= ipc_right_dealloc(space
, name
, entry
); /* unlocks space */
814 * Routine: mach_port_get_refs [kernel call]
816 * Retrieves the number of user references held by a right.
817 * Receive rights, port-set rights, and send-once rights
818 * always have one user reference. Returns zero if the
819 * name denotes a right, but not the queried right.
823 * KERN_SUCCESS Number of urefs returned.
824 * KERN_INVALID_TASK The space is null.
825 * KERN_INVALID_TASK The space is dead.
826 * KERN_INVALID_VALUE "right" isn't a legal value.
827 * KERN_INVALID_NAME The name doesn't denote a right.
833 mach_port_name_t name
,
834 mach_port_right_t right
,
835 mach_port_urefs_t
*urefsp
)
837 mach_port_type_t type
;
838 mach_port_urefs_t urefs
;
842 if (space
== IS_NULL
)
843 return KERN_INVALID_TASK
;
845 if (right
>= MACH_PORT_RIGHT_NUMBER
)
846 return KERN_INVALID_VALUE
;
848 if (!MACH_PORT_VALID(name
)) {
849 if (right
== MACH_PORT_RIGHT_SEND
||
850 right
== MACH_PORT_RIGHT_SEND_ONCE
) {
854 return KERN_INVALID_NAME
;
857 kr
= ipc_right_lookup_write(space
, name
, &entry
);
858 if (kr
!= KERN_SUCCESS
)
861 /* space is write-locked and active */
862 kr
= ipc_right_info(space
, name
, entry
, &type
, &urefs
);
863 /* space is unlocked */
865 if (kr
!= KERN_SUCCESS
)
868 if (type
& MACH_PORT_TYPE(right
))
870 case MACH_PORT_RIGHT_SEND_ONCE
:
874 case MACH_PORT_RIGHT_PORT_SET
:
875 case MACH_PORT_RIGHT_RECEIVE
:
879 case MACH_PORT_RIGHT_DEAD_NAME
:
880 case MACH_PORT_RIGHT_SEND
:
886 panic("mach_port_get_refs: strange rights");
895 * Routine: mach_port_mod_refs
897 * Modifies the number of user references held by a right.
898 * The resulting number of user references must be non-negative.
899 * If it is zero, the right is deallocated. If the name
900 * doesn't denote other rights, it is destroyed.
904 * KERN_SUCCESS Modified number of urefs.
905 * KERN_INVALID_TASK The space is null.
906 * KERN_INVALID_TASK The space is dead.
907 * KERN_INVALID_VALUE "right" isn't a legal value.
908 * KERN_INVALID_NAME The name doesn't denote a right.
909 * KERN_INVALID_RIGHT Name doesn't denote specified right.
910 * KERN_INVALID_VALUE Impossible modification to urefs.
911 * KERN_UREFS_OVERFLOW Urefs would overflow.
917 mach_port_name_t name
,
918 mach_port_right_t right
,
919 mach_port_delta_t delta
)
924 if (space
== IS_NULL
)
925 return KERN_INVALID_TASK
;
927 if (right
>= MACH_PORT_RIGHT_NUMBER
)
928 return KERN_INVALID_VALUE
;
930 if (!MACH_PORT_VALID(name
)) {
931 if (right
== MACH_PORT_RIGHT_SEND
||
932 right
== MACH_PORT_RIGHT_SEND_ONCE
)
934 return KERN_INVALID_NAME
;
937 kr
= ipc_right_lookup_write(space
, name
, &entry
);
938 if (kr
!= KERN_SUCCESS
)
940 /* space is write-locked and active */
942 kr
= ipc_right_delta(space
, name
, entry
, right
, delta
); /* unlocks */
948 * Routine: mach_port_peek [kernel call]
950 * Peek at the message queue for the specified receive
951 * right and return info about a message in the queue.
953 * On input, seqnop points to a sequence number value
954 * to match the message being peeked. If zero is specified
955 * as the seqno, the first message in the queue will be
958 * Only the following trailer types are currently supported:
959 * MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)
961 * or'ed with one of these element types:
962 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_NULL)
963 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SEQNO)
964 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER)
965 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT)
967 * On input, the value pointed to by trailer_sizep must be
968 * large enough to hold the requested trailer size.
970 * The message sequence number, id, size, requested trailer info
971 * and requested trailer size are returned in their respective
972 * output parameters upon success.
977 * KERN_SUCCESS Matching message found, out parameters set.
978 * KERN_INVALID_TASK The space is null or dead.
979 * KERN_INVALID_NAME The name doesn't denote a right.
980 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
981 * KERN_INVALID_VALUE The input parameter values are out of bounds.
982 * KERN_FAILURE The requested message was not found.
988 mach_port_name_t name
,
989 mach_msg_trailer_type_t trailer_type
,
990 mach_port_seqno_t
*seqnop
,
991 mach_msg_size_t
*msg_sizep
,
992 mach_msg_id_t
*msg_idp
,
993 mach_msg_trailer_info_t trailer_infop
,
994 mach_msg_type_number_t
*trailer_sizep
)
999 mach_msg_max_trailer_t max_trailer
;
1001 if (space
== IS_NULL
)
1002 return KERN_INVALID_TASK
;
1004 if (!MACH_PORT_VALID(name
))
1005 return KERN_INVALID_RIGHT
;
1008 * We don't allow anything greater than the audit trailer - to avoid
1009 * leaking the context pointer and to avoid variable-sized context issues.
1011 if (GET_RCV_ELEMENTS(trailer_type
) > MACH_RCV_TRAILER_AUDIT
||
1012 REQUESTED_TRAILER_SIZE(TRUE
, trailer_type
) > *trailer_sizep
)
1013 return KERN_INVALID_VALUE
;
1015 *trailer_sizep
= REQUESTED_TRAILER_SIZE(TRUE
, trailer_type
);
1017 kr
= ipc_port_translate_receive(space
, name
, &port
);
1018 if (kr
!= KERN_SUCCESS
)
1021 /* Port locked and active */
1023 found
= ipc_mqueue_peek(&port
->ip_messages
, seqnop
,
1024 msg_sizep
, msg_idp
, &max_trailer
);
1028 return KERN_FAILURE
;
1030 max_trailer
.msgh_seqno
= *seqnop
;
1031 memcpy(trailer_infop
, &max_trailer
, *trailer_sizep
);
1033 return KERN_SUCCESS
;
1037 * Routine: mach_port_set_mscount [kernel call]
1039 * Changes a receive right's make-send count.
1043 * KERN_SUCCESS Set make-send count.
1044 * KERN_INVALID_TASK The space is null.
1045 * KERN_INVALID_TASK The space is dead.
1046 * KERN_INVALID_NAME The name doesn't denote a right.
1047 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1051 mach_port_set_mscount(
1053 mach_port_name_t name
,
1054 mach_port_mscount_t mscount
)
1059 if (space
== IS_NULL
)
1060 return KERN_INVALID_TASK
;
1062 if (!MACH_PORT_VALID(name
))
1063 return KERN_INVALID_RIGHT
;
1065 kr
= ipc_port_translate_receive(space
, name
, &port
);
1066 if (kr
!= KERN_SUCCESS
)
1068 /* port is locked and active */
1070 ipc_port_set_mscount(port
, mscount
);
1073 return KERN_SUCCESS
;
1077 * Routine: mach_port_set_seqno [kernel call]
1079 * Changes a receive right's sequence number.
1083 * KERN_SUCCESS Set sequence number.
1084 * KERN_INVALID_TASK The space is null.
1085 * KERN_INVALID_TASK The space is dead.
1086 * KERN_INVALID_NAME The name doesn't denote a right.
1087 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1091 mach_port_set_seqno(
1093 mach_port_name_t name
,
1094 mach_port_seqno_t seqno
)
1099 if (space
== IS_NULL
)
1100 return KERN_INVALID_TASK
;
1102 if (!MACH_PORT_VALID(name
))
1103 return KERN_INVALID_RIGHT
;
1105 kr
= ipc_port_translate_receive(space
, name
, &port
);
1106 if (kr
!= KERN_SUCCESS
)
1108 /* port is locked and active */
1110 ipc_mqueue_set_seqno(&port
->ip_messages
, seqno
);
1113 return KERN_SUCCESS
;
1117 * Routine: mach_port_get_context [kernel call]
1119 * Returns a receive right's context pointer.
1123 * KERN_SUCCESS Set context pointer.
1124 * KERN_INVALID_TASK The space is null.
1125 * KERN_INVALID_TASK The space is dead.
1126 * KERN_INVALID_NAME The name doesn't denote a right.
1127 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1131 mach_port_get_context(
1133 mach_port_name_t name
,
1134 mach_vm_address_t
*context
)
1139 if (space
== IS_NULL
)
1140 return KERN_INVALID_TASK
;
1142 if (!MACH_PORT_VALID(name
))
1143 return KERN_INVALID_RIGHT
;
1145 kr
= ipc_port_translate_receive(space
, name
, &port
);
1146 if (kr
!= KERN_SUCCESS
)
1149 /* Port locked and active */
1151 /* For strictly guarded ports, return empty context (which acts as guard) */
1152 if (port
->ip_strict_guard
)
1155 *context
= port
->ip_context
;
1158 return KERN_SUCCESS
;
1163 * Routine: mach_port_set_context [kernel call]
1165 * Changes a receive right's context pointer.
1169 * KERN_SUCCESS Set context pointer.
1170 * KERN_INVALID_TASK The space is null.
1171 * KERN_INVALID_TASK The space is dead.
1172 * KERN_INVALID_NAME The name doesn't denote a right.
1173 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1177 mach_port_set_context(
1179 mach_port_name_t name
,
1180 mach_vm_address_t context
)
1185 if (space
== IS_NULL
)
1186 return KERN_INVALID_TASK
;
1188 if (!MACH_PORT_VALID(name
))
1189 return KERN_INVALID_RIGHT
;
1191 kr
= ipc_port_translate_receive(space
, name
, &port
);
1192 if (kr
!= KERN_SUCCESS
)
1195 /* port is locked and active */
1196 if(port
->ip_strict_guard
) {
1197 uint64_t portguard
= port
->ip_context
;
1199 /* For strictly guarded ports, disallow overwriting context; Raise Exception */
1200 mach_port_guard_exception(name
, context
, portguard
, kGUARD_EXC_SET_CONTEXT
);
1201 return KERN_INVALID_ARGUMENT
;
1204 port
->ip_context
= context
;
1207 return KERN_SUCCESS
;
1212 * Routine: mach_port_get_set_status [kernel call]
1214 * Retrieves a list of members in a port set.
1215 * Returns the space's name for each receive right member.
1219 * KERN_SUCCESS Retrieved list of members.
1220 * KERN_INVALID_TASK The space is null.
1221 * KERN_INVALID_TASK The space is dead.
1222 * KERN_INVALID_NAME The name doesn't denote a right.
1223 * KERN_INVALID_RIGHT Name doesn't denote a port set.
1224 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1228 mach_port_get_set_status(
1230 mach_port_name_t name
,
1231 mach_port_name_t
**members
,
1232 mach_msg_type_number_t
*membersCnt
)
1234 ipc_entry_num_t actual
; /* this many members */
1235 ipc_entry_num_t maxnames
; /* space for this many members */
1238 vm_size_t size
; /* size of allocated memory */
1239 vm_offset_t addr
; /* allocated memory */
1240 vm_map_copy_t memory
; /* copied-in memory */
1242 if (space
== IS_NULL
)
1243 return KERN_INVALID_TASK
;
1245 if (!MACH_PORT_VALID(name
))
1246 return KERN_INVALID_RIGHT
;
1248 size
= VM_MAP_PAGE_SIZE(ipc_kernel_map
); /* initial guess */
1251 mach_port_name_t
*names
;
1255 kr
= vm_allocate(ipc_kernel_map
, &addr
, size
, VM_FLAGS_ANYWHERE
);
1256 if (kr
!= KERN_SUCCESS
)
1257 return KERN_RESOURCE_SHORTAGE
;
1259 /* can't fault while we hold locks */
1261 kr
= vm_map_wire(ipc_kernel_map
, addr
, addr
+ size
,
1262 VM_PROT_READ
|VM_PROT_WRITE
, FALSE
);
1263 assert(kr
== KERN_SUCCESS
);
1265 kr
= ipc_object_translate(space
, name
, MACH_PORT_RIGHT_PORT_SET
, &psobj
);
1266 if (kr
!= KERN_SUCCESS
) {
1267 kmem_free(ipc_kernel_map
, addr
, size
);
1271 /* just use a portset reference from here on out */
1272 pset
= (ipc_pset_t
) psobj
;
1273 ips_reference(pset
);
1276 names
= (mach_port_name_t
*) addr
;
1277 maxnames
= (ipc_entry_num_t
)(size
/ sizeof(mach_port_name_t
));
1279 ipc_mqueue_set_gather_member_names(&pset
->ips_messages
, maxnames
, names
, &actual
);
1281 /* release the portset reference */
1284 if (actual
<= maxnames
)
1287 /* didn't have enough memory; allocate more */
1288 kmem_free(ipc_kernel_map
, addr
, size
);
1289 size
= vm_map_round_page(
1290 (actual
* sizeof(mach_port_name_t
)),
1291 VM_MAP_PAGE_MASK(ipc_kernel_map
)) +
1292 VM_MAP_PAGE_SIZE(ipc_kernel_map
);
1296 memory
= VM_MAP_COPY_NULL
;
1298 kmem_free(ipc_kernel_map
, addr
, size
);
1300 vm_size_t size_used
;
1301 vm_size_t vm_size_used
;
1303 size_used
= actual
* sizeof(mach_port_name_t
);
1304 vm_size_used
= vm_map_round_page(
1306 VM_MAP_PAGE_MASK(ipc_kernel_map
));
1309 * Make used memory pageable and get it into
1310 * copied-in form. Free any unused memory.
1315 vm_map_trunc_page(addr
,
1316 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
1317 vm_map_round_page(addr
+ vm_size_used
,
1318 VM_MAP_PAGE_MASK(ipc_kernel_map
)),
1320 assert(kr
== KERN_SUCCESS
);
1322 kr
= vm_map_copyin(ipc_kernel_map
, (vm_map_address_t
)addr
,
1323 (vm_map_size_t
)size_used
, TRUE
, &memory
);
1324 assert(kr
== KERN_SUCCESS
);
1326 if (vm_size_used
!= size
)
1327 kmem_free(ipc_kernel_map
,
1328 addr
+ vm_size_used
, size
- vm_size_used
);
1331 *members
= (mach_port_name_t
*) memory
;
1332 *membersCnt
= actual
;
1333 return KERN_SUCCESS
;
1337 * Routine: mach_port_move_member [kernel call]
1339 * If after is MACH_PORT_NULL, removes member
1340 * from the port set it is in. Otherwise, adds
1341 * member to after, removing it from any set
1342 * it might already be in.
1346 * KERN_SUCCESS Moved the port.
1347 * KERN_INVALID_TASK The space is null.
1348 * KERN_INVALID_TASK The space is dead.
1349 * KERN_INVALID_NAME Member didn't denote a right.
1350 * KERN_INVALID_RIGHT Member didn't denote a receive right.
1351 * KERN_INVALID_NAME After didn't denote a right.
1352 * KERN_INVALID_RIGHT After didn't denote a port set right.
1354 * After is MACH_PORT_NULL and Member isn't in a port set.
1358 mach_port_move_member(
1360 mach_port_name_t member
,
1361 mach_port_name_t after
)
1367 wait_queue_link_t wql
;
1368 queue_head_t links_data
;
1369 queue_t links
= &links_data
;
1371 if (space
== IS_NULL
)
1372 return KERN_INVALID_TASK
;
1374 if (!MACH_PORT_VALID(member
))
1375 return KERN_INVALID_RIGHT
;
1377 if (after
== MACH_PORT_DEAD
)
1378 return KERN_INVALID_RIGHT
;
1379 else if (after
== MACH_PORT_NULL
)
1380 wql
= WAIT_QUEUE_LINK_NULL
;
1382 wql
= wait_queue_link_allocate();
1386 kr
= ipc_right_lookup_read(space
, member
, &entry
);
1387 if (kr
!= KERN_SUCCESS
)
1389 /* space is read-locked and active */
1391 if ((entry
->ie_bits
& MACH_PORT_TYPE_RECEIVE
) == 0) {
1392 is_read_unlock(space
);
1393 kr
= KERN_INVALID_RIGHT
;
1397 port
= (ipc_port_t
) entry
->ie_object
;
1398 assert(port
!= IP_NULL
);
1400 if (after
== MACH_PORT_NULL
)
1403 entry
= ipc_entry_lookup(space
, after
);
1404 if (entry
== IE_NULL
) {
1405 is_read_unlock(space
);
1406 kr
= KERN_INVALID_NAME
;
1410 if ((entry
->ie_bits
& MACH_PORT_TYPE_PORT_SET
) == 0) {
1411 is_read_unlock(space
);
1412 kr
= KERN_INVALID_RIGHT
;
1416 nset
= (ipc_pset_t
) entry
->ie_object
;
1417 assert(nset
!= IPS_NULL
);
1420 ipc_pset_remove_from_all(port
, links
);
1422 if (nset
!= IPS_NULL
) {
1424 kr
= ipc_pset_add(nset
, port
, wql
);
1428 is_read_unlock(space
);
1431 if (kr
!= KERN_SUCCESS
&& wql
!= WAIT_QUEUE_LINK_NULL
)
1432 wait_queue_link_free(wql
);
1433 while(!queue_empty(links
)) {
1434 wql
= (wait_queue_link_t
) dequeue(links
);
1435 wait_queue_link_free(wql
);
1442 * Routine: mach_port_request_notification [kernel call]
1444 * Requests a notification. The caller supplies
1445 * a send-once right for the notification to use,
1446 * and the call returns the previously registered
1447 * send-once right, if any. Possible types:
1449 * MACH_NOTIFY_PORT_DESTROYED
1450 * Requests a port-destroyed notification
1451 * for a receive right. Sync should be zero.
1452 * MACH_NOTIFY_NO_SENDERS
1453 * Requests a no-senders notification for a
1454 * receive right. If there are currently no
1455 * senders, sync is less than or equal to the
1456 * current make-send count, and a send-once right
1457 * is supplied, then an immediate no-senders
1458 * notification is generated.
1459 * MACH_NOTIFY_DEAD_NAME
1460 * Requests a dead-name notification for a send
1461 * or receive right. If the name is already a
1462 * dead name, sync is non-zero, and a send-once
1463 * right is supplied, then an immediate dead-name
1464 * notification is generated.
1468 * KERN_SUCCESS Requested a notification.
1469 * KERN_INVALID_TASK The space is null.
1470 * KERN_INVALID_TASK The space is dead.
1471 * KERN_INVALID_VALUE Bad id value.
1472 * KERN_INVALID_NAME Name doesn't denote a right.
1473 * KERN_INVALID_RIGHT Name doesn't denote appropriate right.
1474 * KERN_INVALID_CAPABILITY The notify port is dead.
1475 * MACH_NOTIFY_PORT_DESTROYED:
1476 * KERN_INVALID_VALUE Sync isn't zero.
1477 * MACH_NOTIFY_DEAD_NAME:
1478 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1479 * KERN_INVALID_ARGUMENT Name denotes dead name, but
1480 * sync is zero or notify is IP_NULL.
1481 * KERN_UREFS_OVERFLOW Name denotes dead name, but
1482 * generating immediate notif. would overflow urefs.
1486 mach_port_request_notification(
1488 mach_port_name_t name
,
1490 mach_port_mscount_t sync
,
1492 ipc_port_t
*previousp
)
1496 if (space
== IS_NULL
)
1497 return KERN_INVALID_TASK
;
1499 if (notify
== IP_DEAD
)
1500 return KERN_INVALID_CAPABILITY
;
1504 * Requesting notifications on RPC ports is an error.
1510 kr
= ipc_right_lookup_write(space
, name
, &entry
);
1511 if (kr
!= KERN_SUCCESS
)
1514 port
= (ipc_port_t
) entry
->ie_object
;
1516 if (port
->ip_subsystem
!= NULL
) {
1517 is_write_unlock(space
);
1518 panic("mach_port_request_notification: on RPC port!!");
1519 return KERN_INVALID_CAPABILITY
;
1521 is_write_unlock(space
);
1527 case MACH_NOTIFY_PORT_DESTROYED
: {
1528 ipc_port_t port
, previous
;
1531 return KERN_INVALID_VALUE
;
1533 if (!MACH_PORT_VALID(name
))
1534 return KERN_INVALID_RIGHT
;
1536 kr
= ipc_port_translate_receive(space
, name
, &port
);
1537 if (kr
!= KERN_SUCCESS
)
1539 /* port is locked and active */
1541 ipc_port_pdrequest(port
, notify
, &previous
);
1542 /* port is unlocked */
1544 *previousp
= previous
;
1548 case MACH_NOTIFY_NO_SENDERS
: {
1551 if (!MACH_PORT_VALID(name
))
1552 return KERN_INVALID_RIGHT
;
1554 kr
= ipc_port_translate_receive(space
, name
, &port
);
1555 if (kr
!= KERN_SUCCESS
)
1557 /* port is locked and active */
1559 ipc_port_nsrequest(port
, sync
, notify
, previousp
);
1560 /* port is unlocked */
1564 case MACH_NOTIFY_SEND_POSSIBLE
:
1566 if (!MACH_PORT_VALID(name
)) {
1567 return KERN_INVALID_ARGUMENT
;
1570 kr
= ipc_right_request_alloc(space
, name
, sync
!= 0,
1571 TRUE
, notify
, previousp
);
1572 if (kr
!= KERN_SUCCESS
)
1576 case MACH_NOTIFY_DEAD_NAME
:
1578 if (!MACH_PORT_VALID(name
)) {
1581 * Should do immediate delivery check -
1582 * will do that in the near future.
1584 return KERN_INVALID_ARGUMENT
;
1587 kr
= ipc_right_request_alloc(space
, name
, sync
!= 0,
1588 FALSE
, notify
, previousp
);
1589 if (kr
!= KERN_SUCCESS
)
1594 return KERN_INVALID_VALUE
;
1597 return KERN_SUCCESS
;
1601 * Routine: mach_port_insert_right [kernel call]
1603 * Inserts a right into a space, as if the space
1604 * voluntarily received the right in a message,
1605 * except that the right gets the specified name.
1609 * KERN_SUCCESS Inserted the right.
1610 * KERN_INVALID_TASK The space is null.
1611 * KERN_INVALID_TASK The space is dead.
1612 * KERN_INVALID_VALUE The name isn't a legal name.
1613 * KERN_NAME_EXISTS The name already denotes a right.
1614 * KERN_INVALID_VALUE Message doesn't carry a port right.
1615 * KERN_INVALID_CAPABILITY Port is null or dead.
1616 * KERN_UREFS_OVERFLOW Urefs limit would be exceeded.
1617 * KERN_RIGHT_EXISTS Space has rights under another name.
1618 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1622 mach_port_insert_right(
1624 mach_port_name_t name
,
1626 mach_msg_type_name_t polyPoly
)
1628 if (space
== IS_NULL
)
1629 return KERN_INVALID_TASK
;
1631 if (!MACH_PORT_VALID(name
) ||
1632 !MACH_MSG_TYPE_PORT_ANY_RIGHT(polyPoly
))
1633 return KERN_INVALID_VALUE
;
1635 if (!IO_VALID((ipc_object_t
) poly
))
1636 return KERN_INVALID_CAPABILITY
;
1638 return ipc_object_copyout_name(space
, (ipc_object_t
) poly
,
1639 polyPoly
, FALSE
, name
);
1643 * Routine: mach_port_extract_right [kernel call]
1645 * Extracts a right from a space, as if the space
1646 * voluntarily sent the right to the caller.
1650 * KERN_SUCCESS Extracted the right.
1651 * KERN_INVALID_TASK The space is null.
1652 * KERN_INVALID_TASK The space is dead.
1653 * KERN_INVALID_VALUE Requested type isn't a port right.
1654 * KERN_INVALID_NAME Name doesn't denote a right.
1655 * KERN_INVALID_RIGHT Name doesn't denote appropriate right.
1659 mach_port_extract_right(
1661 mach_port_name_t name
,
1662 mach_msg_type_name_t msgt_name
,
1664 mach_msg_type_name_t
*polyPoly
)
1668 if (space
== IS_NULL
)
1669 return KERN_INVALID_TASK
;
1671 if (!MACH_MSG_TYPE_PORT_ANY(msgt_name
))
1672 return KERN_INVALID_VALUE
;
1674 if (!MACH_PORT_VALID(name
)) {
1676 * really should copy out a dead name, if it is a send or
1677 * send-once right being copied, but instead return an
1680 return KERN_INVALID_RIGHT
;
1683 kr
= ipc_object_copyin(space
, name
, msgt_name
, (ipc_object_t
*) poly
);
1685 if (kr
== KERN_SUCCESS
)
1686 *polyPoly
= ipc_object_copyin_type(msgt_name
);
1691 * Routine: mach_port_get_status_helper [helper]
1693 * Populates a mach_port_status_t structure with
1696 * Port needs to be locked
1700 void mach_port_get_status_helper(
1702 mach_port_status_t
*statusp
)
1705 statusp
->mps_pset
= port
->ip_pset_count
;
1708 imq_lock(&port
->ip_messages
);
1709 statusp
->mps_seqno
= port
->ip_messages
.imq_seqno
;
1710 statusp
->mps_qlimit
= port
->ip_messages
.imq_qlimit
;
1711 statusp
->mps_msgcount
= port
->ip_messages
.imq_msgcount
;
1712 imq_unlock(&port
->ip_messages
);
1715 statusp
->mps_mscount
= port
->ip_mscount
;
1716 statusp
->mps_sorights
= port
->ip_sorights
;
1717 statusp
->mps_srights
= port
->ip_srights
> 0;
1718 statusp
->mps_pdrequest
= port
->ip_pdrequest
!= IP_NULL
;
1719 statusp
->mps_nsrequest
= port
->ip_nsrequest
!= IP_NULL
;
1720 statusp
->mps_flags
= 0;
1721 if (port
->ip_impdonation
) {
1722 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_IMP_DONATION
;
1723 if (port
->ip_tempowner
) {
1724 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_TEMPOWNER
;
1725 if (IIT_NULL
!= port
->ip_imp_task
) {
1726 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_TASKPTR
;
1730 if (port
->ip_guarded
) {
1731 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_GUARDED
;
1732 if (port
->ip_strict_guard
) {
1733 statusp
->mps_flags
|= MACH_PORT_STATUS_FLAG_STRICT_GUARD
;
1742 mach_port_get_attributes(
1744 mach_port_name_t name
,
1746 mach_port_info_t info
,
1747 mach_msg_type_number_t
*count
)
1752 if (space
== IS_NULL
)
1753 return KERN_INVALID_TASK
;
1756 case MACH_PORT_LIMITS_INFO
: {
1757 mach_port_limits_t
*lp
= (mach_port_limits_t
*)info
;
1759 if (*count
< MACH_PORT_LIMITS_INFO_COUNT
)
1760 return KERN_FAILURE
;
1762 if (!MACH_PORT_VALID(name
)) {
1767 kr
= ipc_port_translate_receive(space
, name
, &port
);
1768 if (kr
!= KERN_SUCCESS
)
1770 /* port is locked and active */
1772 lp
->mpl_qlimit
= port
->ip_messages
.imq_qlimit
;
1773 *count
= MACH_PORT_LIMITS_INFO_COUNT
;
1778 case MACH_PORT_RECEIVE_STATUS
: {
1779 mach_port_status_t
*statusp
= (mach_port_status_t
*)info
;
1781 if (*count
< MACH_PORT_RECEIVE_STATUS_COUNT
)
1782 return KERN_FAILURE
;
1784 if (!MACH_PORT_VALID(name
))
1785 return KERN_INVALID_RIGHT
;
1787 kr
= ipc_port_translate_receive(space
, name
, &port
);
1788 if (kr
!= KERN_SUCCESS
)
1790 /* port is locked and active */
1791 mach_port_get_status_helper(port
, statusp
);
1792 *count
= MACH_PORT_RECEIVE_STATUS_COUNT
;
1797 case MACH_PORT_DNREQUESTS_SIZE
: {
1798 ipc_port_request_t table
;
1800 if (*count
< MACH_PORT_DNREQUESTS_SIZE_COUNT
)
1801 return KERN_FAILURE
;
1803 if (!MACH_PORT_VALID(name
)) {
1808 kr
= ipc_port_translate_receive(space
, name
, &port
);
1809 if (kr
!= KERN_SUCCESS
)
1811 /* port is locked and active */
1813 table
= port
->ip_requests
;
1814 if (table
== IPR_NULL
)
1817 *(int *)info
= table
->ipr_size
->its_size
;
1818 *count
= MACH_PORT_DNREQUESTS_SIZE_COUNT
;
1823 case MACH_PORT_INFO_EXT
: {
1824 mach_port_info_ext_t
*mp_info
= (mach_port_info_ext_t
*)info
;
1825 if (*count
< MACH_PORT_INFO_EXT_COUNT
)
1826 return KERN_FAILURE
;
1828 if (!MACH_PORT_VALID(name
))
1829 return KERN_INVALID_RIGHT
;
1831 kr
= ipc_port_translate_receive(space
, name
, &port
);
1832 if (kr
!= KERN_SUCCESS
)
1834 /* port is locked and active */
1835 mach_port_get_status_helper(port
, &mp_info
->mpie_status
);
1836 mp_info
->mpie_boost_cnt
= port
->ip_impcount
;
1837 *count
= MACH_PORT_INFO_EXT_COUNT
;
1843 return KERN_INVALID_ARGUMENT
;
1847 return KERN_SUCCESS
;
1851 mach_port_set_attributes(
1853 mach_port_name_t name
,
1855 mach_port_info_t info
,
1856 mach_msg_type_number_t count
)
1861 if (space
== IS_NULL
)
1862 return KERN_INVALID_TASK
;
1866 case MACH_PORT_LIMITS_INFO
: {
1867 mach_port_limits_t
*mplp
= (mach_port_limits_t
*)info
;
1869 if (count
< MACH_PORT_LIMITS_INFO_COUNT
)
1870 return KERN_FAILURE
;
1872 if (mplp
->mpl_qlimit
> MACH_PORT_QLIMIT_MAX
)
1873 return KERN_INVALID_VALUE
;
1875 if (!MACH_PORT_VALID(name
))
1876 return KERN_INVALID_RIGHT
;
1878 kr
= ipc_port_translate_receive(space
, name
, &port
);
1879 if (kr
!= KERN_SUCCESS
)
1881 /* port is locked and active */
1883 ipc_mqueue_set_qlimit(&port
->ip_messages
, mplp
->mpl_qlimit
);
1887 case MACH_PORT_DNREQUESTS_SIZE
: {
1888 if (count
< MACH_PORT_DNREQUESTS_SIZE_COUNT
)
1889 return KERN_FAILURE
;
1891 if (!MACH_PORT_VALID(name
))
1892 return KERN_INVALID_RIGHT
;
1894 kr
= ipc_port_translate_receive(space
, name
, &port
);
1895 if (kr
!= KERN_SUCCESS
)
1897 /* port is locked and active */
1899 kr
= ipc_port_request_grow(port
, *(int *)info
);
1900 if (kr
!= KERN_SUCCESS
)
1904 case MACH_PORT_TEMPOWNER
:
1905 if (!MACH_PORT_VALID(name
))
1906 return KERN_INVALID_RIGHT
;
1908 ipc_importance_task_t release_imp_task
= IIT_NULL
;
1909 natural_t assertcnt
= 0;
1911 kr
= ipc_port_translate_receive(space
, name
, &port
);
1912 if (kr
!= KERN_SUCCESS
)
1914 /* port is locked and active */
1917 * don't allow temp-owner importance donation if user
1918 * associated it with a kobject already (timer, host_notify target).
1920 if (is_ipc_kobject(ip_kotype(port
))) {
1922 return KERN_INVALID_ARGUMENT
;
1925 if (port
->ip_tempowner
!= 0) {
1926 if (IIT_NULL
!= port
->ip_imp_task
) {
1927 release_imp_task
= port
->ip_imp_task
;
1928 port
->ip_imp_task
= IIT_NULL
;
1929 assertcnt
= port
->ip_impcount
;
1932 assertcnt
= port
->ip_impcount
;
1935 port
->ip_impdonation
= 1;
1936 port
->ip_tempowner
= 1;
1939 #if IMPORTANCE_INHERITANCE
1940 /* drop assertions from previous destination task */
1941 if (release_imp_task
!= IIT_NULL
) {
1942 assert(ipc_importance_task_is_any_receiver_type(release_imp_task
));
1944 ipc_importance_task_drop_internal_assertion(release_imp_task
, assertcnt
);
1945 ipc_importance_task_release(release_imp_task
);
1946 } else if (assertcnt
> 0) {
1947 release_imp_task
= current_task()->task_imp_base
;
1948 if (release_imp_task
!= IIT_NULL
&&
1949 ipc_importance_task_is_any_receiver_type(release_imp_task
)) {
1950 ipc_importance_task_drop_internal_assertion(release_imp_task
, assertcnt
);
1954 if (release_imp_task
!= IIT_NULL
)
1955 ipc_importance_task_release(release_imp_task
);
1956 #endif /* IMPORTANCE_INHERITANCE */
1960 #if IMPORTANCE_INHERITANCE
1961 case MACH_PORT_DENAP_RECEIVER
:
1962 case MACH_PORT_IMPORTANCE_RECEIVER
:
1963 if (!MACH_PORT_VALID(name
))
1964 return KERN_INVALID_RIGHT
;
1966 kr
= ipc_port_translate_receive(space
, name
, &port
);
1967 if (kr
!= KERN_SUCCESS
)
1971 * don't allow importance donation if user associated
1972 * it with a kobject already (timer, host_notify target).
1974 if (is_ipc_kobject(ip_kotype(port
))) {
1976 return KERN_INVALID_ARGUMENT
;
1979 /* port is locked and active */
1980 port
->ip_impdonation
= 1;
1984 #endif /* IMPORTANCE_INHERITANCE */
1987 return KERN_INVALID_ARGUMENT
;
1990 return KERN_SUCCESS
;
1994 * Routine: mach_port_insert_member [kernel call]
1996 * Add the receive right, specified by name, to
1998 * The port cannot already be a member of the set.
2002 * KERN_SUCCESS Moved the port.
2003 * KERN_INVALID_TASK The space is null.
2004 * KERN_INVALID_TASK The space is dead.
2005 * KERN_INVALID_NAME name didn't denote a right.
2006 * KERN_INVALID_RIGHT name didn't denote a receive right.
2007 * KERN_INVALID_NAME pset_name didn't denote a right.
2008 * KERN_INVALID_RIGHT pset_name didn't denote a portset right.
2009 * KERN_ALREADY_IN_SET name was already a member of pset.
2013 mach_port_insert_member(
2015 mach_port_name_t name
,
2016 mach_port_name_t psname
)
2021 wait_queue_link_t wql
;
2023 if (space
== IS_NULL
)
2024 return KERN_INVALID_TASK
;
2026 if (!MACH_PORT_VALID(name
) || !MACH_PORT_VALID(psname
))
2027 return KERN_INVALID_RIGHT
;
2029 wql
= wait_queue_link_allocate();
2031 kr
= ipc_object_translate_two(space
,
2032 name
, MACH_PORT_RIGHT_RECEIVE
, &obj
,
2033 psname
, MACH_PORT_RIGHT_PORT_SET
, &psobj
);
2034 if (kr
!= KERN_SUCCESS
)
2037 /* obj and psobj are locked (and were locked in that order) */
2038 assert(psobj
!= IO_NULL
);
2039 assert(obj
!= IO_NULL
);
2041 kr
= ipc_pset_add((ipc_pset_t
)psobj
, (ipc_port_t
)obj
, wql
);
2046 if (kr
!= KERN_SUCCESS
)
2047 wait_queue_link_free(wql
);
2053 * Routine: mach_port_extract_member [kernel call]
2055 * Remove a port from one portset that it is a member of.
2059 * KERN_SUCCESS Moved the port.
2060 * KERN_INVALID_TASK The space is null.
2061 * KERN_INVALID_TASK The space is dead.
2062 * KERN_INVALID_NAME Member didn't denote a right.
2063 * KERN_INVALID_RIGHT Member didn't denote a receive right.
2064 * KERN_INVALID_NAME After didn't denote a right.
2065 * KERN_INVALID_RIGHT After didn't denote a port set right.
2067 * After is MACH_PORT_NULL and Member isn't in a port set.
2071 mach_port_extract_member(
2073 mach_port_name_t name
,
2074 mach_port_name_t psname
)
2079 wait_queue_link_t wql
= WAIT_QUEUE_LINK_NULL
;
2081 if (space
== IS_NULL
)
2082 return KERN_INVALID_TASK
;
2084 if (!MACH_PORT_VALID(name
) || !MACH_PORT_VALID(psname
))
2085 return KERN_INVALID_RIGHT
;
2087 kr
= ipc_object_translate_two(space
,
2088 name
, MACH_PORT_RIGHT_RECEIVE
, &obj
,
2089 psname
, MACH_PORT_RIGHT_PORT_SET
, &psobj
);
2090 if (kr
!= KERN_SUCCESS
)
2093 /* obj and psobj are both locked (and were locked in that order) */
2094 assert(psobj
!= IO_NULL
);
2095 assert(obj
!= IO_NULL
);
2097 kr
= ipc_pset_remove((ipc_pset_t
)psobj
, (ipc_port_t
)obj
, &wql
);
2101 if (wql
!= WAIT_QUEUE_LINK_NULL
)
2102 wait_queue_link_free(wql
);
2108 * task_set_port_space:
2110 * Set port name space of task to specified size.
2113 task_set_port_space(
2119 is_write_lock(space
);
2121 if (!is_active(space
)) {
2122 is_write_unlock(space
);
2123 return KERN_INVALID_TASK
;
2126 kr
= ipc_entry_grow_table(space
, table_entries
);
2127 if (kr
== KERN_SUCCESS
)
2128 is_write_unlock(space
);
2133 * Routine: mach_port_guard_locked [helper routine]
2135 * Sets a new guard for a locked port.
2139 * KERN_SUCCESS Port Guarded.
2140 * KERN_INVALID_ARGUMENT Port already contains a context/guard.
2142 static kern_return_t
2143 mach_port_guard_locked(
2148 if (port
->ip_context
)
2149 return KERN_INVALID_ARGUMENT
;
2151 port
->ip_context
= guard
;
2152 port
->ip_guarded
= 1;
2153 port
->ip_strict_guard
= (strict
)?1:0;
2154 return KERN_SUCCESS
;
2158 * Routine: mach_port_unguard_locked [helper routine]
2160 * Removes guard for a locked port.
2164 * KERN_SUCCESS Port Unguarded.
2165 * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch.
2166 * This also raises a EXC_GUARD exception.
2168 static kern_return_t
2169 mach_port_unguard_locked(
2171 mach_port_name_t name
,
2174 /* Port locked and active */
2175 if (!port
->ip_guarded
) {
2176 /* Port already unguarded; Raise exception */
2177 mach_port_guard_exception(name
, guard
, 0, kGUARD_EXC_UNGUARDED
);
2178 return KERN_INVALID_ARGUMENT
;
2181 if (port
->ip_context
!= guard
) {
2182 /* Incorrect guard; Raise exception */
2183 mach_port_guard_exception(name
, guard
, port
->ip_context
, kGUARD_EXC_INCORRECT_GUARD
);
2184 return KERN_INVALID_ARGUMENT
;
2187 port
->ip_context
= 0;
2188 port
->ip_guarded
= port
->ip_strict_guard
= 0;
2189 return KERN_SUCCESS
;
2194 * Routine: mach_port_guard_exception [helper routine]
2196 * Marks the thread with AST_GUARD for mach port guard violation.
2197 * Also saves exception info in thread structure.
2201 * KERN_FAILURE Thread marked with AST_GUARD.
2204 mach_port_guard_exception(
2205 mach_port_name_t name
,
2210 thread_t t
= current_thread();
2211 uint64_t code
, subcode
;
2213 /* Log exception info to syslog */
2214 printf( "Mach Port Guard Exception - "
2217 "Expected Guard: 0x%x, "
2218 "Received Guard: 0x%x\n",
2221 (unsigned)portguard
,
2225 * EXC_GUARD namespace for mach ports
2228 * Mach Port guards use the exception codes like
2231 * +----------------------------------------------------------------+
2232 * |[63:61] GUARD_TYPE_MACH_PORT | [60:32] flavor | [31:0] port name|
2233 * +----------------------------------------------------------------+
2236 * +----------------------------------------------------------------+
2237 * | [63:0] guard value |
2238 * +----------------------------------------------------------------+
2241 code
= (((uint64_t)GUARD_TYPE_MACH_PORT
) << 61) |
2242 (((uint64_t)reason
) << 32) |
2244 subcode
= (uint64_t)(portguard
);
2246 t
->guard_exc_info
.code
= code
;
2247 t
->guard_exc_info
.subcode
= subcode
;
2249 /* Mark thread with AST_GUARD */
2250 thread_guard_violation(t
, GUARD_TYPE_MACH_PORT
);
2251 return KERN_FAILURE
;
2256 * Routine: mach_port_guard_ast
2258 * Raises an exception for mach port guard violation.
2266 mach_port_guard_ast(thread_t t
)
2268 mach_exception_data_type_t code
[EXCEPTION_CODE_MAX
];
2270 code
[0] = t
->guard_exc_info
.code
;
2271 code
[1] = t
->guard_exc_info
.subcode
;
2273 /* Raise an EXC_GUARD exception */
2274 exception_triage(EXC_GUARD
, code
, EXCEPTION_CODE_MAX
);
2276 /* Terminate task which caused the exception */
2277 (void) task_terminate_internal(current_task());
2282 * Routine: mach_port_construct [kernel call]
2284 * Constructs a mach port with the provided set of options.
2288 * KERN_SUCCESS The right is allocated.
2289 * KERN_INVALID_TASK The space is null.
2290 * KERN_INVALID_TASK The space is dead.
2291 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
2292 * KERN_NO_SPACE No room in space for another right.
2293 * KERN_FAILURE Illegal option values requested.
2297 mach_port_construct(
2299 mach_port_options_t
*options
,
2301 mach_port_name_t
*name
)
2306 if (space
== IS_NULL
)
2307 return (KERN_INVALID_TASK
);
2309 /* Allocate a new port in the IPC space */
2310 kr
= ipc_port_alloc(space
, name
, &port
);
2311 if (kr
!= KERN_SUCCESS
)
2314 /* Port locked and active */
2315 if (options
->flags
& MPO_CONTEXT_AS_GUARD
) {
2316 kr
= mach_port_guard_locked(port
, (uint64_t) context
, (options
->flags
& MPO_STRICT
));
2317 /* A newly allocated and locked port should always be guarded successfully */
2318 assert(kr
== KERN_SUCCESS
);
2320 port
->ip_context
= context
;
2326 /* Set port attributes as requested */
2328 if (options
->flags
& MPO_QLIMIT
) {
2329 kr
= mach_port_set_attributes(space
, *name
, MACH_PORT_LIMITS_INFO
,
2330 (mach_port_info_t
)&options
->mpl
, sizeof(options
->mpl
)/sizeof(int));
2331 if (kr
!= KERN_SUCCESS
)
2335 if (options
->flags
& MPO_TEMPOWNER
) {
2336 kr
= mach_port_set_attributes(space
, *name
, MACH_PORT_TEMPOWNER
, NULL
, 0);
2337 if (kr
!= KERN_SUCCESS
)
2341 if (options
->flags
& MPO_IMPORTANCE_RECEIVER
) {
2342 kr
= mach_port_set_attributes(space
, *name
, MACH_PORT_IMPORTANCE_RECEIVER
, NULL
, 0);
2343 if (kr
!= KERN_SUCCESS
)
2347 if (options
->flags
& MPO_DENAP_RECEIVER
) {
2348 kr
= mach_port_set_attributes(space
, *name
, MACH_PORT_DENAP_RECEIVER
, NULL
, 0);
2349 if (kr
!= KERN_SUCCESS
)
2353 if (options
->flags
& MPO_INSERT_SEND_RIGHT
) {
2354 kr
= ipc_object_copyin(space
, *name
, MACH_MSG_TYPE_MAKE_SEND
, (ipc_object_t
*)&port
);
2355 if (kr
!= KERN_SUCCESS
)
2358 kr
= mach_port_insert_right(space
, *name
, port
, MACH_MSG_TYPE_PORT_SEND
);
2359 if (kr
!= KERN_SUCCESS
)
2363 return KERN_SUCCESS
;
2366 /* Attempt to destroy port. If its already destroyed by some other thread, we're done */
2367 (void) mach_port_destruct(space
, *name
, 0, context
);
2372 * Routine: mach_port_destruct [kernel call]
2374 * Destroys a mach port with appropriate guard
2378 * KERN_SUCCESS The name is destroyed.
2379 * KERN_INVALID_TASK The space is null.
2380 * KERN_INVALID_TASK The space is dead.
2381 * KERN_INVALID_NAME The name doesn't denote a right.
2382 * KERN_INVALID_RIGHT The right isn't correct.
2383 * KERN_INVALID_VALUE The delta for send right is incorrect.
2384 * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch.
2385 * This also raises a EXC_GUARD exception.
2391 mach_port_name_t name
,
2392 mach_port_delta_t srdelta
,
2398 if (space
== IS_NULL
)
2399 return KERN_INVALID_TASK
;
2401 if (!MACH_PORT_VALID(name
))
2402 return KERN_INVALID_NAME
;
2404 /* Remove reference for receive right */
2405 kr
= ipc_right_lookup_write(space
, name
, &entry
);
2406 if (kr
!= KERN_SUCCESS
)
2408 /* space is write-locked and active */
2409 kr
= ipc_right_destruct(space
, name
, entry
, srdelta
, guard
); /* unlocks */
2415 * Routine: mach_port_guard [kernel call]
2417 * Guard a mach port with specified guard value.
2418 * The context field of the port is used as the guard.
2422 * KERN_SUCCESS The name is destroyed.
2423 * KERN_INVALID_TASK The space is null.
2424 * KERN_INVALID_TASK The space is dead.
2425 * KERN_INVALID_NAME The name doesn't denote a right.
2426 * KERN_INVALID_RIGHT The right isn't correct.
2427 * KERN_INVALID_ARGUMENT Port already contains a context/guard.
2432 mach_port_name_t name
,
2439 if (space
== IS_NULL
)
2440 return KERN_INVALID_TASK
;
2442 if (!MACH_PORT_VALID(name
))
2443 return KERN_INVALID_NAME
;
2445 /* Guard can be applied only to receive rights */
2446 kr
= ipc_port_translate_receive(space
, name
, &port
);
2447 if (kr
!= KERN_SUCCESS
)
2450 /* Port locked and active */
2451 kr
= mach_port_guard_locked(port
, guard
, strict
);
2459 * Routine: mach_port_unguard [kernel call]
2461 * Unguard a mach port with specified guard value.
2465 * KERN_SUCCESS The name is destroyed.
2466 * KERN_INVALID_TASK The space is null.
2467 * KERN_INVALID_TASK The space is dead.
2468 * KERN_INVALID_NAME The name doesn't denote a right.
2469 * KERN_INVALID_RIGHT The right isn't correct.
2470 * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch.
2471 * This also raises a EXC_GUARD exception.
2476 mach_port_name_t name
,
2483 if (space
== IS_NULL
)
2484 return KERN_INVALID_TASK
;
2486 if (!MACH_PORT_VALID(name
))
2487 return KERN_INVALID_NAME
;
2489 kr
= ipc_port_translate_receive(space
, name
, &port
);
2490 if (kr
!= KERN_SUCCESS
)
2493 /* Port locked and active */
2494 kr
= mach_port_unguard_locked(port
, name
, guard
);