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 mach_port_mscount_t mscount
= 0;
1315 if ((bits
& MACH_PORT_TYPE_SEND
) == 0)
1318 /* maximum urefs for send is MACH_PORT_UREFS_MAX */
1320 port
= (ipc_port_t
) entry
->ie_object
;
1321 assert(port
!= IP_NULL
);
1323 if (ipc_right_check(space
, port
, name
, entry
)) {
1324 assert((entry
->ie_bits
& MACH_PORT_TYPE_SEND
) == 0);
1327 /* port is locked and active */
1329 assert(port
->ip_srights
> 0);
1331 if (delta
> ((mach_port_delta_t
)MACH_PORT_UREFS_MAX
) ||
1332 delta
< (-((mach_port_delta_t
)MACH_PORT_UREFS_MAX
))) {
1337 urefs
= IE_BITS_UREFS(bits
);
1339 if (urefs
== MACH_PORT_UREFS_MAX
) {
1341 * urefs are pegged due to an overflow
1342 * only a delta removing all refs at once can change it
1345 if (delta
!= (-((mach_port_delta_t
)MACH_PORT_UREFS_MAX
)))
1348 if (MACH_PORT_UREFS_UNDERFLOW(urefs
, delta
)) {
1352 if (MACH_PORT_UREFS_OVERFLOW(urefs
, delta
)) {
1353 /* leave urefs pegged to maximum if it overflowed */
1354 delta
= MACH_PORT_UREFS_MAX
- urefs
;
1358 if ((urefs
+ delta
) == 0) {
1359 if (--port
->ip_srights
== 0) {
1360 nsrequest
= port
->ip_nsrequest
;
1361 if (nsrequest
!= IP_NULL
) {
1362 port
->ip_nsrequest
= IP_NULL
;
1363 mscount
= port
->ip_mscount
;
1367 if (bits
& MACH_PORT_TYPE_RECEIVE
) {
1368 assert(port
->ip_receiver_name
== name
);
1369 assert(port
->ip_receiver
== space
);
1371 assert(IE_BITS_TYPE(bits
) ==
1372 MACH_PORT_TYPE_SEND_RECEIVE
);
1374 entry
->ie_bits
= bits
&~ (IE_BITS_UREFS_MASK
|
1375 MACH_PORT_TYPE_SEND
);
1376 ipc_entry_modified(space
, name
, entry
);
1378 assert(IE_BITS_TYPE(bits
) ==
1379 MACH_PORT_TYPE_SEND
);
1381 request
= ipc_right_request_cancel_macro(space
, port
,
1383 ipc_hash_delete(space
, (ipc_object_t
) port
,
1389 entry
->ie_object
= IO_NULL
;
1390 ipc_entry_dealloc(space
, name
, entry
);
1392 } else if (delta
!= 0) {
1394 entry
->ie_bits
= bits
+ delta
;
1395 ipc_entry_modified(space
, name
, entry
);
1400 is_write_unlock(space
);
1402 if (nsrequest
!= IP_NULL
)
1403 ipc_notify_no_senders(nsrequest
, mscount
);
1405 if (request
!= IP_NULL
)
1406 ipc_notify_port_deleted(request
, name
);
1411 panic("ipc_right_delta: strange right");
1414 return KERN_SUCCESS
;
1417 is_write_unlock(space
);
1418 return KERN_SUCCESS
;
1421 is_write_unlock(space
);
1422 if (port
!= IP_NULL
)
1424 return KERN_INVALID_RIGHT
;
1427 is_write_unlock(space
);
1428 return KERN_INVALID_VALUE
;
1431 return KERN_INVALID_RIGHT
;
1435 * Routine: ipc_right_destruct
1437 * Deallocates the receive right and modifies the
1438 * user-reference count for the send rights as requested.
1440 * The space is write-locked, and is unlocked upon return.
1441 * The space must be active.
1443 * KERN_SUCCESS Count was modified.
1444 * KERN_INVALID_RIGHT Entry has wrong type.
1445 * KERN_INVALID_VALUE Bad delta for the right.
1451 mach_port_name_t name
,
1453 mach_port_delta_t srdelta
,
1456 ipc_port_t port
= IP_NULL
;
1457 ipc_entry_bits_t bits
;
1459 mach_port_urefs_t urefs
;
1460 ipc_port_t request
= IP_NULL
;
1461 ipc_port_t nsrequest
= IP_NULL
;
1462 mach_port_mscount_t mscount
= 0;
1464 bits
= entry
->ie_bits
;
1466 assert(is_active(space
));
1468 if (((bits
& MACH_PORT_TYPE_RECEIVE
) == 0) ||
1469 (srdelta
&& ((bits
& MACH_PORT_TYPE_SEND
) == 0))) {
1470 is_write_unlock(space
);
1471 return KERN_INVALID_RIGHT
;
1477 port
= (ipc_port_t
) entry
->ie_object
;
1478 assert(port
!= IP_NULL
);
1481 assert(ip_active(port
));
1482 assert(port
->ip_receiver_name
== name
);
1483 assert(port
->ip_receiver
== space
);
1485 /* Mach Port Guard Checking */
1486 if(port
->ip_guarded
&& (guard
!= port
->ip_context
)) {
1487 uint64_t portguard
= port
->ip_context
;
1489 is_write_unlock(space
);
1490 mach_port_guard_exception(name
, 0, portguard
, kGUARD_EXC_DESTROY
);
1491 return KERN_INVALID_ARGUMENT
;
1495 * First reduce the send rights as requested and
1496 * adjust the entry->ie_bits accordingly. The
1497 * ipc_entry_modified() call is made once the receive
1498 * right is destroyed too.
1503 assert(port
->ip_srights
> 0);
1505 urefs
= IE_BITS_UREFS(bits
);
1508 * Since we made sure that srdelta is negative,
1509 * the check for urefs overflow is not required.
1511 if (MACH_PORT_UREFS_UNDERFLOW(urefs
, srdelta
)) {
1516 if (urefs
== MACH_PORT_UREFS_MAX
) {
1518 * urefs are pegged due to an overflow
1519 * only a delta removing all refs at once can change it
1521 if (srdelta
!= (-((mach_port_delta_t
)MACH_PORT_UREFS_MAX
)))
1525 if ((urefs
+ srdelta
) == 0) {
1526 if (--port
->ip_srights
== 0) {
1527 nsrequest
= port
->ip_nsrequest
;
1528 if (nsrequest
!= IP_NULL
) {
1529 port
->ip_nsrequest
= IP_NULL
;
1530 mscount
= port
->ip_mscount
;
1533 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND_RECEIVE
);
1534 entry
->ie_bits
= bits
&~ (IE_BITS_UREFS_MASK
|
1535 MACH_PORT_TYPE_SEND
);
1537 entry
->ie_bits
= bits
+ srdelta
;
1542 * Now destroy the receive right. Update space and
1543 * entry accordingly.
1546 bits
= entry
->ie_bits
;
1547 if (bits
& MACH_PORT_TYPE_SEND
) {
1548 assert(IE_BITS_UREFS(bits
) > 0);
1549 assert(IE_BITS_UREFS(bits
) <= MACH_PORT_UREFS_MAX
);
1551 if (port
->ip_pdrequest
!= NULL
) {
1553 * Since another task has requested a
1554 * destroy notification for this port, it
1555 * isn't actually being destroyed - the receive
1556 * right is just being moved to another task.
1557 * Since we still have one or more send rights,
1558 * we need to record the loss of the receive
1559 * right and enter the remaining send right
1560 * into the hash table.
1562 ipc_entry_modified(space
, name
, entry
);
1563 entry
->ie_bits
&= ~MACH_PORT_TYPE_RECEIVE
;
1564 ipc_hash_insert(space
, (ipc_object_t
) port
,
1569 * The remaining send right turns into a
1570 * dead name. Notice we don't decrement
1571 * ip_srights, generate a no-senders notif,
1572 * or use ipc_right_dncancel, because the
1573 * port is destroyed "first".
1575 bits
&= ~IE_BITS_TYPE_MASK
;
1576 bits
|= MACH_PORT_TYPE_DEAD_NAME
;
1577 if (entry
->ie_request
) {
1578 entry
->ie_request
= IE_REQ_NONE
;
1579 if (IE_BITS_UREFS(bits
) < MACH_PORT_UREFS_MAX
)
1580 bits
++; /* increment urefs */
1582 entry
->ie_bits
= bits
;
1583 entry
->ie_object
= IO_NULL
;
1584 ipc_entry_modified(space
, name
, entry
);
1587 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_RECEIVE
);
1588 assert(IE_BITS_UREFS(bits
) == 0);
1589 request
= ipc_right_request_cancel_macro(space
, port
,
1591 entry
->ie_object
= IO_NULL
;
1592 ipc_entry_dealloc(space
, name
, entry
);
1596 is_write_unlock(space
);
1598 if (nsrequest
!= IP_NULL
)
1599 ipc_notify_no_senders(nsrequest
, mscount
);
1601 ipc_port_destroy(port
); /* clears receiver, consumes ref, unlocks */
1603 if (request
!= IP_NULL
)
1604 ipc_notify_port_deleted(request
, name
);
1606 return KERN_SUCCESS
;
1609 is_write_unlock(space
);
1610 return KERN_INVALID_VALUE
;
1616 * Routine: ipc_right_info
1618 * Retrieves information about the right.
1620 * The space is active and write-locked.
1621 * The space is unlocked upon return.
1623 * KERN_SUCCESS Retrieved info
1629 mach_port_name_t name
,
1631 mach_port_type_t
*typep
,
1632 mach_port_urefs_t
*urefsp
)
1635 ipc_entry_bits_t bits
;
1636 mach_port_type_t type
= 0;
1637 ipc_port_request_index_t request
;
1639 bits
= entry
->ie_bits
;
1640 request
= entry
->ie_request
;
1641 port
= (ipc_port_t
) entry
->ie_object
;
1643 if (bits
& MACH_PORT_TYPE_RECEIVE
) {
1644 assert(IP_VALID(port
));
1646 if (request
!= IE_REQ_NONE
) {
1648 assert(ip_active(port
));
1649 type
|= ipc_port_request_type(port
, name
, request
);
1652 is_write_unlock(space
);
1654 } else if (bits
& MACH_PORT_TYPE_SEND_RIGHTS
) {
1656 * validate port is still alive - if so, get request
1657 * types while we still have it locked. Otherwise,
1658 * recapture the (now dead) bits.
1660 if (!ipc_right_check(space
, port
, name
, entry
)) {
1661 if (request
!= IE_REQ_NONE
)
1662 type
|= ipc_port_request_type(port
, name
, request
);
1664 is_write_unlock(space
);
1666 bits
= entry
->ie_bits
;
1667 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_DEAD_NAME
);
1668 is_write_unlock(space
);
1672 is_write_unlock(space
);
1675 type
|= IE_BITS_TYPE(bits
);
1678 *urefsp
= IE_BITS_UREFS(bits
);
1679 return KERN_SUCCESS
;
1683 * Routine: ipc_right_copyin_check
1685 * Check if a subsequent ipc_right_copyin would succeed.
1687 * The space is locked (read or write) and active.
1691 ipc_right_copyin_check(
1692 __assert_only ipc_space_t space
,
1693 __unused mach_port_name_t name
,
1695 mach_msg_type_name_t msgt_name
)
1697 ipc_entry_bits_t bits
;
1700 bits
= entry
->ie_bits
;
1701 assert(is_active(space
));
1703 switch (msgt_name
) {
1704 case MACH_MSG_TYPE_MAKE_SEND
:
1705 if ((bits
& MACH_PORT_TYPE_RECEIVE
) == 0)
1709 case MACH_MSG_TYPE_MAKE_SEND_ONCE
:
1710 if ((bits
& MACH_PORT_TYPE_RECEIVE
) == 0)
1714 case MACH_MSG_TYPE_MOVE_RECEIVE
:
1715 if ((bits
& MACH_PORT_TYPE_RECEIVE
) == 0)
1719 case MACH_MSG_TYPE_COPY_SEND
:
1720 case MACH_MSG_TYPE_MOVE_SEND
:
1721 case MACH_MSG_TYPE_MOVE_SEND_ONCE
: {
1723 if (bits
& MACH_PORT_TYPE_DEAD_NAME
)
1726 if ((bits
& MACH_PORT_TYPE_SEND_RIGHTS
) == 0)
1729 port
= (ipc_port_t
) entry
->ie_object
;
1730 assert(port
!= IP_NULL
);
1733 * active status peek to avoid checks that will be skipped
1734 * on copyin for dead ports. Lock not held, so will not be
1735 * atomic (but once dead, there's no going back).
1737 if (!ip_active(port
)) {
1741 if (msgt_name
== MACH_MSG_TYPE_MOVE_SEND_ONCE
) {
1742 if ((bits
& MACH_PORT_TYPE_SEND_ONCE
) == 0)
1745 if ((bits
& MACH_PORT_TYPE_SEND
) == 0)
1753 panic("ipc_right_copyin_check: strange rights");
1760 * Routine: ipc_right_copyin
1762 * Copyin a capability from a space.
1763 * If successful, the caller gets a ref
1764 * for the resulting object, unless it is IO_DEAD,
1765 * and possibly a send-once right which should
1766 * be used in a port-deleted notification.
1768 * If deadok is not TRUE, the copyin operation
1769 * will fail instead of producing IO_DEAD.
1771 * The entry is never deallocated (except
1772 * when KERN_INVALID_NAME), so the caller
1773 * should deallocate the entry if its type
1774 * is MACH_PORT_TYPE_NONE.
1776 * The space is write-locked and active.
1778 * KERN_SUCCESS Acquired an object, possibly IO_DEAD.
1779 * KERN_INVALID_RIGHT Name doesn't denote correct right.
1785 mach_port_name_t name
,
1787 mach_msg_type_name_t msgt_name
,
1789 ipc_object_t
*objectp
,
1790 ipc_port_t
*sorightp
,
1791 ipc_port_t
*releasep
,
1794 ipc_entry_bits_t bits
;
1797 *releasep
= IP_NULL
;
1800 bits
= entry
->ie_bits
;
1802 assert(is_active(space
));
1804 switch (msgt_name
) {
1805 case MACH_MSG_TYPE_MAKE_SEND
: {
1807 if ((bits
& MACH_PORT_TYPE_RECEIVE
) == 0)
1810 port
= (ipc_port_t
) entry
->ie_object
;
1811 assert(port
!= IP_NULL
);
1814 assert(ip_active(port
));
1815 assert(port
->ip_receiver_name
== name
);
1816 assert(port
->ip_receiver
== space
);
1823 *objectp
= (ipc_object_t
) port
;
1824 *sorightp
= IP_NULL
;
1828 case MACH_MSG_TYPE_MAKE_SEND_ONCE
: {
1830 if ((bits
& MACH_PORT_TYPE_RECEIVE
) == 0)
1833 port
= (ipc_port_t
) entry
->ie_object
;
1834 assert(port
!= IP_NULL
);
1837 assert(ip_active(port
));
1838 assert(port
->ip_receiver_name
== name
);
1839 assert(port
->ip_receiver
== space
);
1841 port
->ip_sorights
++;
1845 *objectp
= (ipc_object_t
) port
;
1846 *sorightp
= IP_NULL
;
1850 case MACH_MSG_TYPE_MOVE_RECEIVE
: {
1851 ipc_port_t request
= IP_NULL
;
1853 if ((bits
& MACH_PORT_TYPE_RECEIVE
) == 0)
1856 port
= (ipc_port_t
) entry
->ie_object
;
1857 assert(port
!= IP_NULL
);
1860 assert(ip_active(port
));
1861 assert(port
->ip_receiver_name
== name
);
1862 assert(port
->ip_receiver
== space
);
1864 if (bits
& MACH_PORT_TYPE_SEND
) {
1865 assert(IE_BITS_TYPE(bits
) ==
1866 MACH_PORT_TYPE_SEND_RECEIVE
);
1867 assert(IE_BITS_UREFS(bits
) > 0);
1868 assert(port
->ip_srights
> 0);
1870 ipc_hash_insert(space
, (ipc_object_t
) port
,
1874 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_RECEIVE
);
1875 assert(IE_BITS_UREFS(bits
) == 0);
1877 request
= ipc_right_request_cancel_macro(space
, port
,
1879 entry
->ie_object
= IO_NULL
;
1881 entry
->ie_bits
= bits
&~ MACH_PORT_TYPE_RECEIVE
;
1882 ipc_entry_modified(space
, name
, entry
);
1884 (void)ipc_port_clear_receiver(port
, FALSE
); /* don't destroy the port/mqueue */
1885 port
->ip_receiver_name
= MACH_PORT_NULL
;
1886 port
->ip_destination
= IP_NULL
;
1888 #if IMPORTANCE_INHERITANCE
1890 * Account for boosts the current task is going to lose when
1891 * copying this right in. Tempowner ports have either not
1892 * been accounting to any task (and therefore are already in
1893 * "limbo" state w.r.t. assertions) or to some other specific
1894 * task. As we have no way to drop the latter task's assertions
1895 * here, We'll deduct those when we enqueue it on its
1896 * destination port (see ipc_port_check_circularity()).
1898 if (port
->ip_tempowner
== 0) {
1899 assert(IIT_NULL
== port
->ip_imp_task
);
1901 /* ports in limbo have to be tempowner */
1902 port
->ip_tempowner
= 1;
1903 *assertcntp
= port
->ip_impcount
;
1905 #endif /* IMPORTANCE_INHERITANCE */
1909 *objectp
= (ipc_object_t
) port
;
1910 *sorightp
= request
;
1914 case MACH_MSG_TYPE_COPY_SEND
: {
1916 if (bits
& MACH_PORT_TYPE_DEAD_NAME
)
1919 /* allow for dead send-once rights */
1921 if ((bits
& MACH_PORT_TYPE_SEND_RIGHTS
) == 0)
1924 assert(IE_BITS_UREFS(bits
) > 0);
1926 port
= (ipc_port_t
) entry
->ie_object
;
1927 assert(port
!= IP_NULL
);
1929 if (ipc_right_check(space
, port
, name
, entry
)) {
1930 bits
= entry
->ie_bits
;
1934 /* port is locked and active */
1936 if ((bits
& MACH_PORT_TYPE_SEND
) == 0) {
1937 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND_ONCE
);
1938 assert(port
->ip_sorights
> 0);
1944 assert(port
->ip_srights
> 0);
1950 *objectp
= (ipc_object_t
) port
;
1951 *sorightp
= IP_NULL
;
1955 case MACH_MSG_TYPE_MOVE_SEND
: {
1956 ipc_port_t request
= IP_NULL
;
1958 if (bits
& MACH_PORT_TYPE_DEAD_NAME
)
1961 /* allow for dead send-once rights */
1963 if ((bits
& MACH_PORT_TYPE_SEND_RIGHTS
) == 0)
1966 assert(IE_BITS_UREFS(bits
) > 0);
1968 port
= (ipc_port_t
) entry
->ie_object
;
1969 assert(port
!= IP_NULL
);
1971 if (ipc_right_check(space
, port
, name
, entry
)) {
1972 bits
= entry
->ie_bits
;
1976 /* port is locked and active */
1978 if ((bits
& MACH_PORT_TYPE_SEND
) == 0) {
1979 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND_ONCE
);
1980 assert(port
->ip_sorights
> 0);
1986 assert(port
->ip_srights
> 0);
1988 if (IE_BITS_UREFS(bits
) == 1) {
1989 if (bits
& MACH_PORT_TYPE_RECEIVE
) {
1990 assert(port
->ip_receiver_name
== name
);
1991 assert(port
->ip_receiver
== space
);
1992 assert(IE_BITS_TYPE(bits
) ==
1993 MACH_PORT_TYPE_SEND_RECEIVE
);
1997 assert(IE_BITS_TYPE(bits
) ==
1998 MACH_PORT_TYPE_SEND
);
2000 request
= ipc_right_request_cancel_macro(space
, port
,
2002 ipc_hash_delete(space
, (ipc_object_t
) port
,
2004 entry
->ie_object
= IO_NULL
;
2005 /* transfer entry's reference to caller */
2007 entry
->ie_bits
= bits
&~
2008 (IE_BITS_UREFS_MASK
|MACH_PORT_TYPE_SEND
);
2012 /* if urefs are pegged due to overflow, leave them pegged */
2013 if (IE_BITS_UREFS(bits
) < MACH_PORT_UREFS_MAX
)
2014 entry
->ie_bits
= bits
-1; /* decrement urefs */
2017 ipc_entry_modified(space
, name
, entry
);
2020 *objectp
= (ipc_object_t
) port
;
2021 *sorightp
= request
;
2025 case MACH_MSG_TYPE_MOVE_SEND_ONCE
: {
2028 if (bits
& MACH_PORT_TYPE_DEAD_NAME
)
2031 /* allow for dead send rights */
2033 if ((bits
& MACH_PORT_TYPE_SEND_RIGHTS
) == 0)
2036 assert(IE_BITS_UREFS(bits
) > 0);
2038 port
= (ipc_port_t
) entry
->ie_object
;
2039 assert(port
!= IP_NULL
);
2041 if (ipc_right_check(space
, port
, name
, entry
)) {
2042 bits
= entry
->ie_bits
;
2046 /* port is locked and active */
2048 if ((bits
& MACH_PORT_TYPE_SEND_ONCE
) == 0) {
2049 assert(bits
& MACH_PORT_TYPE_SEND
);
2050 assert(port
->ip_srights
> 0);
2056 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND_ONCE
);
2057 assert(IE_BITS_UREFS(bits
) == 1);
2058 assert(port
->ip_sorights
> 0);
2060 request
= ipc_right_request_cancel_macro(space
, port
, name
, entry
);
2063 entry
->ie_object
= IO_NULL
;
2064 entry
->ie_bits
= bits
&~
2065 (IE_BITS_UREFS_MASK
| MACH_PORT_TYPE_SEND_ONCE
);
2066 ipc_entry_modified(space
, name
, entry
);
2067 *objectp
= (ipc_object_t
) port
;
2068 *sorightp
= request
;
2074 return KERN_INVALID_RIGHT
;
2077 return KERN_SUCCESS
;
2080 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_DEAD_NAME
);
2081 assert(IE_BITS_UREFS(bits
) > 0);
2082 assert(entry
->ie_request
== IE_REQ_NONE
);
2083 assert(entry
->ie_object
== 0);
2089 *sorightp
= IP_NULL
;
2090 return KERN_SUCCESS
;
2093 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_DEAD_NAME
);
2094 assert(IE_BITS_UREFS(bits
) > 0);
2095 assert(entry
->ie_request
== IE_REQ_NONE
);
2096 assert(entry
->ie_object
== 0);
2101 if (IE_BITS_UREFS(bits
) == 1) {
2102 bits
&= ~MACH_PORT_TYPE_DEAD_NAME
;
2104 /* if urefs are pegged due to overflow, leave them pegged */
2105 if (IE_BITS_UREFS(bits
) < MACH_PORT_UREFS_MAX
)
2106 entry
->ie_bits
= bits
-1; /* decrement urefs */
2108 ipc_entry_modified(space
, name
, entry
);
2110 *sorightp
= IP_NULL
;
2111 return KERN_SUCCESS
;
2116 * Routine: ipc_right_copyin_undo
2118 * Undoes the effects of an ipc_right_copyin
2119 * of a send/send-once right that is dead.
2120 * (Object is either IO_DEAD or a dead port.)
2122 * The space is write-locked and active.
2126 ipc_right_copyin_undo(
2128 mach_port_name_t name
,
2130 mach_msg_type_name_t msgt_name
,
2131 ipc_object_t object
,
2134 ipc_entry_bits_t bits
;
2136 bits
= entry
->ie_bits
;
2138 assert(is_active(space
));
2140 assert((msgt_name
== MACH_MSG_TYPE_MOVE_SEND
) ||
2141 (msgt_name
== MACH_MSG_TYPE_COPY_SEND
) ||
2142 (msgt_name
== MACH_MSG_TYPE_MOVE_SEND_ONCE
));
2144 if (soright
!= IP_NULL
) {
2145 assert((msgt_name
== MACH_MSG_TYPE_MOVE_SEND
) ||
2146 (msgt_name
== MACH_MSG_TYPE_MOVE_SEND_ONCE
));
2147 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_NONE
);
2148 assert(object
!= IO_DEAD
);
2150 entry
->ie_bits
= ((bits
&~ IE_BITS_RIGHT_MASK
) |
2151 MACH_PORT_TYPE_DEAD_NAME
| 2);
2153 } else if (IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_NONE
) {
2154 assert((msgt_name
== MACH_MSG_TYPE_MOVE_SEND
) ||
2155 (msgt_name
== MACH_MSG_TYPE_MOVE_SEND_ONCE
));
2157 entry
->ie_bits
= ((bits
&~ IE_BITS_RIGHT_MASK
) |
2158 MACH_PORT_TYPE_DEAD_NAME
| 1);
2159 } else if (IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_DEAD_NAME
) {
2160 assert(object
== IO_DEAD
);
2161 assert(IE_BITS_UREFS(bits
) > 0);
2163 if (msgt_name
!= MACH_MSG_TYPE_COPY_SEND
) {
2164 assert(IE_BITS_UREFS(bits
) <= MACH_PORT_UREFS_MAX
);
2165 /* if urefs are pegged due to overflow, leave them pegged */
2166 if (IE_BITS_UREFS(bits
) < MACH_PORT_UREFS_MAX
)
2167 entry
->ie_bits
= bits
+1; /* increment urefs */
2170 assert((msgt_name
== MACH_MSG_TYPE_MOVE_SEND
) ||
2171 (msgt_name
== MACH_MSG_TYPE_COPY_SEND
));
2172 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND
);
2173 assert(object
!= IO_DEAD
);
2174 assert(entry
->ie_object
== object
);
2175 assert(IE_BITS_UREFS(bits
) > 0);
2177 if (msgt_name
!= MACH_MSG_TYPE_COPY_SEND
) {
2178 assert(IE_BITS_UREFS(bits
) <= MACH_PORT_UREFS_MAX
);
2179 /* if urefs are pegged due to overflow, leave them pegged */
2180 if (IE_BITS_UREFS(bits
) < MACH_PORT_UREFS_MAX
)
2181 entry
->ie_bits
= bits
+1; /* increment urefs */
2185 * May as well convert the entry to a dead name.
2186 * (Or if it is a compat entry, destroy it.)
2189 (void) ipc_right_check(space
, (ipc_port_t
) object
,
2191 /* object is dead so it is not locked */
2193 ipc_entry_modified(space
, name
, entry
);
2194 /* release the reference acquired by copyin */
2196 if (object
!= IO_DEAD
)
2201 * Routine: ipc_right_copyin_two_move_sends
2203 * Like ipc_right_copyin with MACH_MSG_TYPE_MOVE_SEND
2204 * and deadok == FALSE, except that this moves two
2205 * send rights at once.
2207 * The space is write-locked and active.
2208 * The object is returned with two refs/send rights.
2210 * KERN_SUCCESS Acquired an object.
2211 * KERN_INVALID_RIGHT Name doesn't denote correct right.
2215 ipc_right_copyin_two_move_sends(
2217 mach_port_name_t name
,
2219 ipc_object_t
*objectp
,
2220 ipc_port_t
*sorightp
,
2221 ipc_port_t
*releasep
)
2223 ipc_entry_bits_t bits
;
2224 mach_port_urefs_t urefs
;
2226 ipc_port_t request
= IP_NULL
;
2228 *releasep
= IP_NULL
;
2230 assert(is_active(space
));
2232 bits
= entry
->ie_bits
;
2234 if ((bits
& MACH_PORT_TYPE_SEND
) == 0)
2237 urefs
= IE_BITS_UREFS(bits
);
2241 port
= (ipc_port_t
) entry
->ie_object
;
2242 assert(port
!= IP_NULL
);
2244 if (ipc_right_check(space
, port
, name
, entry
)) {
2248 /* port is locked and active */
2250 assert(port
->ip_srights
> 0);
2253 if (bits
& MACH_PORT_TYPE_RECEIVE
) {
2254 assert(port
->ip_receiver_name
== name
);
2255 assert(port
->ip_receiver
== space
);
2256 assert(IE_BITS_TYPE(bits
) ==
2257 MACH_PORT_TYPE_SEND_RECEIVE
);
2263 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND
);
2265 request
= ipc_right_request_cancel_macro(space
, port
,
2270 ipc_hash_delete(space
, (ipc_object_t
) port
,
2272 entry
->ie_object
= IO_NULL
;
2274 entry
->ie_bits
= bits
&~ (IE_BITS_UREFS_MASK
|MACH_PORT_TYPE_SEND
);
2276 port
->ip_srights
+= 2;
2279 /* if urefs are pegged due to overflow, leave them pegged */
2280 if (IE_BITS_UREFS(bits
) < MACH_PORT_UREFS_MAX
)
2281 entry
->ie_bits
= bits
-2; /* decrement urefs */
2283 ipc_entry_modified(space
, name
, entry
);
2287 *objectp
= (ipc_object_t
) port
;
2288 *sorightp
= request
;
2289 return KERN_SUCCESS
;
2292 return KERN_INVALID_RIGHT
;
2297 * Routine: ipc_right_copyin_two
2299 * Like ipc_right_copyin with two dispositions,
2300 * each of which results in a send or send-once right,
2301 * and deadok = FALSE.
2303 * The space is write-locked and active.
2304 * The object is returned with two refs/rights.
2306 * KERN_SUCCESS Acquired an object.
2307 * KERN_INVALID_RIGHT Name doesn't denote correct right(s).
2308 * KERN_INVALID_CAPABILITY Name doesn't denote correct right for msgt_two.
2311 ipc_right_copyin_two(
2313 mach_port_name_t name
,
2315 mach_msg_type_name_t msgt_one
,
2316 mach_msg_type_name_t msgt_two
,
2317 ipc_object_t
*objectp
,
2318 ipc_port_t
*sorightp
,
2319 ipc_port_t
*releasep
)
2324 assert(MACH_MSG_TYPE_PORT_ANY_SEND(msgt_one
));
2325 assert(MACH_MSG_TYPE_PORT_ANY_SEND(msgt_two
));
2329 * Pre-validate the second disposition is possible all by itself.
2331 if (!ipc_right_copyin_check(space
, name
, entry
, msgt_two
)) {
2332 return KERN_INVALID_CAPABILITY
;
2336 * This is a little tedious to make atomic, because
2337 * there are 25 combinations of valid dispositions.
2338 * However, most are easy.
2342 * If either is move-sonce, then there must be an error.
2344 if (msgt_one
== MACH_MSG_TYPE_MOVE_SEND_ONCE
||
2345 msgt_two
== MACH_MSG_TYPE_MOVE_SEND_ONCE
) {
2346 return KERN_INVALID_RIGHT
;
2349 if ((msgt_one
== MACH_MSG_TYPE_MAKE_SEND
) ||
2350 (msgt_one
== MACH_MSG_TYPE_MAKE_SEND_ONCE
) ||
2351 (msgt_two
== MACH_MSG_TYPE_MAKE_SEND
) ||
2352 (msgt_two
== MACH_MSG_TYPE_MAKE_SEND_ONCE
)) {
2354 * One of the dispositions needs a receive right.
2356 * If the copyin below succeeds, we know the receive
2357 * right is there (because the pre-validation of
2358 * the second disposition already succeeded in our
2361 * Hence the port is not in danger of dying.
2363 ipc_object_t object_two
;
2365 kr
= ipc_right_copyin(space
, name
, entry
,
2367 objectp
, sorightp
, releasep
,
2369 assert(assertcnt
== 0);
2370 if (kr
!= KERN_SUCCESS
) {
2374 assert(IO_VALID(*objectp
));
2375 assert(*sorightp
== IP_NULL
);
2376 assert(*releasep
== IP_NULL
);
2379 * Now copyin the second (previously validated)
2380 * disposition. The result can't be a dead port,
2381 * as no valid disposition can make us lose our
2384 kr
= ipc_right_copyin(space
, name
, entry
,
2386 &object_two
, sorightp
, releasep
,
2388 assert(assertcnt
== 0);
2389 assert(kr
== KERN_SUCCESS
);
2390 assert(*sorightp
== IP_NULL
);
2391 assert(*releasep
== IP_NULL
);
2392 assert(object_two
== *objectp
);
2393 assert(entry
->ie_bits
& MACH_PORT_TYPE_RECEIVE
);
2395 } else if ((msgt_one
== MACH_MSG_TYPE_MOVE_SEND
) &&
2396 (msgt_two
== MACH_MSG_TYPE_MOVE_SEND
)) {
2398 * This is an easy case. Just use our
2399 * handy-dandy special-purpose copyin call
2400 * to get two send rights for the price of one.
2402 kr
= ipc_right_copyin_two_move_sends(space
, name
, entry
,
2405 if (kr
!= KERN_SUCCESS
) {
2410 mach_msg_type_name_t msgt_name
;
2413 * Must be either a single move-send and a
2414 * copy-send, or two copy-send dispositions.
2415 * Use the disposition with the greatest side
2416 * effects for the actual copyin - then just
2417 * duplicate the send right you get back.
2419 if (msgt_one
== MACH_MSG_TYPE_MOVE_SEND
||
2420 msgt_two
== MACH_MSG_TYPE_MOVE_SEND
) {
2421 msgt_name
= MACH_MSG_TYPE_MOVE_SEND
;
2423 msgt_name
= MACH_MSG_TYPE_COPY_SEND
;
2426 kr
= ipc_right_copyin(space
, name
, entry
,
2428 objectp
, sorightp
, releasep
,
2430 assert(assertcnt
== 0);
2431 if (kr
!= KERN_SUCCESS
) {
2436 * Copy the right we got back. If it is dead now,
2437 * that's OK. Neither right will be usable to send
2440 (void)ipc_port_copy_send((ipc_port_t
)*objectp
);
2443 return KERN_SUCCESS
;
2448 * Routine: ipc_right_copyout
2450 * Copyout a capability to a space.
2451 * If successful, consumes a ref for the object.
2453 * Always succeeds when given a newly-allocated entry,
2454 * because user-reference overflow isn't a possibility.
2456 * If copying out the object would cause the user-reference
2457 * count in the entry to overflow, and overflow is TRUE,
2458 * then instead the user-reference count is left pegged
2459 * to its maximum value and the copyout succeeds anyway.
2461 * The space is write-locked and active.
2462 * The object is locked and active.
2463 * The object is unlocked; the space isn't.
2465 * KERN_SUCCESS Copied out capability.
2471 mach_port_name_t name
,
2473 mach_msg_type_name_t msgt_name
,
2474 __unused boolean_t overflow
,
2475 ipc_object_t object
)
2477 ipc_entry_bits_t bits
;
2480 bits
= entry
->ie_bits
;
2482 assert(IO_VALID(object
));
2483 assert(io_otype(object
) == IOT_PORT
);
2484 assert(io_active(object
));
2485 assert(entry
->ie_object
== object
);
2487 port
= (ipc_port_t
) object
;
2489 switch (msgt_name
) {
2490 case MACH_MSG_TYPE_PORT_SEND_ONCE
:
2492 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_NONE
);
2493 assert(IE_BITS_UREFS(bits
) == 0);
2494 assert(port
->ip_sorights
> 0);
2496 /* transfer send-once right and ref to entry */
2499 entry
->ie_bits
= bits
| (MACH_PORT_TYPE_SEND_ONCE
| 1); /* set urefs to 1 */
2500 ipc_entry_modified(space
, name
, entry
);
2503 case MACH_MSG_TYPE_PORT_SEND
:
2504 assert(port
->ip_srights
> 0);
2506 if (bits
& MACH_PORT_TYPE_SEND
) {
2507 mach_port_urefs_t urefs
= IE_BITS_UREFS(bits
);
2509 assert(port
->ip_srights
> 1);
2511 assert(urefs
<= MACH_PORT_UREFS_MAX
);
2513 if (urefs
== MACH_PORT_UREFS_MAX
) {
2515 * leave urefs pegged to maximum,
2516 * consume send right and ref
2522 return KERN_SUCCESS
;
2525 /* consume send right and ref */
2530 } else if (bits
& MACH_PORT_TYPE_RECEIVE
) {
2531 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_RECEIVE
);
2532 assert(IE_BITS_UREFS(bits
) == 0);
2534 /* transfer send right to entry, consume ref */
2539 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_NONE
);
2540 assert(IE_BITS_UREFS(bits
) == 0);
2542 /* transfer send right and ref to entry */
2545 /* entry is locked holding ref, so can use port */
2547 ipc_hash_insert(space
, (ipc_object_t
) port
,
2551 entry
->ie_bits
= (bits
| MACH_PORT_TYPE_SEND
) + 1; /* increment urefs */
2552 ipc_entry_modified(space
, name
, entry
);
2555 case MACH_MSG_TYPE_PORT_RECEIVE
: {
2558 #if IMPORTANCE_INHERITANCE
2559 natural_t assertcnt
= port
->ip_impcount
;
2560 #endif /* IMPORTANCE_INHERITANCE */
2562 assert(port
->ip_mscount
== 0);
2563 assert(port
->ip_receiver_name
== MACH_PORT_NULL
);
2564 dest
= port
->ip_destination
;
2566 port
->ip_receiver_name
= name
;
2567 port
->ip_receiver
= space
;
2569 assert((bits
& MACH_PORT_TYPE_RECEIVE
) == 0);
2571 if (bits
& MACH_PORT_TYPE_SEND
) {
2572 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND
);
2573 assert(IE_BITS_UREFS(bits
) > 0);
2574 assert(port
->ip_srights
> 0);
2579 /* entry is locked holding ref, so can use port */
2581 ipc_hash_delete(space
, (ipc_object_t
) port
,
2584 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_NONE
);
2585 assert(IE_BITS_UREFS(bits
) == 0);
2587 /* transfer ref to entry */
2590 entry
->ie_bits
= bits
| MACH_PORT_TYPE_RECEIVE
;
2591 ipc_entry_modified(space
, name
, entry
);
2593 if (dest
!= IP_NULL
) {
2594 #if IMPORTANCE_INHERITANCE
2596 * Deduct the assertion counts we contributed to
2597 * the old destination port. They've already
2598 * been reflected into the task as a result of
2602 ipc_port_impcount_delta(dest
, 0 - assertcnt
, IP_NULL
);
2604 #endif /* IMPORTANCE_INHERITANCE */
2611 panic("ipc_right_copyout: strange rights");
2613 return KERN_SUCCESS
;
2617 * Routine: ipc_right_rename
2619 * Transfer an entry from one name to another.
2620 * The old entry is deallocated.
2622 * The space is write-locked and active.
2623 * The new entry is unused. Upon return,
2624 * the space is unlocked.
2626 * KERN_SUCCESS Moved entry to new name.
2632 mach_port_name_t oname
,
2634 mach_port_name_t nname
,
2637 ipc_port_request_index_t request
= oentry
->ie_request
;
2638 ipc_entry_bits_t bits
= oentry
->ie_bits
;
2639 ipc_object_t object
= oentry
->ie_object
;
2640 ipc_port_t release_port
= IP_NULL
;
2642 assert(is_active(space
));
2643 assert(oname
!= nname
);
2646 * If IE_BITS_COMPAT, we can't allow the entry to be renamed
2647 * if the port is dead. (This would foil ipc_port_destroy.)
2648 * Instead we should fail because oentry shouldn't exist.
2649 * Note IE_BITS_COMPAT implies ie_request != 0.
2652 if (request
!= IE_REQ_NONE
) {
2655 assert(bits
& MACH_PORT_TYPE_PORT_RIGHTS
);
2656 port
= (ipc_port_t
) object
;
2657 assert(port
!= IP_NULL
);
2659 if (ipc_right_check(space
, port
, oname
, oentry
)) {
2660 request
= IE_REQ_NONE
;
2662 bits
= oentry
->ie_bits
;
2663 release_port
= port
;
2664 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_DEAD_NAME
);
2665 assert(oentry
->ie_request
== IE_REQ_NONE
);
2667 /* port is locked and active */
2669 ipc_port_request_rename(port
, request
, oname
, nname
);
2671 oentry
->ie_request
= IE_REQ_NONE
;
2675 /* initialize nentry before letting ipc_hash_insert see it */
2677 assert((nentry
->ie_bits
& IE_BITS_RIGHT_MASK
) == 0);
2678 nentry
->ie_bits
|= bits
& IE_BITS_RIGHT_MASK
;
2679 nentry
->ie_request
= request
;
2680 nentry
->ie_object
= object
;
2682 switch (IE_BITS_TYPE(bits
)) {
2683 case MACH_PORT_TYPE_SEND
: {
2686 port
= (ipc_port_t
) object
;
2687 assert(port
!= IP_NULL
);
2689 /* remember, there are no other share entries possible */
2690 /* or we can't do the rename. Therefore we do not need */
2691 /* to check the other subspaces */
2692 ipc_hash_delete(space
, (ipc_object_t
) port
, oname
, oentry
);
2693 ipc_hash_insert(space
, (ipc_object_t
) port
, nname
, nentry
);
2697 case MACH_PORT_TYPE_RECEIVE
:
2698 case MACH_PORT_TYPE_SEND_RECEIVE
: {
2701 port
= (ipc_port_t
) object
;
2702 assert(port
!= IP_NULL
);
2705 assert(ip_active(port
));
2706 assert(port
->ip_receiver_name
== oname
);
2707 assert(port
->ip_receiver
== space
);
2709 port
->ip_receiver_name
= nname
;
2714 case MACH_PORT_TYPE_PORT_SET
: {
2717 pset
= (ipc_pset_t
) object
;
2718 assert(pset
!= IPS_NULL
);
2721 assert(ips_active(pset
));
2727 case MACH_PORT_TYPE_SEND_ONCE
:
2728 case MACH_PORT_TYPE_DEAD_NAME
:
2732 panic("ipc_right_rename: strange rights");
2735 assert(oentry
->ie_request
== IE_REQ_NONE
);
2736 oentry
->ie_object
= IO_NULL
;
2737 ipc_entry_dealloc(space
, oname
, oentry
);
2738 ipc_entry_modified(space
, nname
, nentry
);
2739 is_write_unlock(space
);
2741 if (release_port
!= IP_NULL
)
2742 ip_release(release_port
);
2744 return KERN_SUCCESS
;