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 (!is_active(space
)) {
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 (!is_active(space
)) {
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(is_active(space
));
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.
247 * Nothing locked. May allocate memory.
248 * Only consumes/returns refs if successful.
250 * KERN_SUCCESS Made/canceled dead-name request.
251 * KERN_INVALID_TASK The space is dead.
252 * KERN_INVALID_NAME Name doesn't exist in space.
253 * KERN_INVALID_RIGHT Name doesn't denote port/dead rights.
254 * KERN_INVALID_ARGUMENT Name denotes dead name, but
255 * immediate is FALSE or notify is IP_NULL.
256 * KERN_UREFS_OVERFLOW Name denotes dead name, but
257 * generating immediate notif. would overflow urefs.
258 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
262 ipc_right_request_alloc(
264 mach_port_name_t name
,
266 boolean_t send_possible
,
268 ipc_port_t
*previousp
)
270 ipc_port_request_index_t prev_request
;
271 ipc_port_t previous
= IP_NULL
;
276 ipc_port_t port
= IP_NULL
;
278 kr
= ipc_right_lookup_write(space
, name
, &entry
);
279 if (kr
!= KERN_SUCCESS
)
282 /* space is write-locked and active */
284 prev_request
= entry
->ie_request
;
286 /* if nothing to do or undo, we're done */
287 if (notify
== IP_NULL
&& prev_request
== IE_REQ_NONE
) {
288 is_write_unlock(space
);
289 *previousp
= IP_NULL
;
293 /* see if the entry is of proper type for requests */
294 if (entry
->ie_bits
& MACH_PORT_TYPE_PORT_RIGHTS
) {
295 ipc_port_request_index_t new_request
;
297 port
= (ipc_port_t
) entry
->ie_object
;
298 assert(port
!= IP_NULL
);
300 if (!ipc_right_check(space
, port
, name
, entry
)) {
301 /* port is locked and active */
303 /* if no new request, just cancel previous */
304 if (notify
== IP_NULL
) {
305 if (prev_request
!= IE_REQ_NONE
)
306 previous
= ipc_port_request_cancel(port
, name
, prev_request
);
308 entry
->ie_request
= IE_REQ_NONE
;
309 ipc_entry_modified(space
, name
, entry
);
310 is_write_unlock(space
);
315 * send-once rights, kernel objects, and non-full other queues
316 * fire immediately (if immediate specified).
318 if (send_possible
&& immediate
&&
319 ((entry
->ie_bits
& MACH_PORT_TYPE_SEND_ONCE
) ||
320 port
->ip_receiver
== ipc_space_kernel
|| !ip_full(port
))) {
321 if (prev_request
!= IE_REQ_NONE
)
322 previous
= ipc_port_request_cancel(port
, name
, prev_request
);
324 entry
->ie_request
= IE_REQ_NONE
;
325 ipc_entry_modified(space
, name
, entry
);
326 is_write_unlock(space
);
328 ipc_notify_send_possible(notify
, name
);
333 * If there is a previous request, free it. Any subsequent
334 * allocation cannot fail, thus assuring an atomic swap.
336 if (prev_request
!= IE_REQ_NONE
)
337 previous
= ipc_port_request_cancel(port
, name
, prev_request
);
339 kr
= ipc_port_request_alloc(port
, name
, notify
,
340 send_possible
, immediate
,
342 if (kr
!= KERN_SUCCESS
) {
343 assert(previous
== IP_NULL
);
344 is_write_unlock(space
);
346 kr
= ipc_port_request_grow(port
, ITS_SIZE_NONE
);
347 /* port is unlocked */
349 if (kr
!= KERN_SUCCESS
)
355 assert(new_request
!= IE_REQ_NONE
);
357 entry
->ie_request
= new_request
;
358 ipc_entry_modified(space
, name
, entry
);
359 is_write_unlock(space
);
362 /* entry may have changed to dead-name by ipc_right_check() */
366 /* treat send_possible requests as immediate w.r.t. dead-name */
367 if ((send_possible
|| immediate
) && notify
!= IP_NULL
&&
368 (entry
->ie_bits
& MACH_PORT_TYPE_DEAD_NAME
)) {
369 mach_port_urefs_t urefs
= IE_BITS_UREFS(entry
->ie_bits
);
373 if (MACH_PORT_UREFS_OVERFLOW(urefs
, 1)) {
374 is_write_unlock(space
);
377 return KERN_UREFS_OVERFLOW
;
380 (entry
->ie_bits
)++; /* increment urefs */
381 ipc_entry_modified(space
, name
, entry
);
382 is_write_unlock(space
);
387 ipc_notify_dead_name(notify
, name
);
392 is_write_unlock(space
);
397 if (entry
->ie_bits
& MACH_PORT_TYPE_PORT_OR_DEAD
)
398 return KERN_INVALID_ARGUMENT
;
400 return KERN_INVALID_RIGHT
;
403 *previousp
= previous
;
408 * Routine: ipc_right_request_cancel
410 * Cancel a notification request and return the send-once right.
411 * Afterwards, entry->ie_request == 0.
413 * The space must be write-locked; the port must be locked.
414 * The port must be active; the space doesn't have to be.
418 ipc_right_request_cancel(
419 __unused ipc_space_t space
,
421 mach_port_name_t name
,
426 assert(ip_active(port
));
427 assert(port
== (ipc_port_t
) entry
->ie_object
);
429 if (entry
->ie_request
== IE_REQ_NONE
)
432 previous
= ipc_port_request_cancel(port
, name
, entry
->ie_request
);
433 entry
->ie_request
= IE_REQ_NONE
;
434 ipc_entry_modified(space
, name
, entry
);
439 * Routine: ipc_right_inuse
441 * Check if an entry is being used.
442 * Returns TRUE if it is.
444 * The space is write-locked and active.
445 * It is unlocked if the entry is inuse.
451 __unused mach_port_name_t name
,
454 if (IE_BITS_TYPE(entry
->ie_bits
) != MACH_PORT_TYPE_NONE
) {
455 is_write_unlock(space
);
462 * Routine: ipc_right_check
464 * Check if the port has died. If it has,
465 * clean up the entry and return TRUE.
467 * The space is write-locked; the port is not locked.
468 * If returns FALSE, the port is also locked and active.
469 * Otherwise, entry is converted to a dead name.
471 * Caller is responsible for a reference to port if it
472 * had died (returns TRUE).
479 mach_port_name_t name
,
482 ipc_entry_bits_t bits
;
484 assert(is_active(space
));
485 assert(port
== (ipc_port_t
) entry
->ie_object
);
492 /* this was either a pure send right or a send-once right */
494 bits
= entry
->ie_bits
;
495 assert((bits
& MACH_PORT_TYPE_RECEIVE
) == 0);
496 assert(IE_BITS_UREFS(bits
) > 0);
498 if (bits
& MACH_PORT_TYPE_SEND
) {
499 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND
);
501 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND_ONCE
);
502 assert(IE_BITS_UREFS(bits
) == 1);
506 /* convert entry to dead name */
508 if ((bits
& MACH_PORT_TYPE_SEND
) && !(bits
& MACH_PORT_TYPE_RECEIVE
))
509 ipc_hash_delete(space
, (ipc_object_t
)port
, name
, entry
);
511 bits
= (bits
&~ IE_BITS_TYPE_MASK
) | MACH_PORT_TYPE_DEAD_NAME
;
514 * If there was a notification request outstanding on this
515 * name, and the port went dead, that notification
516 * must already be on its way up from the port layer.
518 * Add the reference that the notification carries. It
519 * is done here, and not in the notification delivery,
520 * because the latter doesn't have a space reference and
521 * trying to actually move a send-right reference would
522 * get short-circuited into a MACH_PORT_DEAD by IPC. Since
523 * all calls that deal with the right eventually come
524 * through here, it has the same result.
526 * Once done, clear the request index so we only account
529 if (entry
->ie_request
!= IE_REQ_NONE
) {
530 if (ipc_port_request_type(port
, name
, entry
->ie_request
) != 0) {
531 assert(IE_BITS_UREFS(bits
) < MACH_PORT_UREFS_MAX
);
534 entry
->ie_request
= IE_REQ_NONE
;
536 entry
->ie_bits
= bits
;
537 entry
->ie_object
= IO_NULL
;
538 ipc_entry_modified(space
, name
, entry
);
543 * Routine: ipc_right_terminate
545 * Cleans up an entry in a terminated space.
546 * The entry isn't deallocated or removed
547 * from reverse hash tables.
549 * The space is dead and unlocked.
555 mach_port_name_t name
,
558 ipc_entry_bits_t bits
;
559 mach_port_type_t type
;
561 bits
= entry
->ie_bits
;
562 type
= IE_BITS_TYPE(bits
);
564 assert(!is_active(space
));
567 * IE_BITS_COMPAT/ipc_right_dncancel doesn't have this
568 * problem, because we check that the port is active. If
569 * we didn't cancel IE_BITS_COMPAT, ipc_port_destroy
570 * would still work, but dead space refs would accumulate
571 * in ip_dnrequests. They would use up slots in
572 * ip_dnrequests and keep the spaces from being freed.
576 case MACH_PORT_TYPE_DEAD_NAME
:
577 assert(entry
->ie_request
== IE_REQ_NONE
);
578 assert(entry
->ie_object
== IO_NULL
);
581 case MACH_PORT_TYPE_PORT_SET
: {
582 ipc_pset_t pset
= (ipc_pset_t
) entry
->ie_object
;
584 assert(entry
->ie_request
== IE_REQ_NONE
);
585 assert(pset
!= IPS_NULL
);
588 assert(ips_active(pset
));
589 ipc_pset_destroy(pset
); /* consumes ref, unlocks */
593 case MACH_PORT_TYPE_SEND
:
594 case MACH_PORT_TYPE_RECEIVE
:
595 case MACH_PORT_TYPE_SEND_RECEIVE
:
596 case MACH_PORT_TYPE_SEND_ONCE
: {
597 ipc_port_t port
= (ipc_port_t
) entry
->ie_object
;
599 ipc_port_t nsrequest
= IP_NULL
;
600 mach_port_mscount_t mscount
= 0;
602 assert(port
!= IP_NULL
);
605 if (!ip_active(port
)) {
611 request
= ipc_right_request_cancel_macro(space
, port
,
614 if (type
& MACH_PORT_TYPE_SEND
) {
615 assert(port
->ip_srights
> 0);
616 if (--port
->ip_srights
== 0
618 nsrequest
= port
->ip_nsrequest
;
619 if (nsrequest
!= IP_NULL
) {
620 port
->ip_nsrequest
= IP_NULL
;
621 mscount
= port
->ip_mscount
;
626 if (type
& MACH_PORT_TYPE_RECEIVE
) {
627 wait_queue_link_t wql
;
628 queue_head_t links_data
;
629 queue_t links
= &links_data
;
631 assert(port
->ip_receiver_name
== name
);
632 assert(port
->ip_receiver
== space
);
635 ipc_port_clear_receiver(port
, links
);
636 ipc_port_destroy(port
); /* consumes our ref, unlocks */
637 while(!queue_empty(links
)) {
638 wql
= (wait_queue_link_t
) dequeue(links
);
639 wait_queue_link_free(wql
);
642 } else if (type
& MACH_PORT_TYPE_SEND_ONCE
) {
643 assert(port
->ip_sorights
> 0);
646 ipc_notify_send_once(port
); /* consumes our ref */
648 assert(port
->ip_receiver
!= space
);
654 if (nsrequest
!= IP_NULL
)
655 ipc_notify_no_senders(nsrequest
, mscount
);
657 if (request
!= IP_NULL
)
658 ipc_notify_port_deleted(request
, name
);
663 panic("ipc_right_terminate: strange type - 0x%x", type
);
668 * Routine: ipc_right_destroy
670 * Destroys an entry in a space.
672 * The space is write-locked (returns unlocked).
673 * The space must be active.
675 * KERN_SUCCESS The entry was destroyed.
681 mach_port_name_t name
,
684 ipc_entry_bits_t bits
;
685 mach_port_type_t type
;
687 bits
= entry
->ie_bits
;
688 entry
->ie_bits
&= ~IE_BITS_TYPE_MASK
;
689 type
= IE_BITS_TYPE(bits
);
691 assert(is_active(space
));
694 case MACH_PORT_TYPE_DEAD_NAME
:
695 assert(entry
->ie_request
== IE_REQ_NONE
);
696 assert(entry
->ie_object
== IO_NULL
);
698 ipc_entry_dealloc(space
, name
, entry
);
699 is_write_unlock(space
);
702 case MACH_PORT_TYPE_PORT_SET
: {
703 ipc_pset_t pset
= (ipc_pset_t
) entry
->ie_object
;
705 assert(entry
->ie_request
== IE_REQ_NONE
);
706 assert(pset
!= IPS_NULL
);
708 entry
->ie_object
= IO_NULL
;
709 ipc_entry_dealloc(space
, name
, entry
);
712 is_write_unlock(space
);
714 assert(ips_active(pset
));
715 ipc_pset_destroy(pset
); /* consumes ref, unlocks */
719 case MACH_PORT_TYPE_SEND
:
720 case MACH_PORT_TYPE_RECEIVE
:
721 case MACH_PORT_TYPE_SEND_RECEIVE
:
722 case MACH_PORT_TYPE_SEND_ONCE
: {
723 ipc_port_t port
= (ipc_port_t
) entry
->ie_object
;
724 ipc_port_t nsrequest
= IP_NULL
;
725 mach_port_mscount_t mscount
= 0;
728 assert(port
!= IP_NULL
);
730 if (type
== MACH_PORT_TYPE_SEND
)
731 ipc_hash_delete(space
, (ipc_object_t
) port
,
736 if (!ip_active(port
)) {
737 assert((type
& MACH_PORT_TYPE_RECEIVE
) == 0);
739 entry
->ie_request
= IE_REQ_NONE
;
740 entry
->ie_object
= IO_NULL
;
741 ipc_entry_dealloc(space
, name
, entry
);
742 is_write_unlock(space
);
747 request
= ipc_right_request_cancel_macro(space
, port
, name
, entry
);
749 entry
->ie_object
= IO_NULL
;
750 ipc_entry_dealloc(space
, name
, entry
);
751 is_write_unlock(space
);
753 if (type
& MACH_PORT_TYPE_SEND
) {
754 assert(port
->ip_srights
> 0);
755 if (--port
->ip_srights
== 0) {
756 nsrequest
= port
->ip_nsrequest
;
757 if (nsrequest
!= IP_NULL
) {
758 port
->ip_nsrequest
= IP_NULL
;
759 mscount
= port
->ip_mscount
;
764 if (type
& MACH_PORT_TYPE_RECEIVE
) {
765 queue_head_t links_data
;
766 queue_t links
= &links_data
;
767 wait_queue_link_t wql
;
769 assert(ip_active(port
));
770 assert(port
->ip_receiver
== space
);
773 ipc_port_clear_receiver(port
, links
);
774 ipc_port_destroy(port
); /* consumes our ref, unlocks */
775 while(!queue_empty(links
)) {
776 wql
= (wait_queue_link_t
) dequeue(links
);
777 wait_queue_link_free(wql
);
780 } else if (type
& MACH_PORT_TYPE_SEND_ONCE
) {
781 assert(port
->ip_sorights
> 0);
784 ipc_notify_send_once(port
); /* consumes our ref */
786 assert(port
->ip_receiver
!= space
);
792 if (nsrequest
!= IP_NULL
)
793 ipc_notify_no_senders(nsrequest
, mscount
);
795 if (request
!= IP_NULL
)
796 ipc_notify_port_deleted(request
, name
);
801 panic("ipc_right_destroy: strange type");
808 * Routine: ipc_right_dealloc
810 * Releases a send/send-once/dead-name user ref.
811 * Like ipc_right_delta with a delta of -1,
812 * but looks at the entry to determine the right.
814 * The space is write-locked, and is unlocked upon return.
815 * The space must be active.
817 * KERN_SUCCESS A user ref was released.
818 * KERN_INVALID_RIGHT Entry has wrong type.
824 mach_port_name_t name
,
827 ipc_port_t port
= IP_NULL
;
828 ipc_entry_bits_t bits
;
829 mach_port_type_t type
;
831 bits
= entry
->ie_bits
;
832 type
= IE_BITS_TYPE(bits
);
835 assert(is_active(space
));
838 case MACH_PORT_TYPE_DEAD_NAME
: {
841 assert(IE_BITS_UREFS(bits
) > 0);
842 assert(entry
->ie_request
== IE_REQ_NONE
);
843 assert(entry
->ie_object
== IO_NULL
);
845 if (IE_BITS_UREFS(bits
) == 1) {
846 ipc_entry_dealloc(space
, name
, entry
);
848 entry
->ie_bits
= bits
-1; /* decrement urefs */
849 ipc_entry_modified(space
, name
, entry
);
851 is_write_unlock(space
);
853 /* release any port that got converted to dead name below */
859 case MACH_PORT_TYPE_SEND_ONCE
: {
862 assert(IE_BITS_UREFS(bits
) == 1);
864 port
= (ipc_port_t
) entry
->ie_object
;
865 assert(port
!= IP_NULL
);
867 if (ipc_right_check(space
, port
, name
, entry
)) {
869 bits
= entry
->ie_bits
;
870 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_DEAD_NAME
);
871 goto dead_name
; /* it will release port */
873 /* port is locked and active */
875 assert(port
->ip_sorights
> 0);
877 request
= ipc_right_request_cancel_macro(space
, port
, name
, entry
);
880 entry
->ie_object
= IO_NULL
;
881 ipc_entry_dealloc(space
, name
, entry
);
883 is_write_unlock(space
);
885 ipc_notify_send_once(port
);
887 if (request
!= IP_NULL
)
888 ipc_notify_port_deleted(request
, name
);
892 case MACH_PORT_TYPE_SEND
: {
893 ipc_port_t request
= IP_NULL
;
894 ipc_port_t nsrequest
= IP_NULL
;
895 mach_port_mscount_t mscount
= 0;
898 assert(IE_BITS_UREFS(bits
) > 0);
900 port
= (ipc_port_t
) entry
->ie_object
;
901 assert(port
!= IP_NULL
);
903 if (ipc_right_check(space
, port
, name
, entry
)) {
904 bits
= entry
->ie_bits
;
905 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_DEAD_NAME
);
906 goto dead_name
; /* it will release port */
908 /* port is locked and active */
910 assert(port
->ip_srights
> 0);
912 if (IE_BITS_UREFS(bits
) == 1) {
913 if (--port
->ip_srights
== 0) {
914 nsrequest
= port
->ip_nsrequest
;
915 if (nsrequest
!= IP_NULL
) {
916 port
->ip_nsrequest
= IP_NULL
;
917 mscount
= port
->ip_mscount
;
921 request
= ipc_right_request_cancel_macro(space
, port
,
923 ipc_hash_delete(space
, (ipc_object_t
) port
,
927 entry
->ie_object
= IO_NULL
;
928 ipc_entry_dealloc(space
, name
, entry
);
929 is_write_unlock(space
);
934 entry
->ie_bits
= bits
-1; /* decrement urefs */
935 ipc_entry_modified(space
, name
, entry
);
936 is_write_unlock(space
);
940 if (nsrequest
!= IP_NULL
)
941 ipc_notify_no_senders(nsrequest
, mscount
);
943 if (request
!= IP_NULL
)
944 ipc_notify_port_deleted(request
, name
);
948 case MACH_PORT_TYPE_SEND_RECEIVE
: {
949 ipc_port_t nsrequest
= IP_NULL
;
950 mach_port_mscount_t mscount
= 0;
952 assert(IE_BITS_UREFS(bits
) > 0);
954 port
= (ipc_port_t
) entry
->ie_object
;
955 assert(port
!= IP_NULL
);
958 assert(ip_active(port
));
959 assert(port
->ip_receiver_name
== name
);
960 assert(port
->ip_receiver
== space
);
961 assert(port
->ip_srights
> 0);
963 if (IE_BITS_UREFS(bits
) == 1) {
964 if (--port
->ip_srights
== 0) {
965 nsrequest
= port
->ip_nsrequest
;
966 if (nsrequest
!= IP_NULL
) {
967 port
->ip_nsrequest
= IP_NULL
;
968 mscount
= port
->ip_mscount
;
972 entry
->ie_bits
= bits
&~ (IE_BITS_UREFS_MASK
|
973 MACH_PORT_TYPE_SEND
);
975 entry
->ie_bits
= bits
-1; /* decrement urefs */
979 ipc_entry_modified(space
, name
, entry
);
980 is_write_unlock(space
);
982 if (nsrequest
!= IP_NULL
)
983 ipc_notify_no_senders(nsrequest
, mscount
);
988 is_write_unlock(space
);
989 return KERN_INVALID_RIGHT
;
996 * Routine: ipc_right_delta
998 * Modifies the user-reference count for a right.
999 * May deallocate the right, if the count goes to zero.
1001 * The space is write-locked, and is unlocked upon return.
1002 * The space must be active.
1004 * KERN_SUCCESS Count was modified.
1005 * KERN_INVALID_RIGHT Entry has wrong type.
1006 * KERN_INVALID_VALUE Bad delta for the right.
1007 * KERN_UREFS_OVERFLOW OK delta, except would overflow.
1013 mach_port_name_t name
,
1015 mach_port_right_t right
,
1016 mach_port_delta_t delta
)
1018 ipc_port_t port
= IP_NULL
;
1019 ipc_entry_bits_t bits
;
1021 bits
= entry
->ie_bits
;
1025 * The following is used (for case MACH_PORT_RIGHT_DEAD_NAME) in the
1026 * switch below. It is used to keep track of those cases (in DIPC)
1027 * where we have postponed the dropping of a port reference. Since
1028 * the dropping of the reference could cause the port to disappear
1029 * we postpone doing so when we are holding the space lock.
1032 assert(is_active(space
));
1033 assert(right
< MACH_PORT_RIGHT_NUMBER
);
1035 /* Rights-specific restrictions and operations. */
1038 case MACH_PORT_RIGHT_PORT_SET
: {
1041 if ((bits
& MACH_PORT_TYPE_PORT_SET
) == 0)
1044 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_PORT_SET
);
1045 assert(IE_BITS_UREFS(bits
) == 0);
1046 assert(entry
->ie_request
== IE_REQ_NONE
);
1054 pset
= (ipc_pset_t
) entry
->ie_object
;
1055 assert(pset
!= IPS_NULL
);
1057 entry
->ie_object
= IO_NULL
;
1058 ipc_entry_dealloc(space
, name
, entry
);
1061 assert(ips_active(pset
));
1062 is_write_unlock(space
);
1064 ipc_pset_destroy(pset
); /* consumes ref, unlocks */
1068 case MACH_PORT_RIGHT_RECEIVE
: {
1069 ipc_port_t request
= IP_NULL
;
1070 queue_head_t links_data
;
1071 queue_t links
= &links_data
;
1072 wait_queue_link_t wql
;
1074 if ((bits
& MACH_PORT_TYPE_RECEIVE
) == 0)
1083 port
= (ipc_port_t
) entry
->ie_object
;
1084 assert(port
!= IP_NULL
);
1087 * The port lock is needed for ipc_right_dncancel;
1088 * otherwise, we wouldn't have to take the lock
1089 * until just before dropping the space lock.
1093 assert(ip_active(port
));
1094 assert(port
->ip_receiver_name
== name
);
1095 assert(port
->ip_receiver
== space
);
1097 if (bits
& MACH_PORT_TYPE_SEND
) {
1098 assert(IE_BITS_TYPE(bits
) ==
1099 MACH_PORT_TYPE_SEND_RECEIVE
);
1100 assert(IE_BITS_UREFS(bits
) > 0);
1101 assert(IE_BITS_UREFS(bits
) < MACH_PORT_UREFS_MAX
);
1102 assert(port
->ip_srights
> 0);
1104 if (port
->ip_pdrequest
!= NULL
) {
1106 * Since another task has requested a
1107 * destroy notification for this port, it
1108 * isn't actually being destroyed - the receive
1109 * right is just being moved to another task.
1110 * Since we still have one or more send rights,
1111 * we need to record the loss of the receive
1112 * right and enter the remaining send right
1113 * into the hash table.
1115 ipc_entry_modified(space
, name
, entry
);
1116 entry
->ie_bits
&= ~MACH_PORT_TYPE_RECEIVE
;
1117 ipc_hash_insert(space
, (ipc_object_t
) port
,
1122 * The remaining send right turns into a
1123 * dead name. Notice we don't decrement
1124 * ip_srights, generate a no-senders notif,
1125 * or use ipc_right_dncancel, because the
1126 * port is destroyed "first".
1128 bits
&= ~IE_BITS_TYPE_MASK
;
1129 bits
|= MACH_PORT_TYPE_DEAD_NAME
;
1130 if (entry
->ie_request
) {
1131 entry
->ie_request
= IE_REQ_NONE
;
1134 entry
->ie_bits
= bits
;
1135 entry
->ie_object
= IO_NULL
;
1136 ipc_entry_modified(space
, name
, entry
);
1139 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_RECEIVE
);
1140 assert(IE_BITS_UREFS(bits
) == 0);
1142 request
= ipc_right_request_cancel_macro(space
, port
,
1144 entry
->ie_object
= IO_NULL
;
1145 ipc_entry_dealloc(space
, name
, entry
);
1147 is_write_unlock(space
);
1150 ipc_port_clear_receiver(port
, links
);
1151 ipc_port_destroy(port
); /* consumes ref, unlocks */
1152 while(!queue_empty(links
)) {
1153 wql
= (wait_queue_link_t
) dequeue(links
);
1154 wait_queue_link_free(wql
);
1157 if (request
!= IP_NULL
)
1158 ipc_notify_port_deleted(request
, name
);
1162 case MACH_PORT_RIGHT_SEND_ONCE
: {
1165 if ((bits
& MACH_PORT_TYPE_SEND_ONCE
) == 0)
1168 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND_ONCE
);
1169 assert(IE_BITS_UREFS(bits
) == 1);
1171 port
= (ipc_port_t
) entry
->ie_object
;
1172 assert(port
!= IP_NULL
);
1174 if (ipc_right_check(space
, port
, name
, entry
)) {
1175 assert(!(entry
->ie_bits
& MACH_PORT_TYPE_SEND_ONCE
));
1178 /* port is locked and active */
1180 assert(port
->ip_sorights
> 0);
1182 if ((delta
> 0) || (delta
< -1)) {
1192 request
= ipc_right_request_cancel_macro(space
, port
, name
, entry
);
1195 entry
->ie_object
= IO_NULL
;
1196 ipc_entry_dealloc(space
, name
, entry
);
1198 is_write_unlock(space
);
1200 ipc_notify_send_once(port
);
1202 if (request
!= IP_NULL
)
1203 ipc_notify_port_deleted(request
, name
);
1207 case MACH_PORT_RIGHT_DEAD_NAME
: {
1208 mach_port_urefs_t urefs
;
1210 if (bits
& MACH_PORT_TYPE_SEND_RIGHTS
) {
1212 port
= (ipc_port_t
) entry
->ie_object
;
1213 assert(port
!= IP_NULL
);
1215 if (!ipc_right_check(space
, port
, name
, entry
)) {
1216 /* port is locked and active */
1221 bits
= entry
->ie_bits
;
1222 } else if ((bits
& MACH_PORT_TYPE_DEAD_NAME
) == 0)
1225 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_DEAD_NAME
);
1226 assert(IE_BITS_UREFS(bits
) > 0);
1227 assert(entry
->ie_object
== IO_NULL
);
1228 assert(entry
->ie_request
== IE_REQ_NONE
);
1230 urefs
= IE_BITS_UREFS(bits
);
1231 if (MACH_PORT_UREFS_UNDERFLOW(urefs
, delta
))
1233 if (MACH_PORT_UREFS_OVERFLOW(urefs
, delta
))
1234 goto urefs_overflow
;
1236 if ((urefs
+ delta
) == 0) {
1237 ipc_entry_dealloc(space
, name
, entry
);
1239 entry
->ie_bits
= bits
+ delta
;
1240 ipc_entry_modified(space
, name
, entry
);
1242 is_write_unlock(space
);
1247 case MACH_PORT_RIGHT_SEND
: {
1248 mach_port_urefs_t urefs
;
1249 ipc_port_t request
= IP_NULL
;
1250 ipc_port_t nsrequest
= IP_NULL
;
1251 mach_port_mscount_t mscount
= 0;
1253 if ((bits
& MACH_PORT_TYPE_SEND
) == 0)
1256 /* maximum urefs for send is MACH_PORT_UREFS_MAX-1 */
1258 port
= (ipc_port_t
) entry
->ie_object
;
1259 assert(port
!= IP_NULL
);
1261 if (ipc_right_check(space
, port
, name
, entry
)) {
1262 assert((entry
->ie_bits
& MACH_PORT_TYPE_SEND
) == 0);
1265 /* port is locked and active */
1267 assert(port
->ip_srights
> 0);
1269 urefs
= IE_BITS_UREFS(bits
);
1270 if (MACH_PORT_UREFS_UNDERFLOW(urefs
, delta
)) {
1274 if (MACH_PORT_UREFS_OVERFLOW(urefs
+1, delta
)) {
1276 goto urefs_overflow
;
1279 if ((urefs
+ delta
) == 0) {
1280 if (--port
->ip_srights
== 0) {
1281 nsrequest
= port
->ip_nsrequest
;
1282 if (nsrequest
!= IP_NULL
) {
1283 port
->ip_nsrequest
= IP_NULL
;
1284 mscount
= port
->ip_mscount
;
1288 if (bits
& MACH_PORT_TYPE_RECEIVE
) {
1289 assert(port
->ip_receiver_name
== name
);
1290 assert(port
->ip_receiver
== space
);
1292 assert(IE_BITS_TYPE(bits
) ==
1293 MACH_PORT_TYPE_SEND_RECEIVE
);
1295 entry
->ie_bits
= bits
&~ (IE_BITS_UREFS_MASK
|
1296 MACH_PORT_TYPE_SEND
);
1297 ipc_entry_modified(space
, name
, entry
);
1299 assert(IE_BITS_TYPE(bits
) ==
1300 MACH_PORT_TYPE_SEND
);
1302 request
= ipc_right_request_cancel_macro(space
, port
,
1304 ipc_hash_delete(space
, (ipc_object_t
) port
,
1310 entry
->ie_object
= IO_NULL
;
1311 ipc_entry_dealloc(space
, name
, entry
);
1315 entry
->ie_bits
= bits
+ delta
;
1316 ipc_entry_modified(space
, name
, entry
);
1319 is_write_unlock(space
);
1321 if (nsrequest
!= IP_NULL
)
1322 ipc_notify_no_senders(nsrequest
, mscount
);
1324 if (request
!= IP_NULL
)
1325 ipc_notify_port_deleted(request
, name
);
1330 panic("ipc_right_delta: strange right");
1333 return KERN_SUCCESS
;
1336 is_write_unlock(space
);
1337 return KERN_SUCCESS
;
1340 is_write_unlock(space
);
1341 if (port
!= IP_NULL
)
1343 return KERN_INVALID_RIGHT
;
1346 is_write_unlock(space
);
1347 return KERN_INVALID_VALUE
;
1350 is_write_unlock(space
);
1351 return KERN_UREFS_OVERFLOW
;
1355 * Routine: ipc_right_info
1357 * Retrieves information about the right.
1359 * The space is active and write-locked.
1360 * The space is unlocked upon return.
1362 * KERN_SUCCESS Retrieved info
1368 mach_port_name_t name
,
1370 mach_port_type_t
*typep
,
1371 mach_port_urefs_t
*urefsp
)
1374 ipc_entry_bits_t bits
;
1375 mach_port_type_t type
= 0;
1376 ipc_port_request_index_t request
;
1378 bits
= entry
->ie_bits
;
1379 request
= entry
->ie_request
;
1380 port
= (ipc_port_t
) entry
->ie_object
;
1382 if (bits
& MACH_PORT_TYPE_RECEIVE
) {
1383 assert(IP_VALID(port
));
1385 if (request
!= IE_REQ_NONE
) {
1387 assert(ip_active(port
));
1388 type
|= ipc_port_request_type(port
, name
, request
);
1391 is_write_unlock(space
);
1393 } else if (bits
& MACH_PORT_TYPE_SEND_RIGHTS
) {
1395 * validate port is still alive - if so, get request
1396 * types while we still have it locked. Otherwise,
1397 * recapture the (now dead) bits.
1399 if (!ipc_right_check(space
, port
, name
, entry
)) {
1400 if (request
!= IE_REQ_NONE
)
1401 type
|= ipc_port_request_type(port
, name
, request
);
1403 is_write_unlock(space
);
1405 bits
= entry
->ie_bits
;
1406 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_DEAD_NAME
);
1407 is_write_unlock(space
);
1411 is_write_unlock(space
);
1414 type
|= IE_BITS_TYPE(bits
);
1417 *urefsp
= IE_BITS_UREFS(bits
);
1418 return KERN_SUCCESS
;
1422 * Routine: ipc_right_copyin_check
1424 * Check if a subsequent ipc_right_copyin would succeed.
1426 * The space is locked (read or write) and active.
1430 ipc_right_copyin_check(
1431 __assert_only ipc_space_t space
,
1432 __unused mach_port_name_t name
,
1434 mach_msg_type_name_t msgt_name
)
1436 ipc_entry_bits_t bits
;
1438 #if CONFIG_MACF_MACH
1439 task_t self
= current_task();
1443 bits
= entry
->ie_bits
;
1444 assert(is_active(space
));
1446 switch (msgt_name
) {
1447 case MACH_MSG_TYPE_MAKE_SEND
:
1448 if ((bits
& MACH_PORT_TYPE_RECEIVE
) == 0)
1451 #if CONFIG_MACF_MACH
1452 port
= (ipc_port_t
) entry
->ie_object
;
1454 tasklabel_lock(self
);
1455 rc
= mac_port_check_make_send(&self
->maclabel
, &port
->ip_label
); tasklabel_unlock(self
);
1462 case MACH_MSG_TYPE_MAKE_SEND_ONCE
:
1463 if ((bits
& MACH_PORT_TYPE_RECEIVE
) == 0)
1466 #if CONFIG_MACF_MACH
1467 port
= (ipc_port_t
) entry
->ie_object
;
1469 tasklabel_lock(self
);
1470 rc
= mac_port_check_make_send_once(&self
->maclabel
, &port
->ip_label
);
1471 tasklabel_unlock(self
);
1478 case MACH_MSG_TYPE_MOVE_RECEIVE
:
1479 if ((bits
& MACH_PORT_TYPE_RECEIVE
) == 0)
1482 #if CONFIG_MACF_MACH
1483 port
= (ipc_port_t
) entry
->ie_object
;
1485 tasklabel_lock(self
);
1486 rc
= mac_port_check_move_receive(&self
->maclabel
, &port
->ip_label
);
1487 tasklabel_unlock(self
);
1494 case MACH_MSG_TYPE_COPY_SEND
:
1495 case MACH_MSG_TYPE_MOVE_SEND
:
1496 case MACH_MSG_TYPE_MOVE_SEND_ONCE
: {
1499 if (bits
& MACH_PORT_TYPE_DEAD_NAME
)
1502 if ((bits
& MACH_PORT_TYPE_SEND_RIGHTS
) == 0)
1505 port
= (ipc_port_t
) entry
->ie_object
;
1506 assert(port
!= IP_NULL
);
1509 active
= ip_active(port
);
1510 #if CONFIG_MACF_MACH
1511 tasklabel_lock(self
);
1512 switch (msgt_name
) {
1513 case MACH_MSG_TYPE_COPY_SEND
:
1514 rc
= mac_port_check_copy_send(&self
->maclabel
,
1517 case MACH_MSG_TYPE_MOVE_SEND
:
1518 rc
= mac_port_check_move_send(&self
->maclabel
,
1521 case MACH_MSG_TYPE_MOVE_SEND_ONCE
:
1522 rc
= mac_port_check_move_send_once(&self
->maclabel
,
1526 panic("ipc_right_copyin_check: strange rights");
1528 tasklabel_unlock(self
);
1540 if (msgt_name
== MACH_MSG_TYPE_MOVE_SEND_ONCE
) {
1541 if ((bits
& MACH_PORT_TYPE_SEND_ONCE
) == 0)
1544 if ((bits
& MACH_PORT_TYPE_SEND
) == 0)
1552 panic("ipc_right_copyin_check: strange rights");
1559 * Routine: ipc_right_copyin
1561 * Copyin a capability from a space.
1562 * If successful, the caller gets a ref
1563 * for the resulting object, unless it is IO_DEAD,
1564 * and possibly a send-once right which should
1565 * be used in a port-deleted notification.
1567 * If deadok is not TRUE, the copyin operation
1568 * will fail instead of producing IO_DEAD.
1570 * The entry is never deallocated (except
1571 * when KERN_INVALID_NAME), so the caller
1572 * should deallocate the entry if its type
1573 * is MACH_PORT_TYPE_NONE.
1575 * The space is write-locked and active.
1577 * KERN_SUCCESS Acquired an object, possibly IO_DEAD.
1578 * KERN_INVALID_RIGHT Name doesn't denote correct right.
1584 mach_port_name_t name
,
1586 mach_msg_type_name_t msgt_name
,
1588 ipc_object_t
*objectp
,
1589 ipc_port_t
*sorightp
,
1590 ipc_port_t
*releasep
,
1593 ipc_entry_bits_t bits
;
1595 #if CONFIG_MACF_MACH
1596 task_t self
= current_task();
1600 *releasep
= IP_NULL
;
1602 bits
= entry
->ie_bits
;
1604 assert(is_active(space
));
1606 switch (msgt_name
) {
1607 case MACH_MSG_TYPE_MAKE_SEND
: {
1609 if ((bits
& MACH_PORT_TYPE_RECEIVE
) == 0)
1612 port
= (ipc_port_t
) entry
->ie_object
;
1613 assert(port
!= IP_NULL
);
1616 assert(ip_active(port
));
1617 assert(port
->ip_receiver_name
== name
);
1618 assert(port
->ip_receiver
== space
);
1620 #if CONFIG_MACF_MACH
1621 tasklabel_lock(self
);
1622 rc
= mac_port_check_make_send(&self
->maclabel
, &port
->ip_label
);
1623 tasklabel_unlock(self
);
1626 return KERN_NO_ACCESS
;
1635 *objectp
= (ipc_object_t
) port
;
1636 *sorightp
= IP_NULL
;
1640 case MACH_MSG_TYPE_MAKE_SEND_ONCE
: {
1642 if ((bits
& MACH_PORT_TYPE_RECEIVE
) == 0)
1645 port
= (ipc_port_t
) entry
->ie_object
;
1646 assert(port
!= IP_NULL
);
1649 assert(ip_active(port
));
1650 assert(port
->ip_receiver_name
== name
);
1651 assert(port
->ip_receiver
== space
);
1653 #if CONFIG_MACF_MACH
1654 tasklabel_lock(self
);
1655 rc
= mac_port_check_make_send_once(&self
->maclabel
, &port
->ip_label
);
1656 tasklabel_unlock(self
);
1659 return KERN_NO_ACCESS
;
1663 port
->ip_sorights
++;
1667 *objectp
= (ipc_object_t
) port
;
1668 *sorightp
= IP_NULL
;
1672 case MACH_MSG_TYPE_MOVE_RECEIVE
: {
1673 ipc_port_t request
= IP_NULL
;
1675 if ((bits
& MACH_PORT_TYPE_RECEIVE
) == 0)
1678 port
= (ipc_port_t
) entry
->ie_object
;
1679 assert(port
!= IP_NULL
);
1682 assert(ip_active(port
));
1683 assert(port
->ip_receiver_name
== name
);
1684 assert(port
->ip_receiver
== space
);
1686 #if CONFIG_MACF_MACH
1687 tasklabel_lock(self
);
1688 rc
= mac_port_check_move_receive(&self
->maclabel
,
1690 tasklabel_unlock(self
);
1693 return KERN_NO_ACCESS
;
1697 if (bits
& MACH_PORT_TYPE_SEND
) {
1698 assert(IE_BITS_TYPE(bits
) ==
1699 MACH_PORT_TYPE_SEND_RECEIVE
);
1700 assert(IE_BITS_UREFS(bits
) > 0);
1701 assert(port
->ip_srights
> 0);
1703 ipc_hash_insert(space
, (ipc_object_t
) port
,
1707 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_RECEIVE
);
1708 assert(IE_BITS_UREFS(bits
) == 0);
1710 request
= ipc_right_request_cancel_macro(space
, port
,
1712 entry
->ie_object
= IO_NULL
;
1714 entry
->ie_bits
= bits
&~ MACH_PORT_TYPE_RECEIVE
;
1715 ipc_entry_modified(space
, name
, entry
);
1717 ipc_port_clear_receiver(port
, links
);
1718 port
->ip_receiver_name
= MACH_PORT_NULL
;
1719 port
->ip_destination
= IP_NULL
;
1722 *objectp
= (ipc_object_t
) port
;
1723 *sorightp
= request
;
1727 case MACH_MSG_TYPE_COPY_SEND
: {
1729 if (bits
& MACH_PORT_TYPE_DEAD_NAME
)
1732 /* allow for dead send-once rights */
1734 if ((bits
& MACH_PORT_TYPE_SEND_RIGHTS
) == 0)
1737 assert(IE_BITS_UREFS(bits
) > 0);
1739 port
= (ipc_port_t
) entry
->ie_object
;
1740 assert(port
!= IP_NULL
);
1742 if (ipc_right_check(space
, port
, name
, entry
)) {
1743 bits
= entry
->ie_bits
;
1747 /* port is locked and active */
1749 #if CONFIG_MACF_MACH
1750 tasklabel_lock(self
);
1751 rc
= mac_port_check_copy_send(&self
->maclabel
, &port
->ip_label
);
1752 tasklabel_unlock(self
);
1755 return KERN_NO_ACCESS
;
1759 if ((bits
& MACH_PORT_TYPE_SEND
) == 0) {
1760 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND_ONCE
);
1761 assert(port
->ip_sorights
> 0);
1767 assert(port
->ip_srights
> 0);
1773 *objectp
= (ipc_object_t
) port
;
1774 *sorightp
= IP_NULL
;
1778 case MACH_MSG_TYPE_MOVE_SEND
: {
1779 ipc_port_t request
= IP_NULL
;
1781 if (bits
& MACH_PORT_TYPE_DEAD_NAME
)
1784 /* allow for dead send-once rights */
1786 if ((bits
& MACH_PORT_TYPE_SEND_RIGHTS
) == 0)
1789 assert(IE_BITS_UREFS(bits
) > 0);
1791 port
= (ipc_port_t
) entry
->ie_object
;
1792 assert(port
!= IP_NULL
);
1794 if (ipc_right_check(space
, port
, name
, entry
)) {
1795 bits
= entry
->ie_bits
;
1799 /* port is locked and active */
1801 #if CONFIG_MACF_MACH
1802 tasklabel_lock (self
);
1803 rc
= mac_port_check_copy_send (&self
->maclabel
, &port
->ip_label
);
1804 tasklabel_unlock (self
);
1808 return KERN_NO_ACCESS
;
1812 if ((bits
& MACH_PORT_TYPE_SEND
) == 0) {
1813 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND_ONCE
);
1814 assert(port
->ip_sorights
> 0);
1820 assert(port
->ip_srights
> 0);
1822 if (IE_BITS_UREFS(bits
) == 1) {
1823 if (bits
& MACH_PORT_TYPE_RECEIVE
) {
1824 assert(port
->ip_receiver_name
== name
);
1825 assert(port
->ip_receiver
== space
);
1826 assert(IE_BITS_TYPE(bits
) ==
1827 MACH_PORT_TYPE_SEND_RECEIVE
);
1831 assert(IE_BITS_TYPE(bits
) ==
1832 MACH_PORT_TYPE_SEND
);
1834 request
= ipc_right_request_cancel_macro(space
, port
,
1836 ipc_hash_delete(space
, (ipc_object_t
) port
,
1838 entry
->ie_object
= IO_NULL
;
1840 entry
->ie_bits
= bits
&~
1841 (IE_BITS_UREFS_MASK
|MACH_PORT_TYPE_SEND
);
1845 entry
->ie_bits
= bits
-1; /* decrement urefs */
1847 ipc_entry_modified(space
, name
, entry
);
1850 *objectp
= (ipc_object_t
) port
;
1851 *sorightp
= request
;
1855 case MACH_MSG_TYPE_MOVE_SEND_ONCE
: {
1858 if (bits
& MACH_PORT_TYPE_DEAD_NAME
)
1861 /* allow for dead send rights */
1863 if ((bits
& MACH_PORT_TYPE_SEND_RIGHTS
) == 0)
1866 assert(IE_BITS_UREFS(bits
) > 0);
1868 port
= (ipc_port_t
) entry
->ie_object
;
1869 assert(port
!= IP_NULL
);
1871 if (ipc_right_check(space
, port
, name
, entry
)) {
1872 bits
= entry
->ie_bits
;
1875 /* port is locked and active */
1877 #if CONFIG_MACF_MACH
1878 tasklabel_lock (self
);
1879 rc
= mac_port_check_copy_send (&self
->maclabel
, &port
->ip_label
);
1880 tasklabel_unlock (self
);
1884 return KERN_NO_ACCESS
;
1888 if ((bits
& MACH_PORT_TYPE_SEND_ONCE
) == 0) {
1889 assert(bits
& MACH_PORT_TYPE_SEND
);
1890 assert(port
->ip_srights
> 0);
1896 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND_ONCE
);
1897 assert(IE_BITS_UREFS(bits
) == 1);
1898 assert(port
->ip_sorights
> 0);
1900 request
= ipc_right_request_cancel_macro(space
, port
, name
, entry
);
1903 entry
->ie_object
= IO_NULL
;
1904 entry
->ie_bits
= bits
&~
1905 (IE_BITS_UREFS_MASK
| MACH_PORT_TYPE_SEND_ONCE
);
1906 ipc_entry_modified(space
, name
, entry
);
1907 *objectp
= (ipc_object_t
) port
;
1908 *sorightp
= request
;
1914 return KERN_INVALID_RIGHT
;
1917 return KERN_SUCCESS
;
1920 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_DEAD_NAME
);
1921 assert(IE_BITS_UREFS(bits
) > 0);
1922 assert(entry
->ie_request
== IE_REQ_NONE
);
1923 assert(entry
->ie_object
== 0);
1929 *sorightp
= IP_NULL
;
1930 return KERN_SUCCESS
;
1933 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_DEAD_NAME
);
1934 assert(IE_BITS_UREFS(bits
) > 0);
1935 assert(entry
->ie_request
== IE_REQ_NONE
);
1936 assert(entry
->ie_object
== 0);
1941 if (IE_BITS_UREFS(bits
) == 1) {
1942 bits
&= ~MACH_PORT_TYPE_DEAD_NAME
;
1944 entry
->ie_bits
= bits
-1; /* decrement urefs */
1945 ipc_entry_modified(space
, name
, entry
);
1947 *sorightp
= IP_NULL
;
1948 return KERN_SUCCESS
;
1953 * Routine: ipc_right_copyin_undo
1955 * Undoes the effects of an ipc_right_copyin
1956 * of a send/send-once right that is dead.
1957 * (Object is either IO_DEAD or a dead port.)
1959 * The space is write-locked and active.
1963 ipc_right_copyin_undo(
1965 mach_port_name_t name
,
1967 mach_msg_type_name_t msgt_name
,
1968 ipc_object_t object
,
1971 ipc_entry_bits_t bits
;
1973 bits
= entry
->ie_bits
;
1975 assert(is_active(space
));
1977 assert((msgt_name
== MACH_MSG_TYPE_MOVE_SEND
) ||
1978 (msgt_name
== MACH_MSG_TYPE_COPY_SEND
) ||
1979 (msgt_name
== MACH_MSG_TYPE_MOVE_SEND_ONCE
));
1981 if (soright
!= IP_NULL
) {
1982 assert((msgt_name
== MACH_MSG_TYPE_MOVE_SEND
) ||
1983 (msgt_name
== MACH_MSG_TYPE_MOVE_SEND_ONCE
));
1984 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_NONE
);
1985 assert(object
!= IO_DEAD
);
1987 entry
->ie_bits
= ((bits
&~ IE_BITS_RIGHT_MASK
) |
1988 MACH_PORT_TYPE_DEAD_NAME
| 2);
1990 } else if (IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_NONE
) {
1991 assert((msgt_name
== MACH_MSG_TYPE_MOVE_SEND
) ||
1992 (msgt_name
== MACH_MSG_TYPE_MOVE_SEND_ONCE
));
1994 entry
->ie_bits
= ((bits
&~ IE_BITS_RIGHT_MASK
) |
1995 MACH_PORT_TYPE_DEAD_NAME
| 1);
1996 } else if (IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_DEAD_NAME
) {
1997 assert(object
== IO_DEAD
);
1998 assert(IE_BITS_UREFS(bits
) > 0);
2000 if (msgt_name
!= MACH_MSG_TYPE_COPY_SEND
) {
2001 assert(IE_BITS_UREFS(bits
) < MACH_PORT_UREFS_MAX
);
2002 entry
->ie_bits
= bits
+1; /* increment urefs */
2005 assert((msgt_name
== MACH_MSG_TYPE_MOVE_SEND
) ||
2006 (msgt_name
== MACH_MSG_TYPE_COPY_SEND
));
2007 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND
);
2008 assert(object
!= IO_DEAD
);
2009 assert(entry
->ie_object
== object
);
2010 assert(IE_BITS_UREFS(bits
) > 0);
2012 if (msgt_name
!= MACH_MSG_TYPE_COPY_SEND
) {
2013 assert(IE_BITS_UREFS(bits
) < MACH_PORT_UREFS_MAX
-1);
2014 entry
->ie_bits
= bits
+1; /* increment urefs */
2018 * May as well convert the entry to a dead name.
2019 * (Or if it is a compat entry, destroy it.)
2022 (void) ipc_right_check(space
, (ipc_port_t
) object
,
2024 /* object is dead so it is not locked */
2026 ipc_entry_modified(space
, name
, entry
);
2027 /* release the reference acquired by copyin */
2029 if (object
!= IO_DEAD
)
2034 * Routine: ipc_right_copyin_two
2036 * Like ipc_right_copyin with MACH_MSG_TYPE_MOVE_SEND
2037 * and deadok == FALSE, except that this moves two
2038 * send rights at once.
2040 * The space is write-locked and active.
2041 * The object is returned with two refs/send rights.
2043 * KERN_SUCCESS Acquired an object.
2044 * KERN_INVALID_RIGHT Name doesn't denote correct right.
2048 ipc_right_copyin_two(
2050 mach_port_name_t name
,
2052 ipc_object_t
*objectp
,
2053 ipc_port_t
*sorightp
,
2054 ipc_port_t
*releasep
)
2056 ipc_entry_bits_t bits
;
2057 mach_port_urefs_t urefs
;
2059 ipc_port_t request
= IP_NULL
;
2060 #if CONFIG_MACF_MACH
2061 task_t self
= current_task();
2065 *releasep
= IP_NULL
;
2067 assert(is_active(space
));
2069 bits
= entry
->ie_bits
;
2071 if ((bits
& MACH_PORT_TYPE_SEND
) == 0)
2074 urefs
= IE_BITS_UREFS(bits
);
2078 port
= (ipc_port_t
) entry
->ie_object
;
2079 assert(port
!= IP_NULL
);
2081 if (ipc_right_check(space
, port
, name
, entry
)) {
2085 /* port is locked and active */
2087 #if CONFIG_MACF_MACH
2088 tasklabel_lock(self
);
2089 rc
= mac_port_check_copy_send(&self
->maclabel
, &port
->ip_label
);
2090 tasklabel_unlock(self
);
2093 return KERN_NO_ACCESS
;
2097 assert(port
->ip_srights
> 0);
2100 if (bits
& MACH_PORT_TYPE_RECEIVE
) {
2101 assert(port
->ip_receiver_name
== name
);
2102 assert(port
->ip_receiver
== space
);
2103 assert(IE_BITS_TYPE(bits
) ==
2104 MACH_PORT_TYPE_SEND_RECEIVE
);
2110 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND
);
2112 request
= ipc_right_request_cancel_macro(space
, port
,
2117 ipc_hash_delete(space
, (ipc_object_t
) port
,
2119 entry
->ie_object
= IO_NULL
;
2121 entry
->ie_bits
= bits
&~ (IE_BITS_UREFS_MASK
|MACH_PORT_TYPE_SEND
);
2123 port
->ip_srights
+= 2;
2126 entry
->ie_bits
= bits
-2; /* decrement urefs */
2128 ipc_entry_modified(space
, name
, entry
);
2132 *objectp
= (ipc_object_t
) port
;
2133 *sorightp
= request
;
2134 return KERN_SUCCESS
;
2137 return KERN_INVALID_RIGHT
;
2141 * Routine: ipc_right_copyout
2143 * Copyout a capability to a space.
2144 * If successful, consumes a ref for the object.
2146 * Always succeeds when given a newly-allocated entry,
2147 * because user-reference overflow isn't a possibility.
2149 * If copying out the object would cause the user-reference
2150 * count in the entry to overflow, and overflow is TRUE,
2151 * then instead the user-reference count is left pegged
2152 * to its maximum value and the copyout succeeds anyway.
2154 * The space is write-locked and active.
2155 * The object is locked and active.
2156 * The object is unlocked; the space isn't.
2158 * KERN_SUCCESS Copied out capability.
2159 * KERN_UREFS_OVERFLOW User-refs would overflow;
2160 * guaranteed not to happen with a fresh entry
2161 * or if overflow=TRUE was specified.
2167 mach_port_name_t name
,
2169 mach_msg_type_name_t msgt_name
,
2171 ipc_object_t object
)
2173 ipc_entry_bits_t bits
;
2175 #if CONFIG_MACF_MACH
2179 bits
= entry
->ie_bits
;
2181 assert(IO_VALID(object
));
2182 assert(io_otype(object
) == IOT_PORT
);
2183 assert(io_active(object
));
2184 assert(entry
->ie_object
== object
);
2186 port
= (ipc_port_t
) object
;
2188 switch (msgt_name
) {
2189 case MACH_MSG_TYPE_PORT_SEND_ONCE
:
2191 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_NONE
);
2192 assert(port
->ip_sorights
> 0);
2194 #if CONFIG_MACF_MACH
2195 if (space
->is_task
) {
2196 tasklabel_lock(space
->is_task
);
2197 rc
= mac_port_check_hold_send_once(&space
->is_task
->maclabel
,
2199 tasklabel_unlock(space
->is_task
);
2203 return KERN_NO_ACCESS
;
2207 /* transfer send-once right and ref to entry */
2210 entry
->ie_bits
= bits
| (MACH_PORT_TYPE_SEND_ONCE
| 1);
2211 ipc_entry_modified(space
, name
, entry
);
2214 case MACH_MSG_TYPE_PORT_SEND
:
2215 assert(port
->ip_srights
> 0);
2217 #if CONFIG_MACF_MACH
2218 if (space
->is_task
) {
2219 tasklabel_lock(space
->is_task
);
2220 rc
= mac_port_check_hold_send(&space
->is_task
->maclabel
,
2222 tasklabel_unlock(space
->is_task
);
2226 return KERN_NO_ACCESS
;
2231 if (bits
& MACH_PORT_TYPE_SEND
) {
2232 mach_port_urefs_t urefs
= IE_BITS_UREFS(bits
);
2234 assert(port
->ip_srights
> 1);
2236 assert(urefs
< MACH_PORT_UREFS_MAX
);
2238 if (urefs
+1 == MACH_PORT_UREFS_MAX
) {
2240 /* leave urefs pegged to maximum */
2245 return KERN_SUCCESS
;
2249 return KERN_UREFS_OVERFLOW
;
2255 } else if (bits
& MACH_PORT_TYPE_RECEIVE
) {
2256 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_RECEIVE
);
2257 assert(IE_BITS_UREFS(bits
) == 0);
2259 /* transfer send right to entry */
2264 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_NONE
);
2265 assert(IE_BITS_UREFS(bits
) == 0);
2267 /* transfer send right and ref to entry */
2270 /* entry is locked holding ref, so can use port */
2272 ipc_hash_insert(space
, (ipc_object_t
) port
,
2276 entry
->ie_bits
= (bits
| MACH_PORT_TYPE_SEND
) + 1;
2277 ipc_entry_modified(space
, name
, entry
);
2280 case MACH_MSG_TYPE_PORT_RECEIVE
: {
2283 assert(port
->ip_mscount
== 0);
2284 assert(port
->ip_receiver_name
== MACH_PORT_NULL
);
2285 dest
= port
->ip_destination
;
2287 #if CONFIG_MACF_MACH
2288 if (space
->is_task
) {
2289 tasklabel_lock(space
->is_task
);
2290 rc
= mac_port_check_hold_receive(&space
->is_task
->maclabel
,
2292 tasklabel_unlock(space
->is_task
);
2296 return KERN_NO_ACCESS
;
2301 port
->ip_receiver_name
= name
;
2302 port
->ip_receiver
= space
;
2304 assert((bits
& MACH_PORT_TYPE_RECEIVE
) == 0);
2306 if (bits
& MACH_PORT_TYPE_SEND
) {
2307 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_SEND
);
2308 assert(IE_BITS_UREFS(bits
) > 0);
2309 assert(port
->ip_srights
> 0);
2314 /* entry is locked holding ref, so can use port */
2316 ipc_hash_delete(space
, (ipc_object_t
) port
,
2319 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_NONE
);
2320 assert(IE_BITS_UREFS(bits
) == 0);
2322 /* transfer ref to entry */
2325 entry
->ie_bits
= bits
| MACH_PORT_TYPE_RECEIVE
;
2326 ipc_entry_modified(space
, name
, entry
);
2328 if (dest
!= IP_NULL
)
2334 panic("ipc_right_copyout: strange rights");
2337 return KERN_SUCCESS
;
2341 * Routine: ipc_right_rename
2343 * Transfer an entry from one name to another.
2344 * The old entry is deallocated.
2346 * The space is write-locked and active.
2347 * The new entry is unused. Upon return,
2348 * the space is unlocked.
2350 * KERN_SUCCESS Moved entry to new name.
2356 mach_port_name_t oname
,
2358 mach_port_name_t nname
,
2361 ipc_port_request_index_t request
= oentry
->ie_request
;
2362 ipc_entry_bits_t bits
= oentry
->ie_bits
;
2363 ipc_object_t object
= oentry
->ie_object
;
2364 ipc_port_t release_port
= IP_NULL
;
2366 assert(is_active(space
));
2367 assert(oname
!= nname
);
2370 * If IE_BITS_COMPAT, we can't allow the entry to be renamed
2371 * if the port is dead. (This would foil ipc_port_destroy.)
2372 * Instead we should fail because oentry shouldn't exist.
2373 * Note IE_BITS_COMPAT implies ie_request != 0.
2376 if (request
!= IE_REQ_NONE
) {
2379 assert(bits
& MACH_PORT_TYPE_PORT_RIGHTS
);
2380 port
= (ipc_port_t
) object
;
2381 assert(port
!= IP_NULL
);
2383 if (ipc_right_check(space
, port
, oname
, oentry
)) {
2384 request
= IE_REQ_NONE
;
2386 bits
= oentry
->ie_bits
;
2387 release_port
= port
;
2388 assert(IE_BITS_TYPE(bits
) == MACH_PORT_TYPE_DEAD_NAME
);
2389 assert(oentry
->ie_request
== IE_REQ_NONE
);
2391 /* port is locked and active */
2393 ipc_port_request_rename(port
, request
, oname
, nname
);
2395 oentry
->ie_request
= IE_REQ_NONE
;
2399 /* initialize nentry before letting ipc_hash_insert see it */
2401 assert((nentry
->ie_bits
& IE_BITS_RIGHT_MASK
) == 0);
2402 nentry
->ie_bits
|= bits
& IE_BITS_RIGHT_MASK
;
2403 nentry
->ie_request
= request
;
2404 nentry
->ie_object
= object
;
2406 switch (IE_BITS_TYPE(bits
)) {
2407 case MACH_PORT_TYPE_SEND
: {
2410 port
= (ipc_port_t
) object
;
2411 assert(port
!= IP_NULL
);
2413 /* remember, there are no other share entries possible */
2414 /* or we can't do the rename. Therefore we do not need */
2415 /* to check the other subspaces */
2416 ipc_hash_delete(space
, (ipc_object_t
) port
, oname
, oentry
);
2417 ipc_hash_insert(space
, (ipc_object_t
) port
, nname
, nentry
);
2421 case MACH_PORT_TYPE_RECEIVE
:
2422 case MACH_PORT_TYPE_SEND_RECEIVE
: {
2425 port
= (ipc_port_t
) object
;
2426 assert(port
!= IP_NULL
);
2429 assert(ip_active(port
));
2430 assert(port
->ip_receiver_name
== oname
);
2431 assert(port
->ip_receiver
== space
);
2433 port
->ip_receiver_name
= nname
;
2438 case MACH_PORT_TYPE_PORT_SET
: {
2441 pset
= (ipc_pset_t
) object
;
2442 assert(pset
!= IPS_NULL
);
2445 assert(ips_active(pset
));
2446 assert(pset
->ips_local_name
== oname
);
2448 pset
->ips_local_name
= nname
;
2453 case MACH_PORT_TYPE_SEND_ONCE
:
2454 case MACH_PORT_TYPE_DEAD_NAME
:
2458 panic("ipc_right_rename: strange rights");
2461 assert(oentry
->ie_request
== IE_REQ_NONE
);
2462 oentry
->ie_object
= IO_NULL
;
2463 ipc_entry_dealloc(space
, oname
, oentry
);
2464 ipc_entry_modified(space
, nname
, nentry
);
2465 is_write_unlock(space
);
2467 if (release_port
!= IP_NULL
)
2468 ip_release(release_port
);
2470 return KERN_SUCCESS
;