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