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