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/* Allow IPC to generate mach port guard exceptions */
92extern kern_return_t
93mach_port_guard_exception(
94	mach_port_name_t	name,
95	uint64_t		inguard,
96	uint64_t		portguard,
97	unsigned		reason);
98/*
99 *	Routine:	ipc_right_lookup_write
100 *	Purpose:
101 *		Finds an entry in a space, given the name.
102 *	Conditions:
103 *		Nothing locked.  If successful, the space is write-locked.
104 *	Returns:
105 *		KERN_SUCCESS		Found an entry.
106 *		KERN_INVALID_TASK	The space is dead.
107 *		KERN_INVALID_NAME	Name doesn't exist in space.
108 */
109
110kern_return_t
111ipc_right_lookup_write(
112	ipc_space_t		space,
113	mach_port_name_t	name,
114	ipc_entry_t		*entryp)
115{
116	ipc_entry_t entry;
117
118	assert(space != IS_NULL);
119
120	is_write_lock(space);
121
122	if (!is_active(space)) {
123		is_write_unlock(space);
124		return KERN_INVALID_TASK;
125	}
126
127	if ((entry = ipc_entry_lookup(space, name)) == IE_NULL) {
128		is_write_unlock(space);
129		return KERN_INVALID_NAME;
130	}
131
132	*entryp = entry;
133	return KERN_SUCCESS;
134}
135
136/*
137 *	Routine:	ipc_right_lookup_two_write
138 *	Purpose:
139 *		Like ipc_right_lookup except that it returns two
140 *		entries for two different names that were looked
141 *		up under the same space lock.
142 *	Conditions:
143 *		Nothing locked.  If successful, the space is write-locked.
144 *	Returns:
145 *		KERN_INVALID_TASK	The space is dead.
146 *		KERN_INVALID_NAME	Name doesn't exist in space.
147 */
148
149kern_return_t
150ipc_right_lookup_two_write(
151	ipc_space_t		space,
152	mach_port_name_t	name1,
153	ipc_entry_t		*entryp1,
154	mach_port_name_t	name2,
155	ipc_entry_t		*entryp2)
156{
157	ipc_entry_t entry1;
158	ipc_entry_t entry2;
159
160	assert(space != IS_NULL);
161
162	is_write_lock(space);
163
164	if (!is_active(space)) {
165		is_write_unlock(space);
166		return KERN_INVALID_TASK;
167	}
168
169	if ((entry1 = ipc_entry_lookup(space, name1)) == IE_NULL) {
170		is_write_unlock(space);
171		return KERN_INVALID_NAME;
172	}
173	if ((entry2 = ipc_entry_lookup(space, name2)) == IE_NULL) {
174		is_write_unlock(space);
175		return KERN_INVALID_NAME;
176	}
177	*entryp1 = entry1;
178	*entryp2 = entry2;
179	return KERN_SUCCESS;
180}
181
182/*
183 *	Routine:	ipc_right_reverse
184 *	Purpose:
185 *		Translate (space, object) -> (name, entry).
186 *		Only finds send/receive rights.
187 *		Returns TRUE if an entry is found; if so,
188 *		the object is locked and active.
189 *	Conditions:
190 *		The space must be locked (read or write) and active.
191 *		Nothing else locked.
192 */
193
194boolean_t
195ipc_right_reverse(
196	ipc_space_t		space,
197	ipc_object_t		object,
198	mach_port_name_t	*namep,
199	ipc_entry_t		*entryp)
200{
201	ipc_port_t port;
202	mach_port_name_t name;
203	ipc_entry_t entry;
204
205	/* would switch on io_otype to handle multiple types of object */
206
207	assert(is_active(space));
208	assert(io_otype(object) == IOT_PORT);
209
210	port = (ipc_port_t) object;
211
212	ip_lock(port);
213	if (!ip_active(port)) {
214		ip_unlock(port);
215
216		return FALSE;
217	}
218
219	if (port->ip_receiver == space) {
220		name = port->ip_receiver_name;
221		assert(name != MACH_PORT_NULL);
222
223		entry = ipc_entry_lookup(space, name);
224
225		assert(entry != IE_NULL);
226		assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
227		assert(port == (ipc_port_t) entry->ie_object);
228
229		*namep = name;
230		*entryp = entry;
231		return TRUE;
232	}
233
234	if (ipc_hash_lookup(space, (ipc_object_t) port, namep, entryp)) {
235		assert((entry = *entryp) != IE_NULL);
236		assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_SEND);
237		assert(port == (ipc_port_t) entry->ie_object);
238
239		return TRUE;
240	}
241
242	ip_unlock(port);
243	return FALSE;
244}
245
246/*
247 *	Routine:	ipc_right_dnrequest
248 *	Purpose:
249 *		Make a dead-name request, returning the previously
250 *		registered send-once right.  If notify is IP_NULL,
251 *		just cancels the previously registered request.
252 *
253 *	Conditions:
254 *		Nothing locked.  May allocate memory.
255 *		Only consumes/returns refs if successful.
256 *	Returns:
257 *		KERN_SUCCESS		Made/canceled dead-name request.
258 *		KERN_INVALID_TASK	The space is dead.
259 *		KERN_INVALID_NAME	Name doesn't exist in space.
260 *		KERN_INVALID_RIGHT	Name doesn't denote port/dead rights.
261 *		KERN_INVALID_ARGUMENT	Name denotes dead name, but
262 *			immediate is FALSE or notify is IP_NULL.
263 *		KERN_UREFS_OVERFLOW	Name denotes dead name, but
264 *			generating immediate notif. would overflow urefs.
265 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
266 */
267
268kern_return_t
269ipc_right_request_alloc(
270	ipc_space_t		space,
271	mach_port_name_t	name,
272	boolean_t		immediate,
273	boolean_t		send_possible,
274	ipc_port_t		notify,
275	ipc_port_t		*previousp)
276{
277	ipc_port_request_index_t prev_request;
278	ipc_port_t previous = IP_NULL;
279	ipc_entry_t entry;
280	kern_return_t kr;
281
282#if IMPORTANCE_INHERITANCE
283	boolean_t needboost = FALSE;
284#endif /* IMPORTANCE_INHERITANCE */
285
286	for (;;) {
287		ipc_port_t port = IP_NULL;
288
289		kr = ipc_right_lookup_write(space, name, &entry);
290		if (kr != KERN_SUCCESS)
291			return kr;
292
293		/* space is write-locked and active */
294
295		prev_request = entry->ie_request;
296
297		/* if nothing to do or undo, we're done */
298		if (notify == IP_NULL && prev_request == IE_REQ_NONE) {
299			is_write_unlock(space);
300			*previousp = IP_NULL;
301			return KERN_SUCCESS;
302		}
303
304		/* see if the entry is of proper type for requests */
305		if (entry->ie_bits & MACH_PORT_TYPE_PORT_RIGHTS) {
306			ipc_port_request_index_t new_request;
307
308			port = (ipc_port_t) entry->ie_object;
309			assert(port != IP_NULL);
310
311			if (!ipc_right_check(space, port, name, entry)) {
312				/* port is locked and active */
313
314				/* if no new request, just cancel previous */
315				if (notify == IP_NULL) {
316					if (prev_request != IE_REQ_NONE)
317						previous = ipc_port_request_cancel(port, name, prev_request);
318					ip_unlock(port);
319					entry->ie_request = IE_REQ_NONE;
320					ipc_entry_modified(space, name, entry);
321					is_write_unlock(space);
322					break;
323				}
324
325				/*
326				 * send-once rights, kernel objects, and non-full other queues
327				 * fire immediately (if immediate specified).
328				 */
329				if (send_possible && immediate &&
330				    ((entry->ie_bits & MACH_PORT_TYPE_SEND_ONCE) ||
331				     port->ip_receiver == ipc_space_kernel || !ip_full(port))) {
332					if (prev_request != IE_REQ_NONE)
333						previous = ipc_port_request_cancel(port, name, prev_request);
334					ip_unlock(port);
335					entry->ie_request = IE_REQ_NONE;
336					ipc_entry_modified(space, name, entry);
337					is_write_unlock(space);
338
339					ipc_notify_send_possible(notify, name);
340					break;
341				}
342
343				/*
344				 * If there is a previous request, free it.  Any subsequent
345				 * allocation cannot fail, thus assuring an atomic swap.
346				 */
347				if (prev_request != IE_REQ_NONE)
348					previous = ipc_port_request_cancel(port, name, prev_request);
349
350#if IMPORTANCE_INHERITANCE
351				kr = ipc_port_request_alloc(port, name, notify,
352							    send_possible, immediate,
353							    &new_request, &needboost);
354#else
355				kr = ipc_port_request_alloc(port, name, notify,
356							    send_possible, immediate,
357							    &new_request);
358#endif /* IMPORTANCE_INHERITANCE */
359				if (kr != KERN_SUCCESS) {
360					assert(previous == IP_NULL);
361					is_write_unlock(space);
362
363					kr = ipc_port_request_grow(port, ITS_SIZE_NONE);
364					/* port is unlocked */
365
366					if (kr != KERN_SUCCESS)
367						return kr;
368
369					continue;
370				}
371
372
373				assert(new_request != IE_REQ_NONE);
374				entry->ie_request = new_request;
375				ipc_entry_modified(space, name, entry);
376				is_write_unlock(space);
377
378#if IMPORTANCE_INHERITANCE
379				if (needboost == TRUE) {
380					if (ipc_port_importance_delta(port, 1) == FALSE)
381						ip_unlock(port);
382				} else
383#endif /* IMPORTANCE_INHERITANCE */
384					ip_unlock(port);
385
386				break;
387			}
388			/* entry may have changed to dead-name by ipc_right_check() */
389
390		}
391
392		/* treat send_possible requests as immediate w.r.t. dead-name */
393		if ((send_possible || immediate) && notify != IP_NULL &&
394		    (entry->ie_bits & MACH_PORT_TYPE_DEAD_NAME)) {
395			mach_port_urefs_t urefs = IE_BITS_UREFS(entry->ie_bits);
396
397			assert(urefs > 0);
398
399			if (MACH_PORT_UREFS_OVERFLOW(urefs, 1)) {
400				is_write_unlock(space);
401				if (port != IP_NULL)
402					ip_release(port);
403				return KERN_UREFS_OVERFLOW;
404			}
405
406			(entry->ie_bits)++; /* increment urefs */
407			ipc_entry_modified(space, name, entry);
408			is_write_unlock(space);
409
410			if (port != IP_NULL)
411				ip_release(port);
412
413			ipc_notify_dead_name(notify, name);
414			previous = IP_NULL;
415			break;
416		}
417
418		is_write_unlock(space);
419
420		if (port != IP_NULL)
421			ip_release(port);
422
423		if (entry->ie_bits & MACH_PORT_TYPE_PORT_OR_DEAD)
424			return KERN_INVALID_ARGUMENT;
425		else
426			return KERN_INVALID_RIGHT;
427	}
428
429	*previousp = previous;
430	return KERN_SUCCESS;
431}
432
433/*
434 *	Routine:	ipc_right_request_cancel
435 *	Purpose:
436 *		Cancel a notification request and return the send-once right.
437 *		Afterwards, entry->ie_request == 0.
438 *	Conditions:
439 *		The space must be write-locked; the port must be locked.
440 *		The port must be active; the space doesn't have to be.
441 */
442
443ipc_port_t
444ipc_right_request_cancel(
445	__unused ipc_space_t		space,
446	ipc_port_t			port,
447	mach_port_name_t		name,
448	ipc_entry_t			entry)
449{
450	ipc_port_t previous;
451
452	assert(ip_active(port));
453	assert(port == (ipc_port_t) entry->ie_object);
454
455	if (entry->ie_request == IE_REQ_NONE)
456		return IP_NULL;
457
458	previous = ipc_port_request_cancel(port, name, entry->ie_request);
459	entry->ie_request = IE_REQ_NONE;
460	ipc_entry_modified(space, name, entry);
461	return previous;
462}
463
464/*
465 *	Routine:	ipc_right_inuse
466 *	Purpose:
467 *		Check if an entry is being used.
468 *		Returns TRUE if it is.
469 *	Conditions:
470 *		The space is write-locked and active.
471 *		It is unlocked if the entry is inuse.
472 */
473
474boolean_t
475ipc_right_inuse(
476	ipc_space_t			space,
477	__unused mach_port_name_t	name,
478	ipc_entry_t			entry)
479{
480	if (IE_BITS_TYPE(entry->ie_bits) != MACH_PORT_TYPE_NONE) {
481		is_write_unlock(space);
482		return TRUE;
483	}
484	return FALSE;
485}
486
487/*
488 *	Routine:	ipc_right_check
489 *	Purpose:
490 *		Check if the port has died.  If it has,
491 *		clean up the entry and return TRUE.
492 *	Conditions:
493 *		The space is write-locked; the port is not locked.
494 *		If returns FALSE, the port is also locked and active.
495 *		Otherwise, entry is converted to a dead name.
496 *
497 *		Caller is responsible for a reference to port if it
498 *		had died (returns TRUE).
499 */
500
501boolean_t
502ipc_right_check(
503	ipc_space_t		space,
504	ipc_port_t		port,
505	mach_port_name_t	name,
506	ipc_entry_t		entry)
507{
508	ipc_entry_bits_t bits;
509
510	assert(is_active(space));
511	assert(port == (ipc_port_t) entry->ie_object);
512
513	ip_lock(port);
514	if (ip_active(port))
515		return FALSE;
516
517	/* this was either a pure send right or a send-once right */
518
519	bits = entry->ie_bits;
520	assert((bits & MACH_PORT_TYPE_RECEIVE) == 0);
521	assert(IE_BITS_UREFS(bits) > 0);
522
523	if (bits & MACH_PORT_TYPE_SEND) {
524                assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
525		assert(IE_BITS_UREFS(bits) > 0);
526		assert(port->ip_srights > 0);
527		port->ip_srights--;
528        } else {
529                assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
530                assert(IE_BITS_UREFS(bits) == 1);
531		assert(port->ip_sorights > 0);
532		port->ip_sorights--;
533        }
534	ip_unlock(port);
535
536	/*
537	 * delete SEND rights from ipc hash.
538	 */
539
540	if ((bits & MACH_PORT_TYPE_SEND) != 0) {
541		ipc_hash_delete(space, (ipc_object_t)port, name, entry);
542	}
543
544	/* convert entry to dead name */
545	bits = (bits &~ IE_BITS_TYPE_MASK) | MACH_PORT_TYPE_DEAD_NAME;
546
547	/*
548	 * If there was a notification request outstanding on this
549	 * name, and the port went dead, that notification
550	 * must already be on its way up from the port layer.
551	 *
552	 * Add the reference that the notification carries. It
553	 * is done here, and not in the notification delivery,
554	 * because the latter doesn't have a space reference and
555	 * trying to actually move a send-right reference would
556	 * get short-circuited into a MACH_PORT_DEAD by IPC. Since
557	 * all calls that deal with the right eventually come
558	 * through here, it has the same result.
559	 *
560	 * Once done, clear the request index so we only account
561	 * for it once.
562	 */
563	if (entry->ie_request != IE_REQ_NONE) {
564		if (ipc_port_request_type(port, name, entry->ie_request) != 0) {
565			assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX);
566			bits++;
567		}
568		entry->ie_request = IE_REQ_NONE;
569	}
570	entry->ie_bits = bits;
571	entry->ie_object = IO_NULL;
572	ipc_entry_modified(space, name, entry);
573	return TRUE;
574}
575
576/*
577 *	Routine:	ipc_right_terminate
578 *	Purpose:
579 *		Cleans up an entry in a terminated space.
580 *		The entry isn't deallocated or removed
581 *		from reverse hash tables.
582 *	Conditions:
583 *		The space is dead and unlocked.
584 */
585
586void
587ipc_right_terminate(
588	ipc_space_t		space,
589	mach_port_name_t	name,
590	ipc_entry_t		entry)
591{
592	ipc_entry_bits_t bits;
593	mach_port_type_t type;
594
595	bits = entry->ie_bits;
596	type = IE_BITS_TYPE(bits);
597
598	assert(!is_active(space));
599
600	/*
601	 *	IE_BITS_COMPAT/ipc_right_dncancel doesn't have this
602	 *	problem, because we check that the port is active.  If
603	 *	we didn't cancel IE_BITS_COMPAT, ipc_port_destroy
604	 *	would still work, but dead space refs would accumulate
605	 *	in ip_dnrequests.  They would use up slots in
606	 *	ip_dnrequests and keep the spaces from being freed.
607	 */
608
609	switch (type) {
610	    case MACH_PORT_TYPE_DEAD_NAME:
611		assert(entry->ie_request == IE_REQ_NONE);
612		assert(entry->ie_object == IO_NULL);
613		break;
614
615	    case MACH_PORT_TYPE_PORT_SET: {
616		ipc_pset_t pset = (ipc_pset_t) entry->ie_object;
617
618		assert(entry->ie_request == IE_REQ_NONE);
619		assert(pset != IPS_NULL);
620
621		ips_lock(pset);
622		assert(ips_active(pset));
623		ipc_pset_destroy(pset); /* consumes ref, unlocks */
624		break;
625	    }
626
627	    case MACH_PORT_TYPE_SEND:
628	    case MACH_PORT_TYPE_RECEIVE:
629	    case MACH_PORT_TYPE_SEND_RECEIVE:
630	    case MACH_PORT_TYPE_SEND_ONCE: {
631		ipc_port_t port = (ipc_port_t) entry->ie_object;
632		ipc_port_t request;
633		ipc_port_t nsrequest = IP_NULL;
634		mach_port_mscount_t mscount = 0;
635
636		assert(port != IP_NULL);
637		ip_lock(port);
638
639		if (!ip_active(port)) {
640			ip_unlock(port);
641			ip_release(port);
642			break;
643		}
644
645		request = ipc_right_request_cancel_macro(space, port,
646					name, entry);
647
648		if (type & MACH_PORT_TYPE_SEND) {
649			assert(port->ip_srights > 0);
650			if (--port->ip_srights == 0
651			    ) {
652				nsrequest = port->ip_nsrequest;
653				if (nsrequest != IP_NULL) {
654					port->ip_nsrequest = IP_NULL;
655					mscount = port->ip_mscount;
656				}
657			}
658		}
659
660		if (type & MACH_PORT_TYPE_RECEIVE) {
661			wait_queue_link_t wql;
662			queue_head_t links_data;
663			queue_t links = &links_data;
664
665			assert(port->ip_receiver_name == name);
666			assert(port->ip_receiver == space);
667
668			queue_init(links);
669			ipc_port_clear_receiver(port, links);
670			ipc_port_destroy(port); /* consumes our ref, unlocks */
671			while(!queue_empty(links)) {
672				wql = (wait_queue_link_t) dequeue(links);
673				wait_queue_link_free(wql);
674			}
675
676		} else if (type & MACH_PORT_TYPE_SEND_ONCE) {
677			assert(port->ip_sorights > 0);
678			ip_unlock(port);
679
680			ipc_notify_send_once(port); /* consumes our ref */
681		} else {
682			assert(port->ip_receiver != space);
683
684			ip_unlock(port);
685			ip_release(port);
686		}
687
688		if (nsrequest != IP_NULL)
689			ipc_notify_no_senders(nsrequest, mscount);
690
691		if (request != IP_NULL)
692			ipc_notify_port_deleted(request, name);
693		break;
694	    }
695
696	    default:
697		panic("ipc_right_terminate: strange type - 0x%x", type);
698	}
699}
700
701/*
702 *	Routine:	ipc_right_destroy
703 *	Purpose:
704 *		Destroys an entry in a space.
705 *	Conditions:
706 *		The space is write-locked (returns unlocked).
707 *		The space must be active.
708 *	Returns:
709 *		KERN_SUCCESS		The entry was destroyed.
710 */
711
712kern_return_t
713ipc_right_destroy(
714	ipc_space_t		space,
715	mach_port_name_t	name,
716	ipc_entry_t		entry,
717	boolean_t		check_guard,
718	uint64_t		guard)
719{
720	ipc_entry_bits_t bits;
721	mach_port_type_t type;
722
723	bits = entry->ie_bits;
724	entry->ie_bits &= ~IE_BITS_TYPE_MASK;
725	type = IE_BITS_TYPE(bits);
726
727	assert(is_active(space));
728
729	switch (type) {
730	    case MACH_PORT_TYPE_DEAD_NAME:
731		assert(entry->ie_request == IE_REQ_NONE);
732		assert(entry->ie_object == IO_NULL);
733
734		ipc_entry_dealloc(space, name, entry);
735		is_write_unlock(space);
736		break;
737
738	    case MACH_PORT_TYPE_PORT_SET: {
739		ipc_pset_t pset = (ipc_pset_t) entry->ie_object;
740
741		assert(entry->ie_request == IE_REQ_NONE);
742		assert(pset != IPS_NULL);
743
744		entry->ie_object = IO_NULL;
745		ipc_entry_dealloc(space, name, entry);
746
747		ips_lock(pset);
748		is_write_unlock(space);
749
750		assert(ips_active(pset));
751		ipc_pset_destroy(pset); /* consumes ref, unlocks */
752		break;
753	    }
754
755	    case MACH_PORT_TYPE_SEND:
756	    case MACH_PORT_TYPE_RECEIVE:
757	    case MACH_PORT_TYPE_SEND_RECEIVE:
758	    case MACH_PORT_TYPE_SEND_ONCE: {
759		ipc_port_t port = (ipc_port_t) entry->ie_object;
760		ipc_port_t nsrequest = IP_NULL;
761		mach_port_mscount_t mscount = 0;
762		ipc_port_t request;
763
764		assert(port != IP_NULL);
765
766		if (type == MACH_PORT_TYPE_SEND)
767			ipc_hash_delete(space, (ipc_object_t) port,
768					name, entry);
769
770		ip_lock(port);
771
772		if (!ip_active(port)) {
773			assert((type & MACH_PORT_TYPE_RECEIVE) == 0);
774			ip_unlock(port);
775			entry->ie_request = IE_REQ_NONE;
776			entry->ie_object = IO_NULL;
777			ipc_entry_dealloc(space, name, entry);
778			is_write_unlock(space);
779			ip_release(port);
780			break;
781		}
782
783		/* For receive rights, check for guarding */
784		if ((type & MACH_PORT_TYPE_RECEIVE) &&
785		    (check_guard) && (port->ip_guarded) &&
786		    (guard != port->ip_context)) {
787			/* Guard Violation */
788			uint64_t portguard = port->ip_context;
789			ip_unlock(port);
790			is_write_unlock(space);
791			/* Raise mach port guard exception */
792			mach_port_guard_exception(name, 0, portguard, kGUARD_EXC_DESTROY);
793			return KERN_INVALID_RIGHT;
794		}
795
796
797		request = ipc_right_request_cancel_macro(space, port, name, entry);
798
799		entry->ie_object = IO_NULL;
800		ipc_entry_dealloc(space, name, entry);
801		is_write_unlock(space);
802
803		if (type & MACH_PORT_TYPE_SEND) {
804			assert(port->ip_srights > 0);
805			if (--port->ip_srights == 0) {
806				nsrequest = port->ip_nsrequest;
807				if (nsrequest != IP_NULL) {
808					port->ip_nsrequest = IP_NULL;
809					mscount = port->ip_mscount;
810				}
811			}
812		}
813
814		if (type & MACH_PORT_TYPE_RECEIVE) {
815			queue_head_t links_data;
816			queue_t links = &links_data;
817			wait_queue_link_t wql;
818
819			assert(ip_active(port));
820			assert(port->ip_receiver == space);
821
822			queue_init(links);
823
824			ipc_port_clear_receiver(port, links);
825			ipc_port_destroy(port); /* consumes our ref, unlocks */
826
827			while(!queue_empty(links)) {
828				wql = (wait_queue_link_t) dequeue(links);
829				wait_queue_link_free(wql);
830			}
831
832		} else if (type & MACH_PORT_TYPE_SEND_ONCE) {
833			assert(port->ip_sorights > 0);
834			ip_unlock(port);
835
836			ipc_notify_send_once(port); /* consumes our ref */
837		} else {
838			assert(port->ip_receiver != space);
839
840			ip_unlock(port);
841			ip_release(port);
842		}
843
844		if (nsrequest != IP_NULL)
845			ipc_notify_no_senders(nsrequest, mscount);
846
847		if (request != IP_NULL)
848			ipc_notify_port_deleted(request, name);
849
850
851		break;
852	    }
853
854	    default:
855		panic("ipc_right_destroy: strange type");
856	}
857
858	return KERN_SUCCESS;
859}
860
861/*
862 *	Routine:	ipc_right_dealloc
863 *	Purpose:
864 *		Releases a send/send-once/dead-name user ref.
865 *		Like ipc_right_delta with a delta of -1,
866 *		but looks at the entry to determine the right.
867 *	Conditions:
868 *		The space is write-locked, and is unlocked upon return.
869 *		The space must be active.
870 *	Returns:
871 *		KERN_SUCCESS		A user ref was released.
872 *		KERN_INVALID_RIGHT	Entry has wrong type.
873 */
874
875kern_return_t
876ipc_right_dealloc(
877	ipc_space_t		space,
878	mach_port_name_t	name,
879	ipc_entry_t		entry)
880{
881	ipc_port_t port = IP_NULL;
882	ipc_entry_bits_t bits;
883	mach_port_type_t type;
884
885	bits = entry->ie_bits;
886	type = IE_BITS_TYPE(bits);
887
888
889	assert(is_active(space));
890
891	switch (type) {
892	    case MACH_PORT_TYPE_DEAD_NAME: {
893	    dead_name:
894
895		assert(IE_BITS_UREFS(bits) > 0);
896		assert(entry->ie_request == IE_REQ_NONE);
897		assert(entry->ie_object == IO_NULL);
898
899		if (IE_BITS_UREFS(bits) == 1) {
900			ipc_entry_dealloc(space, name, entry);
901		} else {
902			entry->ie_bits = bits-1; /* decrement urefs */
903			ipc_entry_modified(space, name, entry);
904		}
905		is_write_unlock(space);
906
907		/* release any port that got converted to dead name below */
908		if (port != IP_NULL)
909			ip_release(port);
910		break;
911	    }
912
913	    case MACH_PORT_TYPE_SEND_ONCE: {
914		ipc_port_t request;
915
916		assert(IE_BITS_UREFS(bits) == 1);
917
918		port = (ipc_port_t) entry->ie_object;
919		assert(port != IP_NULL);
920
921		if (ipc_right_check(space, port, name, entry)) {
922
923			bits = entry->ie_bits;
924			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
925			goto dead_name;     /* it will release port */
926		}
927		/* port is locked and active */
928
929		assert(port->ip_sorights > 0);
930
931		request = ipc_right_request_cancel_macro(space, port, name, entry);
932		ip_unlock(port);
933
934		entry->ie_object = IO_NULL;
935		ipc_entry_dealloc(space, name, entry);
936
937		is_write_unlock(space);
938
939		ipc_notify_send_once(port);
940
941		if (request != IP_NULL)
942			ipc_notify_port_deleted(request, name);
943		break;
944	    }
945
946	    case MACH_PORT_TYPE_SEND: {
947		ipc_port_t request = IP_NULL;
948		ipc_port_t nsrequest = IP_NULL;
949		mach_port_mscount_t mscount =  0;
950
951
952		assert(IE_BITS_UREFS(bits) > 0);
953
954		port = (ipc_port_t) entry->ie_object;
955		assert(port != IP_NULL);
956
957		if (ipc_right_check(space, port, name, entry)) {
958			bits = entry->ie_bits;
959			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
960			goto dead_name;     /* it will release port */
961		}
962		/* port is locked and active */
963
964		assert(port->ip_srights > 0);
965
966		if (IE_BITS_UREFS(bits) == 1) {
967			if (--port->ip_srights == 0) {
968				nsrequest = port->ip_nsrequest;
969				if (nsrequest != IP_NULL) {
970					port->ip_nsrequest = IP_NULL;
971					mscount = port->ip_mscount;
972				}
973			}
974
975			request = ipc_right_request_cancel_macro(space, port,
976							     name, entry);
977			ipc_hash_delete(space, (ipc_object_t) port,
978					name, entry);
979
980			ip_unlock(port);
981			entry->ie_object = IO_NULL;
982			ipc_entry_dealloc(space, name, entry);
983			is_write_unlock(space);
984			ip_release(port);
985
986		} else {
987			ip_unlock(port);
988			entry->ie_bits = bits-1; /* decrement urefs */
989			ipc_entry_modified(space, name, entry);
990			is_write_unlock(space);
991		}
992
993
994		if (nsrequest != IP_NULL)
995			ipc_notify_no_senders(nsrequest, mscount);
996
997		if (request != IP_NULL)
998			ipc_notify_port_deleted(request, name);
999		break;
1000	    }
1001
1002	    case MACH_PORT_TYPE_SEND_RECEIVE: {
1003		ipc_port_t nsrequest = IP_NULL;
1004		mach_port_mscount_t mscount = 0;
1005
1006		assert(IE_BITS_UREFS(bits) > 0);
1007
1008		port = (ipc_port_t) entry->ie_object;
1009		assert(port != IP_NULL);
1010
1011		ip_lock(port);
1012		assert(ip_active(port));
1013		assert(port->ip_receiver_name == name);
1014		assert(port->ip_receiver == space);
1015		assert(port->ip_srights > 0);
1016
1017		if (IE_BITS_UREFS(bits) == 1) {
1018			if (--port->ip_srights == 0) {
1019				nsrequest = port->ip_nsrequest;
1020				if (nsrequest != IP_NULL) {
1021					port->ip_nsrequest = IP_NULL;
1022					mscount = port->ip_mscount;
1023				}
1024			}
1025
1026			entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK |
1027						  MACH_PORT_TYPE_SEND);
1028		} else
1029			entry->ie_bits = bits-1; /* decrement urefs */
1030
1031		ip_unlock(port);
1032
1033		ipc_entry_modified(space, name, entry);
1034		is_write_unlock(space);
1035
1036		if (nsrequest != IP_NULL)
1037			ipc_notify_no_senders(nsrequest, mscount);
1038		break;
1039	    }
1040
1041	    default:
1042		is_write_unlock(space);
1043		return KERN_INVALID_RIGHT;
1044	}
1045
1046	return KERN_SUCCESS;
1047}
1048
1049/*
1050 *	Routine:	ipc_right_delta
1051 *	Purpose:
1052 *		Modifies the user-reference count for a right.
1053 *		May deallocate the right, if the count goes to zero.
1054 *	Conditions:
1055 *		The space is write-locked, and is unlocked upon return.
1056 *		The space must be active.
1057 *	Returns:
1058 *		KERN_SUCCESS		Count was modified.
1059 *		KERN_INVALID_RIGHT	Entry has wrong type.
1060 *		KERN_INVALID_VALUE	Bad delta for the right.
1061 *		KERN_UREFS_OVERFLOW	OK delta, except would overflow.
1062 */
1063
1064kern_return_t
1065ipc_right_delta(
1066	ipc_space_t		space,
1067	mach_port_name_t	name,
1068	ipc_entry_t		entry,
1069	mach_port_right_t	right,
1070	mach_port_delta_t	delta)
1071{
1072	ipc_port_t port = IP_NULL;
1073	ipc_entry_bits_t bits;
1074
1075	bits = entry->ie_bits;
1076
1077
1078/*
1079 *	The following is used (for case MACH_PORT_RIGHT_DEAD_NAME) in the
1080 *	switch below. It is used to keep track of those cases (in DIPC)
1081 *	where we have postponed the dropping of a port reference. Since
1082 *	the dropping of the reference could cause the port to disappear
1083 *	we postpone doing so when we are holding the space lock.
1084 */
1085
1086	assert(is_active(space));
1087	assert(right < MACH_PORT_RIGHT_NUMBER);
1088
1089	/* Rights-specific restrictions and operations. */
1090
1091	switch (right) {
1092	    case MACH_PORT_RIGHT_PORT_SET: {
1093		ipc_pset_t pset;
1094
1095		if ((bits & MACH_PORT_TYPE_PORT_SET) == 0)
1096			goto invalid_right;
1097
1098		assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_PORT_SET);
1099		assert(IE_BITS_UREFS(bits) == 0);
1100		assert(entry->ie_request == IE_REQ_NONE);
1101
1102		if (delta == 0)
1103			goto success;
1104
1105		if (delta != -1)
1106			goto invalid_value;
1107
1108		pset = (ipc_pset_t) entry->ie_object;
1109		assert(pset != IPS_NULL);
1110
1111		entry->ie_object = IO_NULL;
1112		ipc_entry_dealloc(space, name, entry);
1113
1114		ips_lock(pset);
1115		assert(ips_active(pset));
1116		is_write_unlock(space);
1117
1118		ipc_pset_destroy(pset); /* consumes ref, unlocks */
1119		break;
1120	    }
1121
1122	    case MACH_PORT_RIGHT_RECEIVE: {
1123		ipc_port_t request = IP_NULL;
1124		queue_head_t links_data;
1125		queue_t links = &links_data;
1126		wait_queue_link_t wql;
1127
1128		if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1129			goto invalid_right;
1130
1131		if (delta == 0)
1132			goto success;
1133
1134		if (delta != -1)
1135			goto invalid_value;
1136
1137		port = (ipc_port_t) entry->ie_object;
1138		assert(port != IP_NULL);
1139
1140		/*
1141		 *	The port lock is needed for ipc_right_dncancel;
1142		 *	otherwise, we wouldn't have to take the lock
1143		 *	until just before dropping the space lock.
1144		 */
1145
1146		ip_lock(port);
1147		assert(ip_active(port));
1148		assert(port->ip_receiver_name == name);
1149		assert(port->ip_receiver == space);
1150
1151		/* Mach Port Guard Checking */
1152		if(port->ip_guarded) {
1153			uint64_t portguard = port->ip_context;
1154			ip_unlock(port);
1155			is_write_unlock(space);
1156			/* Raise mach port guard exception */
1157			mach_port_guard_exception(name, 0, portguard, kGUARD_EXC_MOD_REFS);
1158			goto guard_failure;
1159		}
1160
1161		if (bits & MACH_PORT_TYPE_SEND) {
1162			assert(IE_BITS_TYPE(bits) ==
1163					MACH_PORT_TYPE_SEND_RECEIVE);
1164			assert(IE_BITS_UREFS(bits) > 0);
1165			assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX);
1166			assert(port->ip_srights > 0);
1167
1168			if (port->ip_pdrequest != NULL) {
1169				/*
1170				 * Since another task has requested a
1171				 * destroy notification for this port, it
1172				 * isn't actually being destroyed - the receive
1173				 * right is just being moved to another task.
1174				 * Since we still have one or more send rights,
1175				 * we need to record the loss of the receive
1176				 * right and enter the remaining send right
1177				 * into the hash table.
1178				 */
1179				ipc_entry_modified(space, name, entry);
1180				entry->ie_bits &= ~MACH_PORT_TYPE_RECEIVE;
1181				ipc_hash_insert(space, (ipc_object_t) port,
1182				    name, entry);
1183				ip_reference(port);
1184			} else {
1185				/*
1186				 *	The remaining send right turns into a
1187				 *	dead name.  Notice we don't decrement
1188				 *	ip_srights, generate a no-senders notif,
1189				 *	or use ipc_right_dncancel, because the
1190				 *	port is destroyed "first".
1191				 */
1192				bits &= ~IE_BITS_TYPE_MASK;
1193				bits |= MACH_PORT_TYPE_DEAD_NAME;
1194				if (entry->ie_request) {
1195					entry->ie_request = IE_REQ_NONE;
1196					bits++;
1197				}
1198				entry->ie_bits = bits;
1199				entry->ie_object = IO_NULL;
1200				ipc_entry_modified(space, name, entry);
1201			}
1202		} else {
1203			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
1204			assert(IE_BITS_UREFS(bits) == 0);
1205
1206			request = ipc_right_request_cancel_macro(space, port,
1207							     name, entry);
1208			entry->ie_object = IO_NULL;
1209			ipc_entry_dealloc(space, name, entry);
1210		}
1211		is_write_unlock(space);
1212
1213		queue_init(links);
1214		ipc_port_clear_receiver(port, links);
1215		ipc_port_destroy(port);	/* consumes ref, unlocks */
1216
1217		while(!queue_empty(links)) {
1218			wql = (wait_queue_link_t) dequeue(links);
1219			wait_queue_link_free(wql);
1220		}
1221
1222		if (request != IP_NULL)
1223			ipc_notify_port_deleted(request, name);
1224		break;
1225	    }
1226
1227	    case MACH_PORT_RIGHT_SEND_ONCE: {
1228		ipc_port_t request;
1229
1230		if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0)
1231			goto invalid_right;
1232
1233		assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1234		assert(IE_BITS_UREFS(bits) == 1);
1235
1236		port = (ipc_port_t) entry->ie_object;
1237		assert(port != IP_NULL);
1238
1239		if (ipc_right_check(space, port, name, entry)) {
1240			assert(!(entry->ie_bits & MACH_PORT_TYPE_SEND_ONCE));
1241			goto invalid_right;
1242		}
1243		/* port is locked and active */
1244
1245		assert(port->ip_sorights > 0);
1246
1247		if ((delta > 0) || (delta < -1)) {
1248			ip_unlock(port);
1249			goto invalid_value;
1250		}
1251
1252		if (delta == 0) {
1253			ip_unlock(port);
1254			goto success;
1255		}
1256
1257		request = ipc_right_request_cancel_macro(space, port, name, entry);
1258		ip_unlock(port);
1259
1260		entry->ie_object = IO_NULL;
1261		ipc_entry_dealloc(space, name, entry);
1262
1263		is_write_unlock(space);
1264
1265		ipc_notify_send_once(port);
1266
1267		if (request != IP_NULL)
1268			ipc_notify_port_deleted(request, name);
1269		break;
1270	    }
1271
1272	    case MACH_PORT_RIGHT_DEAD_NAME: {
1273		ipc_port_t relport = IP_NULL;
1274		mach_port_urefs_t urefs;
1275
1276		if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
1277
1278			port = (ipc_port_t) entry->ie_object;
1279			assert(port != IP_NULL);
1280
1281			if (!ipc_right_check(space, port, name, entry)) {
1282				/* port is locked and active */
1283				ip_unlock(port);
1284				port = IP_NULL;
1285				goto invalid_right;
1286			}
1287			bits = entry->ie_bits;
1288			relport = port;
1289			port = IP_NULL;
1290		} else if ((bits & MACH_PORT_TYPE_DEAD_NAME) == 0)
1291			goto invalid_right;
1292
1293		assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1294		assert(IE_BITS_UREFS(bits) > 0);
1295		assert(entry->ie_object == IO_NULL);
1296		assert(entry->ie_request == IE_REQ_NONE);
1297
1298		urefs = IE_BITS_UREFS(bits);
1299		if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta))
1300			goto invalid_value;
1301		if (MACH_PORT_UREFS_OVERFLOW(urefs, delta))
1302			goto urefs_overflow;
1303
1304		if ((urefs + delta) == 0) {
1305			ipc_entry_dealloc(space, name, entry);
1306		} else {
1307			entry->ie_bits = bits + delta;
1308			ipc_entry_modified(space, name, entry);
1309		}
1310		is_write_unlock(space);
1311
1312		if (relport != IP_NULL)
1313			ip_release(relport);
1314
1315		break;
1316	    }
1317
1318	    case MACH_PORT_RIGHT_SEND: {
1319		mach_port_urefs_t urefs;
1320		ipc_port_t request = IP_NULL;
1321		ipc_port_t nsrequest = IP_NULL;
1322		mach_port_mscount_t mscount = 0;
1323
1324		if ((bits & MACH_PORT_TYPE_SEND) == 0)
1325			goto invalid_right;
1326
1327		/* maximum urefs for send is MACH_PORT_UREFS_MAX-1 */
1328
1329		port = (ipc_port_t) entry->ie_object;
1330		assert(port != IP_NULL);
1331
1332		if (ipc_right_check(space, port, name, entry)) {
1333			assert((entry->ie_bits & MACH_PORT_TYPE_SEND) == 0);
1334			goto invalid_right;
1335		}
1336		/* port is locked and active */
1337
1338		assert(port->ip_srights > 0);
1339
1340		urefs = IE_BITS_UREFS(bits);
1341		if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta)) {
1342			ip_unlock(port);
1343			goto invalid_value;
1344		}
1345		if (MACH_PORT_UREFS_OVERFLOW(urefs+1, delta)) {
1346			ip_unlock(port);
1347			goto urefs_overflow;
1348		}
1349
1350		if ((urefs + delta) == 0) {
1351			if (--port->ip_srights == 0) {
1352				nsrequest = port->ip_nsrequest;
1353				if (nsrequest != IP_NULL) {
1354					port->ip_nsrequest = IP_NULL;
1355					mscount = port->ip_mscount;
1356				}
1357			}
1358
1359			if (bits & MACH_PORT_TYPE_RECEIVE) {
1360				assert(port->ip_receiver_name == name);
1361				assert(port->ip_receiver == space);
1362				ip_unlock(port);
1363				assert(IE_BITS_TYPE(bits) ==
1364						MACH_PORT_TYPE_SEND_RECEIVE);
1365
1366				entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK|
1367						       MACH_PORT_TYPE_SEND);
1368				ipc_entry_modified(space, name, entry);
1369			} else {
1370				assert(IE_BITS_TYPE(bits) ==
1371						MACH_PORT_TYPE_SEND);
1372
1373				request = ipc_right_request_cancel_macro(space, port,
1374								     name, entry);
1375				ipc_hash_delete(space, (ipc_object_t) port,
1376						name, entry);
1377
1378				ip_unlock(port);
1379				ip_release(port);
1380
1381				entry->ie_object = IO_NULL;
1382				ipc_entry_dealloc(space, name, entry);
1383			}
1384		} else {
1385			ip_unlock(port);
1386			entry->ie_bits = bits + delta;
1387			ipc_entry_modified(space, name, entry);
1388		}
1389
1390		is_write_unlock(space);
1391
1392		if (nsrequest != IP_NULL)
1393			ipc_notify_no_senders(nsrequest, mscount);
1394
1395		if (request != IP_NULL)
1396			ipc_notify_port_deleted(request, name);
1397		break;
1398	    }
1399
1400	    default:
1401		panic("ipc_right_delta: strange right");
1402	}
1403
1404	return KERN_SUCCESS;
1405
1406    success:
1407	is_write_unlock(space);
1408	return KERN_SUCCESS;
1409
1410    invalid_right:
1411	is_write_unlock(space);
1412	if (port != IP_NULL)
1413		ip_release(port);
1414	return KERN_INVALID_RIGHT;
1415
1416    invalid_value:
1417	is_write_unlock(space);
1418	return KERN_INVALID_VALUE;
1419
1420    urefs_overflow:
1421	is_write_unlock(space);
1422	return KERN_UREFS_OVERFLOW;
1423
1424    guard_failure:
1425	return KERN_INVALID_RIGHT;
1426}
1427
1428/*
1429 *	Routine:	ipc_right_destruct
1430 *	Purpose:
1431 *		Deallocates the receive right and modifies the
1432 *		user-reference count for the send rights as requested.
1433 *	Conditions:
1434 *		The space is write-locked, and is unlocked upon return.
1435 *		The space must be active.
1436 *	Returns:
1437 *		KERN_SUCCESS		Count was modified.
1438 *		KERN_INVALID_RIGHT	Entry has wrong type.
1439 *		KERN_INVALID_VALUE	Bad delta for the right.
1440 */
1441
1442kern_return_t
1443ipc_right_destruct(
1444	ipc_space_t		space,
1445	mach_port_name_t	name,
1446	ipc_entry_t		entry,
1447	mach_port_delta_t	srdelta,
1448	uint64_t		guard)
1449{
1450	ipc_port_t port = IP_NULL;
1451	ipc_entry_bits_t bits;
1452
1453	queue_head_t links_data;
1454	queue_t links = &links_data;
1455	wait_queue_link_t wql;
1456
1457	mach_port_urefs_t urefs;
1458	ipc_port_t request = IP_NULL;
1459	ipc_port_t nsrequest = IP_NULL;
1460	mach_port_mscount_t mscount = 0;
1461
1462	bits = entry->ie_bits;
1463
1464	assert(is_active(space));
1465
1466	if (((bits & MACH_PORT_TYPE_RECEIVE) == 0) ||
1467	    (srdelta && ((bits & MACH_PORT_TYPE_SEND) == 0))) {
1468		is_write_unlock(space);
1469		return KERN_INVALID_RIGHT;
1470	}
1471
1472	if (srdelta > 0)
1473		goto invalid_value;
1474
1475	port = (ipc_port_t) entry->ie_object;
1476	assert(port != IP_NULL);
1477
1478	ip_lock(port);
1479	assert(ip_active(port));
1480	assert(port->ip_receiver_name == name);
1481	assert(port->ip_receiver == space);
1482
1483	/* Mach Port Guard Checking */
1484	if(port->ip_guarded && (guard != port->ip_context)) {
1485		uint64_t portguard = port->ip_context;
1486		ip_unlock(port);
1487		is_write_unlock(space);
1488		mach_port_guard_exception(name, 0, portguard, kGUARD_EXC_DESTROY);
1489		return KERN_INVALID_ARGUMENT;
1490	}
1491
1492	/*
1493	 * First reduce the send rights as requested and
1494	 * adjust the entry->ie_bits accordingly. The
1495	 * ipc_entry_modified() call is made once the receive
1496	 * right is destroyed too.
1497	 */
1498
1499	if (srdelta) {
1500
1501		assert(port->ip_srights > 0);
1502
1503		urefs = IE_BITS_UREFS(bits);
1504		/*
1505		 * Since we made sure that srdelta is negative,
1506		 * the check for urefs overflow is not required.
1507		 */
1508		if (MACH_PORT_UREFS_UNDERFLOW(urefs, srdelta)) {
1509			ip_unlock(port);
1510			goto invalid_value;
1511		}
1512		if ((urefs + srdelta) == 0) {
1513			if (--port->ip_srights == 0) {
1514				nsrequest = port->ip_nsrequest;
1515				if (nsrequest != IP_NULL) {
1516					port->ip_nsrequest = IP_NULL;
1517					mscount = port->ip_mscount;
1518				}
1519			}
1520			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_RECEIVE);
1521			entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK|
1522					       MACH_PORT_TYPE_SEND);
1523		} else {
1524			entry->ie_bits = bits + srdelta;
1525		}
1526	}
1527
1528	/*
1529	 * Now destroy the receive right. Update space and
1530	 * entry accordingly.
1531	 */
1532
1533	bits = entry->ie_bits;
1534	if (bits & MACH_PORT_TYPE_SEND) {
1535		assert(IE_BITS_UREFS(bits) > 0);
1536		assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX);
1537
1538		if (port->ip_pdrequest != NULL) {
1539			/*
1540			 * Since another task has requested a
1541			 * destroy notification for this port, it
1542			 * isn't actually being destroyed - the receive
1543			 * right is just being moved to another task.
1544			 * Since we still have one or more send rights,
1545			 * we need to record the loss of the receive
1546			 * right and enter the remaining send right
1547			 * into the hash table.
1548			 */
1549			ipc_entry_modified(space, name, entry);
1550			entry->ie_bits &= ~MACH_PORT_TYPE_RECEIVE;
1551			ipc_hash_insert(space, (ipc_object_t) port,
1552			    name, entry);
1553			ip_reference(port);
1554		} else {
1555			/*
1556			 *	The remaining send right turns into a
1557			 *	dead name.  Notice we don't decrement
1558			 *	ip_srights, generate a no-senders notif,
1559			 *	or use ipc_right_dncancel, because the
1560			 *	port is destroyed "first".
1561			 */
1562			bits &= ~IE_BITS_TYPE_MASK;
1563			bits |= MACH_PORT_TYPE_DEAD_NAME;
1564			if (entry->ie_request) {
1565				entry->ie_request = IE_REQ_NONE;
1566				bits++;
1567			}
1568			entry->ie_bits = bits;
1569			entry->ie_object = IO_NULL;
1570			ipc_entry_modified(space, name, entry);
1571		}
1572	} else {
1573		assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
1574		assert(IE_BITS_UREFS(bits) == 0);
1575		request = ipc_right_request_cancel_macro(space, port,
1576						     name, entry);
1577		entry->ie_object = IO_NULL;
1578		ipc_entry_dealloc(space, name, entry);
1579	}
1580
1581	/* Unlock space */
1582	is_write_unlock(space);
1583
1584	if (nsrequest != IP_NULL)
1585		ipc_notify_no_senders(nsrequest, mscount);
1586
1587	queue_init(links);
1588	ipc_port_clear_receiver(port, links);
1589	ipc_port_destroy(port);	/* consumes ref, unlocks */
1590
1591	while(!queue_empty(links)) {
1592		wql = (wait_queue_link_t) dequeue(links);
1593		wait_queue_link_free(wql);
1594	}
1595
1596	if (request != IP_NULL)
1597		ipc_notify_port_deleted(request, name);
1598
1599	return KERN_SUCCESS;
1600
1601    invalid_value:
1602	is_write_unlock(space);
1603	return KERN_INVALID_VALUE;
1604
1605}
1606
1607
1608/*
1609 *	Routine:	ipc_right_info
1610 *	Purpose:
1611 *		Retrieves information about the right.
1612 *	Conditions:
1613 *		The space is active and write-locked.
1614 *	        The space is unlocked upon return.
1615 *	Returns:
1616 *		KERN_SUCCESS		Retrieved info
1617 */
1618
1619kern_return_t
1620ipc_right_info(
1621	ipc_space_t		space,
1622	mach_port_name_t	name,
1623	ipc_entry_t		entry,
1624	mach_port_type_t	*typep,
1625	mach_port_urefs_t	*urefsp)
1626{
1627	ipc_port_t port;
1628	ipc_entry_bits_t bits;
1629	mach_port_type_t type = 0;
1630	ipc_port_request_index_t request;
1631
1632	bits = entry->ie_bits;
1633	request = entry->ie_request;
1634	port = (ipc_port_t) entry->ie_object;
1635
1636	if (bits & MACH_PORT_TYPE_RECEIVE) {
1637		assert(IP_VALID(port));
1638
1639		if (request != IE_REQ_NONE) {
1640			ip_lock(port);
1641			assert(ip_active(port));
1642			type |= ipc_port_request_type(port, name, request);
1643			ip_unlock(port);
1644		}
1645		is_write_unlock(space);
1646
1647	} else if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
1648		/*
1649		 * validate port is still alive - if so, get request
1650		 * types while we still have it locked.  Otherwise,
1651		 * recapture the (now dead) bits.
1652		 */
1653		if (!ipc_right_check(space, port, name, entry)) {
1654			if (request != IE_REQ_NONE)
1655				type |= ipc_port_request_type(port, name, request);
1656			ip_unlock(port);
1657			is_write_unlock(space);
1658		} else {
1659			bits = entry->ie_bits;
1660			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1661			is_write_unlock(space);
1662			ip_release(port);
1663		}
1664	} else {
1665		is_write_unlock(space);
1666	}
1667
1668	type |= IE_BITS_TYPE(bits);
1669
1670	*typep = type;
1671	*urefsp = IE_BITS_UREFS(bits);
1672	return KERN_SUCCESS;
1673}
1674
1675/*
1676 *	Routine:	ipc_right_copyin_check
1677 *	Purpose:
1678 *		Check if a subsequent ipc_right_copyin would succeed.
1679 *	Conditions:
1680 *		The space is locked (read or write) and active.
1681 */
1682
1683boolean_t
1684ipc_right_copyin_check(
1685	__assert_only ipc_space_t	space,
1686	__unused mach_port_name_t	name,
1687	ipc_entry_t			entry,
1688	mach_msg_type_name_t		msgt_name)
1689{
1690	ipc_entry_bits_t bits;
1691	ipc_port_t port;
1692#if CONFIG_MACF_MACH
1693	task_t self = current_task();
1694	int rc = 0;
1695#endif
1696
1697	bits= entry->ie_bits;
1698	assert(is_active(space));
1699
1700	switch (msgt_name) {
1701	    case MACH_MSG_TYPE_MAKE_SEND:
1702		if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1703			return FALSE;
1704
1705#if CONFIG_MACF_MACH
1706		port = (ipc_port_t) entry->ie_object;
1707		ip_lock(port);
1708		tasklabel_lock(self);
1709		rc = mac_port_check_make_send(&self->maclabel, &port->ip_label);                tasklabel_unlock(self);
1710		ip_unlock(port);
1711		if (rc)
1712			return FALSE;
1713#endif
1714		break;
1715
1716	    case MACH_MSG_TYPE_MAKE_SEND_ONCE:
1717		if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1718			return FALSE;
1719
1720#if CONFIG_MACF_MACH
1721		port = (ipc_port_t) entry->ie_object;
1722		ip_lock(port);
1723		tasklabel_lock(self);
1724		rc = mac_port_check_make_send_once(&self->maclabel, &port->ip_label);
1725		tasklabel_unlock(self);
1726		ip_unlock(port);
1727		if (rc)
1728			return FALSE;
1729#endif
1730		break;
1731
1732	    case MACH_MSG_TYPE_MOVE_RECEIVE:
1733		if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1734			return FALSE;
1735
1736#if CONFIG_MACF_MACH
1737		port = (ipc_port_t) entry->ie_object;
1738		ip_lock(port);
1739		tasklabel_lock(self);
1740		rc = mac_port_check_move_receive(&self->maclabel, &port->ip_label);
1741		tasklabel_unlock(self);
1742		ip_unlock(port);
1743		if (rc)
1744                        return FALSE;
1745#endif
1746		break;
1747
1748	    case MACH_MSG_TYPE_COPY_SEND:
1749	    case MACH_MSG_TYPE_MOVE_SEND:
1750	    case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
1751		boolean_t active;
1752
1753		if (bits & MACH_PORT_TYPE_DEAD_NAME)
1754			break;
1755
1756		if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
1757			return FALSE;
1758
1759		port = (ipc_port_t) entry->ie_object;
1760		assert(port != IP_NULL);
1761
1762		ip_lock(port);
1763		active = ip_active(port);
1764#if CONFIG_MACF_MACH
1765		tasklabel_lock(self);
1766		switch (msgt_name) {
1767		case MACH_MSG_TYPE_COPY_SEND:
1768			rc = mac_port_check_copy_send(&self->maclabel,
1769			    &port->ip_label);
1770			break;
1771		case MACH_MSG_TYPE_MOVE_SEND:
1772			rc = mac_port_check_move_send(&self->maclabel,
1773			    &port->ip_label);
1774			break;
1775		case MACH_MSG_TYPE_MOVE_SEND_ONCE:
1776			rc = mac_port_check_move_send_once(&self->maclabel,
1777			    &port->ip_label);
1778			break;
1779		default:
1780			panic("ipc_right_copyin_check: strange rights");
1781		}
1782		tasklabel_unlock(self);
1783		if (rc) {
1784			ip_unlock(port);
1785			return FALSE;
1786		}
1787#endif
1788		ip_unlock(port);
1789
1790		if (!active) {
1791			break;
1792		}
1793
1794		if (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE) {
1795			if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0)
1796				return FALSE;
1797		} else {
1798			if ((bits & MACH_PORT_TYPE_SEND) == 0)
1799				return FALSE;
1800		}
1801
1802		break;
1803	    }
1804
1805	    default:
1806		panic("ipc_right_copyin_check: strange rights");
1807	}
1808
1809	return TRUE;
1810}
1811
1812/*
1813 *	Routine:	ipc_right_copyin
1814 *	Purpose:
1815 *		Copyin a capability from a space.
1816 *		If successful, the caller gets a ref
1817 *		for the resulting object, unless it is IO_DEAD,
1818 *		and possibly a send-once right which should
1819 *		be used in a port-deleted notification.
1820 *
1821 *		If deadok is not TRUE, the copyin operation
1822 *		will fail instead of producing IO_DEAD.
1823 *
1824 *		The entry is never deallocated (except
1825 *		when KERN_INVALID_NAME), so the caller
1826 *		should deallocate the entry if its type
1827 *		is MACH_PORT_TYPE_NONE.
1828 *	Conditions:
1829 *		The space is write-locked and active.
1830 *	Returns:
1831 *		KERN_SUCCESS		Acquired an object, possibly IO_DEAD.
1832 *		KERN_INVALID_RIGHT	Name doesn't denote correct right.
1833 */
1834
1835kern_return_t
1836ipc_right_copyin(
1837	ipc_space_t		space,
1838	mach_port_name_t	name,
1839	ipc_entry_t		entry,
1840	mach_msg_type_name_t	msgt_name,
1841	boolean_t		deadok,
1842	ipc_object_t		*objectp,
1843	ipc_port_t		*sorightp,
1844	ipc_port_t		*releasep,
1845#if IMPORTANCE_INHERITANCE
1846	int			*assertcntp,
1847#endif /* IMPORTANCE_INHERITANCE */
1848	queue_t			links)
1849{
1850	ipc_entry_bits_t bits;
1851	ipc_port_t port;
1852#if CONFIG_MACF_MACH
1853	task_t self = current_task();
1854	int    rc;
1855#endif
1856
1857	*releasep = IP_NULL;
1858
1859#if IMPORTANCE_INHERITANCE
1860	*assertcntp = 0;
1861#endif
1862
1863	bits = entry->ie_bits;
1864
1865	assert(is_active(space));
1866
1867	switch (msgt_name) {
1868	    case MACH_MSG_TYPE_MAKE_SEND: {
1869
1870		if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1871			goto invalid_right;
1872
1873		port = (ipc_port_t) entry->ie_object;
1874		assert(port != IP_NULL);
1875
1876		ip_lock(port);
1877		assert(ip_active(port));
1878		assert(port->ip_receiver_name == name);
1879		assert(port->ip_receiver == space);
1880
1881#if CONFIG_MACF_MACH
1882		tasklabel_lock(self);
1883		rc = mac_port_check_make_send(&self->maclabel, &port->ip_label);
1884		tasklabel_unlock(self);
1885		if (rc) {
1886			ip_unlock(port);
1887			return KERN_NO_ACCESS;
1888		}
1889#endif
1890
1891		port->ip_mscount++;
1892		port->ip_srights++;
1893		ip_reference(port);
1894		ip_unlock(port);
1895
1896		*objectp = (ipc_object_t) port;
1897		*sorightp = IP_NULL;
1898		break;
1899	    }
1900
1901	    case MACH_MSG_TYPE_MAKE_SEND_ONCE: {
1902
1903		if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1904			goto invalid_right;
1905
1906		port = (ipc_port_t) entry->ie_object;
1907		assert(port != IP_NULL);
1908
1909		ip_lock(port);
1910		assert(ip_active(port));
1911		assert(port->ip_receiver_name == name);
1912		assert(port->ip_receiver == space);
1913
1914#if CONFIG_MACF_MACH
1915		tasklabel_lock(self);
1916		rc = mac_port_check_make_send_once(&self->maclabel, &port->ip_label);
1917		tasklabel_unlock(self);
1918		if (rc) {
1919			ip_unlock(port);
1920			return KERN_NO_ACCESS;
1921		}
1922#endif
1923
1924		port->ip_sorights++;
1925		ip_reference(port);
1926		ip_unlock(port);
1927
1928		*objectp = (ipc_object_t) port;
1929		*sorightp = IP_NULL;
1930		break;
1931	    }
1932
1933	    case MACH_MSG_TYPE_MOVE_RECEIVE: {
1934		ipc_port_t request = IP_NULL;
1935
1936		if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1937			goto invalid_right;
1938
1939		port = (ipc_port_t) entry->ie_object;
1940		assert(port != IP_NULL);
1941
1942		ip_lock(port);
1943		assert(ip_active(port));
1944		assert(port->ip_receiver_name == name);
1945		assert(port->ip_receiver == space);
1946
1947#if CONFIG_MACF_MACH
1948		tasklabel_lock(self);
1949		rc = mac_port_check_move_receive(&self->maclabel,
1950						 &port->ip_label);
1951		tasklabel_unlock(self);
1952		if (rc) {
1953			ip_unlock(port);
1954			return KERN_NO_ACCESS;
1955		}
1956#endif
1957
1958		if (bits & MACH_PORT_TYPE_SEND) {
1959			assert(IE_BITS_TYPE(bits) ==
1960					MACH_PORT_TYPE_SEND_RECEIVE);
1961			assert(IE_BITS_UREFS(bits) > 0);
1962			assert(port->ip_srights > 0);
1963
1964			ipc_hash_insert(space, (ipc_object_t) port,
1965					name, entry);
1966			ip_reference(port);
1967		} else {
1968			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
1969			assert(IE_BITS_UREFS(bits) == 0);
1970
1971			request = ipc_right_request_cancel_macro(space, port,
1972							     name, entry);
1973			entry->ie_object = IO_NULL;
1974		}
1975		entry->ie_bits = bits &~ MACH_PORT_TYPE_RECEIVE;
1976		ipc_entry_modified(space, name, entry);
1977
1978		ipc_port_clear_receiver(port, links);
1979		port->ip_receiver_name = MACH_PORT_NULL;
1980		port->ip_destination = IP_NULL;
1981
1982#if IMPORTANCE_INHERITANCE
1983		/*
1984		 * Account for boosts the current task is going to lose when
1985		 * copying this right in.  Tempowner ports have either not
1986		 * been accounting to any task (and therefore are already in
1987		 * "limbo" state w.r.t. assertions) or to some other specific
1988		 * task. As we have no way to drop the latter task's assertions
1989		 * here, We'll deduct those when we enqueue it on its
1990		 * destination port (see ipc_port_check_circularity()).
1991		 */
1992		if (port->ip_tempowner == 0) {
1993			assert(port->ip_taskptr == 0);
1994
1995			/* ports in limbo have to be tempowner */
1996			port->ip_tempowner = 1;
1997			*assertcntp = port->ip_impcount;
1998		}
1999#endif /* IMPORTANCE_INHERITANCE */
2000
2001		ip_unlock(port);
2002
2003		*objectp = (ipc_object_t) port;
2004		*sorightp = request;
2005		break;
2006	    }
2007
2008	    case MACH_MSG_TYPE_COPY_SEND: {
2009
2010		if (bits & MACH_PORT_TYPE_DEAD_NAME)
2011			goto copy_dead;
2012
2013		/* allow for dead send-once rights */
2014
2015		if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
2016			goto invalid_right;
2017
2018		assert(IE_BITS_UREFS(bits) > 0);
2019
2020		port = (ipc_port_t) entry->ie_object;
2021		assert(port != IP_NULL);
2022
2023		if (ipc_right_check(space, port, name, entry)) {
2024			bits = entry->ie_bits;
2025			*releasep = port;
2026			goto copy_dead;
2027		}
2028		/* port is locked and active */
2029
2030#if CONFIG_MACF_MACH
2031		tasklabel_lock(self);
2032		rc = mac_port_check_copy_send(&self->maclabel, &port->ip_label);
2033		tasklabel_unlock(self);
2034		if (rc) {
2035			ip_unlock(port);
2036			return KERN_NO_ACCESS;
2037		}
2038#endif
2039
2040		if ((bits & MACH_PORT_TYPE_SEND) == 0) {
2041			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
2042			assert(port->ip_sorights > 0);
2043
2044			ip_unlock(port);
2045			goto invalid_right;
2046		}
2047
2048		assert(port->ip_srights > 0);
2049
2050		port->ip_srights++;
2051		ip_reference(port);
2052		ip_unlock(port);
2053
2054		*objectp = (ipc_object_t) port;
2055		*sorightp = IP_NULL;
2056		break;
2057	    }
2058
2059	    case MACH_MSG_TYPE_MOVE_SEND: {
2060		ipc_port_t request = IP_NULL;
2061
2062		if (bits & MACH_PORT_TYPE_DEAD_NAME)
2063			goto move_dead;
2064
2065		/* allow for dead send-once rights */
2066
2067		if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
2068			goto invalid_right;
2069
2070		assert(IE_BITS_UREFS(bits) > 0);
2071
2072		port = (ipc_port_t) entry->ie_object;
2073		assert(port != IP_NULL);
2074
2075		if (ipc_right_check(space, port, name, entry)) {
2076			bits = entry->ie_bits;
2077			*releasep = port;
2078			goto move_dead;
2079		}
2080		/* port is locked and active */
2081
2082#if CONFIG_MACF_MACH
2083		tasklabel_lock (self);
2084		rc = mac_port_check_copy_send (&self->maclabel, &port->ip_label);
2085		tasklabel_unlock (self);
2086		if (rc)
2087		  {
2088		    ip_unlock (port);
2089		    return KERN_NO_ACCESS;
2090		  }
2091#endif
2092
2093		if ((bits & MACH_PORT_TYPE_SEND) == 0) {
2094			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
2095			assert(port->ip_sorights > 0);
2096
2097			ip_unlock(port);
2098			goto invalid_right;
2099		}
2100
2101		assert(port->ip_srights > 0);
2102
2103		if (IE_BITS_UREFS(bits) == 1) {
2104			if (bits & MACH_PORT_TYPE_RECEIVE) {
2105				assert(port->ip_receiver_name == name);
2106				assert(port->ip_receiver == space);
2107				assert(IE_BITS_TYPE(bits) ==
2108						MACH_PORT_TYPE_SEND_RECEIVE);
2109
2110				ip_reference(port);
2111			} else {
2112				assert(IE_BITS_TYPE(bits) ==
2113						MACH_PORT_TYPE_SEND);
2114
2115				request = ipc_right_request_cancel_macro(space, port,
2116								     name, entry);
2117				ipc_hash_delete(space, (ipc_object_t) port,
2118						name, entry);
2119				entry->ie_object = IO_NULL;
2120			}
2121			entry->ie_bits = bits &~
2122				(IE_BITS_UREFS_MASK|MACH_PORT_TYPE_SEND);
2123		} else {
2124			port->ip_srights++;
2125			ip_reference(port);
2126			entry->ie_bits = bits-1; /* decrement urefs */
2127		}
2128		ipc_entry_modified(space, name, entry);
2129		ip_unlock(port);
2130
2131		*objectp = (ipc_object_t) port;
2132		*sorightp = request;
2133		break;
2134	    }
2135
2136	    case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
2137		ipc_port_t request;
2138
2139		if (bits & MACH_PORT_TYPE_DEAD_NAME)
2140			goto move_dead;
2141
2142		/* allow for dead send rights */
2143
2144		if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
2145			goto invalid_right;
2146
2147		assert(IE_BITS_UREFS(bits) > 0);
2148
2149		port = (ipc_port_t) entry->ie_object;
2150		assert(port != IP_NULL);
2151
2152		if (ipc_right_check(space, port, name, entry)) {
2153			bits = entry->ie_bits;
2154			goto move_dead;
2155		}
2156		/* port is locked and active */
2157
2158#if CONFIG_MACF_MACH
2159		tasklabel_lock (self);
2160		rc = mac_port_check_copy_send (&self->maclabel, &port->ip_label);
2161		tasklabel_unlock (self);
2162		if (rc)
2163		  {
2164		    ip_unlock (port);
2165		    return KERN_NO_ACCESS;
2166		  }
2167#endif
2168
2169		if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0) {
2170			assert(bits & MACH_PORT_TYPE_SEND);
2171			assert(port->ip_srights > 0);
2172
2173			ip_unlock(port);
2174			goto invalid_right;
2175		}
2176
2177		assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
2178		assert(IE_BITS_UREFS(bits) == 1);
2179		assert(port->ip_sorights > 0);
2180
2181		request = ipc_right_request_cancel_macro(space, port, name, entry);
2182		ip_unlock(port);
2183
2184		entry->ie_object = IO_NULL;
2185		entry->ie_bits = bits &~
2186			(IE_BITS_UREFS_MASK | MACH_PORT_TYPE_SEND_ONCE);
2187		ipc_entry_modified(space, name, entry);
2188		*objectp = (ipc_object_t) port;
2189		*sorightp = request;
2190		break;
2191	    }
2192
2193	    default:
2194	    invalid_right:
2195		return KERN_INVALID_RIGHT;
2196	}
2197
2198	return KERN_SUCCESS;
2199
2200    copy_dead:
2201	assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
2202	assert(IE_BITS_UREFS(bits) > 0);
2203	assert(entry->ie_request == IE_REQ_NONE);
2204	assert(entry->ie_object == 0);
2205
2206	if (!deadok)
2207		goto invalid_right;
2208
2209	*objectp = IO_DEAD;
2210	*sorightp = IP_NULL;
2211	return KERN_SUCCESS;
2212
2213    move_dead:
2214	assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
2215	assert(IE_BITS_UREFS(bits) > 0);
2216	assert(entry->ie_request == IE_REQ_NONE);
2217	assert(entry->ie_object == 0);
2218
2219	if (!deadok)
2220		goto invalid_right;
2221
2222	if (IE_BITS_UREFS(bits) == 1) {
2223		bits &= ~MACH_PORT_TYPE_DEAD_NAME;
2224	}
2225	entry->ie_bits = bits-1; /* decrement urefs */
2226	ipc_entry_modified(space, name, entry);
2227	*objectp = IO_DEAD;
2228	*sorightp = IP_NULL;
2229	return KERN_SUCCESS;
2230
2231}
2232
2233/*
2234 *	Routine:	ipc_right_copyin_undo
2235 *	Purpose:
2236 *		Undoes the effects of an ipc_right_copyin
2237 *		of a send/send-once right that is dead.
2238 *		(Object is either IO_DEAD or a dead port.)
2239 *	Conditions:
2240 *		The space is write-locked and active.
2241 */
2242
2243void
2244ipc_right_copyin_undo(
2245	ipc_space_t		space,
2246	mach_port_name_t	name,
2247	ipc_entry_t		entry,
2248	mach_msg_type_name_t	msgt_name,
2249	ipc_object_t		object,
2250	ipc_port_t		soright)
2251{
2252	ipc_entry_bits_t bits;
2253
2254	bits = entry->ie_bits;
2255
2256	assert(is_active(space));
2257
2258	assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
2259	       (msgt_name == MACH_MSG_TYPE_COPY_SEND) ||
2260	       (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
2261
2262	if (soright != IP_NULL) {
2263		assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
2264		       (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
2265		assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2266		assert(object != IO_DEAD);
2267
2268		entry->ie_bits = ((bits &~ IE_BITS_RIGHT_MASK) |
2269				  MACH_PORT_TYPE_DEAD_NAME | 2);
2270
2271	} else if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE) {
2272		assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
2273		       (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
2274
2275		entry->ie_bits = ((bits &~ IE_BITS_RIGHT_MASK) |
2276				  MACH_PORT_TYPE_DEAD_NAME | 1);
2277	} else if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME) {
2278		assert(object == IO_DEAD);
2279		assert(IE_BITS_UREFS(bits) > 0);
2280
2281		if (msgt_name != MACH_MSG_TYPE_COPY_SEND) {
2282			assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX);
2283			entry->ie_bits = bits+1; /* increment urefs */
2284		}
2285	} else {
2286		assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
2287		       (msgt_name == MACH_MSG_TYPE_COPY_SEND));
2288		assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
2289		assert(object != IO_DEAD);
2290		assert(entry->ie_object == object);
2291		assert(IE_BITS_UREFS(bits) > 0);
2292
2293		if (msgt_name != MACH_MSG_TYPE_COPY_SEND) {
2294			assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX-1);
2295			entry->ie_bits = bits+1; /* increment urefs */
2296		}
2297
2298		/*
2299		 *	May as well convert the entry to a dead name.
2300		 *	(Or if it is a compat entry, destroy it.)
2301		 */
2302
2303		(void) ipc_right_check(space, (ipc_port_t) object,
2304				       name, entry);
2305		/* object is dead so it is not locked */
2306	}
2307	ipc_entry_modified(space, name, entry);
2308	/* release the reference acquired by copyin */
2309
2310	if (object != IO_DEAD)
2311		io_release(object);
2312}
2313
2314/*
2315 *	Routine:	ipc_right_copyin_two
2316 *	Purpose:
2317 *		Like ipc_right_copyin with MACH_MSG_TYPE_MOVE_SEND
2318 *		and deadok == FALSE, except that this moves two
2319 *		send rights at once.
2320 *	Conditions:
2321 *		The space is write-locked and active.
2322 *		The object is returned with two refs/send rights.
2323 *	Returns:
2324 *		KERN_SUCCESS		Acquired an object.
2325 *		KERN_INVALID_RIGHT	Name doesn't denote correct right.
2326 */
2327
2328kern_return_t
2329ipc_right_copyin_two(
2330	ipc_space_t		space,
2331	mach_port_name_t	name,
2332	ipc_entry_t		entry,
2333	ipc_object_t		*objectp,
2334	ipc_port_t		*sorightp,
2335	ipc_port_t		*releasep)
2336{
2337	ipc_entry_bits_t bits;
2338	mach_port_urefs_t urefs;
2339	ipc_port_t port;
2340	ipc_port_t request = IP_NULL;
2341#if CONFIG_MACF_MACH
2342	task_t self = current_task();
2343	int    rc;
2344#endif
2345
2346	*releasep = IP_NULL;
2347
2348	assert(is_active(space));
2349
2350	bits = entry->ie_bits;
2351
2352	if ((bits & MACH_PORT_TYPE_SEND) == 0)
2353		goto invalid_right;
2354
2355	urefs = IE_BITS_UREFS(bits);
2356	if (urefs < 2)
2357		goto invalid_right;
2358
2359	port = (ipc_port_t) entry->ie_object;
2360	assert(port != IP_NULL);
2361
2362	if (ipc_right_check(space, port, name, entry)) {
2363		*releasep = port;
2364		goto invalid_right;
2365	}
2366	/* port is locked and active */
2367
2368#if CONFIG_MACF_MACH
2369	tasklabel_lock(self);
2370	rc = mac_port_check_copy_send(&self->maclabel, &port->ip_label);
2371	tasklabel_unlock(self);
2372	if (rc) {
2373		ip_unlock(port);
2374		return KERN_NO_ACCESS;
2375	}
2376#endif
2377
2378	assert(port->ip_srights > 0);
2379
2380	if (urefs == 2) {
2381		if (bits & MACH_PORT_TYPE_RECEIVE) {
2382			assert(port->ip_receiver_name == name);
2383			assert(port->ip_receiver == space);
2384			assert(IE_BITS_TYPE(bits) ==
2385					MACH_PORT_TYPE_SEND_RECEIVE);
2386
2387			port->ip_srights++;
2388			ip_reference(port);
2389			ip_reference(port);
2390		} else {
2391			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
2392
2393			request = ipc_right_request_cancel_macro(space, port,
2394							     name, entry);
2395
2396			port->ip_srights++;
2397			ip_reference(port);
2398			ipc_hash_delete(space, (ipc_object_t) port,
2399					name, entry);
2400			entry->ie_object = IO_NULL;
2401		}
2402		entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK|MACH_PORT_TYPE_SEND);
2403	} else {
2404		port->ip_srights += 2;
2405		ip_reference(port);
2406		ip_reference(port);
2407		entry->ie_bits = bits-2; /* decrement urefs */
2408	}
2409	ipc_entry_modified(space, name, entry);
2410
2411	ip_unlock(port);
2412
2413	*objectp = (ipc_object_t) port;
2414	*sorightp = request;
2415	return KERN_SUCCESS;
2416
2417    invalid_right:
2418	return KERN_INVALID_RIGHT;
2419}
2420
2421/*
2422 *	Routine:	ipc_right_copyout
2423 *	Purpose:
2424 *		Copyout a capability to a space.
2425 *		If successful, consumes a ref for the object.
2426 *
2427 *		Always succeeds when given a newly-allocated entry,
2428 *		because user-reference overflow isn't a possibility.
2429 *
2430 *		If copying out the object would cause the user-reference
2431 *		count in the entry to overflow, and overflow is TRUE,
2432 *		then instead the user-reference count is left pegged
2433 *		to its maximum value and the copyout succeeds anyway.
2434 *	Conditions:
2435 *		The space is write-locked and active.
2436 *		The object is locked and active.
2437 *		The object is unlocked; the space isn't.
2438 *	Returns:
2439 *		KERN_SUCCESS		Copied out capability.
2440 *		KERN_UREFS_OVERFLOW	User-refs would overflow;
2441 *			guaranteed not to happen with a fresh entry
2442 *			or if overflow=TRUE was specified.
2443 */
2444
2445kern_return_t
2446ipc_right_copyout(
2447	ipc_space_t		space,
2448	mach_port_name_t	name,
2449	ipc_entry_t		entry,
2450	mach_msg_type_name_t	msgt_name,
2451	boolean_t		overflow,
2452	ipc_object_t		object)
2453{
2454	ipc_entry_bits_t bits;
2455	ipc_port_t port;
2456#if CONFIG_MACF_MACH
2457	int rc;
2458#endif
2459
2460	bits = entry->ie_bits;
2461
2462	assert(IO_VALID(object));
2463	assert(io_otype(object) == IOT_PORT);
2464	assert(io_active(object));
2465	assert(entry->ie_object == object);
2466
2467	port = (ipc_port_t) object;
2468
2469	switch (msgt_name) {
2470	    case MACH_MSG_TYPE_PORT_SEND_ONCE:
2471
2472		assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2473		assert(port->ip_sorights > 0);
2474
2475#if CONFIG_MACF_MACH
2476		if (space->is_task) {
2477			tasklabel_lock(space->is_task);
2478			rc = mac_port_check_hold_send_once(&space->is_task->maclabel,
2479							   &port->ip_label);
2480			tasklabel_unlock(space->is_task);
2481
2482			if (rc) {
2483				ip_unlock(port);
2484				return KERN_NO_ACCESS;
2485			}
2486		}
2487#endif
2488		/* transfer send-once right and ref to entry */
2489		ip_unlock(port);
2490
2491		entry->ie_bits = bits | (MACH_PORT_TYPE_SEND_ONCE | 1);
2492		ipc_entry_modified(space, name, entry);
2493		break;
2494
2495	    case MACH_MSG_TYPE_PORT_SEND:
2496		assert(port->ip_srights > 0);
2497
2498#if CONFIG_MACF_MACH
2499		if (space->is_task) {
2500			tasklabel_lock(space->is_task);
2501			rc = mac_port_check_hold_send(&space->is_task->maclabel,
2502						      &port->ip_label);
2503			tasklabel_unlock(space->is_task);
2504
2505			if (rc) {
2506				ip_unlock(port);
2507				return KERN_NO_ACCESS;
2508			}
2509		}
2510#endif
2511
2512		if (bits & MACH_PORT_TYPE_SEND) {
2513			mach_port_urefs_t urefs = IE_BITS_UREFS(bits);
2514
2515			assert(port->ip_srights > 1);
2516			assert(urefs > 0);
2517			assert(urefs < MACH_PORT_UREFS_MAX);
2518
2519			if (urefs+1 == MACH_PORT_UREFS_MAX) {
2520				if (overflow) {
2521					/* leave urefs pegged to maximum */
2522
2523					port->ip_srights--;
2524					ip_unlock(port);
2525					ip_release(port);
2526					return KERN_SUCCESS;
2527				}
2528
2529				ip_unlock(port);
2530				return KERN_UREFS_OVERFLOW;
2531			}
2532			port->ip_srights--;
2533			ip_unlock(port);
2534			ip_release(port);
2535
2536		} else if (bits & MACH_PORT_TYPE_RECEIVE) {
2537			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
2538			assert(IE_BITS_UREFS(bits) == 0);
2539
2540			/* transfer send right to entry */
2541			ip_unlock(port);
2542			ip_release(port);
2543
2544		} else {
2545			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2546			assert(IE_BITS_UREFS(bits) == 0);
2547
2548			/* transfer send right and ref to entry */
2549			ip_unlock(port);
2550
2551			/* entry is locked holding ref, so can use port */
2552
2553			ipc_hash_insert(space, (ipc_object_t) port,
2554					name, entry);
2555		}
2556
2557		entry->ie_bits = (bits | MACH_PORT_TYPE_SEND) + 1;
2558		ipc_entry_modified(space, name, entry);
2559		break;
2560
2561	    case MACH_MSG_TYPE_PORT_RECEIVE: {
2562		ipc_port_t dest;
2563
2564#if IMPORTANCE_INHERITANCE
2565		natural_t assertcnt = port->ip_impcount;
2566#endif /* IMPORTANCE_INHERITANCE */
2567
2568		assert(port->ip_mscount == 0);
2569		assert(port->ip_receiver_name == MACH_PORT_NULL);
2570		dest = port->ip_destination;
2571
2572#if CONFIG_MACF_MACH
2573		if (space->is_task) {
2574			tasklabel_lock(space->is_task);
2575			rc = mac_port_check_hold_receive(&space->is_task->maclabel,
2576							 &port->ip_label);
2577			tasklabel_unlock(space->is_task);
2578
2579			if (rc) {
2580				ip_unlock(port);
2581				return KERN_NO_ACCESS;
2582			}
2583		}
2584#endif
2585
2586		port->ip_receiver_name = name;
2587		port->ip_receiver = space;
2588
2589		assert((bits & MACH_PORT_TYPE_RECEIVE) == 0);
2590
2591		if (bits & MACH_PORT_TYPE_SEND) {
2592			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
2593			assert(IE_BITS_UREFS(bits) > 0);
2594			assert(port->ip_srights > 0);
2595
2596			ip_unlock(port);
2597			ip_release(port);
2598
2599			/* entry is locked holding ref, so can use port */
2600
2601			ipc_hash_delete(space, (ipc_object_t) port,
2602					name, entry);
2603		} else {
2604			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2605			assert(IE_BITS_UREFS(bits) == 0);
2606
2607			/* transfer ref to entry */
2608			ip_unlock(port);
2609		}
2610		entry->ie_bits = bits | MACH_PORT_TYPE_RECEIVE;
2611		ipc_entry_modified(space, name, entry);
2612
2613		if (dest != IP_NULL) {
2614#if IMPORTANCE_INHERITANCE
2615			/*
2616			 * Deduct the assertion counts we contributed to
2617			 * the old destination port.  They've already
2618			 * been reflected into the task as a result of
2619			 * getting enqueued.
2620			 */
2621			ip_lock(dest);
2622			assert(dest->ip_impcount >= assertcnt);
2623			dest->ip_impcount -= assertcnt;
2624			ip_unlock(dest);
2625#endif /* IMPORTANCE_INHERITANCE */
2626			ip_release(dest);
2627		}
2628		break;
2629	    }
2630
2631	    default:
2632		panic("ipc_right_copyout: strange rights");
2633	}
2634	return KERN_SUCCESS;
2635}
2636
2637/*
2638 *	Routine:	ipc_right_rename
2639 *	Purpose:
2640 *		Transfer an entry from one name to another.
2641 *		The old entry is deallocated.
2642 *	Conditions:
2643 *		The space is write-locked and active.
2644 *		The new entry is unused.  Upon return,
2645 *		the space is unlocked.
2646 *	Returns:
2647 *		KERN_SUCCESS		Moved entry to new name.
2648 */
2649
2650kern_return_t
2651ipc_right_rename(
2652	ipc_space_t		space,
2653	mach_port_name_t	oname,
2654	ipc_entry_t		oentry,
2655	mach_port_name_t	nname,
2656	ipc_entry_t		nentry)
2657{
2658	ipc_port_request_index_t request = oentry->ie_request;
2659	ipc_entry_bits_t bits = oentry->ie_bits;
2660	ipc_object_t object = oentry->ie_object;
2661	ipc_port_t release_port = IP_NULL;
2662
2663	assert(is_active(space));
2664	assert(oname != nname);
2665
2666	/*
2667	 *	If IE_BITS_COMPAT, we can't allow the entry to be renamed
2668	 *	if the port is dead.  (This would foil ipc_port_destroy.)
2669	 *	Instead we should fail because oentry shouldn't exist.
2670	 *	Note IE_BITS_COMPAT implies ie_request != 0.
2671	 */
2672
2673	if (request != IE_REQ_NONE) {
2674		ipc_port_t port;
2675
2676		assert(bits & MACH_PORT_TYPE_PORT_RIGHTS);
2677		port = (ipc_port_t) object;
2678		assert(port != IP_NULL);
2679
2680		if (ipc_right_check(space, port, oname, oentry)) {
2681			request = IE_REQ_NONE;
2682			object = IO_NULL;
2683			bits = oentry->ie_bits;
2684			release_port = port;
2685			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
2686			assert(oentry->ie_request == IE_REQ_NONE);
2687		} else {
2688			/* port is locked and active */
2689
2690			ipc_port_request_rename(port, request, oname, nname);
2691			ip_unlock(port);
2692			oentry->ie_request = IE_REQ_NONE;
2693		}
2694	}
2695
2696	/* initialize nentry before letting ipc_hash_insert see it */
2697
2698	assert((nentry->ie_bits & IE_BITS_RIGHT_MASK) == 0);
2699	nentry->ie_bits |= bits & IE_BITS_RIGHT_MASK;
2700	nentry->ie_request = request;
2701	nentry->ie_object = object;
2702
2703	switch (IE_BITS_TYPE(bits)) {
2704	    case MACH_PORT_TYPE_SEND: {
2705		ipc_port_t port;
2706
2707		port = (ipc_port_t) object;
2708		assert(port != IP_NULL);
2709
2710		/* remember, there are no other share entries possible */
2711		/* or we can't do the rename.  Therefore we do not need */
2712		/* to check the other subspaces */
2713	  	ipc_hash_delete(space, (ipc_object_t) port, oname, oentry);
2714		ipc_hash_insert(space, (ipc_object_t) port, nname, nentry);
2715		break;
2716	    }
2717
2718	    case MACH_PORT_TYPE_RECEIVE:
2719	    case MACH_PORT_TYPE_SEND_RECEIVE: {
2720		ipc_port_t port;
2721
2722		port = (ipc_port_t) object;
2723		assert(port != IP_NULL);
2724
2725		ip_lock(port);
2726		assert(ip_active(port));
2727		assert(port->ip_receiver_name == oname);
2728		assert(port->ip_receiver == space);
2729
2730		port->ip_receiver_name = nname;
2731		ip_unlock(port);
2732		break;
2733	    }
2734
2735	    case MACH_PORT_TYPE_PORT_SET: {
2736		ipc_pset_t pset;
2737
2738		pset = (ipc_pset_t) object;
2739		assert(pset != IPS_NULL);
2740
2741		ips_lock(pset);
2742		assert(ips_active(pset));
2743		assert(pset->ips_local_name == oname);
2744
2745		pset->ips_local_name = nname;
2746		ips_unlock(pset);
2747		break;
2748	    }
2749
2750	    case MACH_PORT_TYPE_SEND_ONCE:
2751	    case MACH_PORT_TYPE_DEAD_NAME:
2752		break;
2753
2754	    default:
2755		panic("ipc_right_rename: strange rights");
2756	}
2757
2758	assert(oentry->ie_request == IE_REQ_NONE);
2759	oentry->ie_object = IO_NULL;
2760	ipc_entry_dealloc(space, oname, oentry);
2761	ipc_entry_modified(space, nname, nentry);
2762	is_write_unlock(space);
2763
2764	if (release_port != IP_NULL)
2765		ip_release(release_port);
2766
2767	return KERN_SUCCESS;
2768}
2769