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_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_object.c
67 *	Author:	Rich Draves
68 *	Date:	1989
69 *
70 *	Functions to manipulate IPC objects.
71 */
72
73#include <mach_rt.h>
74
75#include <mach/mach_types.h>
76#include <mach/boolean.h>
77#include <mach/kern_return.h>
78#include <mach/port.h>
79#include <mach/message.h>
80
81#include <kern/kern_types.h>
82#include <kern/misc_protos.h>
83#include <kern/ipc_kobject.h>
84
85#include <ipc/ipc_types.h>
86#include <ipc/ipc_importance.h>
87#include <ipc/port.h>
88#include <ipc/ipc_space.h>
89#include <ipc/ipc_entry.h>
90#include <ipc/ipc_object.h>
91#include <ipc/ipc_hash.h>
92#include <ipc/ipc_right.h>
93#include <ipc/ipc_notify.h>
94#include <ipc/ipc_port.h>
95#include <ipc/ipc_pset.h>
96
97#include <security/mac_mach_internal.h>
98
99zone_t ipc_object_zones[IOT_NUMBER];
100
101/*
102 *	Routine:	ipc_object_reference
103 *	Purpose:
104 *		Take a reference to an object.
105 */
106
107void
108ipc_object_reference(
109	ipc_object_t	object)
110{
111	io_reference(object);
112}
113
114/*
115 *	Routine:	ipc_object_release
116 *	Purpose:
117 *		Release a reference to an object.
118 */
119
120void
121ipc_object_release(
122	ipc_object_t	object)
123{
124	io_release(object);
125}
126
127/*
128 *	Routine:	ipc_object_translate
129 *	Purpose:
130 *		Look up an object in a space.
131 *	Conditions:
132 *		Nothing locked before.  If successful, the object
133 *		is returned locked.  The caller doesn't get a ref.
134 *	Returns:
135 *		KERN_SUCCESS		Object returned locked.
136 *		KERN_INVALID_TASK	The space is dead.
137 *		KERN_INVALID_NAME	The name doesn't denote a right.
138 *		KERN_INVALID_RIGHT	Name doesn't denote the correct right.
139 */
140
141kern_return_t
142ipc_object_translate(
143	ipc_space_t		space,
144	mach_port_name_t	name,
145	mach_port_right_t	right,
146	ipc_object_t		*objectp)
147{
148	ipc_entry_t entry;
149	ipc_object_t object;
150	kern_return_t kr;
151
152	kr = ipc_right_lookup_read(space, name, &entry);
153	if (kr != KERN_SUCCESS)
154		return kr;
155	/* space is read-locked and active */
156
157	if ((entry->ie_bits & MACH_PORT_TYPE(right)) == MACH_PORT_TYPE_NONE) {
158		is_read_unlock(space);
159		return KERN_INVALID_RIGHT;
160	}
161
162	object = entry->ie_object;
163	assert(object != IO_NULL);
164
165	io_lock(object);
166	is_read_unlock(space);
167
168	*objectp = object;
169	return KERN_SUCCESS;
170}
171
172/*
173 *	Routine:	ipc_object_translate_two
174 *	Purpose:
175 *		Look up two objects in a space.
176 *	Conditions:
177 *		Nothing locked before.  If successful, the objects
178 *		are returned locked.  The caller doesn't get a ref.
179 *	Returns:
180 *		KERN_SUCCESS		Objects returned locked.
181 *		KERN_INVALID_TASK	The space is dead.
182 *		KERN_INVALID_NAME	A name doesn't denote a right.
183 *		KERN_INVALID_RIGHT	A name doesn't denote the correct right.
184 */
185
186kern_return_t
187ipc_object_translate_two(
188	ipc_space_t		space,
189	mach_port_name_t	name1,
190	mach_port_right_t	right1,
191	ipc_object_t		*objectp1,
192	mach_port_name_t	name2,
193	mach_port_right_t	right2,
194	ipc_object_t		*objectp2)
195{
196	ipc_entry_t entry1;
197	ipc_entry_t entry2;
198	ipc_object_t object;
199	kern_return_t kr;
200
201	kr = ipc_right_lookup_two_read(space, name1, &entry1, name2, &entry2);
202	if (kr != KERN_SUCCESS)
203		return kr;
204	/* space is read-locked and active */
205
206	if ((entry1->ie_bits & MACH_PORT_TYPE(right1)) == MACH_PORT_TYPE_NONE) {
207		is_read_unlock(space);
208		return KERN_INVALID_RIGHT;
209	}
210
211	if ((entry2->ie_bits & MACH_PORT_TYPE(right2)) == MACH_PORT_TYPE_NONE) {
212		is_read_unlock(space);
213		return KERN_INVALID_RIGHT;
214	}
215
216	object = entry1->ie_object;
217	assert(object != IO_NULL);
218	io_lock(object);
219	*objectp1 = object;
220
221	object = entry2->ie_object;
222	assert(object != IO_NULL);
223	io_lock(object);
224	*objectp2 = object;
225
226	is_read_unlock(space);
227	return KERN_SUCCESS;
228}
229
230/*
231 *	Routine:	ipc_object_alloc_dead
232 *	Purpose:
233 *		Allocate a dead-name entry.
234 *	Conditions:
235 *		Nothing locked.
236 *	Returns:
237 *		KERN_SUCCESS		The dead name is allocated.
238 *		KERN_INVALID_TASK	The space is dead.
239 *		KERN_NO_SPACE		No room for an entry in the space.
240 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
241 */
242
243kern_return_t
244ipc_object_alloc_dead(
245	ipc_space_t		space,
246	mach_port_name_t	*namep)
247{
248	ipc_entry_t entry;
249	kern_return_t kr;
250
251	kr = ipc_entry_alloc(space, namep, &entry);
252	if (kr != KERN_SUCCESS)
253		return kr;
254	/* space is write-locked */
255
256	/* null object, MACH_PORT_TYPE_DEAD_NAME, 1 uref */
257
258	assert(entry->ie_object == IO_NULL);
259	entry->ie_bits |= MACH_PORT_TYPE_DEAD_NAME | 1;
260	ipc_entry_modified(space, *namep, entry);
261	is_write_unlock(space);
262	return KERN_SUCCESS;
263}
264
265/*
266 *	Routine:	ipc_object_alloc_dead_name
267 *	Purpose:
268 *		Allocate a dead-name entry, with a specific name.
269 *	Conditions:
270 *		Nothing locked.
271 *	Returns:
272 *		KERN_SUCCESS		The dead name is allocated.
273 *		KERN_INVALID_TASK	The space is dead.
274 *		KERN_NAME_EXISTS	The name already denotes a right.
275 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
276 */
277
278kern_return_t
279ipc_object_alloc_dead_name(
280	ipc_space_t		space,
281	mach_port_name_t	name)
282{
283	ipc_entry_t entry;
284	kern_return_t kr;
285
286	kr = ipc_entry_alloc_name(space, name, &entry);
287	if (kr != KERN_SUCCESS)
288		return kr;
289	/* space is write-locked */
290
291	if (ipc_right_inuse(space, name, entry))
292		return KERN_NAME_EXISTS;
293
294	/* null object, MACH_PORT_TYPE_DEAD_NAME, 1 uref */
295
296	assert(entry->ie_object == IO_NULL);
297	entry->ie_bits |= MACH_PORT_TYPE_DEAD_NAME | 1;
298	ipc_entry_modified(space, name, entry);
299	is_write_unlock(space);
300	return KERN_SUCCESS;
301}
302
303/*
304 *	Routine:	ipc_object_alloc
305 *	Purpose:
306 *		Allocate an object.
307 *	Conditions:
308 *		Nothing locked.  If successful, the object is returned locked.
309 *		The space is write locked on successful return.
310 *		The caller doesn't get a reference for the object.
311 *	Returns:
312 *		KERN_SUCCESS		The object is allocated.
313 *		KERN_INVALID_TASK	The space is dead.
314 *		KERN_NO_SPACE		No room for an entry in the space.
315 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
316 */
317
318kern_return_t
319ipc_object_alloc(
320	ipc_space_t		space,
321	ipc_object_type_t	otype,
322	mach_port_type_t	type,
323	mach_port_urefs_t	urefs,
324	mach_port_name_t	*namep,
325	ipc_object_t		*objectp)
326{
327	ipc_object_t object;
328	ipc_entry_t entry;
329	kern_return_t kr;
330
331	assert(otype < IOT_NUMBER);
332	assert((type & MACH_PORT_TYPE_ALL_RIGHTS) == type);
333	assert(type != MACH_PORT_TYPE_NONE);
334	assert(urefs <= MACH_PORT_UREFS_MAX);
335
336	object = io_alloc(otype);
337	if (object == IO_NULL)
338		return KERN_RESOURCE_SHORTAGE;
339
340	if (otype == IOT_PORT) {
341		ipc_port_t port = (ipc_port_t)object;
342
343		bzero((char *)port, sizeof(*port));
344	} else if (otype == IOT_PORT_SET) {
345		ipc_pset_t pset = (ipc_pset_t)object;
346
347		bzero((char *)pset, sizeof(*pset));
348	}
349
350	io_lock_init(object);
351	*namep = CAST_MACH_PORT_TO_NAME(object);
352	kr = ipc_entry_alloc(space, namep, &entry);
353	if (kr != KERN_SUCCESS) {
354		io_free(otype, object);
355		return kr;
356	}
357	/* space is write-locked */
358
359	entry->ie_bits |= type | urefs;
360	entry->ie_object = object;
361	ipc_entry_modified(space, *namep, entry);
362
363	io_lock(object);
364
365	object->io_references = 1; /* for entry, not caller */
366	object->io_bits = io_makebits(TRUE, otype, 0);
367
368	*objectp = object;
369	return KERN_SUCCESS;
370}
371
372/*
373 *	Routine:	ipc_object_alloc_name
374 *	Purpose:
375 *		Allocate an object, with a specific name.
376 *	Conditions:
377 *		Nothing locked.  If successful, the object is returned locked.
378 *		The caller doesn't get a reference for the object.
379 *	Returns:
380 *		KERN_SUCCESS		The object is allocated.
381 *		KERN_INVALID_TASK	The space is dead.
382 *		KERN_NAME_EXISTS	The name already denotes a right.
383 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
384 */
385
386kern_return_t
387ipc_object_alloc_name(
388	ipc_space_t		space,
389	ipc_object_type_t	otype,
390	mach_port_type_t	type,
391	mach_port_urefs_t	urefs,
392	mach_port_name_t	name,
393	ipc_object_t		*objectp)
394{
395	ipc_object_t object;
396	ipc_entry_t entry;
397	kern_return_t kr;
398
399	assert(otype < IOT_NUMBER);
400	assert((type & MACH_PORT_TYPE_ALL_RIGHTS) == type);
401	assert(type != MACH_PORT_TYPE_NONE);
402	assert(urefs <= MACH_PORT_UREFS_MAX);
403
404	object = io_alloc(otype);
405	if (object == IO_NULL)
406		return KERN_RESOURCE_SHORTAGE;
407
408	if (otype == IOT_PORT) {
409		ipc_port_t port = (ipc_port_t)object;
410
411		bzero((char *)port, sizeof(*port));
412	} else if (otype == IOT_PORT_SET) {
413		ipc_pset_t pset = (ipc_pset_t)object;
414
415		bzero((char *)pset, sizeof(*pset));
416	}
417
418	io_lock_init(object);
419	kr = ipc_entry_alloc_name(space, name, &entry);
420	if (kr != KERN_SUCCESS) {
421		io_free(otype, object);
422		return kr;
423	}
424	/* space is write-locked */
425
426	if (ipc_right_inuse(space, name, entry)) {
427		io_free(otype, object);
428		return KERN_NAME_EXISTS;
429	}
430
431	entry->ie_bits |= type | urefs;
432	entry->ie_object = object;
433	ipc_entry_modified(space, name, entry);
434
435	io_lock(object);
436	is_write_unlock(space);
437
438	object->io_references = 1; /* for entry, not caller */
439	object->io_bits = io_makebits(TRUE, otype, 0);
440
441	*objectp = object;
442	return KERN_SUCCESS;
443}
444
445/*
446 *	Routine:	ipc_object_copyin_type
447 *	Purpose:
448 *		Convert a send type name to a received type name.
449 */
450
451mach_msg_type_name_t
452ipc_object_copyin_type(
453	mach_msg_type_name_t	msgt_name)
454{
455	switch (msgt_name) {
456
457	    case MACH_MSG_TYPE_MOVE_RECEIVE:
458		return MACH_MSG_TYPE_PORT_RECEIVE;
459
460	    case MACH_MSG_TYPE_MOVE_SEND_ONCE:
461	    case MACH_MSG_TYPE_MAKE_SEND_ONCE:
462		return MACH_MSG_TYPE_PORT_SEND_ONCE;
463
464	    case MACH_MSG_TYPE_MOVE_SEND:
465	    case MACH_MSG_TYPE_MAKE_SEND:
466	    case MACH_MSG_TYPE_COPY_SEND:
467		return MACH_MSG_TYPE_PORT_SEND;
468
469	    case MACH_MSG_TYPE_DISPOSE_RECEIVE:
470	    case MACH_MSG_TYPE_DISPOSE_SEND:
471	    case MACH_MSG_TYPE_DISPOSE_SEND_ONCE:
472		/* fall thru */
473	    default:
474		return MACH_MSG_TYPE_PORT_NONE;
475	}
476}
477
478/*
479 *	Routine:	ipc_object_copyin
480 *	Purpose:
481 *		Copyin a capability from a space.
482 *		If successful, the caller gets a ref
483 *		for the resulting object, unless it is IO_DEAD.
484 *	Conditions:
485 *		Nothing locked.
486 *	Returns:
487 *		KERN_SUCCESS		Acquired an object, possibly IO_DEAD.
488 *		KERN_INVALID_TASK	The space is dead.
489 *		KERN_INVALID_NAME	Name doesn't exist in space.
490 *		KERN_INVALID_RIGHT	Name doesn't denote correct right.
491 */
492
493kern_return_t
494ipc_object_copyin(
495	ipc_space_t		space,
496	mach_port_name_t	name,
497	mach_msg_type_name_t	msgt_name,
498	ipc_object_t		*objectp)
499{
500	ipc_entry_t entry;
501	ipc_port_t soright;
502	ipc_port_t release_port;
503	kern_return_t kr;
504	queue_head_t links_data;
505	queue_t links = &links_data;
506	wait_queue_link_t wql;
507
508#if IMPORTANCE_INHERITANCE
509	int assertcnt = 0;
510#endif
511
512	queue_init(links);
513
514	/*
515	 *	Could first try a read lock when doing
516	 *	MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND,
517	 *	and MACH_MSG_TYPE_MAKE_SEND_ONCE.
518	 */
519
520	kr = ipc_right_lookup_write(space, name, &entry);
521	if (kr != KERN_SUCCESS)
522		return kr;
523	/* space is write-locked and active */
524
525	release_port = IP_NULL;
526	kr = ipc_right_copyin(space, name, entry,
527			      msgt_name, TRUE,
528			      objectp, &soright,
529			      &release_port,
530#if IMPORTANCE_INHERITANCE
531			      &assertcnt,
532#endif /* IMPORTANCE_INHERITANCE */
533			      links);
534	if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
535		ipc_entry_dealloc(space, name, entry);
536	is_write_unlock(space);
537
538	while(!queue_empty(links)) {
539		wql = (wait_queue_link_t) dequeue(links);
540		wait_queue_link_free(wql);
541	}
542
543#if IMPORTANCE_INHERITANCE
544	if (0 < assertcnt && ipc_importance_task_is_any_receiver_type(current_task()->task_imp_base)) {
545		ipc_importance_task_drop_internal_assertion(current_task()->task_imp_base, assertcnt);
546	}
547#endif /* IMPORTANCE_INHERITANCE */
548
549	if (release_port != IP_NULL)
550		ip_release(release_port);
551
552	if ((kr == KERN_SUCCESS) && (soright != IP_NULL))
553		ipc_notify_port_deleted(soright, name);
554
555	return kr;
556}
557
558/*
559 *	Routine:	ipc_object_copyin_from_kernel
560 *	Purpose:
561 *		Copyin a naked capability from the kernel.
562 *
563 *		MACH_MSG_TYPE_MOVE_RECEIVE
564 *			The receiver must be ipc_space_kernel
565 *			or the receive right must already be in limbo.
566 *			Consumes the naked receive right.
567 *		MACH_MSG_TYPE_COPY_SEND
568 *			A naked send right must be supplied.
569 *			The port gains a reference, and a send right
570 *			if the port is still active.
571 *		MACH_MSG_TYPE_MAKE_SEND
572 *			The receiver must be ipc_space_kernel.
573 *			The port gains a reference and a send right.
574 *		MACH_MSG_TYPE_MOVE_SEND
575 *			Consumes a naked send right.
576 *		MACH_MSG_TYPE_MAKE_SEND_ONCE
577 *			The port gains a reference and a send-once right.
578 *			Receiver also be the caller of device subsystem,
579 *			so no assertion.
580 *		MACH_MSG_TYPE_MOVE_SEND_ONCE
581 *			Consumes a naked send-once right.
582 *	Conditions:
583 *		Nothing locked.
584 */
585
586void
587ipc_object_copyin_from_kernel(
588	ipc_object_t		object,
589	mach_msg_type_name_t	msgt_name)
590{
591	assert(IO_VALID(object));
592
593	switch (msgt_name) {
594	    case MACH_MSG_TYPE_MOVE_RECEIVE: {
595		ipc_port_t port = (ipc_port_t) object;
596
597		ip_lock(port);
598		assert(ip_active(port));
599		if (port->ip_destination != IP_NULL) {
600			assert(port->ip_receiver == ipc_space_kernel);
601
602			/* relevant part of ipc_port_clear_receiver */
603			ipc_port_set_mscount(port, 0);
604
605			port->ip_receiver_name = MACH_PORT_NULL;
606			port->ip_destination = IP_NULL;
607		}
608		ip_unlock(port);
609		break;
610	    }
611
612	    case MACH_MSG_TYPE_COPY_SEND: {
613		ipc_port_t port = (ipc_port_t) object;
614
615		ip_lock(port);
616		if (ip_active(port)) {
617			assert(port->ip_srights > 0);
618			port->ip_srights++;
619		}
620		ip_reference(port);
621		ip_unlock(port);
622		break;
623	    }
624
625	    case MACH_MSG_TYPE_MAKE_SEND: {
626		ipc_port_t port = (ipc_port_t) object;
627
628		ip_lock(port);
629		if (ip_active(port)) {
630			assert(port->ip_receiver_name != MACH_PORT_NULL);
631			assert(port->ip_receiver == ipc_space_kernel);
632			port->ip_mscount++;
633		}
634
635		port->ip_srights++;
636		ip_reference(port);
637		ip_unlock(port);
638		break;
639	    }
640
641	    case MACH_MSG_TYPE_MOVE_SEND: {
642		/* move naked send right into the message */
643		assert(((ipc_port_t)object)->ip_srights);
644		break;
645	    }
646
647	    case MACH_MSG_TYPE_MAKE_SEND_ONCE: {
648		ipc_port_t port = (ipc_port_t) object;
649
650		ip_lock(port);
651		if (ip_active(port)) {
652			assert(port->ip_receiver_name != MACH_PORT_NULL);
653		}
654		port->ip_sorights++;
655		ip_reference(port);
656		ip_unlock(port);
657		break;
658	    }
659
660	    case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
661		/* move naked send-once right into the message */
662	    	assert(((ipc_port_t)object)->ip_sorights);
663		break;
664	    }
665
666	    default:
667		panic("ipc_object_copyin_from_kernel: strange rights");
668	}
669}
670
671/*
672 *	Routine:	ipc_object_destroy
673 *	Purpose:
674 *		Destroys a naked capability.
675 *		Consumes a ref for the object.
676 *
677 *		A receive right should be in limbo or in transit.
678 *	Conditions:
679 *		Nothing locked.
680 */
681
682void
683ipc_object_destroy(
684	ipc_object_t		object,
685	mach_msg_type_name_t	msgt_name)
686{
687	assert(IO_VALID(object));
688	assert(io_otype(object) == IOT_PORT);
689
690	switch (msgt_name) {
691	    case MACH_MSG_TYPE_PORT_SEND:
692		ipc_port_release_send((ipc_port_t) object);
693		break;
694
695	    case MACH_MSG_TYPE_PORT_SEND_ONCE:
696		ipc_notify_send_once((ipc_port_t) object);
697		break;
698
699	    case MACH_MSG_TYPE_PORT_RECEIVE:
700		ipc_port_release_receive((ipc_port_t) object);
701		break;
702
703	    default:
704		panic("ipc_object_destroy: strange rights");
705	}
706}
707
708/*
709 *	Routine:	ipc_object_destroy_dest
710 *	Purpose:
711 *		Destroys a naked capability for the destination of
712 *		of a message. Consumes a ref for the object.
713 *
714 *	Conditions:
715 *		Nothing locked.
716 */
717
718void
719ipc_object_destroy_dest(
720	ipc_object_t		object,
721	mach_msg_type_name_t	msgt_name)
722{
723	assert(IO_VALID(object));
724	assert(io_otype(object) == IOT_PORT);
725
726	switch (msgt_name) {
727	    case MACH_MSG_TYPE_PORT_SEND:
728		ipc_port_release_send((ipc_port_t) object);
729		break;
730
731	    case MACH_MSG_TYPE_PORT_SEND_ONCE:
732		if (io_active(object) &&
733		    !ip_full_kernel((ipc_port_t) object))
734			ipc_notify_send_once((ipc_port_t) object);
735		else
736			ipc_port_release_sonce((ipc_port_t) object);
737		break;
738
739	    default:
740		panic("ipc_object_destroy_dest: strange rights");
741	}
742}
743
744/*
745 *	Routine:	ipc_object_copyout
746 *	Purpose:
747 *		Copyout a capability, placing it into a space.
748 *		If successful, consumes a ref for the object.
749 *	Conditions:
750 *		Nothing locked.
751 *	Returns:
752 *		KERN_SUCCESS		Copied out object, consumed ref.
753 *		KERN_INVALID_TASK	The space is dead.
754 *		KERN_INVALID_CAPABILITY	The object is dead.
755 *		KERN_NO_SPACE		No room in space for another right.
756 *		KERN_RESOURCE_SHORTAGE	No memory available.
757 *		KERN_UREFS_OVERFLOW	Urefs limit exceeded
758 *			and overflow wasn't specified.
759 */
760
761kern_return_t
762ipc_object_copyout(
763	ipc_space_t		space,
764	ipc_object_t		object,
765	mach_msg_type_name_t	msgt_name,
766	boolean_t		overflow,
767	mach_port_name_t	*namep)
768{
769	mach_port_name_t name;
770	ipc_entry_t entry;
771	kern_return_t kr;
772
773	assert(IO_VALID(object));
774	assert(io_otype(object) == IOT_PORT);
775
776	is_write_lock(space);
777
778	for (;;) {
779		if (!is_active(space)) {
780			is_write_unlock(space);
781			return KERN_INVALID_TASK;
782		}
783
784		if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
785		    ipc_right_reverse(space, object, &name, &entry)) {
786			/* object is locked and active */
787
788			assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
789			break;
790		}
791
792		name = CAST_MACH_PORT_TO_NAME(object);
793		kr = ipc_entry_get(space, &name, &entry);
794		if (kr != KERN_SUCCESS) {
795			/* unlocks/locks space, so must start again */
796
797			kr = ipc_entry_grow_table(space, ITS_SIZE_NONE);
798			if (kr != KERN_SUCCESS)
799				return kr; /* space is unlocked */
800
801			continue;
802		}
803
804		assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
805		assert(entry->ie_object == IO_NULL);
806
807		io_lock(object);
808		if (!io_active(object)) {
809			io_unlock(object);
810			ipc_entry_dealloc(space, name, entry);
811			is_write_unlock(space);
812			return KERN_INVALID_CAPABILITY;
813		}
814
815		entry->ie_object = object;
816		break;
817	}
818
819	/* space is write-locked and active, object is locked and active */
820
821	kr = ipc_right_copyout(space, name, entry,
822			       msgt_name, overflow, object);
823
824	/* object is unlocked */
825	is_write_unlock(space);
826
827	if (kr == KERN_SUCCESS)
828		*namep = name;
829	return kr;
830}
831
832/*
833 *	Routine:	ipc_object_copyout_name
834 *	Purpose:
835 *		Copyout a capability, placing it into a space.
836 *		The specified name is used for the capability.
837 *		If successful, consumes a ref for the object.
838 *	Conditions:
839 *		Nothing locked.
840 *	Returns:
841 *		KERN_SUCCESS		Copied out object, consumed ref.
842 *		KERN_INVALID_TASK	The space is dead.
843 *		KERN_INVALID_CAPABILITY	The object is dead.
844 *		KERN_RESOURCE_SHORTAGE	No memory available.
845 *		KERN_UREFS_OVERFLOW	Urefs limit exceeded
846 *			and overflow wasn't specified.
847 *		KERN_RIGHT_EXISTS	Space has rights under another name.
848 *		KERN_NAME_EXISTS	Name is already used.
849 */
850
851kern_return_t
852ipc_object_copyout_name(
853	ipc_space_t		space,
854	ipc_object_t		object,
855	mach_msg_type_name_t	msgt_name,
856	boolean_t		overflow,
857	mach_port_name_t	name)
858{
859	mach_port_name_t oname;
860	ipc_entry_t oentry;
861	ipc_entry_t entry;
862	kern_return_t kr;
863
864#if IMPORTANCE_INHERITANCE
865	int assertcnt = 0;
866	ipc_importance_task_t task_imp = IIT_NULL;
867#endif /* IMPORTANCE_INHERITANCE */
868
869	assert(IO_VALID(object));
870	assert(io_otype(object) == IOT_PORT);
871
872	kr = ipc_entry_alloc_name(space, name, &entry);
873	if (kr != KERN_SUCCESS)
874		return kr;
875	/* space is write-locked and active */
876
877	if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
878	    ipc_right_reverse(space, object, &oname, &oentry)) {
879		/* object is locked and active */
880
881		if (name != oname) {
882			io_unlock(object);
883
884			if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
885				ipc_entry_dealloc(space, name, entry);
886
887			is_write_unlock(space);
888			return KERN_RIGHT_EXISTS;
889		}
890
891		assert(entry == oentry);
892		assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
893	} else {
894		if (ipc_right_inuse(space, name, entry))
895			return KERN_NAME_EXISTS;
896
897		assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
898		assert(entry->ie_object == IO_NULL);
899
900		io_lock(object);
901		if (!io_active(object)) {
902			io_unlock(object);
903			ipc_entry_dealloc(space, name, entry);
904			is_write_unlock(space);
905			return KERN_INVALID_CAPABILITY;
906		}
907
908		entry->ie_object = object;
909	}
910
911	/* space is write-locked and active, object is locked and active */
912
913#if IMPORTANCE_INHERITANCE
914	/*
915	 * We are slamming a receive right into the space, without
916	 * first having been enqueued on a port destined there.  So,
917	 * we have to arrange to boost the task appropriately if this
918	 * port has assertions (and the task wants them).
919	 */
920	if (msgt_name == MACH_MSG_TYPE_PORT_RECEIVE) {
921		ipc_port_t port = (ipc_port_t)object;
922
923		if (space->is_task != TASK_NULL) {
924			task_imp = space->is_task->task_imp_base;
925			if (ipc_importance_task_is_any_receiver_type(task_imp)) {
926				assertcnt = port->ip_impcount;
927				ipc_importance_task_reference(task_imp);
928			}
929		}
930
931		/* take port out of limbo */
932		assert(port->ip_tempowner != 0);
933		port->ip_tempowner = 0;
934	}
935
936#endif /* IMPORTANCE_INHERITANCE */
937
938	kr = ipc_right_copyout(space, name, entry,
939			       msgt_name, overflow, object);
940
941	/* object is unlocked */
942	is_write_unlock(space);
943
944#if IMPORTANCE_INHERITANCE
945	/*
946	 * Add the assertions to the task that we captured before
947	 */
948	if (task_imp != IIT_NULL) {
949		ipc_importance_task_hold_internal_assertion(task_imp, assertcnt);
950		ipc_importance_task_release(task_imp);
951	}
952#endif /* IMPORTANCE_INHERITANCE */
953
954	return kr;
955}
956
957/*
958 *	Routine:	ipc_object_copyout_dest
959 *	Purpose:
960 *		Translates/consumes the destination right of a message.
961 *		This is unlike normal copyout because the right is consumed
962 *		in a funny way instead of being given to the receiving space.
963 *		The receiver gets his name for the port, if he has receive
964 *		rights, otherwise MACH_PORT_NULL.
965 *	Conditions:
966 *		The object is locked and active.  Nothing else locked.
967 *		The object is unlocked and loses a reference.
968 */
969
970void
971ipc_object_copyout_dest(
972	ipc_space_t		space,
973	ipc_object_t		object,
974	mach_msg_type_name_t	msgt_name,
975	mach_port_name_t	*namep)
976{
977	mach_port_name_t name;
978
979	assert(IO_VALID(object));
980	assert(io_active(object));
981
982	io_release(object);
983
984	/*
985	 *	If the space is the receiver/owner of the object,
986	 *	then we quietly consume the right and return
987	 *	the space's name for the object.  Otherwise
988	 *	we destroy the right and return MACH_PORT_NULL.
989	 */
990
991	switch (msgt_name) {
992	    case MACH_MSG_TYPE_PORT_SEND: {
993		ipc_port_t port = (ipc_port_t) object;
994		ipc_port_t nsrequest = IP_NULL;
995		mach_port_mscount_t mscount;
996
997		if (port->ip_receiver == space)
998			name = port->ip_receiver_name;
999		else
1000			name = MACH_PORT_NULL;
1001
1002		assert(port->ip_srights > 0);
1003		if (--port->ip_srights == 0 &&
1004		    port->ip_nsrequest != IP_NULL) {
1005			nsrequest = port->ip_nsrequest;
1006			port->ip_nsrequest = IP_NULL;
1007			mscount = port->ip_mscount;
1008			ip_unlock(port);
1009			ipc_notify_no_senders(nsrequest, mscount);
1010		} else
1011			ip_unlock(port);
1012		break;
1013	    }
1014
1015	    case MACH_MSG_TYPE_PORT_SEND_ONCE: {
1016		ipc_port_t port = (ipc_port_t) object;
1017
1018		assert(port->ip_sorights > 0);
1019
1020		if (port->ip_receiver == space) {
1021			/* quietly consume the send-once right */
1022
1023			port->ip_sorights--;
1024			name = port->ip_receiver_name;
1025			ip_unlock(port);
1026		} else {
1027			/*
1028			 *	A very bizarre case.  The message
1029			 *	was received, but before this copyout
1030			 *	happened the space lost receive rights.
1031			 *	We can't quietly consume the soright
1032			 *	out from underneath some other task,
1033			 *	so generate a send-once notification.
1034			 */
1035
1036			ip_reference(port); /* restore ref */
1037			ip_unlock(port);
1038
1039			ipc_notify_send_once(port);
1040			name = MACH_PORT_NULL;
1041		}
1042
1043		break;
1044	    }
1045
1046	    default:
1047		panic("ipc_object_copyout_dest: strange rights");
1048		name = MACH_PORT_DEAD;
1049	}
1050
1051	*namep = name;
1052}
1053
1054/*
1055 *	Routine:	ipc_object_rename
1056 *	Purpose:
1057 *		Rename an entry in a space.
1058 *	Conditions:
1059 *		Nothing locked.
1060 *	Returns:
1061 *		KERN_SUCCESS		Renamed the entry.
1062 *		KERN_INVALID_TASK	The space was dead.
1063 *		KERN_INVALID_NAME	oname didn't denote an entry.
1064 *		KERN_NAME_EXISTS	nname already denoted an entry.
1065 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate new entry.
1066 */
1067
1068kern_return_t
1069ipc_object_rename(
1070	ipc_space_t		space,
1071	mach_port_name_t	oname,
1072	mach_port_name_t	nname)
1073{
1074	ipc_entry_t oentry, nentry;
1075	kern_return_t kr;
1076
1077	kr = ipc_entry_alloc_name(space, nname, &nentry);
1078	if (kr != KERN_SUCCESS)
1079		return kr;
1080
1081	/* space is write-locked and active */
1082
1083	if (ipc_right_inuse(space, nname, nentry)) {
1084		/* space is unlocked */
1085		return KERN_NAME_EXISTS;
1086	}
1087
1088	/* don't let ipc_entry_lookup see the uninitialized new entry */
1089
1090	if ((oname == nname) ||
1091	    ((oentry = ipc_entry_lookup(space, oname)) == IE_NULL)) {
1092		ipc_entry_dealloc(space, nname, nentry);
1093		is_write_unlock(space);
1094		return KERN_INVALID_NAME;
1095	}
1096
1097	kr = ipc_right_rename(space, oname, oentry, nname, nentry);
1098	/* space is unlocked */
1099	return kr;
1100}
1101
1102/*
1103 *	Check whether the object is a port if so, free it.  But
1104 *	keep track of that fact.
1105 */
1106void
1107io_free(
1108	unsigned int	otype,
1109	ipc_object_t	object)
1110{
1111	ipc_port_t	port;
1112
1113	if (otype == IOT_PORT) {
1114		port = (ipc_port_t) object;
1115		ipc_port_finalize(port);
1116	}
1117	io_lock_destroy(object);
1118	zfree(ipc_object_zones[otype], object);
1119}
1120