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@
29 * @OSF_FREE_COPYRIGHT@
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/ipc_right.c
70 * Functions to manipulate IPC capabilities.
73 #include <mach/boolean.h>
74 #include <mach/kern_return.h>
75 #include <mach/port.h>
76 #include <mach/message.h>
77 #include <kern/assert.h>
78 #include <kern/misc_protos.h>
80 #include <ipc/ipc_entry.h>
81 #include <ipc/ipc_space.h>
82 #include <ipc/ipc_object.h>
83 #include <ipc/ipc_hash.h>
84 #include <ipc/ipc_port.h>
85 #include <ipc/ipc_pset.h>
86 #include <ipc/ipc_right.h>
87 #include <ipc/ipc_notify.h>
88 #include <ipc/ipc_table.h>
89 #include <ipc/ipc_importance.h>
90 #include <security/mac_mach_internal.h>
92 /* Allow IPC to generate mach port guard exceptions */
94 mach_port_guard_exception(
95 mach_port_name_t name
,
100 * Routine: ipc_right_lookup_write
102 * Finds an entry in a space, given the name.
104 * Nothing locked. If successful, the space is write-locked.
106 * KERN_SUCCESS Found an entry.
107 * KERN_INVALID_TASK The space is dead.
108 * KERN_INVALID_NAME Name doesn't exist in space.
112 ipc_right_lookup_write(
114 mach_port_name_t name
,
119 assert(space
!= IS_NULL
);
121 is_write_lock(space
);
123 if (!is_active(space
)) {
124 is_write_unlock(space
);
125 return KERN_INVALID_TASK
;
128 if ((entry
= ipc_entry_lookup(space
, name
)) == IE_NULL
) {
129 is_write_unlock(space
);
130 return KERN_INVALID_NAME
;
138 * Routine: ipc_right_lookup_two_write
140 * Like ipc_right_lookup except that it returns two
141 * entries for two different names that were looked
142 * up under the same space lock.
144 * Nothing locked. If successful, the space is write-locked.
146 * KERN_INVALID_TASK The space is dead.
147 * KERN_INVALID_NAME Name doesn't exist in space.
151 ipc_right_lookup_two_write(
153 mach_port_name_t name1
,
154 ipc_entry_t
*entryp1
,
155 mach_port_name_t name2
,
156 ipc_entry_t
*entryp2
)
161 assert(space
!= IS_NULL
);
163 is_write_lock(space
);
165 if (!is_active(space
)) {
166 is_write_unlock(space
);
167 return KERN_INVALID_TASK
;
170 if ((entry1
= ipc_entry_lookup(space
, name1
)) == IE_NULL
) {
171 is_write_unlock(space
);
172 return KERN_INVALID_NAME
;
174 if ((entry2
= ipc_entry_lookup(space
, name2
)) == IE_NULL
) {
175 is_write_unlock(space
);
176 return KERN_INVALID_NAME
;
184 * Routine: ipc_right_reverse
186 * Translate (space, object) -> (name, entry).
187 * Only finds send/receive rights.
188 * Returns TRUE if an entry is found; if so,
189 * the object is locked and active.
191 * The space must be locked (read or write) and active.
192 * Nothing else locked.
199 mach_port_name_t
*namep
,
203 mach_port_name_t name
;
206 /* would switch on io_otype to handle multiple types of object */
208 assert(is_active(space
));
209 assert(io_otype(object
) == IOT_PORT
);
211 port
= (ipc_port_t
) object
;
214 if (!ip_active(port
)) {
220 if (port
->ip_receiver
== space
) {
221 name
= port
->ip_receiver_name
;
222 assert(name
!= MACH_PORT_NULL
);
224 entry
= ipc_entry_lookup(space
, name
);
226 assert(entry
!= IE_NULL
);
227 assert(entry
->ie_bits
& MACH_PORT_TYPE_RECEIVE
);
228 assert(port
== (ipc_port_t
) entry
->ie_object
);
235 if (ipc_hash_lookup(space
, (ipc_object_t
) port
, namep
, entryp
)) {
236 assert((entry
= *entryp
) != IE_NULL
);
237 assert(IE_BITS_TYPE(entry
->ie_bits
) == MACH_PORT_TYPE_SEND
);
238 assert(port
== (ipc_port_t
) entry
->ie_object
);
248 * Routine: ipc_right_dnrequest
250 * Make a dead-name request, returning the previously
251 * registered send-once right. If notify is IP_NULL,
252 * just cancels the previously registered request.
255 * Nothing locked. May allocate memory.
256 * Only consumes/returns refs if successful.
258 * KERN_SUCCESS Made/canceled dead-name request.
259 * KERN_INVALID_TASK The space is dead.
260 * KERN_INVALID_NAME Name doesn't exist in space.
261 * KERN_INVALID_RIGHT Name doesn't denote port/dead rights.
262 * KERN_INVALID_ARGUMENT Name denotes dead name, but
263 * immediate is FALSE or notify is IP_NULL.
264 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
268 ipc_right_request_alloc(
270 mach_port_name_t name
,
272 boolean_t send_possible
,
274 ipc_port_t
*previousp
)
276 ipc_port_request_index_t prev_request
;
277 ipc_port_t previous
= IP_NULL
;
281 #if IMPORTANCE_INHERITANCE
282 boolean_t needboost
= FALSE
;
283 #endif /* IMPORTANCE_INHERITANCE */
286 ipc_port_t port
= IP_NULL
;
288 kr
= ipc_right_lookup_write(space
, name
, &entry
);
289 if (kr
!= KERN_SUCCESS
)
292 /* space is write-locked and active */
294 prev_request
= entry
->ie_request
;
296 /* if nothing to do or undo, we're done */
297 if (notify
== IP_NULL
&& prev_request
== IE_REQ_NONE
) {
298 is_write_unlock(space
);
299 *previousp
= IP_NULL
;
303 /* see if the entry is of proper type for requests */
304 if (entry
->ie_bits
& MACH_PORT_TYPE_PORT_RIGHTS
) {
305 ipc_port_request_index_t new_request
;
307 port
= (ipc_port_t
) entry
->ie_object
;
308 assert(port
!= IP_NULL
);
310 if (!ipc_right_check(space
, port
, name
, entry
)) {
311 /* port is locked and active */
313 /* if no new request, just cancel previous */
314 if (notify
== IP_NULL
) {
315 if (prev_request
!= IE_REQ_NONE
)
316 previous
= ipc_port_request_cancel(port
, name
, prev_request
);
318 entry
->ie_request
= IE_REQ_NONE
;
319 ipc_entry_modified(space
, name
, entry
);
320 is_write_unlock(space
);
325 * send-once rights, kernel objects, and non-full other queues
326 * fire immediately (if immediate specified).
328 if (send_possible
&& immediate
&&
329 ((entry
->ie_bits
& MACH_PORT_TYPE_SEND_ONCE
) ||
330 port
->ip_receiver
== ipc_space_kernel
|| !ip_full(port
))) {
331 if (prev_request
!= IE_REQ_NONE
)
332 previous
= ipc_port_request_cancel(port
, name
, prev_request
);
334 entry
->ie_request
= IE_REQ_NONE
;
335 ipc_entry_modified(space
, name
, entry
);
336 is_write_unlock(space
);
338 ipc_notify_send_possible(notify
, name
);
343 * If there is a previous request, free it. Any subsequent
344 * allocation cannot fail, thus assuring an atomic swap.
346 if (prev_request
!= IE_REQ_NONE
)
347 previous
= ipc_port_request_cancel(port
, name
, prev_request
);
349 #if IMPORTANCE_INHERITANCE
350 kr
= ipc_port_request_alloc(port
, name
, notify
,
351 send_possible
, immediate
,
352 &new_request
, &needboost
);
354 kr
= ipc_port_request_alloc(port
, name
, notify
,
355 send_possible
, immediate
,
357 #endif /* IMPORTANCE_INHERITANCE */
358 if (kr
!= KERN_SUCCESS
) {
359 assert(previous
== IP_NULL
);
360 is_write_unlock(space
);
362 kr
= ipc_port_request_grow(port
, ITS_SIZE_NONE
);
363 /* port is unlocked */
365 if (kr
!= KERN_SUCCESS
)
372 assert(new_request
!= IE_REQ_NONE
);
373 entry
->ie_request
= new_request
;
374 ipc_entry_modified(space
, name
, entry
);
375 is_write_unlock(space
);
377 #if IMPORTANCE_INHERITANCE
378 if (needboost
== TRUE
) {
379 if (ipc_port_importance_delta(port
, IPID_OPTION_SENDPOSSIBLE
, 1) == FALSE
)
382 #endif /* IMPORTANCE_INHERITANCE */
387 /* entry may have changed to dead-name by ipc_right_check() */
391 /* treat send_possible requests as immediate w.r.t. dead-name */
392 if ((send_possible
|| immediate
) && notify
!= IP_NULL
&&
393 (entry
->ie_bits
& MACH_PORT_TYPE_DEAD_NAME
)) {
394 mach_port_urefs_t urefs
= IE_BITS_UREFS(entry
->ie_bits
);
398 /* leave urefs pegged to maximum if it overflowed */
399 if (urefs
< MACH_PORT_UREFS_MAX
)
400 (entry
->ie_bits
)++; /* increment urefs */
402 ipc_entry_modified(space
, name
, entry
);
404 is_write_unlock(space
);
409 ipc_notify_dead_name(notify
, name
);
414 kr
= (entry
->ie_bits
& MACH_PORT_TYPE_PORT_OR_DEAD
) ?
415 KERN_INVALID_ARGUMENT
: KERN_INVALID_RIGHT
;
417 is_write_unlock(space
);
425 *previousp
= previous
;
430 * Routine: ipc_right_request_cancel
432 * Cancel a notification request and return the send-once right.
433 * Afterwards, entry->ie_request == 0.
435 * The space must be write-locked; the port must be locked.
436 * The port must be active; the space doesn't have to be.
440 ipc_right_request_cancel(
441 __unused ipc_space_t space
,
443 mach_port_name_t name
,
448 assert(ip_active(port
));
449 assert(port
== (ipc_port_t
) entry
->ie_object
);
451 if (entry
->ie_request
== IE_REQ_NONE
)
454 previous
= ipc_port_request_cancel(port
, name
, entry
->ie_request
);
455 entry
->ie_request
= IE_REQ_NONE
;
456 ipc_entry_modified(space
, name
, entry
);
461 * Routine: ipc_right_inuse
463 * Check if an entry is being used.
464 * Returns TRUE if it is.
466 * The space is write-locked and active.
467 * It is unlocked if the entry is inuse.
473 __unused mach_port_name_t name
,
476 if (IE_BITS_TYPE(entry
->ie_bits
) != MACH_PORT_TYPE_NONE
) {
477 is_write_unlock(space
);
484 * Routine: ipc_right_check
486 * Check if the port has died. If it has,
487 * clean up the entry and return TRUE.
489 * The space is write-locked; the port is not locked.
490 * If returns FALSE, the port is also locked and active.
491 * Otherwise, entry is converted to a dead name.
493 * Caller is responsible for a reference to port if it
494 * had died (returns TRUE).
501 mach_port_name_t name
,
504 ipc_entry_bits_t bits
;
506 assert(is_active(space
));
507 assert(port
== (ipc_port_t
) entry
->ie_object
);
513 /* this was either a pure send right or a send-once right */
515 bits
= entry
->ie_bits
;
516 assert((bits
& MACH_PORT_TYPE_RECEIVE
) == 0);
517 assert(IE_BITS_UREFS(bits
) > 0);
519 if (bits
& MACH_PORT_TYPE_SEND
) {
520 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND
);
521 assert(IE_BITS_UREFS(bits
) > 0);
522 assert(port
->ip_srights
> 0);
525 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND_ONCE
);
526 assert(IE_BITS_UREFS(bits
) == 1);
527 assert(port
->ip_sorights
> 0);
533 * delete SEND rights from ipc hash.
536 if ((bits
& MACH_PORT_TYPE_SEND
) != 0) {
537 ipc_hash_delete(space
, (ipc_object_t
)port
, name
, entry
);
540 /* convert entry to dead name */
541 bits
= (bits
&~ IE_BITS_TYPE_MASK
) | MACH_PORT_TYPE_DEAD_NAME
;
544 * If there was a notification request outstanding on this
545 * name, and the port went dead, that notification
546 * must already be on its way up from the port layer.
548 * Add the reference that the notification carries. It
549 * is done here, and not in the notification delivery,
550 * because the latter doesn't have a space reference and
551 * trying to actually move a send-right reference would
552 * get short-circuited into a MACH_PORT_DEAD by IPC. Since
553 * all calls that deal with the right eventually come
554 * through here, it has the same result.
556 * Once done, clear the request index so we only account
559 if (entry
->ie_request
!= IE_REQ_NONE
) {
560 if (ipc_port_request_type(port
, name
, entry
->ie_request
) != 0) {
561 /* if urefs are pegged due to overflow, leave them pegged */
562 if (IE_BITS_UREFS(bits
) < MACH_PORT_UREFS_MAX
)
563 bits
++; /* increment urefs */
565 entry
->ie_request
= IE_REQ_NONE
;
567 entry
->ie_bits
= bits
;
568 entry
->ie_object
= IO_NULL
;
569 ipc_entry_modified(space
, name
, entry
);
574 * Routine: ipc_right_terminate
576 * Cleans up an entry in a terminated space.
577 * The entry isn't deallocated or removed
578 * from reverse hash tables.
580 * The space is dead and unlocked.
586 mach_port_name_t name
,
589 ipc_entry_bits_t bits
;
590 mach_port_type_t type
;
592 bits
= entry
->ie_bits
;
593 type
= IE_BITS_TYPE(bits
);
595 assert(!is_active(space
));
598 * IE_BITS_COMPAT/ipc_right_dncancel doesn't have this
599 * problem, because we check that the port is active. If
600 * we didn't cancel IE_BITS_COMPAT, ipc_port_destroy
601 * would still work, but dead space refs would accumulate
602 * in ip_dnrequests. They would use up slots in
603 * ip_dnrequests and keep the spaces from being freed.
607 case MACH_PORT_TYPE_DEAD_NAME
:
608 assert(entry
->ie_request
== IE_REQ_NONE
);
609 assert(entry
->ie_object
== IO_NULL
);
612 case MACH_PORT_TYPE_PORT_SET
: {
613 ipc_pset_t pset
= (ipc_pset_t
) entry
->ie_object
;
615 assert(entry
->ie_request
== IE_REQ_NONE
);
616 assert(pset
!= IPS_NULL
);
619 assert(ips_active(pset
));
620 ipc_pset_destroy(pset
); /* consumes ref, unlocks */
624 case MACH_PORT_TYPE_SEND
:
625 case MACH_PORT_TYPE_RECEIVE
:
626 case MACH_PORT_TYPE_SEND_RECEIVE
:
627 case MACH_PORT_TYPE_SEND_ONCE
: {
628 ipc_port_t port
= (ipc_port_t
) entry
->ie_object
;
630 ipc_port_t nsrequest
= IP_NULL
;
631 mach_port_mscount_t mscount
= 0;
633 assert(port
!= IP_NULL
);
636 if (!ip_active(port
)) {
642 request
= ipc_right_request_cancel_macro(space
, port
,
645 if (type
& MACH_PORT_TYPE_SEND
) {
646 assert(port
->ip_srights
> 0);
647 if (--port
->ip_srights
== 0
649 nsrequest
= port
->ip_nsrequest
;
650 if (nsrequest
!= IP_NULL
) {
651 port
->ip_nsrequest
= IP_NULL
;
652 mscount
= port
->ip_mscount
;
657 if (type
& MACH_PORT_TYPE_RECEIVE
) {
658 assert(port
->ip_receiver_name
== name
);
659 assert(port
->ip_receiver
== space
);
661 ipc_port_destroy(port
); /* clears receiver, consumes our ref, unlocks */
663 } else if (type
& MACH_PORT_TYPE_SEND_ONCE
) {
664 assert(port
->ip_sorights
> 0);
667 ipc_notify_send_once(port
); /* consumes our ref */
669 assert(port
->ip_receiver
!= space
);
675 if (nsrequest
!= IP_NULL
)
676 ipc_notify_no_senders(nsrequest
, mscount
);
678 if (request
!= IP_NULL
)
679 ipc_notify_port_deleted(request
, name
);
684 panic("ipc_right_terminate: strange type - 0x%x", type
);
689 * Routine: ipc_right_destroy
691 * Destroys an entry in a space.
693 * The space is write-locked (returns unlocked).
694 * The space must be active.
696 * KERN_SUCCESS The entry was destroyed.
702 mach_port_name_t name
,
704 boolean_t check_guard
,
707 ipc_entry_bits_t bits
;
708 mach_port_type_t type
;
710 bits
= entry
->ie_bits
;
711 entry
->ie_bits
&= ~IE_BITS_TYPE_MASK
;
712 type
= IE_BITS_TYPE(bits
);
714 assert(is_active(space
));
717 case MACH_PORT_TYPE_DEAD_NAME
:
718 assert(entry
->ie_request
== IE_REQ_NONE
);
719 assert(entry
->ie_object
== IO_NULL
);
721 ipc_entry_dealloc(space
, name
, entry
);
722 is_write_unlock(space
);
725 case MACH_PORT_TYPE_PORT_SET
: {
726 ipc_pset_t pset
= (ipc_pset_t
) entry
->ie_object
;
728 assert(entry
->ie_request
== IE_REQ_NONE
);
729 assert(pset
!= IPS_NULL
);
731 entry
->ie_object
= IO_NULL
;
732 ipc_entry_dealloc(space
, name
, entry
);
735 is_write_unlock(space
);
737 assert(ips_active(pset
));
738 ipc_pset_destroy(pset
); /* consumes ref, unlocks */
742 case MACH_PORT_TYPE_SEND
:
743 case MACH_PORT_TYPE_RECEIVE
:
744 case MACH_PORT_TYPE_SEND_RECEIVE
:
745 case MACH_PORT_TYPE_SEND_ONCE
: {
746 ipc_port_t port
= (ipc_port_t
) entry
->ie_object
;
747 ipc_port_t nsrequest
= IP_NULL
;
748 mach_port_mscount_t mscount
= 0;
751 assert(port
!= IP_NULL
);
753 if (type
== MACH_PORT_TYPE_SEND
)
754 ipc_hash_delete(space
, (ipc_object_t
) port
,
759 if (!ip_active(port
)) {
760 assert((type
& MACH_PORT_TYPE_RECEIVE
) == 0);
762 entry
->ie_request
= IE_REQ_NONE
;
763 entry
->ie_object
= IO_NULL
;
764 ipc_entry_dealloc(space
, name
, entry
);
765 is_write_unlock(space
);
770 /* For receive rights, check for guarding */
771 if ((type
& MACH_PORT_TYPE_RECEIVE
) &&
772 (check_guard
) && (port
->ip_guarded
) &&
773 (guard
!= port
->ip_context
)) {
774 /* Guard Violation */
775 uint64_t portguard
= port
->ip_context
;
777 is_write_unlock(space
);
778 /* Raise mach port guard exception */
779 mach_port_guard_exception(name
, 0, portguard
, kGUARD_EXC_DESTROY
);
780 return KERN_INVALID_RIGHT
;
784 request
= ipc_right_request_cancel_macro(space
, port
, name
, entry
);
786 entry
->ie_object
= IO_NULL
;
787 ipc_entry_dealloc(space
, name
, entry
);
788 is_write_unlock(space
);
790 if (type
& MACH_PORT_TYPE_SEND
) {
791 assert(port
->ip_srights
> 0);
792 if (--port
->ip_srights
== 0) {
793 nsrequest
= port
->ip_nsrequest
;
794 if (nsrequest
!= IP_NULL
) {
795 port
->ip_nsrequest
= IP_NULL
;
796 mscount
= port
->ip_mscount
;
801 if (type
& MACH_PORT_TYPE_RECEIVE
) {
802 assert(ip_active(port
));
803 assert(port
->ip_receiver
== space
);
805 ipc_port_destroy(port
); /* clears receiver, consumes our ref, unlocks */
807 } else if (type
& MACH_PORT_TYPE_SEND_ONCE
) {
808 assert(port
->ip_sorights
> 0);
811 ipc_notify_send_once(port
); /* consumes our ref */
813 assert(port
->ip_receiver
!= space
);
819 if (nsrequest
!= IP_NULL
)
820 ipc_notify_no_senders(nsrequest
, mscount
);
822 if (request
!= IP_NULL
)
823 ipc_notify_port_deleted(request
, name
);
830 panic("ipc_right_destroy: strange type");
837 * Routine: ipc_right_dealloc
839 * Releases a send/send-once/dead-name user ref.
840 * Like ipc_right_delta with a delta of -1,
841 * but looks at the entry to determine the right.
843 * The space is write-locked, and is unlocked upon return.
844 * The space must be active.
846 * KERN_SUCCESS A user ref was released.
847 * KERN_INVALID_RIGHT Entry has wrong type.
853 mach_port_name_t name
,
856 ipc_port_t port
= IP_NULL
;
857 ipc_entry_bits_t bits
;
858 mach_port_type_t type
;
860 bits
= entry
->ie_bits
;
861 type
= IE_BITS_TYPE(bits
);
864 assert(is_active(space
));
867 case MACH_PORT_TYPE_DEAD_NAME
: {
870 assert(IE_BITS_UREFS(bits
) > 0);
871 assert(entry
->ie_request
== IE_REQ_NONE
);
872 assert(entry
->ie_object
== IO_NULL
);
874 if (IE_BITS_UREFS(bits
) == 1) {
875 ipc_entry_dealloc(space
, name
, entry
);
877 /* if urefs are pegged due to overflow, leave them pegged */
878 if (IE_BITS_UREFS(bits
) < MACH_PORT_UREFS_MAX
)
879 entry
->ie_bits
= bits
-1; /* decrement urefs */
880 ipc_entry_modified(space
, name
, entry
);
882 is_write_unlock(space
);
884 /* release any port that got converted to dead name below */
890 case MACH_PORT_TYPE_SEND_ONCE
: {
893 assert(IE_BITS_UREFS(bits
) == 1);
895 port
= (ipc_port_t
) entry
->ie_object
;
896 assert(port
!= IP_NULL
);
898 if (ipc_right_check(space
, port
, name
, entry
)) {
900 bits
= entry
->ie_bits
;
901 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_DEAD_NAME
);
902 goto dead_name
; /* it will release port */
904 /* port is locked and active */
906 assert(port
->ip_sorights
> 0);
908 request
= ipc_right_request_cancel_macro(space
, port
, name
, entry
);
911 entry
->ie_object
= IO_NULL
;
912 ipc_entry_dealloc(space
, name
, entry
);
914 is_write_unlock(space
);
916 ipc_notify_send_once(port
);
918 if (request
!= IP_NULL
)
919 ipc_notify_port_deleted(request
, name
);
923 case MACH_PORT_TYPE_SEND
: {
924 ipc_port_t request
= IP_NULL
;
925 ipc_port_t nsrequest
= IP_NULL
;
926 mach_port_mscount_t mscount
= 0;
929 assert(IE_BITS_UREFS(bits
) > 0);
931 port
= (ipc_port_t
) entry
->ie_object
;
932 assert(port
!= IP_NULL
);
934 if (ipc_right_check(space
, port
, name
, entry
)) {
935 bits
= entry
->ie_bits
;
936 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_DEAD_NAME
);
937 goto dead_name
; /* it will release port */
939 /* port is locked and active */
941 assert(port
->ip_srights
> 0);
943 if (IE_BITS_UREFS(bits
) == 1) {
944 if (--port
->ip_srights
== 0) {
945 nsrequest
= port
->ip_nsrequest
;
946 if (nsrequest
!= IP_NULL
) {
947 port
->ip_nsrequest
= IP_NULL
;
948 mscount
= port
->ip_mscount
;
952 request
= ipc_right_request_cancel_macro(space
, port
,
954 ipc_hash_delete(space
, (ipc_object_t
) port
,
958 entry
->ie_object
= IO_NULL
;
959 ipc_entry_dealloc(space
, name
, entry
);
960 is_write_unlock(space
);
965 /* if urefs are pegged due to overflow, leave them pegged */
966 if (IE_BITS_UREFS(bits
) < MACH_PORT_UREFS_MAX
)
967 entry
->ie_bits
= bits
-1; /* decrement urefs */
968 ipc_entry_modified(space
, name
, entry
);
969 is_write_unlock(space
);
972 if (nsrequest
!= IP_NULL
)
973 ipc_notify_no_senders(nsrequest
, mscount
);
975 if (request
!= IP_NULL
)
976 ipc_notify_port_deleted(request
, name
);
980 case MACH_PORT_TYPE_SEND_RECEIVE
: {
981 ipc_port_t nsrequest
= IP_NULL
;
982 mach_port_mscount_t mscount
= 0;
984 assert(IE_BITS_UREFS(bits
) > 0);
986 port
= (ipc_port_t
) entry
->ie_object
;
987 assert(port
!= IP_NULL
);
990 assert(ip_active(port
));
991 assert(port
->ip_receiver_name
== name
);
992 assert(port
->ip_receiver
== space
);
993 assert(port
->ip_srights
> 0);
995 if (IE_BITS_UREFS(bits
) == 1) {
996 if (--port
->ip_srights
== 0) {
997 nsrequest
= port
->ip_nsrequest
;
998 if (nsrequest
!= IP_NULL
) {
999 port
->ip_nsrequest
= IP_NULL
;
1000 mscount
= port
->ip_mscount
;
1004 entry
->ie_bits
= bits
&~ (IE_BITS_UREFS_MASK
|
1005 MACH_PORT_TYPE_SEND
);
1007 /* if urefs are pegged due to overflow, leave them pegged */
1008 if (IE_BITS_UREFS(bits
) < MACH_PORT_UREFS_MAX
) {
1009 entry
->ie_bits
= bits
-1; /* decrement urefs */
1014 ipc_entry_modified(space
, name
, entry
);
1015 is_write_unlock(space
);
1017 if (nsrequest
!= IP_NULL
)
1018 ipc_notify_no_senders(nsrequest
, mscount
);
1023 is_write_unlock(space
);
1024 return KERN_INVALID_RIGHT
;
1027 return KERN_SUCCESS
;
1031 * Routine: ipc_right_delta
1033 * Modifies the user-reference count for a right.
1034 * May deallocate the right, if the count goes to zero.
1036 * The space is write-locked, and is unlocked upon return.
1037 * The space must be active.
1039 * KERN_SUCCESS Count was modified.
1040 * KERN_INVALID_RIGHT Entry has wrong type.
1041 * KERN_INVALID_VALUE Bad delta for the right.
1047 mach_port_name_t name
,
1049 mach_port_right_t right
,
1050 mach_port_delta_t delta
)
1052 ipc_port_t port
= IP_NULL
;
1053 ipc_entry_bits_t bits
;
1055 bits
= entry
->ie_bits
;
1059 * The following is used (for case MACH_PORT_RIGHT_DEAD_NAME) in the
1060 * switch below. It is used to keep track of those cases (in DIPC)
1061 * where we have postponed the dropping of a port reference. Since
1062 * the dropping of the reference could cause the port to disappear
1063 * we postpone doing so when we are holding the space lock.
1066 assert(is_active(space
));
1067 assert(right
< MACH_PORT_RIGHT_NUMBER
);
1069 /* Rights-specific restrictions and operations. */
1072 case MACH_PORT_RIGHT_PORT_SET
: {
1075 if ((bits
& MACH_PORT_TYPE_PORT_SET
) == 0)
1078 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_PORT_SET
);
1079 assert(IE_BITS_UREFS(bits
) == 0);
1080 assert(entry
->ie_request
== IE_REQ_NONE
);
1088 pset
= (ipc_pset_t
) entry
->ie_object
;
1089 assert(pset
!= IPS_NULL
);
1091 entry
->ie_object
= IO_NULL
;
1092 ipc_entry_dealloc(space
, name
, entry
);
1095 assert(ips_active(pset
));
1096 is_write_unlock(space
);
1098 ipc_pset_destroy(pset
); /* consumes ref, unlocks */
1102 case MACH_PORT_RIGHT_RECEIVE
: {
1103 ipc_port_t request
= IP_NULL
;
1105 if ((bits
& MACH_PORT_TYPE_RECEIVE
) == 0)
1114 port
= (ipc_port_t
) entry
->ie_object
;
1115 assert(port
!= IP_NULL
);
1118 * The port lock is needed for ipc_right_dncancel;
1119 * otherwise, we wouldn't have to take the lock
1120 * until just before dropping the space lock.
1124 assert(ip_active(port
));
1125 assert(port
->ip_receiver_name
== name
);
1126 assert(port
->ip_receiver
== space
);
1128 /* Mach Port Guard Checking */
1129 if(port
->ip_guarded
) {
1130 uint64_t portguard
= port
->ip_context
;
1132 is_write_unlock(space
);
1133 /* Raise mach port guard exception */
1134 mach_port_guard_exception(name
, 0, portguard
, kGUARD_EXC_MOD_REFS
);
1138 if (bits
& MACH_PORT_TYPE_SEND
) {
1139 assert(IE_BITS_TYPE(bits
) ==
1140 MACH_PORT_TYPE_SEND_RECEIVE
);
1141 assert(IE_BITS_UREFS(bits
) > 0);
1142 assert(port
->ip_srights
> 0);
1144 if (port
->ip_pdrequest
!= NULL
) {
1146 * Since another task has requested a
1147 * destroy notification for this port, it
1148 * isn't actually being destroyed - the receive
1149 * right is just being moved to another task.
1150 * Since we still have one or more send rights,
1151 * we need to record the loss of the receive
1152 * right and enter the remaining send right
1153 * into the hash table.
1155 ipc_entry_modified(space
, name
, entry
);
1156 entry
->ie_bits
&= ~MACH_PORT_TYPE_RECEIVE
;
1157 ipc_hash_insert(space
, (ipc_object_t
) port
,
1162 * The remaining send right turns into a
1163 * dead name. Notice we don't decrement
1164 * ip_srights, generate a no-senders notif,
1165 * or use ipc_right_dncancel, because the
1166 * port is destroyed "first".
1168 bits
&= ~IE_BITS_TYPE_MASK
;
1169 bits
|= MACH_PORT_TYPE_DEAD_NAME
;
1170 if (entry
->ie_request
) {
1171 entry
->ie_request
= IE_REQ_NONE
;
1172 /* if urefs are pegged due to overflow, leave them pegged */
1173 if (IE_BITS_UREFS(bits
) < MACH_PORT_UREFS_MAX
)
1174 bits
++; /* increment urefs */
1176 entry
->ie_bits
= bits
;
1177 entry
->ie_object
= IO_NULL
;
1178 ipc_entry_modified(space
, name
, entry
);
1181 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_RECEIVE
);
1182 assert(IE_BITS_UREFS(bits
) == 0);
1184 request
= ipc_right_request_cancel_macro(space
, port
,
1186 entry
->ie_object
= IO_NULL
;
1187 ipc_entry_dealloc(space
, name
, entry
);
1189 is_write_unlock(space
);
1191 ipc_port_destroy(port
); /* clears receiver, consumes ref, unlocks */
1193 if (request
!= IP_NULL
)
1194 ipc_notify_port_deleted(request
, name
);
1198 case MACH_PORT_RIGHT_SEND_ONCE
: {
1201 if ((bits
& MACH_PORT_TYPE_SEND_ONCE
) == 0)
1204 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND_ONCE
);
1205 assert(IE_BITS_UREFS(bits
) == 1);
1207 port
= (ipc_port_t
) entry
->ie_object
;
1208 assert(port
!= IP_NULL
);
1210 if (ipc_right_check(space
, port
, name
, entry
)) {
1211 assert(!(entry
->ie_bits
& MACH_PORT_TYPE_SEND_ONCE
));
1214 /* port is locked and active */
1216 assert(port
->ip_sorights
> 0);
1218 if ((delta
> 0) || (delta
< -1)) {
1228 request
= ipc_right_request_cancel_macro(space
, port
, name
, entry
);
1231 entry
->ie_object
= IO_NULL
;
1232 ipc_entry_dealloc(space
, name
, entry
);
1234 is_write_unlock(space
);
1236 ipc_notify_send_once(port
);
1238 if (request
!= IP_NULL
)
1239 ipc_notify_port_deleted(request
, name
);
1243 case MACH_PORT_RIGHT_DEAD_NAME
: {
1244 ipc_port_t relport
= IP_NULL
;
1245 mach_port_urefs_t urefs
;
1247 if (bits
& MACH_PORT_TYPE_SEND_RIGHTS
) {
1249 port
= (ipc_port_t
) entry
->ie_object
;
1250 assert(port
!= IP_NULL
);
1252 if (!ipc_right_check(space
, port
, name
, entry
)) {
1253 /* port is locked and active */
1258 bits
= entry
->ie_bits
;
1261 } else if ((bits
& MACH_PORT_TYPE_DEAD_NAME
) == 0) {
1265 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_DEAD_NAME
);
1266 assert(IE_BITS_UREFS(bits
) > 0);
1267 assert(entry
->ie_object
== IO_NULL
);
1268 assert(entry
->ie_request
== IE_REQ_NONE
);
1270 if (delta
> ((mach_port_delta_t
)MACH_PORT_UREFS_MAX
) ||
1271 delta
< (-((mach_port_delta_t
)MACH_PORT_UREFS_MAX
))) {
1275 urefs
= IE_BITS_UREFS(bits
);
1277 if (urefs
== MACH_PORT_UREFS_MAX
) {
1279 * urefs are pegged due to an overflow
1280 * only a delta removing all refs at once can change it
1283 if (delta
!= (-((mach_port_delta_t
)MACH_PORT_UREFS_MAX
)))
1286 if (MACH_PORT_UREFS_UNDERFLOW(urefs
, delta
))
1288 if (MACH_PORT_UREFS_OVERFLOW(urefs
, delta
)) {
1289 /* leave urefs pegged to maximum if it overflowed */
1290 delta
= MACH_PORT_UREFS_MAX
- urefs
;
1294 if ((urefs
+ delta
) == 0) {
1295 ipc_entry_dealloc(space
, name
, entry
);
1296 } else if (delta
!= 0) {
1297 entry
->ie_bits
= bits
+ delta
;
1298 ipc_entry_modified(space
, name
, entry
);
1301 is_write_unlock(space
);
1303 if (relport
!= IP_NULL
)
1304 ip_release(relport
);
1309 case MACH_PORT_RIGHT_SEND
: {
1310 mach_port_urefs_t urefs
;
1311 ipc_port_t request
= IP_NULL
;
1312 ipc_port_t nsrequest
= IP_NULL
;
1313 ipc_port_t port_to_release
= IP_NULL
;
1314 mach_port_mscount_t mscount
= 0;
1316 if ((bits
& MACH_PORT_TYPE_SEND
) == 0)
1319 /* maximum urefs for send is MACH_PORT_UREFS_MAX */
1321 port
= (ipc_port_t
) entry
->ie_object
;
1322 assert(port
!= IP_NULL
);
1324 if (ipc_right_check(space
, port
, name
, entry
)) {
1325 assert((entry
->ie_bits
& MACH_PORT_TYPE_SEND
) == 0);
1328 /* port is locked and active */
1330 assert(port
->ip_srights
> 0);
1332 if (delta
> ((mach_port_delta_t
)MACH_PORT_UREFS_MAX
) ||
1333 delta
< (-((mach_port_delta_t
)MACH_PORT_UREFS_MAX
))) {
1338 urefs
= IE_BITS_UREFS(bits
);
1340 if (urefs
== MACH_PORT_UREFS_MAX
) {
1342 * urefs are pegged due to an overflow
1343 * only a delta removing all refs at once can change it
1346 if (delta
!= (-((mach_port_delta_t
)MACH_PORT_UREFS_MAX
)))
1349 if (MACH_PORT_UREFS_UNDERFLOW(urefs
, delta
)) {
1353 if (MACH_PORT_UREFS_OVERFLOW(urefs
, delta
)) {
1354 /* leave urefs pegged to maximum if it overflowed */
1355 delta
= MACH_PORT_UREFS_MAX
- urefs
;
1359 if ((urefs
+ delta
) == 0) {
1360 if (--port
->ip_srights
== 0) {
1361 nsrequest
= port
->ip_nsrequest
;
1362 if (nsrequest
!= IP_NULL
) {
1363 port
->ip_nsrequest
= IP_NULL
;
1364 mscount
= port
->ip_mscount
;
1368 if (bits
& MACH_PORT_TYPE_RECEIVE
) {
1369 assert(port
->ip_receiver_name
== name
);
1370 assert(port
->ip_receiver
== space
);
1372 assert(IE_BITS_TYPE(bits
) ==
1373 MACH_PORT_TYPE_SEND_RECEIVE
);
1375 entry
->ie_bits
= bits
&~ (IE_BITS_UREFS_MASK
|
1376 MACH_PORT_TYPE_SEND
);
1377 ipc_entry_modified(space
, name
, entry
);
1379 assert(IE_BITS_TYPE(bits
) ==
1380 MACH_PORT_TYPE_SEND
);
1382 request
= ipc_right_request_cancel_macro(space
, port
,
1384 ipc_hash_delete(space
, (ipc_object_t
) port
,
1388 port_to_release
= port
;
1390 entry
->ie_object
= IO_NULL
;
1391 ipc_entry_dealloc(space
, name
, entry
);
1393 } else if (delta
!= 0) {
1395 entry
->ie_bits
= bits
+ delta
;
1396 ipc_entry_modified(space
, name
, entry
);
1401 is_write_unlock(space
);
1403 if (port_to_release
!= IP_NULL
)
1404 ip_release(port_to_release
);
1406 if (nsrequest
!= IP_NULL
)
1407 ipc_notify_no_senders(nsrequest
, mscount
);
1409 if (request
!= IP_NULL
)
1410 ipc_notify_port_deleted(request
, name
);
1415 panic("ipc_right_delta: strange right");
1418 return KERN_SUCCESS
;
1421 is_write_unlock(space
);
1422 return KERN_SUCCESS
;
1425 is_write_unlock(space
);
1426 if (port
!= IP_NULL
)
1428 return KERN_INVALID_RIGHT
;
1431 is_write_unlock(space
);
1432 return KERN_INVALID_VALUE
;
1435 return KERN_INVALID_RIGHT
;
1439 * Routine: ipc_right_destruct
1441 * Deallocates the receive right and modifies the
1442 * user-reference count for the send rights as requested.
1444 * The space is write-locked, and is unlocked upon return.
1445 * The space must be active.
1447 * KERN_SUCCESS Count was modified.
1448 * KERN_INVALID_RIGHT Entry has wrong type.
1449 * KERN_INVALID_VALUE Bad delta for the right.
1455 mach_port_name_t name
,
1457 mach_port_delta_t srdelta
,
1460 ipc_port_t port
= IP_NULL
;
1461 ipc_entry_bits_t bits
;
1463 mach_port_urefs_t urefs
;
1464 ipc_port_t request
= IP_NULL
;
1465 ipc_port_t nsrequest
= IP_NULL
;
1466 mach_port_mscount_t mscount
= 0;
1468 bits
= entry
->ie_bits
;
1470 assert(is_active(space
));
1472 if (((bits
& MACH_PORT_TYPE_RECEIVE
) == 0) ||
1473 (srdelta
&& ((bits
& MACH_PORT_TYPE_SEND
) == 0))) {
1474 is_write_unlock(space
);
1475 return KERN_INVALID_RIGHT
;
1481 port
= (ipc_port_t
) entry
->ie_object
;
1482 assert(port
!= IP_NULL
);
1485 assert(ip_active(port
));
1486 assert(port
->ip_receiver_name
== name
);
1487 assert(port
->ip_receiver
== space
);
1489 /* Mach Port Guard Checking */
1490 if(port
->ip_guarded
&& (guard
!= port
->ip_context
)) {
1491 uint64_t portguard
= port
->ip_context
;
1493 is_write_unlock(space
);
1494 mach_port_guard_exception(name
, 0, portguard
, kGUARD_EXC_DESTROY
);
1495 return KERN_INVALID_ARGUMENT
;
1499 * First reduce the send rights as requested and
1500 * adjust the entry->ie_bits accordingly. The
1501 * ipc_entry_modified() call is made once the receive
1502 * right is destroyed too.
1507 assert(port
->ip_srights
> 0);
1509 urefs
= IE_BITS_UREFS(bits
);
1512 * Since we made sure that srdelta is negative,
1513 * the check for urefs overflow is not required.
1515 if (MACH_PORT_UREFS_UNDERFLOW(urefs
, srdelta
)) {
1520 if (urefs
== MACH_PORT_UREFS_MAX
) {
1522 * urefs are pegged due to an overflow
1523 * only a delta removing all refs at once can change it
1525 if (srdelta
!= (-((mach_port_delta_t
)MACH_PORT_UREFS_MAX
)))
1529 if ((urefs
+ srdelta
) == 0) {
1530 if (--port
->ip_srights
== 0) {
1531 nsrequest
= port
->ip_nsrequest
;
1532 if (nsrequest
!= IP_NULL
) {
1533 port
->ip_nsrequest
= IP_NULL
;
1534 mscount
= port
->ip_mscount
;
1537 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND_RECEIVE
);
1538 entry
->ie_bits
= bits
&~ (IE_BITS_UREFS_MASK
|
1539 MACH_PORT_TYPE_SEND
);
1541 entry
->ie_bits
= bits
+ srdelta
;
1546 * Now destroy the receive right. Update space and
1547 * entry accordingly.
1550 bits
= entry
->ie_bits
;
1551 if (bits
& MACH_PORT_TYPE_SEND
) {
1552 assert(IE_BITS_UREFS(bits
) > 0);
1553 assert(IE_BITS_UREFS(bits
) <= MACH_PORT_UREFS_MAX
);
1555 if (port
->ip_pdrequest
!= NULL
) {
1557 * Since another task has requested a
1558 * destroy notification for this port, it
1559 * isn't actually being destroyed - the receive
1560 * right is just being moved to another task.
1561 * Since we still have one or more send rights,
1562 * we need to record the loss of the receive
1563 * right and enter the remaining send right
1564 * into the hash table.
1566 ipc_entry_modified(space
, name
, entry
);
1567 entry
->ie_bits
&= ~MACH_PORT_TYPE_RECEIVE
;
1568 ipc_hash_insert(space
, (ipc_object_t
) port
,
1573 * The remaining send right turns into a
1574 * dead name. Notice we don't decrement
1575 * ip_srights, generate a no-senders notif,
1576 * or use ipc_right_dncancel, because the
1577 * port is destroyed "first".
1579 bits
&= ~IE_BITS_TYPE_MASK
;
1580 bits
|= MACH_PORT_TYPE_DEAD_NAME
;
1581 if (entry
->ie_request
) {
1582 entry
->ie_request
= IE_REQ_NONE
;
1583 if (IE_BITS_UREFS(bits
) < MACH_PORT_UREFS_MAX
)
1584 bits
++; /* increment urefs */
1586 entry
->ie_bits
= bits
;
1587 entry
->ie_object
= IO_NULL
;
1588 ipc_entry_modified(space
, name
, entry
);
1591 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_RECEIVE
);
1592 assert(IE_BITS_UREFS(bits
) == 0);
1593 request
= ipc_right_request_cancel_macro(space
, port
,
1595 entry
->ie_object
= IO_NULL
;
1596 ipc_entry_dealloc(space
, name
, entry
);
1600 is_write_unlock(space
);
1602 if (nsrequest
!= IP_NULL
)
1603 ipc_notify_no_senders(nsrequest
, mscount
);
1605 ipc_port_destroy(port
); /* clears receiver, consumes ref, unlocks */
1607 if (request
!= IP_NULL
)
1608 ipc_notify_port_deleted(request
, name
);
1610 return KERN_SUCCESS
;
1613 is_write_unlock(space
);
1614 return KERN_INVALID_VALUE
;
1620 * Routine: ipc_right_info
1622 * Retrieves information about the right.
1624 * The space is active and write-locked.
1625 * The space is unlocked upon return.
1627 * KERN_SUCCESS Retrieved info
1633 mach_port_name_t name
,
1635 mach_port_type_t
*typep
,
1636 mach_port_urefs_t
*urefsp
)
1639 ipc_entry_bits_t bits
;
1640 mach_port_type_t type
= 0;
1641 ipc_port_request_index_t request
;
1643 bits
= entry
->ie_bits
;
1644 request
= entry
->ie_request
;
1645 port
= (ipc_port_t
) entry
->ie_object
;
1647 if (bits
& MACH_PORT_TYPE_RECEIVE
) {
1648 assert(IP_VALID(port
));
1650 if (request
!= IE_REQ_NONE
) {
1652 assert(ip_active(port
));
1653 type
|= ipc_port_request_type(port
, name
, request
);
1656 is_write_unlock(space
);
1658 } else if (bits
& MACH_PORT_TYPE_SEND_RIGHTS
) {
1660 * validate port is still alive - if so, get request
1661 * types while we still have it locked. Otherwise,
1662 * recapture the (now dead) bits.
1664 if (!ipc_right_check(space
, port
, name
, entry
)) {
1665 if (request
!= IE_REQ_NONE
)
1666 type
|= ipc_port_request_type(port
, name
, request
);
1668 is_write_unlock(space
);
1670 bits
= entry
->ie_bits
;
1671 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_DEAD_NAME
);
1672 is_write_unlock(space
);
1676 is_write_unlock(space
);
1679 type
|= IE_BITS_TYPE(bits
);
1682 *urefsp
= IE_BITS_UREFS(bits
);
1683 return KERN_SUCCESS
;
1687 * Routine: ipc_right_copyin_check
1689 * Check if a subsequent ipc_right_copyin would succeed.
1691 * The space is locked (read or write) and active.
1695 ipc_right_copyin_check(
1696 __assert_only ipc_space_t space
,
1697 __unused mach_port_name_t name
,
1699 mach_msg_type_name_t msgt_name
)
1701 ipc_entry_bits_t bits
;
1704 bits
= entry
->ie_bits
;
1705 assert(is_active(space
));
1707 switch (msgt_name
) {
1708 case MACH_MSG_TYPE_MAKE_SEND
:
1709 if ((bits
& MACH_PORT_TYPE_RECEIVE
) == 0)
1713 case MACH_MSG_TYPE_MAKE_SEND_ONCE
:
1714 if ((bits
& MACH_PORT_TYPE_RECEIVE
) == 0)
1718 case MACH_MSG_TYPE_MOVE_RECEIVE
:
1719 if ((bits
& MACH_PORT_TYPE_RECEIVE
) == 0)
1723 case MACH_MSG_TYPE_COPY_SEND
:
1724 case MACH_MSG_TYPE_MOVE_SEND
:
1725 case MACH_MSG_TYPE_MOVE_SEND_ONCE
: {
1727 if (bits
& MACH_PORT_TYPE_DEAD_NAME
)
1730 if ((bits
& MACH_PORT_TYPE_SEND_RIGHTS
) == 0)
1733 port
= (ipc_port_t
) entry
->ie_object
;
1734 assert(port
!= IP_NULL
);
1737 * active status peek to avoid checks that will be skipped
1738 * on copyin for dead ports. Lock not held, so will not be
1739 * atomic (but once dead, there's no going back).
1741 if (!ip_active(port
)) {
1745 if (msgt_name
== MACH_MSG_TYPE_MOVE_SEND_ONCE
) {
1746 if ((bits
& MACH_PORT_TYPE_SEND_ONCE
) == 0)
1749 if ((bits
& MACH_PORT_TYPE_SEND
) == 0)
1757 panic("ipc_right_copyin_check: strange rights");
1764 * Routine: ipc_right_copyin
1766 * Copyin a capability from a space.
1767 * If successful, the caller gets a ref
1768 * for the resulting object, unless it is IO_DEAD,
1769 * and possibly a send-once right which should
1770 * be used in a port-deleted notification.
1772 * If deadok is not TRUE, the copyin operation
1773 * will fail instead of producing IO_DEAD.
1775 * The entry is never deallocated (except
1776 * when KERN_INVALID_NAME), so the caller
1777 * should deallocate the entry if its type
1778 * is MACH_PORT_TYPE_NONE.
1780 * The space is write-locked and active.
1782 * KERN_SUCCESS Acquired an object, possibly IO_DEAD.
1783 * KERN_INVALID_RIGHT Name doesn't denote correct right.
1789 mach_port_name_t name
,
1791 mach_msg_type_name_t msgt_name
,
1793 ipc_object_t
*objectp
,
1794 ipc_port_t
*sorightp
,
1795 ipc_port_t
*releasep
,
1798 ipc_entry_bits_t bits
;
1801 *releasep
= IP_NULL
;
1804 bits
= entry
->ie_bits
;
1806 assert(is_active(space
));
1808 switch (msgt_name
) {
1809 case MACH_MSG_TYPE_MAKE_SEND
: {
1811 if ((bits
& MACH_PORT_TYPE_RECEIVE
) == 0)
1814 port
= (ipc_port_t
) entry
->ie_object
;
1815 assert(port
!= IP_NULL
);
1818 assert(ip_active(port
));
1819 assert(port
->ip_receiver_name
== name
);
1820 assert(port
->ip_receiver
== space
);
1827 *objectp
= (ipc_object_t
) port
;
1828 *sorightp
= IP_NULL
;
1832 case MACH_MSG_TYPE_MAKE_SEND_ONCE
: {
1834 if ((bits
& MACH_PORT_TYPE_RECEIVE
) == 0)
1837 port
= (ipc_port_t
) entry
->ie_object
;
1838 assert(port
!= IP_NULL
);
1841 assert(ip_active(port
));
1842 assert(port
->ip_receiver_name
== name
);
1843 assert(port
->ip_receiver
== space
);
1845 port
->ip_sorights
++;
1849 *objectp
= (ipc_object_t
) port
;
1850 *sorightp
= IP_NULL
;
1854 case MACH_MSG_TYPE_MOVE_RECEIVE
: {
1855 ipc_port_t request
= IP_NULL
;
1857 if ((bits
& MACH_PORT_TYPE_RECEIVE
) == 0)
1860 port
= (ipc_port_t
) entry
->ie_object
;
1861 assert(port
!= IP_NULL
);
1864 assert(ip_active(port
));
1865 assert(port
->ip_receiver_name
== name
);
1866 assert(port
->ip_receiver
== space
);
1868 if (bits
& MACH_PORT_TYPE_SEND
) {
1869 assert(IE_BITS_TYPE(bits
) ==
1870 MACH_PORT_TYPE_SEND_RECEIVE
);
1871 assert(IE_BITS_UREFS(bits
) > 0);
1872 assert(port
->ip_srights
> 0);
1874 ipc_hash_insert(space
, (ipc_object_t
) port
,
1878 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_RECEIVE
);
1879 assert(IE_BITS_UREFS(bits
) == 0);
1881 request
= ipc_right_request_cancel_macro(space
, port
,
1883 entry
->ie_object
= IO_NULL
;
1885 entry
->ie_bits
= bits
&~ MACH_PORT_TYPE_RECEIVE
;
1886 ipc_entry_modified(space
, name
, entry
);
1888 (void)ipc_port_clear_receiver(port
, FALSE
); /* don't destroy the port/mqueue */
1889 port
->ip_receiver_name
= MACH_PORT_NULL
;
1890 port
->ip_destination
= IP_NULL
;
1892 #if IMPORTANCE_INHERITANCE
1894 * Account for boosts the current task is going to lose when
1895 * copying this right in. Tempowner ports have either not
1896 * been accounting to any task (and therefore are already in
1897 * "limbo" state w.r.t. assertions) or to some other specific
1898 * task. As we have no way to drop the latter task's assertions
1899 * here, We'll deduct those when we enqueue it on its
1900 * destination port (see ipc_port_check_circularity()).
1902 if (port
->ip_tempowner
== 0) {
1903 assert(IIT_NULL
== port
->ip_imp_task
);
1905 /* ports in limbo have to be tempowner */
1906 port
->ip_tempowner
= 1;
1907 *assertcntp
= port
->ip_impcount
;
1909 #endif /* IMPORTANCE_INHERITANCE */
1913 *objectp
= (ipc_object_t
) port
;
1914 *sorightp
= request
;
1918 case MACH_MSG_TYPE_COPY_SEND
: {
1920 if (bits
& MACH_PORT_TYPE_DEAD_NAME
)
1923 /* allow for dead send-once rights */
1925 if ((bits
& MACH_PORT_TYPE_SEND_RIGHTS
) == 0)
1928 assert(IE_BITS_UREFS(bits
) > 0);
1930 port
= (ipc_port_t
) entry
->ie_object
;
1931 assert(port
!= IP_NULL
);
1933 if (ipc_right_check(space
, port
, name
, entry
)) {
1934 bits
= entry
->ie_bits
;
1938 /* port is locked and active */
1940 if ((bits
& MACH_PORT_TYPE_SEND
) == 0) {
1941 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND_ONCE
);
1942 assert(port
->ip_sorights
> 0);
1948 assert(port
->ip_srights
> 0);
1954 *objectp
= (ipc_object_t
) port
;
1955 *sorightp
= IP_NULL
;
1959 case MACH_MSG_TYPE_MOVE_SEND
: {
1960 ipc_port_t request
= IP_NULL
;
1962 if (bits
& MACH_PORT_TYPE_DEAD_NAME
)
1965 /* allow for dead send-once rights */
1967 if ((bits
& MACH_PORT_TYPE_SEND_RIGHTS
) == 0)
1970 assert(IE_BITS_UREFS(bits
) > 0);
1972 port
= (ipc_port_t
) entry
->ie_object
;
1973 assert(port
!= IP_NULL
);
1975 if (ipc_right_check(space
, port
, name
, entry
)) {
1976 bits
= entry
->ie_bits
;
1980 /* port is locked and active */
1982 if ((bits
& MACH_PORT_TYPE_SEND
) == 0) {
1983 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND_ONCE
);
1984 assert(port
->ip_sorights
> 0);
1990 assert(port
->ip_srights
> 0);
1992 if (IE_BITS_UREFS(bits
) == 1) {
1993 if (bits
& MACH_PORT_TYPE_RECEIVE
) {
1994 assert(port
->ip_receiver_name
== name
);
1995 assert(port
->ip_receiver
== space
);
1996 assert(IE_BITS_TYPE(bits
) ==
1997 MACH_PORT_TYPE_SEND_RECEIVE
);
2001 assert(IE_BITS_TYPE(bits
) ==
2002 MACH_PORT_TYPE_SEND
);
2004 request
= ipc_right_request_cancel_macro(space
, port
,
2006 ipc_hash_delete(space
, (ipc_object_t
) port
,
2008 entry
->ie_object
= IO_NULL
;
2009 /* transfer entry's reference to caller */
2011 entry
->ie_bits
= bits
&~
2012 (IE_BITS_UREFS_MASK
|MACH_PORT_TYPE_SEND
);
2016 /* if urefs are pegged due to overflow, leave them pegged */
2017 if (IE_BITS_UREFS(bits
) < MACH_PORT_UREFS_MAX
)
2018 entry
->ie_bits
= bits
-1; /* decrement urefs */
2021 ipc_entry_modified(space
, name
, entry
);
2024 *objectp
= (ipc_object_t
) port
;
2025 *sorightp
= request
;
2029 case MACH_MSG_TYPE_MOVE_SEND_ONCE
: {
2032 if (bits
& MACH_PORT_TYPE_DEAD_NAME
)
2035 /* allow for dead send rights */
2037 if ((bits
& MACH_PORT_TYPE_SEND_RIGHTS
) == 0)
2040 assert(IE_BITS_UREFS(bits
) > 0);
2042 port
= (ipc_port_t
) entry
->ie_object
;
2043 assert(port
!= IP_NULL
);
2045 if (ipc_right_check(space
, port
, name
, entry
)) {
2046 bits
= entry
->ie_bits
;
2050 /* port is locked and active */
2052 if ((bits
& MACH_PORT_TYPE_SEND_ONCE
) == 0) {
2053 assert(bits
& MACH_PORT_TYPE_SEND
);
2054 assert(port
->ip_srights
> 0);
2060 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND_ONCE
);
2061 assert(IE_BITS_UREFS(bits
) == 1);
2062 assert(port
->ip_sorights
> 0);
2064 request
= ipc_right_request_cancel_macro(space
, port
, name
, entry
);
2067 entry
->ie_object
= IO_NULL
;
2068 entry
->ie_bits
= bits
&~
2069 (IE_BITS_UREFS_MASK
| MACH_PORT_TYPE_SEND_ONCE
);
2070 ipc_entry_modified(space
, name
, entry
);
2071 *objectp
= (ipc_object_t
) port
;
2072 *sorightp
= request
;
2078 return KERN_INVALID_RIGHT
;
2081 return KERN_SUCCESS
;
2084 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_DEAD_NAME
);
2085 assert(IE_BITS_UREFS(bits
) > 0);
2086 assert(entry
->ie_request
== IE_REQ_NONE
);
2087 assert(entry
->ie_object
== 0);
2093 *sorightp
= IP_NULL
;
2094 return KERN_SUCCESS
;
2097 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_DEAD_NAME
);
2098 assert(IE_BITS_UREFS(bits
) > 0);
2099 assert(entry
->ie_request
== IE_REQ_NONE
);
2100 assert(entry
->ie_object
== 0);
2105 if (IE_BITS_UREFS(bits
) == 1) {
2106 bits
&= ~MACH_PORT_TYPE_DEAD_NAME
;
2108 /* if urefs are pegged due to overflow, leave them pegged */
2109 if (IE_BITS_UREFS(bits
) < MACH_PORT_UREFS_MAX
)
2110 entry
->ie_bits
= bits
-1; /* decrement urefs */
2112 ipc_entry_modified(space
, name
, entry
);
2114 *sorightp
= IP_NULL
;
2115 return KERN_SUCCESS
;
2120 * Routine: ipc_right_copyin_undo
2122 * Undoes the effects of an ipc_right_copyin
2123 * of a send/send-once right that is dead.
2124 * (Object is either IO_DEAD or a dead port.)
2126 * The space is write-locked and active.
2130 ipc_right_copyin_undo(
2132 mach_port_name_t name
,
2134 mach_msg_type_name_t msgt_name
,
2135 ipc_object_t object
,
2138 ipc_entry_bits_t bits
;
2140 bits
= entry
->ie_bits
;
2142 assert(is_active(space
));
2144 assert((msgt_name
== MACH_MSG_TYPE_MOVE_SEND
) ||
2145 (msgt_name
== MACH_MSG_TYPE_COPY_SEND
) ||
2146 (msgt_name
== MACH_MSG_TYPE_MOVE_SEND_ONCE
));
2148 if (soright
!= IP_NULL
) {
2149 assert((msgt_name
== MACH_MSG_TYPE_MOVE_SEND
) ||
2150 (msgt_name
== MACH_MSG_TYPE_MOVE_SEND_ONCE
));
2151 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_NONE
);
2152 assert(object
!= IO_DEAD
);
2154 entry
->ie_bits
= ((bits
&~ IE_BITS_RIGHT_MASK
) |
2155 MACH_PORT_TYPE_DEAD_NAME
| 2);
2157 } else if (IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_NONE
) {
2158 assert((msgt_name
== MACH_MSG_TYPE_MOVE_SEND
) ||
2159 (msgt_name
== MACH_MSG_TYPE_MOVE_SEND_ONCE
));
2161 entry
->ie_bits
= ((bits
&~ IE_BITS_RIGHT_MASK
) |
2162 MACH_PORT_TYPE_DEAD_NAME
| 1);
2163 } else if (IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_DEAD_NAME
) {
2164 assert(object
== IO_DEAD
);
2165 assert(IE_BITS_UREFS(bits
) > 0);
2167 if (msgt_name
!= MACH_MSG_TYPE_COPY_SEND
) {
2168 assert(IE_BITS_UREFS(bits
) <= MACH_PORT_UREFS_MAX
);
2169 /* if urefs are pegged due to overflow, leave them pegged */
2170 if (IE_BITS_UREFS(bits
) < MACH_PORT_UREFS_MAX
)
2171 entry
->ie_bits
= bits
+1; /* increment urefs */
2174 assert((msgt_name
== MACH_MSG_TYPE_MOVE_SEND
) ||
2175 (msgt_name
== MACH_MSG_TYPE_COPY_SEND
));
2176 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND
);
2177 assert(object
!= IO_DEAD
);
2178 assert(entry
->ie_object
== object
);
2179 assert(IE_BITS_UREFS(bits
) > 0);
2181 if (msgt_name
!= MACH_MSG_TYPE_COPY_SEND
) {
2182 assert(IE_BITS_UREFS(bits
) <= MACH_PORT_UREFS_MAX
);
2183 /* if urefs are pegged due to overflow, leave them pegged */
2184 if (IE_BITS_UREFS(bits
) < MACH_PORT_UREFS_MAX
)
2185 entry
->ie_bits
= bits
+1; /* increment urefs */
2189 * May as well convert the entry to a dead name.
2190 * (Or if it is a compat entry, destroy it.)
2193 (void) ipc_right_check(space
, (ipc_port_t
) object
,
2195 /* object is dead so it is not locked */
2197 ipc_entry_modified(space
, name
, entry
);
2198 /* release the reference acquired by copyin */
2200 if (object
!= IO_DEAD
)
2205 * Routine: ipc_right_copyin_two_move_sends
2207 * Like ipc_right_copyin with MACH_MSG_TYPE_MOVE_SEND
2208 * and deadok == FALSE, except that this moves two
2209 * send rights at once.
2211 * The space is write-locked and active.
2212 * The object is returned with two refs/send rights.
2214 * KERN_SUCCESS Acquired an object.
2215 * KERN_INVALID_RIGHT Name doesn't denote correct right.
2219 ipc_right_copyin_two_move_sends(
2221 mach_port_name_t name
,
2223 ipc_object_t
*objectp
,
2224 ipc_port_t
*sorightp
,
2225 ipc_port_t
*releasep
)
2227 ipc_entry_bits_t bits
;
2228 mach_port_urefs_t urefs
;
2230 ipc_port_t request
= IP_NULL
;
2232 *releasep
= IP_NULL
;
2234 assert(is_active(space
));
2236 bits
= entry
->ie_bits
;
2238 if ((bits
& MACH_PORT_TYPE_SEND
) == 0)
2241 urefs
= IE_BITS_UREFS(bits
);
2245 port
= (ipc_port_t
) entry
->ie_object
;
2246 assert(port
!= IP_NULL
);
2248 if (ipc_right_check(space
, port
, name
, entry
)) {
2252 /* port is locked and active */
2254 assert(port
->ip_srights
> 0);
2257 if (bits
& MACH_PORT_TYPE_RECEIVE
) {
2258 assert(port
->ip_receiver_name
== name
);
2259 assert(port
->ip_receiver
== space
);
2260 assert(IE_BITS_TYPE(bits
) ==
2261 MACH_PORT_TYPE_SEND_RECEIVE
);
2267 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND
);
2269 request
= ipc_right_request_cancel_macro(space
, port
,
2274 ipc_hash_delete(space
, (ipc_object_t
) port
,
2276 entry
->ie_object
= IO_NULL
;
2278 entry
->ie_bits
= bits
&~ (IE_BITS_UREFS_MASK
|MACH_PORT_TYPE_SEND
);
2280 port
->ip_srights
+= 2;
2283 /* if urefs are pegged due to overflow, leave them pegged */
2284 if (IE_BITS_UREFS(bits
) < MACH_PORT_UREFS_MAX
)
2285 entry
->ie_bits
= bits
-2; /* decrement urefs */
2287 ipc_entry_modified(space
, name
, entry
);
2291 *objectp
= (ipc_object_t
) port
;
2292 *sorightp
= request
;
2293 return KERN_SUCCESS
;
2296 return KERN_INVALID_RIGHT
;
2301 * Routine: ipc_right_copyin_two
2303 * Like ipc_right_copyin with two dispositions,
2304 * each of which results in a send or send-once right,
2305 * and deadok = FALSE.
2307 * The space is write-locked and active.
2308 * The object is returned with two refs/rights.
2310 * KERN_SUCCESS Acquired an object.
2311 * KERN_INVALID_RIGHT Name doesn't denote correct right(s).
2312 * KERN_INVALID_CAPABILITY Name doesn't denote correct right for msgt_two.
2315 ipc_right_copyin_two(
2317 mach_port_name_t name
,
2319 mach_msg_type_name_t msgt_one
,
2320 mach_msg_type_name_t msgt_two
,
2321 ipc_object_t
*objectp
,
2322 ipc_port_t
*sorightp
,
2323 ipc_port_t
*releasep
)
2328 assert(MACH_MSG_TYPE_PORT_ANY_SEND(msgt_one
));
2329 assert(MACH_MSG_TYPE_PORT_ANY_SEND(msgt_two
));
2333 * Pre-validate the second disposition is possible all by itself.
2335 if (!ipc_right_copyin_check(space
, name
, entry
, msgt_two
)) {
2336 return KERN_INVALID_CAPABILITY
;
2340 * This is a little tedious to make atomic, because
2341 * there are 25 combinations of valid dispositions.
2342 * However, most are easy.
2346 * If either is move-sonce, then there must be an error.
2348 if (msgt_one
== MACH_MSG_TYPE_MOVE_SEND_ONCE
||
2349 msgt_two
== MACH_MSG_TYPE_MOVE_SEND_ONCE
) {
2350 return KERN_INVALID_RIGHT
;
2353 if ((msgt_one
== MACH_MSG_TYPE_MAKE_SEND
) ||
2354 (msgt_one
== MACH_MSG_TYPE_MAKE_SEND_ONCE
) ||
2355 (msgt_two
== MACH_MSG_TYPE_MAKE_SEND
) ||
2356 (msgt_two
== MACH_MSG_TYPE_MAKE_SEND_ONCE
)) {
2358 * One of the dispositions needs a receive right.
2360 * If the copyin below succeeds, we know the receive
2361 * right is there (because the pre-validation of
2362 * the second disposition already succeeded in our
2365 * Hence the port is not in danger of dying.
2367 ipc_object_t object_two
;
2369 kr
= ipc_right_copyin(space
, name
, entry
,
2371 objectp
, sorightp
, releasep
,
2373 assert(assertcnt
== 0);
2374 if (kr
!= KERN_SUCCESS
) {
2378 assert(IO_VALID(*objectp
));
2379 assert(*sorightp
== IP_NULL
);
2380 assert(*releasep
== IP_NULL
);
2383 * Now copyin the second (previously validated)
2384 * disposition. The result can't be a dead port,
2385 * as no valid disposition can make us lose our
2388 kr
= ipc_right_copyin(space
, name
, entry
,
2390 &object_two
, sorightp
, releasep
,
2392 assert(assertcnt
== 0);
2393 assert(kr
== KERN_SUCCESS
);
2394 assert(*sorightp
== IP_NULL
);
2395 assert(*releasep
== IP_NULL
);
2396 assert(object_two
== *objectp
);
2397 assert(entry
->ie_bits
& MACH_PORT_TYPE_RECEIVE
);
2399 } else if ((msgt_one
== MACH_MSG_TYPE_MOVE_SEND
) &&
2400 (msgt_two
== MACH_MSG_TYPE_MOVE_SEND
)) {
2402 * This is an easy case. Just use our
2403 * handy-dandy special-purpose copyin call
2404 * to get two send rights for the price of one.
2406 kr
= ipc_right_copyin_two_move_sends(space
, name
, entry
,
2409 if (kr
!= KERN_SUCCESS
) {
2414 mach_msg_type_name_t msgt_name
;
2417 * Must be either a single move-send and a
2418 * copy-send, or two copy-send dispositions.
2419 * Use the disposition with the greatest side
2420 * effects for the actual copyin - then just
2421 * duplicate the send right you get back.
2423 if (msgt_one
== MACH_MSG_TYPE_MOVE_SEND
||
2424 msgt_two
== MACH_MSG_TYPE_MOVE_SEND
) {
2425 msgt_name
= MACH_MSG_TYPE_MOVE_SEND
;
2427 msgt_name
= MACH_MSG_TYPE_COPY_SEND
;
2430 kr
= ipc_right_copyin(space
, name
, entry
,
2432 objectp
, sorightp
, releasep
,
2434 assert(assertcnt
== 0);
2435 if (kr
!= KERN_SUCCESS
) {
2440 * Copy the right we got back. If it is dead now,
2441 * that's OK. Neither right will be usable to send
2444 (void)ipc_port_copy_send((ipc_port_t
)*objectp
);
2447 return KERN_SUCCESS
;
2452 * Routine: ipc_right_copyout
2454 * Copyout a capability to a space.
2455 * If successful, consumes a ref for the object.
2457 * Always succeeds when given a newly-allocated entry,
2458 * because user-reference overflow isn't a possibility.
2460 * If copying out the object would cause the user-reference
2461 * count in the entry to overflow, and overflow is TRUE,
2462 * then instead the user-reference count is left pegged
2463 * to its maximum value and the copyout succeeds anyway.
2465 * The space is write-locked and active.
2466 * The object is locked and active.
2467 * The object is unlocked; the space isn't.
2469 * KERN_SUCCESS Copied out capability.
2475 mach_port_name_t name
,
2477 mach_msg_type_name_t msgt_name
,
2478 __unused boolean_t overflow
,
2479 ipc_object_t object
)
2481 ipc_entry_bits_t bits
;
2484 bits
= entry
->ie_bits
;
2486 assert(IO_VALID(object
));
2487 assert(io_otype(object
) == IOT_PORT
);
2488 assert(io_active(object
));
2489 assert(entry
->ie_object
== object
);
2491 port
= (ipc_port_t
) object
;
2493 switch (msgt_name
) {
2494 case MACH_MSG_TYPE_PORT_SEND_ONCE
:
2496 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_NONE
);
2497 assert(IE_BITS_UREFS(bits
) == 0);
2498 assert(port
->ip_sorights
> 0);
2500 /* transfer send-once right and ref to entry */
2503 entry
->ie_bits
= bits
| (MACH_PORT_TYPE_SEND_ONCE
| 1); /* set urefs to 1 */
2504 ipc_entry_modified(space
, name
, entry
);
2507 case MACH_MSG_TYPE_PORT_SEND
:
2508 assert(port
->ip_srights
> 0);
2510 if (bits
& MACH_PORT_TYPE_SEND
) {
2511 mach_port_urefs_t urefs
= IE_BITS_UREFS(bits
);
2513 assert(port
->ip_srights
> 1);
2515 assert(urefs
<= MACH_PORT_UREFS_MAX
);
2517 if (urefs
== MACH_PORT_UREFS_MAX
) {
2519 * leave urefs pegged to maximum,
2520 * consume send right and ref
2526 return KERN_SUCCESS
;
2529 /* consume send right and ref */
2534 } else if (bits
& MACH_PORT_TYPE_RECEIVE
) {
2535 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_RECEIVE
);
2536 assert(IE_BITS_UREFS(bits
) == 0);
2538 /* transfer send right to entry, consume ref */
2543 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_NONE
);
2544 assert(IE_BITS_UREFS(bits
) == 0);
2546 /* transfer send right and ref to entry */
2549 /* entry is locked holding ref, so can use port */
2551 ipc_hash_insert(space
, (ipc_object_t
) port
,
2555 entry
->ie_bits
= (bits
| MACH_PORT_TYPE_SEND
) + 1; /* increment urefs */
2556 ipc_entry_modified(space
, name
, entry
);
2559 case MACH_MSG_TYPE_PORT_RECEIVE
: {
2562 #if IMPORTANCE_INHERITANCE
2563 natural_t assertcnt
= port
->ip_impcount
;
2564 #endif /* IMPORTANCE_INHERITANCE */
2566 assert(port
->ip_mscount
== 0);
2567 assert(port
->ip_receiver_name
== MACH_PORT_NULL
);
2568 dest
= port
->ip_destination
;
2570 port
->ip_receiver_name
= name
;
2571 port
->ip_receiver
= space
;
2573 assert((bits
& MACH_PORT_TYPE_RECEIVE
) == 0);
2575 if (bits
& MACH_PORT_TYPE_SEND
) {
2576 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND
);
2577 assert(IE_BITS_UREFS(bits
) > 0);
2578 assert(port
->ip_srights
> 0);
2583 /* entry is locked holding ref, so can use port */
2585 ipc_hash_delete(space
, (ipc_object_t
) port
,
2588 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_NONE
);
2589 assert(IE_BITS_UREFS(bits
) == 0);
2591 /* transfer ref to entry */
2594 entry
->ie_bits
= bits
| MACH_PORT_TYPE_RECEIVE
;
2595 ipc_entry_modified(space
, name
, entry
);
2597 if (dest
!= IP_NULL
) {
2598 #if IMPORTANCE_INHERITANCE
2600 * Deduct the assertion counts we contributed to
2601 * the old destination port. They've already
2602 * been reflected into the task as a result of
2606 ipc_port_impcount_delta(dest
, 0 - assertcnt
, IP_NULL
);
2608 #endif /* IMPORTANCE_INHERITANCE */
2615 panic("ipc_right_copyout: strange rights");
2617 return KERN_SUCCESS
;
2621 * Routine: ipc_right_rename
2623 * Transfer an entry from one name to another.
2624 * The old entry is deallocated.
2626 * The space is write-locked and active.
2627 * The new entry is unused. Upon return,
2628 * the space is unlocked.
2630 * KERN_SUCCESS Moved entry to new name.
2636 mach_port_name_t oname
,
2638 mach_port_name_t nname
,
2641 ipc_port_request_index_t request
= oentry
->ie_request
;
2642 ipc_entry_bits_t bits
= oentry
->ie_bits
;
2643 ipc_object_t object
= oentry
->ie_object
;
2644 ipc_port_t release_port
= IP_NULL
;
2646 assert(is_active(space
));
2647 assert(oname
!= nname
);
2650 * If IE_BITS_COMPAT, we can't allow the entry to be renamed
2651 * if the port is dead. (This would foil ipc_port_destroy.)
2652 * Instead we should fail because oentry shouldn't exist.
2653 * Note IE_BITS_COMPAT implies ie_request != 0.
2656 if (request
!= IE_REQ_NONE
) {
2659 assert(bits
& MACH_PORT_TYPE_PORT_RIGHTS
);
2660 port
= (ipc_port_t
) object
;
2661 assert(port
!= IP_NULL
);
2663 if (ipc_right_check(space
, port
, oname
, oentry
)) {
2664 request
= IE_REQ_NONE
;
2666 bits
= oentry
->ie_bits
;
2667 release_port
= port
;
2668 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_DEAD_NAME
);
2669 assert(oentry
->ie_request
== IE_REQ_NONE
);
2671 /* port is locked and active */
2673 ipc_port_request_rename(port
, request
, oname
, nname
);
2675 oentry
->ie_request
= IE_REQ_NONE
;
2679 /* initialize nentry before letting ipc_hash_insert see it */
2681 assert((nentry
->ie_bits
& IE_BITS_RIGHT_MASK
) == 0);
2682 nentry
->ie_bits
|= bits
& IE_BITS_RIGHT_MASK
;
2683 nentry
->ie_request
= request
;
2684 nentry
->ie_object
= object
;
2686 switch (IE_BITS_TYPE(bits
)) {
2687 case MACH_PORT_TYPE_SEND
: {
2690 port
= (ipc_port_t
) object
;
2691 assert(port
!= IP_NULL
);
2693 /* remember, there are no other share entries possible */
2694 /* or we can't do the rename. Therefore we do not need */
2695 /* to check the other subspaces */
2696 ipc_hash_delete(space
, (ipc_object_t
) port
, oname
, oentry
);
2697 ipc_hash_insert(space
, (ipc_object_t
) port
, nname
, nentry
);
2701 case MACH_PORT_TYPE_RECEIVE
:
2702 case MACH_PORT_TYPE_SEND_RECEIVE
: {
2705 port
= (ipc_port_t
) object
;
2706 assert(port
!= IP_NULL
);
2709 assert(ip_active(port
));
2710 assert(port
->ip_receiver_name
== oname
);
2711 assert(port
->ip_receiver
== space
);
2713 port
->ip_receiver_name
= nname
;
2718 case MACH_PORT_TYPE_PORT_SET
: {
2721 pset
= (ipc_pset_t
) object
;
2722 assert(pset
!= IPS_NULL
);
2725 assert(ips_active(pset
));
2731 case MACH_PORT_TYPE_SEND_ONCE
:
2732 case MACH_PORT_TYPE_DEAD_NAME
:
2736 panic("ipc_right_rename: strange rights");
2739 assert(oentry
->ie_request
== IE_REQ_NONE
);
2740 oentry
->ie_object
= IO_NULL
;
2741 ipc_entry_dealloc(space
, oname
, oentry
);
2742 ipc_entry_modified(space
, nname
, nentry
);
2743 is_write_unlock(space
);
2745 if (release_port
!= IP_NULL
)
2746 ip_release(release_port
);
2748 return KERN_SUCCESS
;