1/*
2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*
29 * @OSF_FREE_COPYRIGHT@
30 */
31/*
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
34 * All Rights Reserved.
35 *
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.
41 *
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.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
49 *  School of Computer Science
50 *  Carnegie Mellon University
51 *  Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56/*
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,
60 * Version 2.0.
61 * Copyright (c) 2005-2006 SPARTA, Inc.
62 */
63/*
64 */
65/*
66 *	File:	ipc/ipc_right.c
67 *	Author:	Rich Draves
68 *	Date:	1989
69 *
70 *	Functions to manipulate IPC capabilities.
71 */
72
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>
79#include <ipc/port.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>
90
91/*
92 *	Routine:	ipc_right_lookup_write
93 *	Purpose:
94 *		Finds an entry in a space, given the name.
95 *	Conditions:
96 *		Nothing locked.  If successful, the space is write-locked.
97 *	Returns:
98 *		KERN_SUCCESS		Found an entry.
99 *		KERN_INVALID_TASK	The space is dead.
100 *		KERN_INVALID_NAME	Name doesn't exist in space.
101 */
102
103kern_return_t
104ipc_right_lookup_write(
105	ipc_space_t		space,
106	mach_port_name_t	name,
107	ipc_entry_t		*entryp)
108{
109	ipc_entry_t entry;
110
111	assert(space != IS_NULL);
112
113	is_write_lock(space);
114
115	if (!space->is_active) {
116		is_write_unlock(space);
117		return KERN_INVALID_TASK;
118	}
119
120	if ((entry = ipc_entry_lookup(space, name)) == IE_NULL) {
121		is_write_unlock(space);
122		return KERN_INVALID_NAME;
123	}
124
125	*entryp = entry;
126	return KERN_SUCCESS;
127}
128
129/*
130 *	Routine:	ipc_right_lookup_two_write
131 *	Purpose:
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.
135 *	Conditions:
136 *		Nothing locked.  If successful, the space is write-locked.
137 *	Returns:
138 *		KERN_INVALID_TASK	The space is dead.
139 *		KERN_INVALID_NAME	Name doesn't exist in space.
140 */
141
142kern_return_t
143ipc_right_lookup_two_write(
144	ipc_space_t		space,
145	mach_port_name_t	name1,
146	ipc_entry_t		*entryp1,
147	mach_port_name_t	name2,
148	ipc_entry_t		*entryp2)
149{
150	ipc_entry_t entry1;
151	ipc_entry_t entry2;
152
153	assert(space != IS_NULL);
154
155	is_write_lock(space);
156
157	if (!space->is_active) {
158		is_write_unlock(space);
159		return KERN_INVALID_TASK;
160	}
161
162	if ((entry1 = ipc_entry_lookup(space, name1)) == IE_NULL) {
163		is_write_unlock(space);
164		return KERN_INVALID_NAME;
165	}
166	if ((entry2 = ipc_entry_lookup(space, name2)) == IE_NULL) {
167		is_write_unlock(space);
168		return KERN_INVALID_NAME;
169	}
170	*entryp1 = entry1;
171	*entryp2 = entry2;
172	return KERN_SUCCESS;
173}
174
175/*
176 *	Routine:	ipc_right_reverse
177 *	Purpose:
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.
182 *	Conditions:
183 *		The space must be locked (read or write) and active.
184 *		Nothing else locked.
185 */
186
187boolean_t
188ipc_right_reverse(
189	ipc_space_t		space,
190	ipc_object_t		object,
191	mach_port_name_t	*namep,
192	ipc_entry_t		*entryp)
193{
194	ipc_port_t port;
195	mach_port_name_t name;
196	ipc_entry_t entry;
197
198	/* would switch on io_otype to handle multiple types of object */
199
200	assert(space->is_active);
201	assert(io_otype(object) == IOT_PORT);
202
203	port = (ipc_port_t) object;
204
205	ip_lock(port);
206	if (!ip_active(port)) {
207		ip_unlock(port);
208
209		return FALSE;
210	}
211
212	if (port->ip_receiver == space) {
213		name = port->ip_receiver_name;
214		assert(name != MACH_PORT_NULL);
215
216		entry = ipc_entry_lookup(space, name);
217
218		assert(entry != IE_NULL);
219		assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
220		assert(port == (ipc_port_t) entry->ie_object);
221
222		*namep = name;
223		*entryp = entry;
224		return TRUE;
225	}
226
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);
231
232		return TRUE;
233	}
234
235	ip_unlock(port);
236	return FALSE;
237}
238
239/*
240 *	Routine:	ipc_right_dnrequest
241 *	Purpose:
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.
245 *
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.
252 *	Conditions:
253 *		Nothing locked.  May allocate memory.
254 *		Only consumes/returns refs if successful.
255 *	Returns:
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.
265 */
266
267kern_return_t
268ipc_right_dnrequest(
269	ipc_space_t		space,
270	mach_port_name_t	name,
271	boolean_t		immediate,
272	ipc_port_t		notify,
273	ipc_port_t		*previousp)
274{
275	ipc_port_t previous;
276
277	for (;;) {
278		ipc_entry_t entry;
279		ipc_entry_bits_t bits;
280		kern_return_t kr;
281
282		kr = ipc_right_lookup_write(space, name, &entry);
283		if (kr != KERN_SUCCESS)
284			return kr;
285		/* space is write-locked and active */
286		bits = entry->ie_bits;
287		if (bits & MACH_PORT_TYPE_PORT_RIGHTS) {
288			ipc_port_t port;
289			ipc_port_request_index_t request;
290
291			port = (ipc_port_t) entry->ie_object;
292			assert(port != IP_NULL);
293
294			if (!ipc_right_check(space, port, name, entry)) {
295				/* port is locked and active */
296
297				if (notify == IP_NULL) {
298					previous = ipc_right_dncancel_macro(
299						   space, port, name, entry);
300
301					ip_unlock(port);
302					is_write_unlock(space);
303					break;
304				}
305
306				/*
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.
314				 */
315
316				previous = ipc_right_dncancel_macro(space,
317						port, name, entry);
318
319				kr = ipc_port_dnrequest(port, name, notify,
320							&request);
321				if (kr != KERN_SUCCESS) {
322					assert(previous == IP_NULL);
323					is_write_unlock(space);
324
325					kr = ipc_port_dngrow(port,
326							     ITS_SIZE_NONE);
327					/* port is unlocked */
328					if (kr != KERN_SUCCESS)
329						return kr;
330
331					continue;
332				}
333
334				assert(request != 0);
335				ip_unlock(port);
336
337				entry->ie_request = request;
338				is_write_unlock(space);
339				break;
340			} else {
341
342			  /*
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).
348			   */
349			  bits = entry->ie_bits;
350
351			}
352
353			assert(bits & MACH_PORT_TYPE_DEAD_NAME);
354		}
355
356		if ((bits & MACH_PORT_TYPE_DEAD_NAME) &&
357		    immediate && (notify != IP_NULL)) {
358			mach_port_urefs_t urefs = IE_BITS_UREFS(bits);
359
360			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
361			assert(urefs > 0);
362
363			if (MACH_PORT_UREFS_OVERFLOW(urefs, 1)) {
364				is_write_unlock(space);
365				return KERN_UREFS_OVERFLOW;
366			}
367
368			(entry->ie_bits)++; /* increment urefs */
369			is_write_unlock(space);
370
371			ipc_notify_dead_name(notify, name);
372			previous = IP_NULL;
373			break;
374		}
375
376		is_write_unlock(space);
377		if (bits & MACH_PORT_TYPE_PORT_OR_DEAD)
378			return KERN_INVALID_ARGUMENT;
379		else
380			return KERN_INVALID_RIGHT;
381	}
382
383	*previousp = previous;
384	return KERN_SUCCESS;
385}
386
387/*
388 *	Routine:	ipc_right_dncancel
389 *	Purpose:
390 *		Cancel a dead-name request and return the send-once right.
391 *		Afterwards, entry->ie_request == 0.
392 *	Conditions:
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.
395 */
396
397ipc_port_t
398ipc_right_dncancel(
399	__unused ipc_space_t		space,
400	ipc_port_t			port,
401	mach_port_name_t		name,
402	ipc_entry_t			entry)
403{
404	ipc_port_t dnrequest;
405
406	assert(ip_active(port));
407	assert(port == (ipc_port_t) entry->ie_object);
408
409	dnrequest = ipc_port_dncancel(port, name, entry->ie_request);
410	entry->ie_request = 0;
411
412	return dnrequest;
413}
414
415/*
416 *	Routine:	ipc_right_inuse
417 *	Purpose:
418 *		Check if an entry is being used.
419 *		Returns TRUE if it is.
420 *	Conditions:
421 *		The space is write-locked and active.
422 *		It is unlocked if the entry is inuse.
423 */
424
425boolean_t
426ipc_right_inuse(
427	ipc_space_t			space,
428	__unused mach_port_name_t	name,
429	ipc_entry_t			entry)
430{
431	if (IE_BITS_TYPE(entry->ie_bits) != MACH_PORT_TYPE_NONE) {
432		is_write_unlock(space);
433		return TRUE;
434	}
435	return FALSE;
436}
437
438/*
439 *	Routine:	ipc_right_check
440 *	Purpose:
441 *		Check if the port has died.  If it has,
442 *		clean up the entry and return TRUE.
443 *	Conditions:
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.
448 */
449
450boolean_t
451ipc_right_check(
452	ipc_space_t		space,
453	ipc_port_t		port,
454	mach_port_name_t	name,
455	ipc_entry_t		entry)
456{
457	ipc_entry_bits_t bits;
458
459	assert(space->is_active);
460	assert(port == (ipc_port_t) entry->ie_object);
461
462	ip_lock(port);
463	if (ip_active(port))
464		return FALSE;
465	ip_unlock(port);
466
467	/* this was either a pure send right or a send-once right */
468
469	bits = entry->ie_bits;
470	assert((bits & MACH_PORT_TYPE_RECEIVE) == 0);
471	assert(IE_BITS_UREFS(bits) > 0);
472
473	if (bits & MACH_PORT_TYPE_SEND) {
474                assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
475        } else {
476                assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
477                assert(IE_BITS_UREFS(bits) == 1);
478        }
479
480
481	ipc_port_release(port);
482
483	/* convert entry to dead name */
484
485	if ((bits & MACH_PORT_TYPE_SEND) && !(bits & MACH_PORT_TYPE_RECEIVE))
486		ipc_hash_delete(space, (ipc_object_t)port, name, entry);
487
488	bits = (bits &~ IE_BITS_TYPE_MASK) | MACH_PORT_TYPE_DEAD_NAME;
489
490	/*
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.
495	 *
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)
505	 */
506	if (entry->ie_request != 0) {
507		assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX);
508		entry->ie_request = 0;
509		bits++;
510	}
511	entry->ie_bits = bits;
512	entry->ie_object = IO_NULL;
513	return TRUE;
514}
515
516/*
517 *	Routine:	ipc_right_clean
518 *	Purpose:
519 *		Cleans up an entry in a dead space.
520 *		The entry isn't deallocated or removed
521 *		from reverse hash tables.
522 *	Conditions:
523 *		The space is dead and unlocked.
524 */
525
526void
527ipc_right_clean(
528	ipc_space_t		space,
529	mach_port_name_t	name,
530	ipc_entry_t		entry)
531{
532	ipc_entry_bits_t bits;
533	mach_port_type_t type;
534
535	bits = entry->ie_bits;
536	type = IE_BITS_TYPE(bits);
537
538	assert(!space->is_active);
539
540	/*
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.
547	 */
548
549	switch (type) {
550	    case MACH_PORT_TYPE_DEAD_NAME:
551		assert(entry->ie_request == 0);
552		assert(entry->ie_object == IO_NULL);
553		break;
554
555	    case MACH_PORT_TYPE_PORT_SET: {
556		ipc_pset_t pset = (ipc_pset_t) entry->ie_object;
557
558		assert(entry->ie_request == 0);
559		assert(pset != IPS_NULL);
560
561		ips_lock(pset);
562		assert(ips_active(pset));
563
564		ipc_pset_destroy(pset); /* consumes ref, unlocks */
565		break;
566	    }
567
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;
576
577		assert(port != IP_NULL);
578		ip_lock(port);
579
580		if (!ip_active(port)) {
581			ip_release(port);
582			ip_check_unlock(port);
583			break;
584		}
585
586		dnrequest = ipc_right_dncancel_macro(space, port,
587					name, entry);
588
589		if (type & MACH_PORT_TYPE_SEND) {
590			assert(port->ip_srights > 0);
591			if (--port->ip_srights == 0
592			    ) {
593				nsrequest = port->ip_nsrequest;
594				if (nsrequest != IP_NULL) {
595					port->ip_nsrequest = IP_NULL;
596					mscount = port->ip_mscount;
597				}
598			}
599		}
600
601		if (type & MACH_PORT_TYPE_RECEIVE) {
602			assert(port->ip_receiver_name == name);
603			assert(port->ip_receiver == space);
604
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);
609			ip_unlock(port);
610
611			ipc_notify_send_once(port); /* consumes our ref */
612		} else {
613			assert(port->ip_receiver != space);
614
615			ip_release(port);
616			ip_unlock(port); /* port is active */
617		}
618
619		if (nsrequest != IP_NULL)
620			ipc_notify_no_senders(nsrequest, mscount);
621
622		if (dnrequest != IP_NULL)
623			ipc_notify_port_deleted(dnrequest, name);
624		break;
625	    }
626
627	    default:
628		panic("ipc_right_clean: strange type - 0x%x", type);
629	}
630}
631
632/*
633 *	Routine:	ipc_right_destroy
634 *	Purpose:
635 *		Destroys an entry in a space.
636 *	Conditions:
637 *		The space is write-locked.
638 *		The space must be active.
639 *	Returns:
640 *		KERN_SUCCESS		The entry was destroyed.
641 */
642
643kern_return_t
644ipc_right_destroy(
645	ipc_space_t		space,
646	mach_port_name_t	name,
647	ipc_entry_t		entry)
648{
649	ipc_entry_bits_t bits;
650	mach_port_type_t type;
651
652	bits = entry->ie_bits;
653	entry->ie_bits &= ~IE_BITS_TYPE_MASK;
654	type = IE_BITS_TYPE(bits);
655
656	assert(space->is_active);
657
658	switch (type) {
659	    case MACH_PORT_TYPE_DEAD_NAME:
660		assert(entry->ie_request == 0);
661		assert(entry->ie_object == IO_NULL);
662
663		ipc_entry_dealloc(space, name, entry);
664		break;
665
666	    case MACH_PORT_TYPE_PORT_SET: {
667		ipc_pset_t pset = (ipc_pset_t) entry->ie_object;
668
669		assert(entry->ie_request == 0);
670		assert(pset != IPS_NULL);
671
672		entry->ie_object = IO_NULL;
673		ipc_entry_dealloc(space, name, entry);
674
675		ips_lock(pset);
676		assert(ips_active(pset));
677
678		ipc_pset_destroy(pset); /* consumes ref, unlocks */
679		break;
680	    }
681
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;
690
691		assert(port != IP_NULL);
692
693		if (type == MACH_PORT_TYPE_SEND)
694			ipc_hash_delete(space, (ipc_object_t) port,
695					name, entry);
696
697		ip_lock(port);
698
699		if (!ip_active(port)) {
700			assert((type & MACH_PORT_TYPE_RECEIVE) == 0);
701			ip_release(port);
702			ip_check_unlock(port);
703
704			entry->ie_request = 0;
705			entry->ie_object = IO_NULL;
706			ipc_entry_dealloc(space, name, entry);
707
708			break;
709		}
710
711		dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
712
713		entry->ie_object = IO_NULL;
714		ipc_entry_dealloc(space, name, entry);
715
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;
723				}
724			}
725		}
726
727		if (type & MACH_PORT_TYPE_RECEIVE) {
728			assert(ip_active(port));
729			assert(port->ip_receiver == space);
730
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);
735			ip_unlock(port);
736
737			ipc_notify_send_once(port); /* consumes our ref */
738		} else {
739			assert(port->ip_receiver != space);
740
741			ip_release(port);
742			ip_unlock(port);
743		}
744
745		if (nsrequest != IP_NULL)
746			ipc_notify_no_senders(nsrequest, mscount);
747
748		if (dnrequest != IP_NULL)
749			ipc_notify_port_deleted(dnrequest, name);
750		break;
751	    }
752
753	    default:
754		panic("ipc_right_destroy: strange type");
755	}
756
757	return KERN_SUCCESS;
758}
759
760/*
761 *	Routine:	ipc_right_dealloc
762 *	Purpose:
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.
766 *	Conditions:
767 *		The space is write-locked, and is unlocked upon return.
768 *		The space must be active.
769 *	Returns:
770 *		KERN_SUCCESS		A user ref was released.
771 *		KERN_INVALID_RIGHT	Entry has wrong type.
772 */
773
774kern_return_t
775ipc_right_dealloc(
776	ipc_space_t		space,
777	mach_port_name_t	name,
778	ipc_entry_t		entry)
779{
780
781	ipc_entry_bits_t bits;
782	mach_port_type_t type;
783
784	bits = entry->ie_bits;
785	type = IE_BITS_TYPE(bits);
786
787
788	assert(space->is_active);
789
790	switch (type) {
791	    case MACH_PORT_TYPE_DEAD_NAME: {
792	    dead_name:
793
794		assert(IE_BITS_UREFS(bits) > 0);
795		assert(entry->ie_request == 0);
796		assert(entry->ie_object == IO_NULL);
797
798		if (IE_BITS_UREFS(bits) == 1) {
799			ipc_entry_dealloc(space, name, entry);
800		}
801		else
802			entry->ie_bits = bits-1; /* decrement urefs */
803
804		is_write_unlock(space);
805		break;
806	    }
807
808	    case MACH_PORT_TYPE_SEND_ONCE: {
809		ipc_port_t port, dnrequest;
810
811		assert(IE_BITS_UREFS(bits) == 1);
812
813		port = (ipc_port_t) entry->ie_object;
814		assert(port != IP_NULL);
815
816		if (ipc_right_check(space, port, name, entry)) {
817
818			bits = entry->ie_bits;
819			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
820			goto dead_name;
821		}
822		/* port is locked and active */
823
824		assert(port->ip_sorights > 0);
825
826		dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
827		ip_unlock(port);
828
829		entry->ie_object = IO_NULL;
830		ipc_entry_dealloc(space, name, entry);
831
832		is_write_unlock(space);
833
834		ipc_notify_send_once(port);
835
836		if (dnrequest != IP_NULL)
837			ipc_notify_port_deleted(dnrequest, name);
838		break;
839	    }
840
841	    case MACH_PORT_TYPE_SEND: {
842		ipc_port_t port;
843		ipc_port_t dnrequest = IP_NULL;
844		ipc_port_t nsrequest = IP_NULL;
845		mach_port_mscount_t mscount =  0;
846
847
848		assert(IE_BITS_UREFS(bits) > 0);
849
850		port = (ipc_port_t) entry->ie_object;
851		assert(port != IP_NULL);
852
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);
856			goto dead_name;
857		}
858		/* port is locked and active */
859
860		assert(port->ip_srights > 0);
861
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;
868				}
869			}
870
871			dnrequest = ipc_right_dncancel_macro(space, port,
872							     name, entry);
873			ipc_hash_delete(space, (ipc_object_t) port,
874					name, entry);
875
876			ip_release(port);
877			entry->ie_object = IO_NULL;
878			ipc_entry_dealloc(space, name, entry);
879
880		} else
881			entry->ie_bits = bits-1; /* decrement urefs */
882
883		/* even if dropped a ref, port is active */
884		ip_unlock(port);
885		is_write_unlock(space);
886
887		if (nsrequest != IP_NULL)
888			ipc_notify_no_senders(nsrequest, mscount);
889
890		if (dnrequest != IP_NULL)
891			ipc_notify_port_deleted(dnrequest, name);
892		break;
893	    }
894
895	    case MACH_PORT_TYPE_SEND_RECEIVE: {
896		ipc_port_t port;
897		ipc_port_t nsrequest = IP_NULL;
898		mach_port_mscount_t mscount = 0;
899
900		assert(IE_BITS_UREFS(bits) > 0);
901
902		port = (ipc_port_t) entry->ie_object;
903		assert(port != IP_NULL);
904
905		ip_lock(port);
906		assert(ip_active(port));
907		assert(port->ip_receiver_name == name);
908		assert(port->ip_receiver == space);
909		assert(port->ip_srights > 0);
910
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;
917				}
918			}
919
920			entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK |
921						  MACH_PORT_TYPE_SEND);
922		} else
923			entry->ie_bits = bits-1; /* decrement urefs */
924
925		ip_unlock(port);
926		is_write_unlock(space);
927
928		if (nsrequest != IP_NULL)
929			ipc_notify_no_senders(nsrequest, mscount);
930		break;
931	    }
932
933	    default:
934		is_write_unlock(space);
935		return KERN_INVALID_RIGHT;
936	}
937
938	return KERN_SUCCESS;
939}
940
941/*
942 *	Routine:	ipc_right_delta
943 *	Purpose:
944 *		Modifies the user-reference count for a right.
945 *		May deallocate the right, if the count goes to zero.
946 *	Conditions:
947 *		The space is write-locked, and is unlocked upon return.
948 *		The space must be active.
949 *	Returns:
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.
954 */
955
956kern_return_t
957ipc_right_delta(
958	ipc_space_t		space,
959	mach_port_name_t	name,
960	ipc_entry_t		entry,
961	mach_port_right_t	right,
962	mach_port_delta_t	delta)
963{
964	ipc_entry_bits_t bits;
965
966	bits = entry->ie_bits;
967
968
969/*
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.
975 */
976
977	assert(space->is_active);
978	assert(right < MACH_PORT_RIGHT_NUMBER);
979
980	/* Rights-specific restrictions and operations. */
981
982	switch (right) {
983	    case MACH_PORT_RIGHT_PORT_SET: {
984		ipc_pset_t pset;
985
986		if ((bits & MACH_PORT_TYPE_PORT_SET) == 0)
987			goto invalid_right;
988
989		assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_PORT_SET);
990		assert(IE_BITS_UREFS(bits) == 0);
991		assert(entry->ie_request == 0);
992
993		if (delta == 0)
994			goto success;
995
996		if (delta != -1)
997			goto invalid_value;
998
999		pset = (ipc_pset_t) entry->ie_object;
1000		assert(pset != IPS_NULL);
1001
1002
1003
1004		entry->ie_object = IO_NULL;
1005		ipc_entry_dealloc(space, name, entry);
1006
1007
1008		ips_lock(pset);
1009		assert(ips_active(pset));
1010		is_write_unlock(space);
1011
1012		ipc_pset_destroy(pset); /* consumes ref, unlocks */
1013		break;
1014	    }
1015
1016	    case MACH_PORT_RIGHT_RECEIVE: {
1017		ipc_port_t port;
1018		ipc_port_t dnrequest = IP_NULL;
1019
1020		if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1021			goto invalid_right;
1022
1023		if (delta == 0)
1024			goto success;
1025
1026		if (delta != -1)
1027			goto invalid_value;
1028
1029		port = (ipc_port_t) entry->ie_object;
1030		assert(port != IP_NULL);
1031
1032		/*
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.
1036		 */
1037
1038		ip_lock(port);
1039		assert(ip_active(port));
1040		assert(port->ip_receiver_name == name);
1041		assert(port->ip_receiver == space);
1042
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);
1049
1050			/*
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".
1056			 */
1057			bits &= ~IE_BITS_TYPE_MASK;
1058			bits |= MACH_PORT_TYPE_DEAD_NAME;
1059			if (entry->ie_request) {
1060				entry->ie_request = 0;
1061				bits++;
1062			}
1063			entry->ie_bits = bits;
1064			entry->ie_object = IO_NULL;
1065		} else {
1066			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
1067			assert(IE_BITS_UREFS(bits) == 0);
1068
1069			dnrequest = ipc_right_dncancel_macro(space, port,
1070							     name, entry);
1071			entry->ie_object = IO_NULL;
1072			ipc_entry_dealloc(space, name, entry);
1073		}
1074		is_write_unlock(space);
1075
1076		ipc_port_clear_receiver(port);
1077		ipc_port_destroy(port);	/* consumes ref, unlocks */
1078
1079		if (dnrequest != IP_NULL)
1080			ipc_notify_port_deleted(dnrequest, name);
1081		break;
1082	    }
1083
1084	    case MACH_PORT_RIGHT_SEND_ONCE: {
1085		ipc_port_t port, dnrequest;
1086
1087		if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0)
1088			goto invalid_right;
1089
1090		assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1091		assert(IE_BITS_UREFS(bits) == 1);
1092
1093		port = (ipc_port_t) entry->ie_object;
1094		assert(port != IP_NULL);
1095
1096		if (ipc_right_check(space, port, name, entry)) {
1097			assert(!(entry->ie_bits & MACH_PORT_TYPE_SEND_ONCE));
1098			goto invalid_right;
1099		}
1100		/* port is locked and active */
1101
1102		assert(port->ip_sorights > 0);
1103
1104		if ((delta > 0) || (delta < -1)) {
1105			ip_unlock(port);
1106			goto invalid_value;
1107		}
1108
1109		if (delta == 0) {
1110			ip_unlock(port);
1111			goto success;
1112		}
1113
1114		dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
1115		ip_unlock(port);
1116
1117		entry->ie_object = IO_NULL;
1118		ipc_entry_dealloc(space, name, entry);
1119
1120		is_write_unlock(space);
1121
1122		ipc_notify_send_once(port);
1123
1124		if (dnrequest != IP_NULL)
1125			ipc_notify_port_deleted(dnrequest, name);
1126		break;
1127	    }
1128
1129	    case MACH_PORT_RIGHT_DEAD_NAME: {
1130		mach_port_urefs_t urefs;
1131
1132		if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
1133			ipc_port_t port;
1134
1135			port = (ipc_port_t) entry->ie_object;
1136			assert(port != IP_NULL);
1137
1138			if (!ipc_right_check(space, port, name, entry)) {
1139				/* port is locked and active */
1140				ip_unlock(port);
1141				goto invalid_right;
1142			}
1143			bits = entry->ie_bits;
1144		} else if ((bits & MACH_PORT_TYPE_DEAD_NAME) == 0)
1145			goto invalid_right;
1146
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);
1151
1152		urefs = IE_BITS_UREFS(bits);
1153		if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta))
1154			goto invalid_value;
1155		if (MACH_PORT_UREFS_OVERFLOW(urefs, delta))
1156			goto urefs_overflow;
1157
1158		if ((urefs + delta) == 0) {
1159			ipc_entry_dealloc(space, name, entry);
1160		}
1161		else
1162			entry->ie_bits = bits + delta;
1163
1164		is_write_unlock(space);
1165
1166		break;
1167	    }
1168
1169	    case MACH_PORT_RIGHT_SEND: {
1170		mach_port_urefs_t urefs;
1171		ipc_port_t port;
1172		ipc_port_t dnrequest = IP_NULL;
1173		ipc_port_t nsrequest = IP_NULL;
1174		mach_port_mscount_t mscount = 0;
1175
1176		if ((bits & MACH_PORT_TYPE_SEND) == 0)
1177			goto invalid_right;
1178
1179		/* maximum urefs for send is MACH_PORT_UREFS_MAX-1 */
1180
1181		port = (ipc_port_t) entry->ie_object;
1182		assert(port != IP_NULL);
1183
1184		if (ipc_right_check(space, port, name, entry)) {
1185			assert((entry->ie_bits & MACH_PORT_TYPE_SEND) == 0);
1186			goto invalid_right;
1187		}
1188		/* port is locked and active */
1189
1190		assert(port->ip_srights > 0);
1191
1192		urefs = IE_BITS_UREFS(bits);
1193		if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta)) {
1194			ip_unlock(port);
1195			goto invalid_value;
1196		}
1197		if (MACH_PORT_UREFS_OVERFLOW(urefs+1, delta)) {
1198			ip_unlock(port);
1199			goto urefs_overflow;
1200		}
1201
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;
1208				}
1209			}
1210
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);
1216
1217				entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK|
1218						       MACH_PORT_TYPE_SEND);
1219			} else {
1220				assert(IE_BITS_TYPE(bits) ==
1221						MACH_PORT_TYPE_SEND);
1222
1223				dnrequest = ipc_right_dncancel_macro(space, port,
1224								     name, entry);
1225				ipc_hash_delete(space, (ipc_object_t) port,
1226						name, entry);
1227
1228				ip_release(port);
1229
1230				entry->ie_object = IO_NULL;
1231				ipc_entry_dealloc(space, name, entry);
1232			}
1233		} else
1234			entry->ie_bits = bits + delta;
1235
1236		/* even if dropped a ref, port is active */
1237		ip_unlock(port);
1238		is_write_unlock(space);
1239
1240		if (nsrequest != IP_NULL)
1241			ipc_notify_no_senders(nsrequest, mscount);
1242
1243		if (dnrequest != IP_NULL)
1244			ipc_notify_port_deleted(dnrequest, name);
1245		break;
1246	    }
1247
1248	    default:
1249		panic("ipc_right_delta: strange right");
1250	}
1251
1252	return KERN_SUCCESS;
1253
1254    success:
1255	is_write_unlock(space);
1256	return KERN_SUCCESS;
1257
1258    invalid_right:
1259	is_write_unlock(space);
1260	return KERN_INVALID_RIGHT;
1261
1262    invalid_value:
1263	is_write_unlock(space);
1264	return KERN_INVALID_VALUE;
1265
1266    urefs_overflow:
1267	is_write_unlock(space);
1268	return KERN_UREFS_OVERFLOW;
1269}
1270
1271/*
1272 *	Routine:	ipc_right_info
1273 *	Purpose:
1274 *		Retrieves information about the right.
1275 *	Conditions:
1276 *		The space is write-locked, and is unlocked upon return
1277 *		if the call is unsuccessful.  The space must be active.
1278 *	Returns:
1279 *		KERN_SUCCESS		Retrieved info; space still locked.
1280 */
1281
1282kern_return_t
1283ipc_right_info(
1284	ipc_space_t		space,
1285	mach_port_name_t	name,
1286	ipc_entry_t		entry,
1287	mach_port_type_t	*typep,
1288	mach_port_urefs_t	*urefsp)
1289{
1290	ipc_entry_bits_t bits;
1291	mach_port_type_t type;
1292	ipc_port_request_index_t request;
1293
1294	bits = entry->ie_bits;
1295
1296	if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
1297		ipc_port_t port = (ipc_port_t) entry->ie_object;
1298
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);
1302		} else
1303			ip_unlock(port);
1304	}
1305
1306	type = IE_BITS_TYPE(bits);
1307	request = entry->ie_request;
1308
1309	if (request != 0)
1310		type |= MACH_PORT_TYPE_DNREQUEST;
1311
1312	*typep = type;
1313	*urefsp = IE_BITS_UREFS(bits);
1314	return KERN_SUCCESS;
1315}
1316
1317/*
1318 *	Routine:	ipc_right_copyin_check
1319 *	Purpose:
1320 *		Check if a subsequent ipc_right_copyin would succeed.
1321 *	Conditions:
1322 *		The space is locked (read or write) and active.
1323 */
1324
1325boolean_t
1326ipc_right_copyin_check(
1327	__assert_only ipc_space_t	space,
1328	__unused mach_port_name_t	name,
1329	ipc_entry_t			entry,
1330	mach_msg_type_name_t		msgt_name)
1331{
1332	ipc_entry_bits_t bits;
1333	ipc_port_t port;
1334#if CONFIG_MACF_MACH
1335	task_t self = current_task();
1336	int rc = 0;
1337#endif
1338
1339	bits= entry->ie_bits;
1340	assert(space->is_active);
1341
1342	switch (msgt_name) {
1343	    case MACH_MSG_TYPE_MAKE_SEND:
1344		if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1345			return FALSE;
1346
1347#if CONFIG_MACF_MACH
1348		port = (ipc_port_t) entry->ie_object;
1349		ip_lock(port);
1350		tasklabel_lock(self);
1351		rc = mac_port_check_make_send(&self->maclabel, &port->ip_label);                tasklabel_unlock(self);
1352		ip_unlock(port);
1353		if (rc)
1354			return FALSE;
1355#endif
1356		break;
1357
1358	    case MACH_MSG_TYPE_MAKE_SEND_ONCE:
1359		if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1360			return FALSE;
1361
1362#if CONFIG_MACF_MACH
1363		port = (ipc_port_t) entry->ie_object;
1364		ip_lock(port);
1365		tasklabel_lock(self);
1366		rc = mac_port_check_make_send_once(&self->maclabel, &port->ip_label);
1367		tasklabel_unlock(self);
1368		ip_unlock(port);
1369		if (rc)
1370			return FALSE;
1371#endif
1372		break;
1373
1374	    case MACH_MSG_TYPE_MOVE_RECEIVE:
1375		if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1376			return FALSE;
1377
1378#if CONFIG_MACF_MACH
1379		port = (ipc_port_t) entry->ie_object;
1380		ip_lock(port);
1381		tasklabel_lock(self);
1382		rc = mac_port_check_move_receive(&self->maclabel, &port->ip_label);
1383		tasklabel_unlock(self);
1384		ip_unlock(port);
1385		if (rc)
1386                        return FALSE;
1387#endif
1388		break;
1389
1390	    case MACH_MSG_TYPE_COPY_SEND:
1391	    case MACH_MSG_TYPE_MOVE_SEND:
1392	    case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
1393		boolean_t active;
1394
1395		if (bits & MACH_PORT_TYPE_DEAD_NAME)
1396			break;
1397
1398		if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
1399			return FALSE;
1400
1401		port = (ipc_port_t) entry->ie_object;
1402		assert(port != IP_NULL);
1403
1404		ip_lock(port);
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,
1411			    &port->ip_label);
1412			break;
1413		case MACH_MSG_TYPE_MOVE_SEND:
1414			rc = mac_port_check_move_send(&self->maclabel,
1415			    &port->ip_label);
1416			break;
1417		case MACH_MSG_TYPE_MOVE_SEND_ONCE:
1418			rc = mac_port_check_move_send_once(&self->maclabel,
1419			    &port->ip_label);
1420			break;
1421		default:
1422			panic("ipc_right_copyin_check: strange rights");
1423		}
1424		tasklabel_unlock(self);
1425		if (rc) {
1426			ip_unlock(port);
1427			return FALSE;
1428		}
1429#endif
1430		ip_unlock(port);
1431
1432		if (!active) {
1433			break;
1434		}
1435
1436		if (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE) {
1437			if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0)
1438				return FALSE;
1439		} else {
1440			if ((bits & MACH_PORT_TYPE_SEND) == 0)
1441				return FALSE;
1442		}
1443
1444		break;
1445	    }
1446
1447	    default:
1448		panic("ipc_right_copyin_check: strange rights");
1449	}
1450
1451	return TRUE;
1452}
1453
1454/*
1455 *	Routine:	ipc_right_copyin
1456 *	Purpose:
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.
1462 *
1463 *		If deadok is not TRUE, the copyin operation
1464 *		will fail instead of producing IO_DEAD.
1465 *
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.
1470 *	Conditions:
1471 *		The space is write-locked and active.
1472 *	Returns:
1473 *		KERN_SUCCESS		Acquired an object, possibly IO_DEAD.
1474 *		KERN_INVALID_RIGHT	Name doesn't denote correct right.
1475 */
1476
1477kern_return_t
1478ipc_right_copyin(
1479	ipc_space_t		space,
1480	mach_port_name_t	name,
1481	ipc_entry_t		entry,
1482	mach_msg_type_name_t	msgt_name,
1483	boolean_t		deadok,
1484	ipc_object_t		*objectp,
1485	ipc_port_t		*sorightp)
1486{
1487	ipc_entry_bits_t bits;
1488#if CONFIG_MACF_MACH
1489	task_t self = current_task();
1490	int    rc;
1491#endif
1492
1493	bits = entry->ie_bits;
1494
1495	assert(space->is_active);
1496
1497	switch (msgt_name) {
1498	    case MACH_MSG_TYPE_MAKE_SEND: {
1499		ipc_port_t port;
1500
1501		if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1502			goto invalid_right;
1503
1504		port = (ipc_port_t) entry->ie_object;
1505		assert(port != IP_NULL);
1506
1507		ip_lock(port);
1508		assert(ip_active(port));
1509		assert(port->ip_receiver_name == name);
1510		assert(port->ip_receiver == space);
1511
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);
1516		if (rc) {
1517			ip_unlock(port);
1518			return KERN_NO_ACCESS;
1519		}
1520#endif
1521
1522		port->ip_mscount++;
1523		port->ip_srights++;
1524		ip_reference(port);
1525		ip_unlock(port);
1526
1527		*objectp = (ipc_object_t) port;
1528		*sorightp = IP_NULL;
1529		break;
1530	    }
1531
1532	    case MACH_MSG_TYPE_MAKE_SEND_ONCE: {
1533		ipc_port_t port;
1534
1535		if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1536			goto invalid_right;
1537
1538		port = (ipc_port_t) entry->ie_object;
1539		assert(port != IP_NULL);
1540
1541		ip_lock(port);
1542		assert(ip_active(port));
1543		assert(port->ip_receiver_name == name);
1544		assert(port->ip_receiver == space);
1545
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);
1550		if (rc) {
1551			ip_unlock(port);
1552			return KERN_NO_ACCESS;
1553		}
1554#endif
1555
1556		port->ip_sorights++;
1557		ip_reference(port);
1558		ip_unlock(port);
1559
1560		*objectp = (ipc_object_t) port;
1561		*sorightp = IP_NULL;
1562		break;
1563	    }
1564
1565	    case MACH_MSG_TYPE_MOVE_RECEIVE: {
1566		ipc_port_t port;
1567		ipc_port_t dnrequest = IP_NULL;
1568
1569		if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1570			goto invalid_right;
1571
1572		port = (ipc_port_t) entry->ie_object;
1573		assert(port != IP_NULL);
1574
1575		ip_lock(port);
1576		assert(ip_active(port));
1577		assert(port->ip_receiver_name == name);
1578		assert(port->ip_receiver == space);
1579
1580#if CONFIG_MACF_MACH
1581		tasklabel_lock(self);
1582		rc = mac_port_check_move_receive(&self->maclabel,
1583						 &port->ip_label);
1584		tasklabel_unlock(self);
1585		if (rc) {
1586			ip_unlock(port);
1587			return KERN_NO_ACCESS;
1588		}
1589#endif
1590
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);
1596
1597			ipc_hash_insert(space, (ipc_object_t) port,
1598					name, entry);
1599			ip_reference(port);
1600		} else {
1601			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
1602			assert(IE_BITS_UREFS(bits) == 0);
1603
1604			dnrequest = ipc_right_dncancel_macro(space, port,
1605							     name, entry);
1606			entry->ie_object = IO_NULL;
1607		}
1608		entry->ie_bits = bits &~ MACH_PORT_TYPE_RECEIVE;
1609
1610		ipc_port_clear_receiver(port);
1611
1612		port->ip_receiver_name = MACH_PORT_NULL;
1613		port->ip_destination = IP_NULL;
1614		ip_unlock(port);
1615
1616		*objectp = (ipc_object_t) port;
1617		*sorightp = dnrequest;
1618		break;
1619	    }
1620
1621	    case MACH_MSG_TYPE_COPY_SEND: {
1622		ipc_port_t port;
1623
1624		if (bits & MACH_PORT_TYPE_DEAD_NAME)
1625			goto copy_dead;
1626
1627		/* allow for dead send-once rights */
1628
1629		if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
1630			goto invalid_right;
1631
1632		assert(IE_BITS_UREFS(bits) > 0);
1633
1634		port = (ipc_port_t) entry->ie_object;
1635		assert(port != IP_NULL);
1636
1637		if (ipc_right_check(space, port, name, entry)) {
1638			bits = entry->ie_bits;
1639			goto copy_dead;
1640		}
1641		/* port is locked and active */
1642
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);
1647		if (rc) {
1648			ip_unlock(port);
1649			return KERN_NO_ACCESS;
1650		}
1651#endif
1652
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);
1656
1657			ip_unlock(port);
1658			goto invalid_right;
1659		}
1660
1661		assert(port->ip_srights > 0);
1662
1663		port->ip_srights++;
1664		ip_reference(port);
1665		ip_unlock(port);
1666
1667		*objectp = (ipc_object_t) port;
1668		*sorightp = IP_NULL;
1669		break;
1670	    }
1671
1672	    case MACH_MSG_TYPE_MOVE_SEND: {
1673		ipc_port_t port;
1674		ipc_port_t dnrequest = IP_NULL;
1675
1676		if (bits & MACH_PORT_TYPE_DEAD_NAME)
1677			goto move_dead;
1678
1679		/* allow for dead send-once rights */
1680
1681		if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
1682			goto invalid_right;
1683
1684		assert(IE_BITS_UREFS(bits) > 0);
1685
1686		port = (ipc_port_t) entry->ie_object;
1687		assert(port != IP_NULL);
1688
1689		if (ipc_right_check(space, port, name, entry)) {
1690			bits = entry->ie_bits;
1691			goto move_dead;
1692		}
1693		/* port is locked and active */
1694
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);
1699		if (rc)
1700		  {
1701		    ip_unlock (port);
1702		    return KERN_NO_ACCESS;
1703		  }
1704#endif
1705
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);
1709
1710			ip_unlock(port);
1711			goto invalid_right;
1712		}
1713
1714		assert(port->ip_srights > 0);
1715
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);
1722
1723				ip_reference(port);
1724			} else {
1725				assert(IE_BITS_TYPE(bits) ==
1726						MACH_PORT_TYPE_SEND);
1727
1728				dnrequest = ipc_right_dncancel_macro(space, port,
1729								     name, entry);
1730				ipc_hash_delete(space, (ipc_object_t) port,
1731						name, entry);
1732				entry->ie_object = IO_NULL;
1733			}
1734			entry->ie_bits = bits &~
1735				(IE_BITS_UREFS_MASK|MACH_PORT_TYPE_SEND);
1736		} else {
1737			port->ip_srights++;
1738			ip_reference(port);
1739			entry->ie_bits = bits-1; /* decrement urefs */
1740		}
1741
1742		ip_unlock(port);
1743
1744		*objectp = (ipc_object_t) port;
1745		*sorightp = dnrequest;
1746		break;
1747	    }
1748
1749	    case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
1750		ipc_port_t port;
1751		ipc_port_t dnrequest;
1752
1753		if (bits & MACH_PORT_TYPE_DEAD_NAME)
1754			goto move_dead;
1755
1756		/* allow for dead send rights */
1757
1758		if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
1759			goto invalid_right;
1760
1761		assert(IE_BITS_UREFS(bits) > 0);
1762
1763		port = (ipc_port_t) entry->ie_object;
1764		assert(port != IP_NULL);
1765
1766		if (ipc_right_check(space, port, name, entry)) {
1767			bits = entry->ie_bits;
1768			goto move_dead;
1769		}
1770		/* port is locked and active */
1771
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);
1776		if (rc)
1777		  {
1778		    ip_unlock (port);
1779		    return KERN_NO_ACCESS;
1780		  }
1781#endif
1782
1783		if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0) {
1784			assert(bits & MACH_PORT_TYPE_SEND);
1785			assert(port->ip_srights > 0);
1786
1787			ip_unlock(port);
1788			goto invalid_right;
1789		}
1790
1791		assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1792		assert(IE_BITS_UREFS(bits) == 1);
1793		assert(port->ip_sorights > 0);
1794
1795		dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
1796		ip_unlock(port);
1797
1798		entry->ie_object = IO_NULL;
1799		entry->ie_bits = bits &~
1800			(IE_BITS_UREFS_MASK | MACH_PORT_TYPE_SEND_ONCE);
1801
1802		*objectp = (ipc_object_t) port;
1803		*sorightp = dnrequest;
1804		break;
1805	    }
1806
1807	    default:
1808	    invalid_right:
1809		return KERN_INVALID_RIGHT;
1810	}
1811
1812	return KERN_SUCCESS;
1813
1814    copy_dead:
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);
1819
1820	if (!deadok)
1821		goto invalid_right;
1822
1823	*objectp = IO_DEAD;
1824	*sorightp = IP_NULL;
1825	return KERN_SUCCESS;
1826
1827    move_dead:
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);
1832
1833	if (!deadok)
1834		goto invalid_right;
1835
1836	if (IE_BITS_UREFS(bits) == 1) {
1837		bits &= ~MACH_PORT_TYPE_DEAD_NAME;
1838	}
1839	entry->ie_bits = bits-1; /* decrement urefs */
1840
1841	*objectp = IO_DEAD;
1842	*sorightp = IP_NULL;
1843	return KERN_SUCCESS;
1844
1845}
1846
1847/*
1848 *	Routine:	ipc_right_copyin_undo
1849 *	Purpose:
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.)
1853 *	Conditions:
1854 *		The space is write-locked and active.
1855 */
1856
1857void
1858ipc_right_copyin_undo(
1859	ipc_space_t		space,
1860	mach_port_name_t	name,
1861	ipc_entry_t		entry,
1862	mach_msg_type_name_t	msgt_name,
1863	ipc_object_t		object,
1864	ipc_port_t		soright)
1865{
1866	ipc_entry_bits_t bits;
1867
1868	bits = entry->ie_bits;
1869
1870	assert(space->is_active);
1871
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));
1875
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);
1881
1882		entry->ie_bits = ((bits &~ IE_BITS_RIGHT_MASK) |
1883				  MACH_PORT_TYPE_DEAD_NAME | 2);
1884
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));
1888
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);
1894
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 */
1898		}
1899	} else {
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);
1906
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 */
1910		}
1911
1912		/*
1913		 *	May as well convert the entry to a dead name.
1914		 *	(Or if it is a compat entry, destroy it.)
1915		 */
1916
1917		(void) ipc_right_check(space, (ipc_port_t) object,
1918				       name, entry);
1919		/* object is dead so it is not locked */
1920	}
1921
1922	/* release the reference acquired by copyin */
1923
1924	if (object != IO_DEAD)
1925		ipc_object_release(object);
1926}
1927
1928/*
1929 *	Routine:	ipc_right_copyin_two
1930 *	Purpose:
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.
1934 *	Conditions:
1935 *		The space is write-locked and active.
1936 *		The object is returned with two refs/send rights.
1937 *	Returns:
1938 *		KERN_SUCCESS		Acquired an object.
1939 *		KERN_INVALID_RIGHT	Name doesn't denote correct right.
1940 */
1941
1942kern_return_t
1943ipc_right_copyin_two(
1944	ipc_space_t		space,
1945	mach_port_name_t	name,
1946	ipc_entry_t		entry,
1947	ipc_object_t		*objectp,
1948	ipc_port_t		*sorightp)
1949{
1950	ipc_entry_bits_t bits;
1951	mach_port_urefs_t urefs;
1952	ipc_port_t port;
1953	ipc_port_t dnrequest = IP_NULL;
1954#if CONFIG_MACF_MACH
1955	task_t self = current_task();
1956	int    rc;
1957#endif
1958
1959	assert(space->is_active);
1960
1961	bits = entry->ie_bits;
1962
1963	if ((bits & MACH_PORT_TYPE_SEND) == 0)
1964		goto invalid_right;
1965
1966	urefs = IE_BITS_UREFS(bits);
1967	if (urefs < 2)
1968		goto invalid_right;
1969
1970	port = (ipc_port_t) entry->ie_object;
1971	assert(port != IP_NULL);
1972
1973	if (ipc_right_check(space, port, name, entry)) {
1974		goto invalid_right;
1975	}
1976	/* port is locked and active */
1977
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);
1982	if (rc) {
1983		ip_unlock(port);
1984		return KERN_NO_ACCESS;
1985	}
1986#endif
1987
1988	assert(port->ip_srights > 0);
1989
1990	if (urefs == 2) {
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);
1996
1997			port->ip_srights++;
1998			ip_reference(port);
1999			ip_reference(port);
2000		} else {
2001			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
2002
2003			dnrequest = ipc_right_dncancel_macro(space, port,
2004							     name, entry);
2005
2006			port->ip_srights++;
2007			ip_reference(port);
2008			ipc_hash_delete(space, (ipc_object_t) port,
2009					name, entry);
2010			entry->ie_object = IO_NULL;
2011		}
2012		entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK|MACH_PORT_TYPE_SEND);
2013	} else {
2014		port->ip_srights += 2;
2015		ip_reference(port);
2016		ip_reference(port);
2017		entry->ie_bits = bits-2; /* decrement urefs */
2018	}
2019	ip_unlock(port);
2020
2021	*objectp = (ipc_object_t) port;
2022	*sorightp = dnrequest;
2023	return KERN_SUCCESS;
2024
2025    invalid_right:
2026	return KERN_INVALID_RIGHT;
2027}
2028
2029/*
2030 *	Routine:	ipc_right_copyout
2031 *	Purpose:
2032 *		Copyout a capability to a space.
2033 *		If successful, consumes a ref for the object.
2034 *
2035 *		Always succeeds when given a newly-allocated entry,
2036 *		because user-reference overflow isn't a possibility.
2037 *
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.
2042 *	Conditions:
2043 *		The space is write-locked and active.
2044 *		The object is locked and active.
2045 *		The object is unlocked; the space isn't.
2046 *	Returns:
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.
2051 */
2052
2053kern_return_t
2054ipc_right_copyout(
2055	ipc_space_t		space,
2056	mach_port_name_t	name,
2057	ipc_entry_t		entry,
2058	mach_msg_type_name_t	msgt_name,
2059	boolean_t		overflow,
2060	ipc_object_t		object)
2061{
2062	ipc_entry_bits_t bits;
2063	ipc_port_t port;
2064#if CONFIG_MACF_MACH
2065	int rc;
2066#endif
2067
2068	bits = entry->ie_bits;
2069
2070	assert(IO_VALID(object));
2071	assert(io_otype(object) == IOT_PORT);
2072	assert(io_active(object));
2073	assert(entry->ie_object == object);
2074
2075	port = (ipc_port_t) object;
2076
2077	switch (msgt_name) {
2078	    case MACH_MSG_TYPE_PORT_SEND_ONCE:
2079
2080		assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2081		assert(port->ip_sorights > 0);
2082
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,
2087							   &port->ip_label);
2088			tasklabel_unlock(space->is_task);
2089
2090			if (rc) {
2091				ip_unlock(port);
2092				return KERN_NO_ACCESS;
2093			}
2094		}
2095#endif
2096		/* transfer send-once right and ref to entry */
2097		ip_unlock(port);
2098
2099		entry->ie_bits = bits | (MACH_PORT_TYPE_SEND_ONCE | 1);
2100		break;
2101
2102	    case MACH_MSG_TYPE_PORT_SEND:
2103		assert(port->ip_srights > 0);
2104
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,
2109						      &port->ip_label);
2110			tasklabel_unlock(space->is_task);
2111
2112			if (rc) {
2113				ip_unlock(port);
2114				return KERN_NO_ACCESS;
2115			}
2116		}
2117#endif
2118
2119		if (bits & MACH_PORT_TYPE_SEND) {
2120			mach_port_urefs_t urefs = IE_BITS_UREFS(bits);
2121
2122			assert(port->ip_srights > 1);
2123			assert(urefs > 0);
2124			assert(urefs < MACH_PORT_UREFS_MAX);
2125
2126			if (urefs+1 == MACH_PORT_UREFS_MAX) {
2127				if (overflow) {
2128					/* leave urefs pegged to maximum */
2129
2130					port->ip_srights--;
2131					ip_release(port);
2132					ip_unlock(port);
2133					return KERN_SUCCESS;
2134				}
2135
2136				ip_unlock(port);
2137				return KERN_UREFS_OVERFLOW;
2138			}
2139
2140			port->ip_srights--;
2141			ip_release(port);
2142			ip_unlock(port);
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);
2146
2147			/* transfer send right to entry */
2148			ip_release(port);
2149			ip_unlock(port);
2150		} else {
2151			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2152			assert(IE_BITS_UREFS(bits) == 0);
2153
2154			/* transfer send right and ref to entry */
2155			ip_unlock(port);
2156
2157			/* entry is locked holding ref, so can use port */
2158
2159			ipc_hash_insert(space, (ipc_object_t) port,
2160					name, entry);
2161		}
2162
2163		entry->ie_bits = (bits | MACH_PORT_TYPE_SEND) + 1;
2164		break;
2165
2166	    case MACH_MSG_TYPE_PORT_RECEIVE: {
2167		ipc_port_t dest;
2168
2169		assert(port->ip_mscount == 0);
2170		assert(port->ip_receiver_name == MACH_PORT_NULL);
2171		dest = port->ip_destination;
2172
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,
2177							 &port->ip_label);
2178			tasklabel_unlock(space->is_task);
2179
2180			if (rc) {
2181				ip_unlock(port);
2182				return KERN_NO_ACCESS;
2183			}
2184		}
2185#endif
2186
2187		port->ip_receiver_name = name;
2188		port->ip_receiver = space;
2189
2190		assert((bits & MACH_PORT_TYPE_RECEIVE) == 0);
2191
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);
2196
2197			ip_release(port);
2198			ip_unlock(port);
2199
2200			/* entry is locked holding ref, so can use port */
2201
2202			ipc_hash_delete(space, (ipc_object_t) port,
2203					name, entry);
2204		} else {
2205			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2206			assert(IE_BITS_UREFS(bits) == 0);
2207
2208			/* transfer ref to entry */
2209			ip_unlock(port);
2210		}
2211		entry->ie_bits = bits | MACH_PORT_TYPE_RECEIVE;
2212
2213		if (dest != IP_NULL)
2214			ipc_port_release(dest);
2215		break;
2216	    }
2217
2218	    default:
2219		panic("ipc_right_copyout: strange rights");
2220	}
2221
2222	return KERN_SUCCESS;
2223}
2224
2225/*
2226 *	Routine:	ipc_right_rename
2227 *	Purpose:
2228 *		Transfer an entry from one name to another.
2229 *		The old entry is deallocated.
2230 *	Conditions:
2231 *		The space is write-locked and active.
2232 *		The new entry is unused.  Upon return,
2233 *		the space is unlocked.
2234 *	Returns:
2235 *		KERN_SUCCESS		Moved entry to new name.
2236 */
2237
2238kern_return_t
2239ipc_right_rename(
2240	ipc_space_t		space,
2241	mach_port_name_t	oname,
2242	ipc_entry_t		oentry,
2243	mach_port_name_t	nname,
2244	ipc_entry_t		nentry)
2245{
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;
2249
2250	assert(space->is_active);
2251	assert(oname != nname);
2252
2253	/*
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.
2258	 */
2259
2260	if (request != 0) {
2261		ipc_port_t port;
2262
2263		assert(bits & MACH_PORT_TYPE_PORT_RIGHTS);
2264		port = (ipc_port_t) object;
2265		assert(port != IP_NULL);
2266
2267		if (ipc_right_check(space, port, oname, oentry)) {
2268			request = 0;
2269			object = IO_NULL;
2270			bits = oentry->ie_bits;
2271			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
2272			assert(oentry->ie_request == 0);
2273		} else {
2274			/* port is locked and active */
2275
2276			ipc_port_dnrename(port, request, oname, nname);
2277			ip_unlock(port);
2278			oentry->ie_request = 0;
2279		}
2280	}
2281
2282	/* initialize nentry before letting ipc_hash_insert see it */
2283
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;
2288
2289	switch (IE_BITS_TYPE(bits)) {
2290	    case MACH_PORT_TYPE_SEND: {
2291		ipc_port_t port;
2292
2293		port = (ipc_port_t) object;
2294		assert(port != IP_NULL);
2295
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);
2301		break;
2302	    }
2303
2304	    case MACH_PORT_TYPE_RECEIVE:
2305	    case MACH_PORT_TYPE_SEND_RECEIVE: {
2306		ipc_port_t port;
2307
2308		port = (ipc_port_t) object;
2309		assert(port != IP_NULL);
2310
2311		ip_lock(port);
2312		assert(ip_active(port));
2313		assert(port->ip_receiver_name == oname);
2314		assert(port->ip_receiver == space);
2315
2316		port->ip_receiver_name = nname;
2317		ip_unlock(port);
2318		break;
2319	    }
2320
2321	    case MACH_PORT_TYPE_PORT_SET: {
2322		ipc_pset_t pset;
2323
2324		pset = (ipc_pset_t) object;
2325		assert(pset != IPS_NULL);
2326
2327		ips_lock(pset);
2328		assert(ips_active(pset));
2329		assert(pset->ips_local_name == oname);
2330
2331		pset->ips_local_name = nname;
2332		ips_unlock(pset);
2333		break;
2334	    }
2335
2336	    case MACH_PORT_TYPE_SEND_ONCE:
2337	    case MACH_PORT_TYPE_DEAD_NAME:
2338		break;
2339
2340	    default:
2341		panic("ipc_right_rename: strange rights");
2342	}
2343
2344	assert(oentry->ie_request == 0);
2345	oentry->ie_object = IO_NULL;
2346	ipc_entry_dealloc(space, oname, oentry);
2347	is_write_unlock(space);
2348
2349	return KERN_SUCCESS;
2350}
2351