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 <security/mac_mach_internal.h>
92 * Routine: ipc_right_lookup_write
94 * Finds an entry in a space, given the name.
96 * Nothing locked. If successful, the space is write-locked.
98 * KERN_SUCCESS Found an entry.
99 * KERN_INVALID_TASK The space is dead.
100 * KERN_INVALID_NAME Name doesn't exist in space.
104 ipc_right_lookup_write(
106 mach_port_name_t name
,
111 assert(space
!= IS_NULL
);
113 is_write_lock(space
);
115 if (!space
->is_active
) {
116 is_write_unlock(space
);
117 return KERN_INVALID_TASK
;
120 if ((entry
= ipc_entry_lookup(space
, name
)) == IE_NULL
) {
121 is_write_unlock(space
);
122 return KERN_INVALID_NAME
;
130 * Routine: ipc_right_lookup_two_write
132 * Like ipc_right_lookup except that it returns two
133 * entries for two different names that were looked
134 * up under the same space lock.
136 * Nothing locked. If successful, the space is write-locked.
138 * KERN_INVALID_TASK The space is dead.
139 * KERN_INVALID_NAME Name doesn't exist in space.
143 ipc_right_lookup_two_write(
145 mach_port_name_t name1
,
146 ipc_entry_t
*entryp1
,
147 mach_port_name_t name2
,
148 ipc_entry_t
*entryp2
)
153 assert(space
!= IS_NULL
);
155 is_write_lock(space
);
157 if (!space
->is_active
) {
158 is_write_unlock(space
);
159 return KERN_INVALID_TASK
;
162 if ((entry1
= ipc_entry_lookup(space
, name1
)) == IE_NULL
) {
163 is_write_unlock(space
);
164 return KERN_INVALID_NAME
;
166 if ((entry2
= ipc_entry_lookup(space
, name2
)) == IE_NULL
) {
167 is_write_unlock(space
);
168 return KERN_INVALID_NAME
;
176 * Routine: ipc_right_reverse
178 * Translate (space, object) -> (name, entry).
179 * Only finds send/receive rights.
180 * Returns TRUE if an entry is found; if so,
181 * the object is locked and active.
183 * The space must be locked (read or write) and active.
184 * Nothing else locked.
191 mach_port_name_t
*namep
,
195 mach_port_name_t name
;
198 /* would switch on io_otype to handle multiple types of object */
200 assert(space
->is_active
);
201 assert(io_otype(object
) == IOT_PORT
);
203 port
= (ipc_port_t
) object
;
206 if (!ip_active(port
)) {
212 if (port
->ip_receiver
== space
) {
213 name
= port
->ip_receiver_name
;
214 assert(name
!= MACH_PORT_NULL
);
216 entry
= ipc_entry_lookup(space
, name
);
218 assert(entry
!= IE_NULL
);
219 assert(entry
->ie_bits
& MACH_PORT_TYPE_RECEIVE
);
220 assert(port
== (ipc_port_t
) entry
->ie_object
);
227 if (ipc_hash_lookup(space
, (ipc_object_t
) port
, namep
, entryp
)) {
228 assert((entry
= *entryp
) != IE_NULL
);
229 assert(IE_BITS_TYPE(entry
->ie_bits
) == MACH_PORT_TYPE_SEND
);
230 assert(port
== (ipc_port_t
) entry
->ie_object
);
240 * Routine: ipc_right_dnrequest
242 * Make a dead-name request, returning the previously
243 * registered send-once right. If notify is IP_NULL,
244 * just cancels the previously registered request.
246 * This interacts with the IE_BITS_COMPAT, because they
247 * both use ie_request. If this is a compat entry, then
248 * previous always gets IP_NULL. If notify is IP_NULL,
249 * then the entry remains a compat entry. Otherwise
250 * the real dead-name request is registered and the entry
251 * is no longer a compat entry.
253 * Nothing locked. May allocate memory.
254 * Only consumes/returns refs if successful.
256 * KERN_SUCCESS Made/canceled dead-name request.
257 * KERN_INVALID_TASK The space is dead.
258 * KERN_INVALID_NAME Name doesn't exist in space.
259 * KERN_INVALID_RIGHT Name doesn't denote port/dead rights.
260 * KERN_INVALID_ARGUMENT Name denotes dead name, but
261 * immediate is FALSE or notify is IP_NULL.
262 * KERN_UREFS_OVERFLOW Name denotes dead name, but
263 * generating immediate notif. would overflow urefs.
264 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
270 mach_port_name_t name
,
273 ipc_port_t
*previousp
)
279 ipc_entry_bits_t bits
;
282 kr
= ipc_right_lookup_write(space
, name
, &entry
);
283 if (kr
!= KERN_SUCCESS
)
285 /* space is write-locked and active */
286 bits
= entry
->ie_bits
;
287 if (bits
& MACH_PORT_TYPE_PORT_RIGHTS
) {
289 ipc_port_request_index_t request
;
291 port
= (ipc_port_t
) entry
->ie_object
;
292 assert(port
!= IP_NULL
);
294 if (!ipc_right_check(space
, port
, name
, entry
)) {
295 /* port is locked and active */
297 if (notify
== IP_NULL
) {
298 previous
= ipc_right_dncancel_macro(
299 space
, port
, name
, entry
);
302 is_write_unlock(space
);
307 * If a registered soright exists,
308 * want to atomically switch with it.
309 * If ipc_port_dncancel finds us a
310 * soright, then the following
311 * ipc_port_dnrequest will reuse
312 * that slot, so we are guaranteed
313 * not to unlock and retry.
316 previous
= ipc_right_dncancel_macro(space
,
319 kr
= ipc_port_dnrequest(port
, name
, notify
,
321 if (kr
!= KERN_SUCCESS
) {
322 assert(previous
== IP_NULL
);
323 is_write_unlock(space
);
325 kr
= ipc_port_dngrow(port
,
327 /* port is unlocked */
328 if (kr
!= KERN_SUCCESS
)
334 assert(request
!= 0);
337 entry
->ie_request
= request
;
338 is_write_unlock(space
);
343 * Our capability bits were changed by ipc_right_check
344 * because it found an inactive port and removed our
345 * references to it (converting our entry into a dead
346 * one). Reload the bits (and obviously we can't use
347 * the port name anymore).
349 bits
= entry
->ie_bits
;
353 assert(bits
& MACH_PORT_TYPE_DEAD_NAME
);
356 if ((bits
& MACH_PORT_TYPE_DEAD_NAME
) &&
357 immediate
&& (notify
!= IP_NULL
)) {
358 mach_port_urefs_t urefs
= IE_BITS_UREFS(bits
);
360 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_DEAD_NAME
);
363 if (MACH_PORT_UREFS_OVERFLOW(urefs
, 1)) {
364 is_write_unlock(space
);
365 return KERN_UREFS_OVERFLOW
;
368 (entry
->ie_bits
)++; /* increment urefs */
369 is_write_unlock(space
);
371 ipc_notify_dead_name(notify
, name
);
376 is_write_unlock(space
);
377 if (bits
& MACH_PORT_TYPE_PORT_OR_DEAD
)
378 return KERN_INVALID_ARGUMENT
;
380 return KERN_INVALID_RIGHT
;
383 *previousp
= previous
;
388 * Routine: ipc_right_dncancel
390 * Cancel a dead-name request and return the send-once right.
391 * Afterwards, entry->ie_request == 0.
393 * The space must be write-locked; the port must be locked.
394 * The port must be active; the space doesn't have to be.
399 __unused ipc_space_t space
,
401 mach_port_name_t name
,
404 ipc_port_t dnrequest
;
406 assert(ip_active(port
));
407 assert(port
== (ipc_port_t
) entry
->ie_object
);
409 dnrequest
= ipc_port_dncancel(port
, name
, entry
->ie_request
);
410 entry
->ie_request
= 0;
416 * Routine: ipc_right_inuse
418 * Check if an entry is being used.
419 * Returns TRUE if it is.
421 * The space is write-locked and active.
422 * It is unlocked if the entry is inuse.
428 __unused mach_port_name_t name
,
431 if (IE_BITS_TYPE(entry
->ie_bits
) != MACH_PORT_TYPE_NONE
) {
432 is_write_unlock(space
);
439 * Routine: ipc_right_check
441 * Check if the port has died. If it has,
442 * clean up the entry and return TRUE.
444 * The space is write-locked; the port is not locked.
445 * If returns FALSE, the port is also locked and active.
446 * Otherwise, entry is converted to a dead name, freeing
447 * a reference to port.
454 mach_port_name_t name
,
457 ipc_entry_bits_t bits
;
459 assert(space
->is_active
);
460 assert(port
== (ipc_port_t
) entry
->ie_object
);
467 /* this was either a pure send right or a send-once right */
469 bits
= entry
->ie_bits
;
470 assert((bits
& MACH_PORT_TYPE_RECEIVE
) == 0);
471 assert(IE_BITS_UREFS(bits
) > 0);
473 if (bits
& MACH_PORT_TYPE_SEND
) {
474 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND
);
476 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND_ONCE
);
477 assert(IE_BITS_UREFS(bits
) == 1);
481 ipc_port_release(port
);
483 /* convert entry to dead name */
485 if ((bits
& MACH_PORT_TYPE_SEND
) && !(bits
& MACH_PORT_TYPE_RECEIVE
))
486 ipc_hash_delete(space
, (ipc_object_t
)port
, name
, entry
);
488 bits
= (bits
&~ IE_BITS_TYPE_MASK
) | MACH_PORT_TYPE_DEAD_NAME
;
491 * If there was a notification request outstanding on this
492 * name, and since the port went dead, that notification
493 * must already be on its way up from the port layer. We
494 * don't need the index of the notification port anymore.
496 * JMM - We also add a reference to the entry since the
497 * notification only carries the name and NOT a reference
498 * (or right). This makes for pretty loose reference
499 * counting, since it is only happenstance that we
500 * detected the notification in progress like this.
501 * But most (all?) calls that try to deal with this entry
502 * will also come through here, so the reference gets added
503 * before the entry gets used eventually (I would rather it
504 * be explicit in the notification generation, though)
506 if (entry
->ie_request
!= 0) {
507 assert(IE_BITS_UREFS(bits
) < MACH_PORT_UREFS_MAX
);
508 entry
->ie_request
= 0;
511 entry
->ie_bits
= bits
;
512 entry
->ie_object
= IO_NULL
;
517 * Routine: ipc_right_clean
519 * Cleans up an entry in a dead space.
520 * The entry isn't deallocated or removed
521 * from reverse hash tables.
523 * The space is dead and unlocked.
529 mach_port_name_t name
,
532 ipc_entry_bits_t bits
;
533 mach_port_type_t type
;
535 bits
= entry
->ie_bits
;
536 type
= IE_BITS_TYPE(bits
);
538 assert(!space
->is_active
);
541 * IE_BITS_COMPAT/ipc_right_dncancel doesn't have this
542 * problem, because we check that the port is active. If
543 * we didn't cancel IE_BITS_COMPAT, ipc_port_destroy
544 * would still work, but dead space refs would accumulate
545 * in ip_dnrequests. They would use up slots in
546 * ip_dnrequests and keep the spaces from being freed.
550 case MACH_PORT_TYPE_DEAD_NAME
:
551 assert(entry
->ie_request
== 0);
552 assert(entry
->ie_object
== IO_NULL
);
555 case MACH_PORT_TYPE_PORT_SET
: {
556 ipc_pset_t pset
= (ipc_pset_t
) entry
->ie_object
;
558 assert(entry
->ie_request
== 0);
559 assert(pset
!= IPS_NULL
);
562 assert(ips_active(pset
));
564 ipc_pset_destroy(pset
); /* consumes ref, unlocks */
568 case MACH_PORT_TYPE_SEND
:
569 case MACH_PORT_TYPE_RECEIVE
:
570 case MACH_PORT_TYPE_SEND_RECEIVE
:
571 case MACH_PORT_TYPE_SEND_ONCE
: {
572 ipc_port_t port
= (ipc_port_t
) entry
->ie_object
;
573 ipc_port_t dnrequest
;
574 ipc_port_t nsrequest
= IP_NULL
;
575 mach_port_mscount_t mscount
= 0;
577 assert(port
!= IP_NULL
);
580 if (!ip_active(port
)) {
582 ip_check_unlock(port
);
586 dnrequest
= ipc_right_dncancel_macro(space
, port
,
589 if (type
& MACH_PORT_TYPE_SEND
) {
590 assert(port
->ip_srights
> 0);
591 if (--port
->ip_srights
== 0
593 nsrequest
= port
->ip_nsrequest
;
594 if (nsrequest
!= IP_NULL
) {
595 port
->ip_nsrequest
= IP_NULL
;
596 mscount
= port
->ip_mscount
;
601 if (type
& MACH_PORT_TYPE_RECEIVE
) {
602 assert(port
->ip_receiver_name
== name
);
603 assert(port
->ip_receiver
== space
);
605 ipc_port_clear_receiver(port
);
606 ipc_port_destroy(port
); /* consumes our ref, unlocks */
607 } else if (type
& MACH_PORT_TYPE_SEND_ONCE
) {
608 assert(port
->ip_sorights
> 0);
611 ipc_notify_send_once(port
); /* consumes our ref */
613 assert(port
->ip_receiver
!= space
);
616 ip_unlock(port
); /* port is active */
619 if (nsrequest
!= IP_NULL
)
620 ipc_notify_no_senders(nsrequest
, mscount
);
622 if (dnrequest
!= IP_NULL
)
623 ipc_notify_port_deleted(dnrequest
, name
);
628 panic("ipc_right_clean: strange type");
633 * Routine: ipc_right_destroy
635 * Destroys an entry in a space.
637 * The space is write-locked.
638 * The space must be active.
640 * KERN_SUCCESS The entry was destroyed.
646 mach_port_name_t name
,
649 ipc_entry_bits_t bits
;
650 mach_port_type_t type
;
652 bits
= entry
->ie_bits
;
653 entry
->ie_bits
&= ~IE_BITS_TYPE_MASK
;
654 type
= IE_BITS_TYPE(bits
);
656 assert(space
->is_active
);
659 case MACH_PORT_TYPE_DEAD_NAME
:
660 assert(entry
->ie_request
== 0);
661 assert(entry
->ie_object
== IO_NULL
);
663 ipc_entry_dealloc(space
, name
, entry
);
666 case MACH_PORT_TYPE_PORT_SET
: {
667 ipc_pset_t pset
= (ipc_pset_t
) entry
->ie_object
;
669 assert(entry
->ie_request
== 0);
670 assert(pset
!= IPS_NULL
);
672 entry
->ie_object
= IO_NULL
;
673 ipc_entry_dealloc(space
, name
, entry
);
676 assert(ips_active(pset
));
678 ipc_pset_destroy(pset
); /* consumes ref, unlocks */
682 case MACH_PORT_TYPE_SEND
:
683 case MACH_PORT_TYPE_RECEIVE
:
684 case MACH_PORT_TYPE_SEND_RECEIVE
:
685 case MACH_PORT_TYPE_SEND_ONCE
: {
686 ipc_port_t port
= (ipc_port_t
) entry
->ie_object
;
687 ipc_port_t nsrequest
= IP_NULL
;
688 mach_port_mscount_t mscount
= 0;
689 ipc_port_t dnrequest
;
691 assert(port
!= IP_NULL
);
693 if (type
== MACH_PORT_TYPE_SEND
)
694 ipc_hash_delete(space
, (ipc_object_t
) port
,
699 if (!ip_active(port
)) {
700 assert((type
& MACH_PORT_TYPE_RECEIVE
) == 0);
702 ip_check_unlock(port
);
704 entry
->ie_request
= 0;
705 entry
->ie_object
= IO_NULL
;
706 ipc_entry_dealloc(space
, name
, entry
);
711 dnrequest
= ipc_right_dncancel_macro(space
, port
, name
, entry
);
713 entry
->ie_object
= IO_NULL
;
714 ipc_entry_dealloc(space
, name
, entry
);
716 if (type
& MACH_PORT_TYPE_SEND
) {
717 assert(port
->ip_srights
> 0);
718 if (--port
->ip_srights
== 0) {
719 nsrequest
= port
->ip_nsrequest
;
720 if (nsrequest
!= IP_NULL
) {
721 port
->ip_nsrequest
= IP_NULL
;
722 mscount
= port
->ip_mscount
;
727 if (type
& MACH_PORT_TYPE_RECEIVE
) {
728 assert(ip_active(port
));
729 assert(port
->ip_receiver
== space
);
731 ipc_port_clear_receiver(port
);
732 ipc_port_destroy(port
); /* consumes our ref, unlocks */
733 } else if (type
& MACH_PORT_TYPE_SEND_ONCE
) {
734 assert(port
->ip_sorights
> 0);
737 ipc_notify_send_once(port
); /* consumes our ref */
739 assert(port
->ip_receiver
!= space
);
745 if (nsrequest
!= IP_NULL
)
746 ipc_notify_no_senders(nsrequest
, mscount
);
748 if (dnrequest
!= IP_NULL
)
749 ipc_notify_port_deleted(dnrequest
, name
);
754 panic("ipc_right_destroy: strange type");
761 * Routine: ipc_right_dealloc
763 * Releases a send/send-once/dead-name user ref.
764 * Like ipc_right_delta with a delta of -1,
765 * but looks at the entry to determine the right.
767 * The space is write-locked, and is unlocked upon return.
768 * The space must be active.
770 * KERN_SUCCESS A user ref was released.
771 * KERN_INVALID_RIGHT Entry has wrong type.
777 mach_port_name_t name
,
781 ipc_entry_bits_t bits
;
782 mach_port_type_t type
;
784 bits
= entry
->ie_bits
;
785 type
= IE_BITS_TYPE(bits
);
788 assert(space
->is_active
);
791 case MACH_PORT_TYPE_DEAD_NAME
: {
794 assert(IE_BITS_UREFS(bits
) > 0);
795 assert(entry
->ie_request
== 0);
796 assert(entry
->ie_object
== IO_NULL
);
798 if (IE_BITS_UREFS(bits
) == 1) {
799 ipc_entry_dealloc(space
, name
, entry
);
802 entry
->ie_bits
= bits
-1; /* decrement urefs */
804 is_write_unlock(space
);
808 case MACH_PORT_TYPE_SEND_ONCE
: {
809 ipc_port_t port
, dnrequest
;
811 assert(IE_BITS_UREFS(bits
) == 1);
813 port
= (ipc_port_t
) entry
->ie_object
;
814 assert(port
!= IP_NULL
);
816 if (ipc_right_check(space
, port
, name
, entry
)) {
818 bits
= entry
->ie_bits
;
819 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_DEAD_NAME
);
822 /* port is locked and active */
824 assert(port
->ip_sorights
> 0);
826 dnrequest
= ipc_right_dncancel_macro(space
, port
, name
, entry
);
829 entry
->ie_object
= IO_NULL
;
830 ipc_entry_dealloc(space
, name
, entry
);
832 is_write_unlock(space
);
834 ipc_notify_send_once(port
);
836 if (dnrequest
!= IP_NULL
)
837 ipc_notify_port_deleted(dnrequest
, name
);
841 case MACH_PORT_TYPE_SEND
: {
843 ipc_port_t dnrequest
= IP_NULL
;
844 ipc_port_t nsrequest
= IP_NULL
;
845 mach_port_mscount_t mscount
= 0;
848 assert(IE_BITS_UREFS(bits
) > 0);
850 port
= (ipc_port_t
) entry
->ie_object
;
851 assert(port
!= IP_NULL
);
853 if (ipc_right_check(space
, port
, name
, entry
)) {
854 bits
= entry
->ie_bits
;
855 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_DEAD_NAME
);
858 /* port is locked and active */
860 assert(port
->ip_srights
> 0);
862 if (IE_BITS_UREFS(bits
) == 1) {
863 if (--port
->ip_srights
== 0) {
864 nsrequest
= port
->ip_nsrequest
;
865 if (nsrequest
!= IP_NULL
) {
866 port
->ip_nsrequest
= IP_NULL
;
867 mscount
= port
->ip_mscount
;
871 dnrequest
= ipc_right_dncancel_macro(space
, port
,
873 ipc_hash_delete(space
, (ipc_object_t
) port
,
877 entry
->ie_object
= IO_NULL
;
878 ipc_entry_dealloc(space
, name
, entry
);
881 entry
->ie_bits
= bits
-1; /* decrement urefs */
883 /* even if dropped a ref, port is active */
885 is_write_unlock(space
);
887 if (nsrequest
!= IP_NULL
)
888 ipc_notify_no_senders(nsrequest
, mscount
);
890 if (dnrequest
!= IP_NULL
)
891 ipc_notify_port_deleted(dnrequest
, name
);
895 case MACH_PORT_TYPE_SEND_RECEIVE
: {
897 ipc_port_t nsrequest
= IP_NULL
;
898 mach_port_mscount_t mscount
= 0;
900 assert(IE_BITS_UREFS(bits
) > 0);
902 port
= (ipc_port_t
) entry
->ie_object
;
903 assert(port
!= IP_NULL
);
906 assert(ip_active(port
));
907 assert(port
->ip_receiver_name
== name
);
908 assert(port
->ip_receiver
== space
);
909 assert(port
->ip_srights
> 0);
911 if (IE_BITS_UREFS(bits
) == 1) {
912 if (--port
->ip_srights
== 0) {
913 nsrequest
= port
->ip_nsrequest
;
914 if (nsrequest
!= IP_NULL
) {
915 port
->ip_nsrequest
= IP_NULL
;
916 mscount
= port
->ip_mscount
;
920 entry
->ie_bits
= bits
&~ (IE_BITS_UREFS_MASK
|
921 MACH_PORT_TYPE_SEND
);
923 entry
->ie_bits
= bits
-1; /* decrement urefs */
926 is_write_unlock(space
);
928 if (nsrequest
!= IP_NULL
)
929 ipc_notify_no_senders(nsrequest
, mscount
);
934 is_write_unlock(space
);
935 return KERN_INVALID_RIGHT
;
942 * Routine: ipc_right_delta
944 * Modifies the user-reference count for a right.
945 * May deallocate the right, if the count goes to zero.
947 * The space is write-locked, and is unlocked upon return.
948 * The space must be active.
950 * KERN_SUCCESS Count was modified.
951 * KERN_INVALID_RIGHT Entry has wrong type.
952 * KERN_INVALID_VALUE Bad delta for the right.
953 * KERN_UREFS_OVERFLOW OK delta, except would overflow.
959 mach_port_name_t name
,
961 mach_port_right_t right
,
962 mach_port_delta_t delta
)
964 ipc_entry_bits_t bits
;
966 bits
= entry
->ie_bits
;
970 * The following is used (for case MACH_PORT_RIGHT_DEAD_NAME) in the
971 * switch below. It is used to keep track of those cases (in DIPC)
972 * where we have postponed the dropping of a port reference. Since
973 * the dropping of the reference could cause the port to disappear
974 * we postpone doing so when we are holding the space lock.
977 assert(space
->is_active
);
978 assert(right
< MACH_PORT_RIGHT_NUMBER
);
980 /* Rights-specific restrictions and operations. */
983 case MACH_PORT_RIGHT_PORT_SET
: {
986 if ((bits
& MACH_PORT_TYPE_PORT_SET
) == 0)
989 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_PORT_SET
);
990 assert(IE_BITS_UREFS(bits
) == 0);
991 assert(entry
->ie_request
== 0);
999 pset
= (ipc_pset_t
) entry
->ie_object
;
1000 assert(pset
!= IPS_NULL
);
1004 entry
->ie_object
= IO_NULL
;
1005 ipc_entry_dealloc(space
, name
, entry
);
1009 assert(ips_active(pset
));
1010 is_write_unlock(space
);
1012 ipc_pset_destroy(pset
); /* consumes ref, unlocks */
1016 case MACH_PORT_RIGHT_RECEIVE
: {
1018 ipc_port_t dnrequest
= IP_NULL
;
1020 if ((bits
& MACH_PORT_TYPE_RECEIVE
) == 0)
1029 port
= (ipc_port_t
) entry
->ie_object
;
1030 assert(port
!= IP_NULL
);
1033 * The port lock is needed for ipc_right_dncancel;
1034 * otherwise, we wouldn't have to take the lock
1035 * until just before dropping the space lock.
1039 assert(ip_active(port
));
1040 assert(port
->ip_receiver_name
== name
);
1041 assert(port
->ip_receiver
== space
);
1043 if (bits
& MACH_PORT_TYPE_SEND
) {
1044 assert(IE_BITS_TYPE(bits
) ==
1045 MACH_PORT_TYPE_SEND_RECEIVE
);
1046 assert(IE_BITS_UREFS(bits
) > 0);
1047 assert(IE_BITS_UREFS(bits
) < MACH_PORT_UREFS_MAX
);
1048 assert(port
->ip_srights
> 0);
1051 * The remaining send right turns into a
1052 * dead name. Notice we don't decrement
1053 * ip_srights, generate a no-senders notif,
1054 * or use ipc_right_dncancel, because the
1055 * port is destroyed "first".
1057 bits
&= ~IE_BITS_TYPE_MASK
;
1058 bits
|= MACH_PORT_TYPE_DEAD_NAME
;
1059 if (entry
->ie_request
) {
1060 entry
->ie_request
= 0;
1063 entry
->ie_bits
= bits
;
1064 entry
->ie_object
= IO_NULL
;
1066 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_RECEIVE
);
1067 assert(IE_BITS_UREFS(bits
) == 0);
1069 dnrequest
= ipc_right_dncancel_macro(space
, port
,
1071 entry
->ie_object
= IO_NULL
;
1072 ipc_entry_dealloc(space
, name
, entry
);
1074 is_write_unlock(space
);
1076 ipc_port_clear_receiver(port
);
1077 ipc_port_destroy(port
); /* consumes ref, unlocks */
1079 if (dnrequest
!= IP_NULL
)
1080 ipc_notify_port_deleted(dnrequest
, name
);
1084 case MACH_PORT_RIGHT_SEND_ONCE
: {
1085 ipc_port_t port
, dnrequest
;
1087 if ((bits
& MACH_PORT_TYPE_SEND_ONCE
) == 0)
1090 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND_ONCE
);
1091 assert(IE_BITS_UREFS(bits
) == 1);
1093 port
= (ipc_port_t
) entry
->ie_object
;
1094 assert(port
!= IP_NULL
);
1096 if (ipc_right_check(space
, port
, name
, entry
)) {
1097 assert(!(entry
->ie_bits
& MACH_PORT_TYPE_SEND_ONCE
));
1100 /* port is locked and active */
1102 assert(port
->ip_sorights
> 0);
1104 if ((delta
> 0) || (delta
< -1)) {
1114 dnrequest
= ipc_right_dncancel_macro(space
, port
, name
, entry
);
1117 entry
->ie_object
= IO_NULL
;
1118 ipc_entry_dealloc(space
, name
, entry
);
1120 is_write_unlock(space
);
1122 ipc_notify_send_once(port
);
1124 if (dnrequest
!= IP_NULL
)
1125 ipc_notify_port_deleted(dnrequest
, name
);
1129 case MACH_PORT_RIGHT_DEAD_NAME
: {
1130 mach_port_urefs_t urefs
;
1132 if (bits
& MACH_PORT_TYPE_SEND_RIGHTS
) {
1135 port
= (ipc_port_t
) entry
->ie_object
;
1136 assert(port
!= IP_NULL
);
1138 if (!ipc_right_check(space
, port
, name
, entry
)) {
1139 /* port is locked and active */
1143 bits
= entry
->ie_bits
;
1144 } else if ((bits
& MACH_PORT_TYPE_DEAD_NAME
) == 0)
1147 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_DEAD_NAME
);
1148 assert(IE_BITS_UREFS(bits
) > 0);
1149 assert(entry
->ie_object
== IO_NULL
);
1150 assert(entry
->ie_request
== 0);
1152 urefs
= IE_BITS_UREFS(bits
);
1153 if (MACH_PORT_UREFS_UNDERFLOW(urefs
, delta
))
1155 if (MACH_PORT_UREFS_OVERFLOW(urefs
, delta
))
1156 goto urefs_overflow
;
1158 if ((urefs
+ delta
) == 0) {
1159 ipc_entry_dealloc(space
, name
, entry
);
1162 entry
->ie_bits
= bits
+ delta
;
1164 is_write_unlock(space
);
1169 case MACH_PORT_RIGHT_SEND
: {
1170 mach_port_urefs_t urefs
;
1172 ipc_port_t dnrequest
= IP_NULL
;
1173 ipc_port_t nsrequest
= IP_NULL
;
1174 mach_port_mscount_t mscount
= 0;
1176 if ((bits
& MACH_PORT_TYPE_SEND
) == 0)
1179 /* maximum urefs for send is MACH_PORT_UREFS_MAX-1 */
1181 port
= (ipc_port_t
) entry
->ie_object
;
1182 assert(port
!= IP_NULL
);
1184 if (ipc_right_check(space
, port
, name
, entry
)) {
1185 assert((entry
->ie_bits
& MACH_PORT_TYPE_SEND
) == 0);
1188 /* port is locked and active */
1190 assert(port
->ip_srights
> 0);
1192 urefs
= IE_BITS_UREFS(bits
);
1193 if (MACH_PORT_UREFS_UNDERFLOW(urefs
, delta
)) {
1197 if (MACH_PORT_UREFS_OVERFLOW(urefs
+1, delta
)) {
1199 goto urefs_overflow
;
1202 if ((urefs
+ delta
) == 0) {
1203 if (--port
->ip_srights
== 0) {
1204 nsrequest
= port
->ip_nsrequest
;
1205 if (nsrequest
!= IP_NULL
) {
1206 port
->ip_nsrequest
= IP_NULL
;
1207 mscount
= port
->ip_mscount
;
1211 if (bits
& MACH_PORT_TYPE_RECEIVE
) {
1212 assert(port
->ip_receiver_name
== name
);
1213 assert(port
->ip_receiver
== space
);
1214 assert(IE_BITS_TYPE(bits
) ==
1215 MACH_PORT_TYPE_SEND_RECEIVE
);
1217 entry
->ie_bits
= bits
&~ (IE_BITS_UREFS_MASK
|
1218 MACH_PORT_TYPE_SEND
);
1220 assert(IE_BITS_TYPE(bits
) ==
1221 MACH_PORT_TYPE_SEND
);
1223 dnrequest
= ipc_right_dncancel_macro(space
, port
,
1225 ipc_hash_delete(space
, (ipc_object_t
) port
,
1230 entry
->ie_object
= IO_NULL
;
1231 ipc_entry_dealloc(space
, name
, entry
);
1234 entry
->ie_bits
= bits
+ delta
;
1236 /* even if dropped a ref, port is active */
1238 is_write_unlock(space
);
1240 if (nsrequest
!= IP_NULL
)
1241 ipc_notify_no_senders(nsrequest
, mscount
);
1243 if (dnrequest
!= IP_NULL
)
1244 ipc_notify_port_deleted(dnrequest
, name
);
1249 panic("ipc_right_delta: strange right");
1252 return KERN_SUCCESS
;
1255 is_write_unlock(space
);
1256 return KERN_SUCCESS
;
1259 is_write_unlock(space
);
1260 return KERN_INVALID_RIGHT
;
1263 is_write_unlock(space
);
1264 return KERN_INVALID_VALUE
;
1267 is_write_unlock(space
);
1268 return KERN_UREFS_OVERFLOW
;
1272 * Routine: ipc_right_info
1274 * Retrieves information about the right.
1276 * The space is write-locked, and is unlocked upon return
1277 * if the call is unsuccessful. The space must be active.
1279 * KERN_SUCCESS Retrieved info; space still locked.
1285 mach_port_name_t name
,
1287 mach_port_type_t
*typep
,
1288 mach_port_urefs_t
*urefsp
)
1290 ipc_entry_bits_t bits
;
1291 mach_port_type_t type
;
1292 ipc_port_request_index_t request
;
1294 bits
= entry
->ie_bits
;
1296 if (bits
& MACH_PORT_TYPE_SEND_RIGHTS
) {
1297 ipc_port_t port
= (ipc_port_t
) entry
->ie_object
;
1299 if (ipc_right_check(space
, port
, name
, entry
)) {
1300 bits
= entry
->ie_bits
;
1301 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_DEAD_NAME
);
1306 type
= IE_BITS_TYPE(bits
);
1307 request
= entry
->ie_request
;
1310 type
|= MACH_PORT_TYPE_DNREQUEST
;
1313 *urefsp
= IE_BITS_UREFS(bits
);
1314 return KERN_SUCCESS
;
1318 * Routine: ipc_right_copyin_check
1320 * Check if a subsequent ipc_right_copyin would succeed.
1322 * The space is locked (read or write) and active.
1326 ipc_right_copyin_check(
1327 __assert_only ipc_space_t space
,
1328 __unused mach_port_name_t name
,
1330 mach_msg_type_name_t msgt_name
)
1332 ipc_entry_bits_t bits
;
1334 #if CONFIG_MACF_MACH
1335 task_t self
= current_task();
1339 bits
= entry
->ie_bits
;
1340 assert(space
->is_active
);
1342 switch (msgt_name
) {
1343 case MACH_MSG_TYPE_MAKE_SEND
:
1344 if ((bits
& MACH_PORT_TYPE_RECEIVE
) == 0)
1347 #if CONFIG_MACF_MACH
1348 port
= (ipc_port_t
) entry
->ie_object
;
1350 tasklabel_lock(self
);
1351 rc
= mac_port_check_make_send(&self
->maclabel
, &port
->ip_label
); tasklabel_unlock(self
);
1358 case MACH_MSG_TYPE_MAKE_SEND_ONCE
:
1359 if ((bits
& MACH_PORT_TYPE_RECEIVE
) == 0)
1362 #if CONFIG_MACF_MACH
1363 port
= (ipc_port_t
) entry
->ie_object
;
1365 tasklabel_lock(self
);
1366 rc
= mac_port_check_make_send_once(&self
->maclabel
, &port
->ip_label
);
1367 tasklabel_unlock(self
);
1374 case MACH_MSG_TYPE_MOVE_RECEIVE
:
1375 if ((bits
& MACH_PORT_TYPE_RECEIVE
) == 0)
1378 #if CONFIG_MACF_MACH
1379 port
= (ipc_port_t
) entry
->ie_object
;
1381 tasklabel_lock(self
);
1382 rc
= mac_port_check_move_receive(&self
->maclabel
, &port
->ip_label
);
1383 tasklabel_unlock(self
);
1390 case MACH_MSG_TYPE_COPY_SEND
:
1391 case MACH_MSG_TYPE_MOVE_SEND
:
1392 case MACH_MSG_TYPE_MOVE_SEND_ONCE
: {
1395 if (bits
& MACH_PORT_TYPE_DEAD_NAME
)
1398 if ((bits
& MACH_PORT_TYPE_SEND_RIGHTS
) == 0)
1401 port
= (ipc_port_t
) entry
->ie_object
;
1402 assert(port
!= IP_NULL
);
1405 active
= ip_active(port
);
1406 #if CONFIG_MACF_MACH
1407 tasklabel_lock(self
);
1408 switch (msgt_name
) {
1409 case MACH_MSG_TYPE_COPY_SEND
:
1410 rc
= mac_port_check_copy_send(&self
->maclabel
,
1413 case MACH_MSG_TYPE_MOVE_SEND
:
1414 rc
= mac_port_check_move_send(&self
->maclabel
,
1417 case MACH_MSG_TYPE_MOVE_SEND_ONCE
:
1418 rc
= mac_port_check_move_send_once(&self
->maclabel
,
1422 panic("ipc_right_copyin_check: strange rights");
1424 tasklabel_unlock(self
);
1436 if (msgt_name
== MACH_MSG_TYPE_MOVE_SEND_ONCE
) {
1437 if ((bits
& MACH_PORT_TYPE_SEND_ONCE
) == 0)
1440 if ((bits
& MACH_PORT_TYPE_SEND
) == 0)
1448 panic("ipc_right_copyin_check: strange rights");
1455 * Routine: ipc_right_copyin
1457 * Copyin a capability from a space.
1458 * If successful, the caller gets a ref
1459 * for the resulting object, unless it is IO_DEAD,
1460 * and possibly a send-once right which should
1461 * be used in a port-deleted notification.
1463 * If deadok is not TRUE, the copyin operation
1464 * will fail instead of producing IO_DEAD.
1466 * The entry is never deallocated (except
1467 * when KERN_INVALID_NAME), so the caller
1468 * should deallocate the entry if its type
1469 * is MACH_PORT_TYPE_NONE.
1471 * The space is write-locked and active.
1473 * KERN_SUCCESS Acquired an object, possibly IO_DEAD.
1474 * KERN_INVALID_RIGHT Name doesn't denote correct right.
1480 mach_port_name_t name
,
1482 mach_msg_type_name_t msgt_name
,
1484 ipc_object_t
*objectp
,
1485 ipc_port_t
*sorightp
)
1487 ipc_entry_bits_t bits
;
1488 #if CONFIG_MACF_MACH
1489 task_t self
= current_task();
1493 bits
= entry
->ie_bits
;
1495 assert(space
->is_active
);
1497 switch (msgt_name
) {
1498 case MACH_MSG_TYPE_MAKE_SEND
: {
1501 if ((bits
& MACH_PORT_TYPE_RECEIVE
) == 0)
1504 port
= (ipc_port_t
) entry
->ie_object
;
1505 assert(port
!= IP_NULL
);
1508 assert(ip_active(port
));
1509 assert(port
->ip_receiver_name
== name
);
1510 assert(port
->ip_receiver
== space
);
1512 #if CONFIG_MACF_MACH
1513 tasklabel_lock(self
);
1514 rc
= mac_port_check_make_send(&self
->maclabel
, &port
->ip_label
);
1515 tasklabel_unlock(self
);
1518 return KERN_NO_ACCESS
;
1527 *objectp
= (ipc_object_t
) port
;
1528 *sorightp
= IP_NULL
;
1532 case MACH_MSG_TYPE_MAKE_SEND_ONCE
: {
1535 if ((bits
& MACH_PORT_TYPE_RECEIVE
) == 0)
1538 port
= (ipc_port_t
) entry
->ie_object
;
1539 assert(port
!= IP_NULL
);
1542 assert(ip_active(port
));
1543 assert(port
->ip_receiver_name
== name
);
1544 assert(port
->ip_receiver
== space
);
1546 #if CONFIG_MACF_MACH
1547 tasklabel_lock(self
);
1548 rc
= mac_port_check_make_send_once(&self
->maclabel
, &port
->ip_label
);
1549 tasklabel_unlock(self
);
1552 return KERN_NO_ACCESS
;
1556 port
->ip_sorights
++;
1560 *objectp
= (ipc_object_t
) port
;
1561 *sorightp
= IP_NULL
;
1565 case MACH_MSG_TYPE_MOVE_RECEIVE
: {
1567 ipc_port_t dnrequest
= IP_NULL
;
1569 if ((bits
& MACH_PORT_TYPE_RECEIVE
) == 0)
1572 port
= (ipc_port_t
) entry
->ie_object
;
1573 assert(port
!= IP_NULL
);
1576 assert(ip_active(port
));
1577 assert(port
->ip_receiver_name
== name
);
1578 assert(port
->ip_receiver
== space
);
1580 #if CONFIG_MACF_MACH
1581 tasklabel_lock(self
);
1582 rc
= mac_port_check_move_receive(&self
->maclabel
,
1584 tasklabel_unlock(self
);
1587 return KERN_NO_ACCESS
;
1591 if (bits
& MACH_PORT_TYPE_SEND
) {
1592 assert(IE_BITS_TYPE(bits
) ==
1593 MACH_PORT_TYPE_SEND_RECEIVE
);
1594 assert(IE_BITS_UREFS(bits
) > 0);
1595 assert(port
->ip_srights
> 0);
1597 ipc_hash_insert(space
, (ipc_object_t
) port
,
1601 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_RECEIVE
);
1602 assert(IE_BITS_UREFS(bits
) == 0);
1604 dnrequest
= ipc_right_dncancel_macro(space
, port
,
1606 entry
->ie_object
= IO_NULL
;
1608 entry
->ie_bits
= bits
&~ MACH_PORT_TYPE_RECEIVE
;
1610 ipc_port_clear_receiver(port
);
1612 port
->ip_receiver_name
= MACH_PORT_NULL
;
1613 port
->ip_destination
= IP_NULL
;
1616 *objectp
= (ipc_object_t
) port
;
1617 *sorightp
= dnrequest
;
1621 case MACH_MSG_TYPE_COPY_SEND
: {
1624 if (bits
& MACH_PORT_TYPE_DEAD_NAME
)
1627 /* allow for dead send-once rights */
1629 if ((bits
& MACH_PORT_TYPE_SEND_RIGHTS
) == 0)
1632 assert(IE_BITS_UREFS(bits
) > 0);
1634 port
= (ipc_port_t
) entry
->ie_object
;
1635 assert(port
!= IP_NULL
);
1637 if (ipc_right_check(space
, port
, name
, entry
)) {
1638 bits
= entry
->ie_bits
;
1641 /* port is locked and active */
1643 #if CONFIG_MACF_MACH
1644 tasklabel_lock(self
);
1645 rc
= mac_port_check_copy_send(&self
->maclabel
, &port
->ip_label
);
1646 tasklabel_unlock(self
);
1649 return KERN_NO_ACCESS
;
1653 if ((bits
& MACH_PORT_TYPE_SEND
) == 0) {
1654 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND_ONCE
);
1655 assert(port
->ip_sorights
> 0);
1661 assert(port
->ip_srights
> 0);
1667 *objectp
= (ipc_object_t
) port
;
1668 *sorightp
= IP_NULL
;
1672 case MACH_MSG_TYPE_MOVE_SEND
: {
1674 ipc_port_t dnrequest
= IP_NULL
;
1676 if (bits
& MACH_PORT_TYPE_DEAD_NAME
)
1679 /* allow for dead send-once rights */
1681 if ((bits
& MACH_PORT_TYPE_SEND_RIGHTS
) == 0)
1684 assert(IE_BITS_UREFS(bits
) > 0);
1686 port
= (ipc_port_t
) entry
->ie_object
;
1687 assert(port
!= IP_NULL
);
1689 if (ipc_right_check(space
, port
, name
, entry
)) {
1690 bits
= entry
->ie_bits
;
1693 /* port is locked and active */
1695 #if CONFIG_MACF_MACH
1696 tasklabel_lock (self
);
1697 rc
= mac_port_check_copy_send (&self
->maclabel
, &port
->ip_label
);
1698 tasklabel_unlock (self
);
1702 return KERN_NO_ACCESS
;
1706 if ((bits
& MACH_PORT_TYPE_SEND
) == 0) {
1707 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND_ONCE
);
1708 assert(port
->ip_sorights
> 0);
1714 assert(port
->ip_srights
> 0);
1716 if (IE_BITS_UREFS(bits
) == 1) {
1717 if (bits
& MACH_PORT_TYPE_RECEIVE
) {
1718 assert(port
->ip_receiver_name
== name
);
1719 assert(port
->ip_receiver
== space
);
1720 assert(IE_BITS_TYPE(bits
) ==
1721 MACH_PORT_TYPE_SEND_RECEIVE
);
1725 assert(IE_BITS_TYPE(bits
) ==
1726 MACH_PORT_TYPE_SEND
);
1728 dnrequest
= ipc_right_dncancel_macro(space
, port
,
1730 ipc_hash_delete(space
, (ipc_object_t
) port
,
1732 entry
->ie_object
= IO_NULL
;
1734 entry
->ie_bits
= bits
&~
1735 (IE_BITS_UREFS_MASK
|MACH_PORT_TYPE_SEND
);
1739 entry
->ie_bits
= bits
-1; /* decrement urefs */
1744 *objectp
= (ipc_object_t
) port
;
1745 *sorightp
= dnrequest
;
1749 case MACH_MSG_TYPE_MOVE_SEND_ONCE
: {
1751 ipc_port_t dnrequest
;
1753 if (bits
& MACH_PORT_TYPE_DEAD_NAME
)
1756 /* allow for dead send rights */
1758 if ((bits
& MACH_PORT_TYPE_SEND_RIGHTS
) == 0)
1761 assert(IE_BITS_UREFS(bits
) > 0);
1763 port
= (ipc_port_t
) entry
->ie_object
;
1764 assert(port
!= IP_NULL
);
1766 if (ipc_right_check(space
, port
, name
, entry
)) {
1767 bits
= entry
->ie_bits
;
1770 /* port is locked and active */
1772 #if CONFIG_MACF_MACH
1773 tasklabel_lock (self
);
1774 rc
= mac_port_check_copy_send (&self
->maclabel
, &port
->ip_label
);
1775 tasklabel_unlock (self
);
1779 return KERN_NO_ACCESS
;
1783 if ((bits
& MACH_PORT_TYPE_SEND_ONCE
) == 0) {
1784 assert(bits
& MACH_PORT_TYPE_SEND
);
1785 assert(port
->ip_srights
> 0);
1791 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND_ONCE
);
1792 assert(IE_BITS_UREFS(bits
) == 1);
1793 assert(port
->ip_sorights
> 0);
1795 dnrequest
= ipc_right_dncancel_macro(space
, port
, name
, entry
);
1798 entry
->ie_object
= IO_NULL
;
1799 entry
->ie_bits
= bits
&~
1800 (IE_BITS_UREFS_MASK
| MACH_PORT_TYPE_SEND_ONCE
);
1802 *objectp
= (ipc_object_t
) port
;
1803 *sorightp
= dnrequest
;
1809 return KERN_INVALID_RIGHT
;
1812 return KERN_SUCCESS
;
1815 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_DEAD_NAME
);
1816 assert(IE_BITS_UREFS(bits
) > 0);
1817 assert(entry
->ie_request
== 0);
1818 assert(entry
->ie_object
== 0);
1824 *sorightp
= IP_NULL
;
1825 return KERN_SUCCESS
;
1828 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_DEAD_NAME
);
1829 assert(IE_BITS_UREFS(bits
) > 0);
1830 assert(entry
->ie_request
== 0);
1831 assert(entry
->ie_object
== 0);
1836 if (IE_BITS_UREFS(bits
) == 1) {
1837 bits
&= ~MACH_PORT_TYPE_DEAD_NAME
;
1839 entry
->ie_bits
= bits
-1; /* decrement urefs */
1842 *sorightp
= IP_NULL
;
1843 return KERN_SUCCESS
;
1848 * Routine: ipc_right_copyin_undo
1850 * Undoes the effects of an ipc_right_copyin
1851 * of a send/send-once right that is dead.
1852 * (Object is either IO_DEAD or a dead port.)
1854 * The space is write-locked and active.
1858 ipc_right_copyin_undo(
1860 mach_port_name_t name
,
1862 mach_msg_type_name_t msgt_name
,
1863 ipc_object_t object
,
1866 ipc_entry_bits_t bits
;
1868 bits
= entry
->ie_bits
;
1870 assert(space
->is_active
);
1872 assert((msgt_name
== MACH_MSG_TYPE_MOVE_SEND
) ||
1873 (msgt_name
== MACH_MSG_TYPE_COPY_SEND
) ||
1874 (msgt_name
== MACH_MSG_TYPE_MOVE_SEND_ONCE
));
1876 if (soright
!= IP_NULL
) {
1877 assert((msgt_name
== MACH_MSG_TYPE_MOVE_SEND
) ||
1878 (msgt_name
== MACH_MSG_TYPE_MOVE_SEND_ONCE
));
1879 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_NONE
);
1880 assert(object
!= IO_DEAD
);
1882 entry
->ie_bits
= ((bits
&~ IE_BITS_RIGHT_MASK
) |
1883 MACH_PORT_TYPE_DEAD_NAME
| 2);
1885 } else if (IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_NONE
) {
1886 assert((msgt_name
== MACH_MSG_TYPE_MOVE_SEND
) ||
1887 (msgt_name
== MACH_MSG_TYPE_MOVE_SEND_ONCE
));
1889 entry
->ie_bits
= ((bits
&~ IE_BITS_RIGHT_MASK
) |
1890 MACH_PORT_TYPE_DEAD_NAME
| 1);
1891 } else if (IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_DEAD_NAME
) {
1892 assert(object
== IO_DEAD
);
1893 assert(IE_BITS_UREFS(bits
) > 0);
1895 if (msgt_name
!= MACH_MSG_TYPE_COPY_SEND
) {
1896 assert(IE_BITS_UREFS(bits
) < MACH_PORT_UREFS_MAX
);
1897 entry
->ie_bits
= bits
+1; /* increment urefs */
1900 assert((msgt_name
== MACH_MSG_TYPE_MOVE_SEND
) ||
1901 (msgt_name
== MACH_MSG_TYPE_COPY_SEND
));
1902 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND
);
1903 assert(object
!= IO_DEAD
);
1904 assert(entry
->ie_object
== object
);
1905 assert(IE_BITS_UREFS(bits
) > 0);
1907 if (msgt_name
!= MACH_MSG_TYPE_COPY_SEND
) {
1908 assert(IE_BITS_UREFS(bits
) < MACH_PORT_UREFS_MAX
-1);
1909 entry
->ie_bits
= bits
+1; /* increment urefs */
1913 * May as well convert the entry to a dead name.
1914 * (Or if it is a compat entry, destroy it.)
1917 (void) ipc_right_check(space
, (ipc_port_t
) object
,
1919 /* object is dead so it is not locked */
1922 /* release the reference acquired by copyin */
1924 if (object
!= IO_DEAD
)
1925 ipc_object_release(object
);
1929 * Routine: ipc_right_copyin_two
1931 * Like ipc_right_copyin with MACH_MSG_TYPE_MOVE_SEND
1932 * and deadok == FALSE, except that this moves two
1933 * send rights at once.
1935 * The space is write-locked and active.
1936 * The object is returned with two refs/send rights.
1938 * KERN_SUCCESS Acquired an object.
1939 * KERN_INVALID_RIGHT Name doesn't denote correct right.
1943 ipc_right_copyin_two(
1945 mach_port_name_t name
,
1947 ipc_object_t
*objectp
,
1948 ipc_port_t
*sorightp
)
1950 ipc_entry_bits_t bits
;
1951 mach_port_urefs_t urefs
;
1953 ipc_port_t dnrequest
= IP_NULL
;
1954 #if CONFIG_MACF_MACH
1955 task_t self
= current_task();
1959 assert(space
->is_active
);
1961 bits
= entry
->ie_bits
;
1963 if ((bits
& MACH_PORT_TYPE_SEND
) == 0)
1966 urefs
= IE_BITS_UREFS(bits
);
1970 port
= (ipc_port_t
) entry
->ie_object
;
1971 assert(port
!= IP_NULL
);
1973 if (ipc_right_check(space
, port
, name
, entry
)) {
1976 /* port is locked and active */
1978 #if CONFIG_MACF_MACH
1979 tasklabel_lock(self
);
1980 rc
= mac_port_check_copy_send(&self
->maclabel
, &port
->ip_label
);
1981 tasklabel_unlock(self
);
1984 return KERN_NO_ACCESS
;
1988 assert(port
->ip_srights
> 0);
1991 if (bits
& MACH_PORT_TYPE_RECEIVE
) {
1992 assert(port
->ip_receiver_name
== name
);
1993 assert(port
->ip_receiver
== space
);
1994 assert(IE_BITS_TYPE(bits
) ==
1995 MACH_PORT_TYPE_SEND_RECEIVE
);
2001 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND
);
2003 dnrequest
= ipc_right_dncancel_macro(space
, port
,
2008 ipc_hash_delete(space
, (ipc_object_t
) port
,
2010 entry
->ie_object
= IO_NULL
;
2012 entry
->ie_bits
= bits
&~ (IE_BITS_UREFS_MASK
|MACH_PORT_TYPE_SEND
);
2014 port
->ip_srights
+= 2;
2017 entry
->ie_bits
= bits
-2; /* decrement urefs */
2021 *objectp
= (ipc_object_t
) port
;
2022 *sorightp
= dnrequest
;
2023 return KERN_SUCCESS
;
2026 return KERN_INVALID_RIGHT
;
2030 * Routine: ipc_right_copyout
2032 * Copyout a capability to a space.
2033 * If successful, consumes a ref for the object.
2035 * Always succeeds when given a newly-allocated entry,
2036 * because user-reference overflow isn't a possibility.
2038 * If copying out the object would cause the user-reference
2039 * count in the entry to overflow, and overflow is TRUE,
2040 * then instead the user-reference count is left pegged
2041 * to its maximum value and the copyout succeeds anyway.
2043 * The space is write-locked and active.
2044 * The object is locked and active.
2045 * The object is unlocked; the space isn't.
2047 * KERN_SUCCESS Copied out capability.
2048 * KERN_UREFS_OVERFLOW User-refs would overflow;
2049 * guaranteed not to happen with a fresh entry
2050 * or if overflow=TRUE was specified.
2056 mach_port_name_t name
,
2058 mach_msg_type_name_t msgt_name
,
2060 ipc_object_t object
)
2062 ipc_entry_bits_t bits
;
2064 #if CONFIG_MACF_MACH
2068 bits
= entry
->ie_bits
;
2070 assert(IO_VALID(object
));
2071 assert(io_otype(object
) == IOT_PORT
);
2072 assert(io_active(object
));
2073 assert(entry
->ie_object
== object
);
2075 port
= (ipc_port_t
) object
;
2077 switch (msgt_name
) {
2078 case MACH_MSG_TYPE_PORT_SEND_ONCE
:
2080 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_NONE
);
2081 assert(port
->ip_sorights
> 0);
2083 #if CONFIG_MACF_MACH
2084 if (space
->is_task
) {
2085 tasklabel_lock(space
->is_task
);
2086 rc
= mac_port_check_hold_send_once(&space
->is_task
->maclabel
,
2088 tasklabel_unlock(space
->is_task
);
2092 return KERN_NO_ACCESS
;
2096 /* transfer send-once right and ref to entry */
2099 entry
->ie_bits
= bits
| (MACH_PORT_TYPE_SEND_ONCE
| 1);
2102 case MACH_MSG_TYPE_PORT_SEND
:
2103 assert(port
->ip_srights
> 0);
2105 #if CONFIG_MACF_MACH
2106 if (space
->is_task
) {
2107 tasklabel_lock(space
->is_task
);
2108 rc
= mac_port_check_hold_send(&space
->is_task
->maclabel
,
2110 tasklabel_unlock(space
->is_task
);
2114 return KERN_NO_ACCESS
;
2119 if (bits
& MACH_PORT_TYPE_SEND
) {
2120 mach_port_urefs_t urefs
= IE_BITS_UREFS(bits
);
2122 assert(port
->ip_srights
> 1);
2124 assert(urefs
< MACH_PORT_UREFS_MAX
);
2126 if (urefs
+1 == MACH_PORT_UREFS_MAX
) {
2128 /* leave urefs pegged to maximum */
2133 return KERN_SUCCESS
;
2137 return KERN_UREFS_OVERFLOW
;
2143 } else if (bits
& MACH_PORT_TYPE_RECEIVE
) {
2144 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_RECEIVE
);
2145 assert(IE_BITS_UREFS(bits
) == 0);
2147 /* transfer send right to entry */
2151 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_NONE
);
2152 assert(IE_BITS_UREFS(bits
) == 0);
2154 /* transfer send right and ref to entry */
2157 /* entry is locked holding ref, so can use port */
2159 ipc_hash_insert(space
, (ipc_object_t
) port
,
2163 entry
->ie_bits
= (bits
| MACH_PORT_TYPE_SEND
) + 1;
2166 case MACH_MSG_TYPE_PORT_RECEIVE
: {
2169 assert(port
->ip_mscount
== 0);
2170 assert(port
->ip_receiver_name
== MACH_PORT_NULL
);
2171 dest
= port
->ip_destination
;
2173 #if CONFIG_MACF_MACH
2174 if (space
->is_task
) {
2175 tasklabel_lock(space
->is_task
);
2176 rc
= mac_port_check_hold_receive(&space
->is_task
->maclabel
,
2178 tasklabel_unlock(space
->is_task
);
2182 return KERN_NO_ACCESS
;
2187 port
->ip_receiver_name
= name
;
2188 port
->ip_receiver
= space
;
2190 assert((bits
& MACH_PORT_TYPE_RECEIVE
) == 0);
2192 if (bits
& MACH_PORT_TYPE_SEND
) {
2193 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND
);
2194 assert(IE_BITS_UREFS(bits
) > 0);
2195 assert(port
->ip_srights
> 0);
2200 /* entry is locked holding ref, so can use port */
2202 ipc_hash_delete(space
, (ipc_object_t
) port
,
2205 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_NONE
);
2206 assert(IE_BITS_UREFS(bits
) == 0);
2208 /* transfer ref to entry */
2211 entry
->ie_bits
= bits
| MACH_PORT_TYPE_RECEIVE
;
2213 if (dest
!= IP_NULL
)
2214 ipc_port_release(dest
);
2219 panic("ipc_right_copyout: strange rights");
2222 return KERN_SUCCESS
;
2226 * Routine: ipc_right_rename
2228 * Transfer an entry from one name to another.
2229 * The old entry is deallocated.
2231 * The space is write-locked and active.
2232 * The new entry is unused. Upon return,
2233 * the space is unlocked.
2235 * KERN_SUCCESS Moved entry to new name.
2241 mach_port_name_t oname
,
2243 mach_port_name_t nname
,
2246 ipc_port_request_index_t request
= oentry
->ie_request
;
2247 ipc_entry_bits_t bits
= oentry
->ie_bits
;
2248 ipc_object_t object
= oentry
->ie_object
;
2250 assert(space
->is_active
);
2251 assert(oname
!= nname
);
2254 * If IE_BITS_COMPAT, we can't allow the entry to be renamed
2255 * if the port is dead. (This would foil ipc_port_destroy.)
2256 * Instead we should fail because oentry shouldn't exist.
2257 * Note IE_BITS_COMPAT implies ie_request != 0.
2263 assert(bits
& MACH_PORT_TYPE_PORT_RIGHTS
);
2264 port
= (ipc_port_t
) object
;
2265 assert(port
!= IP_NULL
);
2267 if (ipc_right_check(space
, port
, oname
, oentry
)) {
2270 bits
= oentry
->ie_bits
;
2271 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_DEAD_NAME
);
2272 assert(oentry
->ie_request
== 0);
2274 /* port is locked and active */
2276 ipc_port_dnrename(port
, request
, oname
, nname
);
2278 oentry
->ie_request
= 0;
2282 /* initialize nentry before letting ipc_hash_insert see it */
2284 assert((nentry
->ie_bits
& IE_BITS_RIGHT_MASK
) == 0);
2285 nentry
->ie_bits
|= bits
& IE_BITS_RIGHT_MASK
;
2286 nentry
->ie_request
= request
;
2287 nentry
->ie_object
= object
;
2289 switch (IE_BITS_TYPE(bits
)) {
2290 case MACH_PORT_TYPE_SEND
: {
2293 port
= (ipc_port_t
) object
;
2294 assert(port
!= IP_NULL
);
2296 /* remember, there are no other share entries possible */
2297 /* or we can't do the rename. Therefore we do not need */
2298 /* to check the other subspaces */
2299 ipc_hash_delete(space
, (ipc_object_t
) port
, oname
, oentry
);
2300 ipc_hash_insert(space
, (ipc_object_t
) port
, nname
, nentry
);
2304 case MACH_PORT_TYPE_RECEIVE
:
2305 case MACH_PORT_TYPE_SEND_RECEIVE
: {
2308 port
= (ipc_port_t
) object
;
2309 assert(port
!= IP_NULL
);
2312 assert(ip_active(port
));
2313 assert(port
->ip_receiver_name
== oname
);
2314 assert(port
->ip_receiver
== space
);
2316 port
->ip_receiver_name
= nname
;
2321 case MACH_PORT_TYPE_PORT_SET
: {
2324 pset
= (ipc_pset_t
) object
;
2325 assert(pset
!= IPS_NULL
);
2328 assert(ips_active(pset
));
2329 assert(pset
->ips_local_name
== oname
);
2331 pset
->ips_local_name
= nname
;
2336 case MACH_PORT_TYPE_SEND_ONCE
:
2337 case MACH_PORT_TYPE_DEAD_NAME
:
2341 panic("ipc_right_rename: strange rights");
2344 assert(oentry
->ie_request
== 0);
2345 oentry
->ie_object
= IO_NULL
;
2346 ipc_entry_dealloc(space
, oname
, oentry
);
2347 is_write_unlock(space
);
2349 return KERN_SUCCESS
;