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/port.h>
87#include <ipc/ipc_space.h>
88#include <ipc/ipc_entry.h>
89#include <ipc/ipc_object.h>
90#include <ipc/ipc_hash.h>
91#include <ipc/ipc_right.h>
92#include <ipc/ipc_notify.h>
93#include <ipc/ipc_port.h>
94#include <ipc/ipc_pset.h>
95#include <ipc/ipc_labelh.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#if CONFIG_MACF_MACH
345		mac_port_label_init(&port->ip_label);
346#endif
347	} else if (otype == IOT_PORT_SET) {
348		ipc_pset_t pset = (ipc_pset_t)object;
349
350		bzero((char *)pset, sizeof(*pset));
351	}
352
353	io_lock_init(object);
354	*namep = CAST_MACH_PORT_TO_NAME(object);
355	kr = ipc_entry_alloc(space, namep, &entry);
356	if (kr != KERN_SUCCESS) {
357		io_free(otype, object);
358		return kr;
359	}
360	/* space is write-locked */
361
362	entry->ie_bits |= type | urefs;
363	entry->ie_object = object;
364	ipc_entry_modified(space, *namep, entry);
365
366	io_lock(object);
367
368	object->io_references = 1; /* for entry, not caller */
369	object->io_bits = io_makebits(TRUE, otype, 0);
370
371	*objectp = object;
372	return KERN_SUCCESS;
373}
374
375/*
376 *	Routine:	ipc_object_alloc_name
377 *	Purpose:
378 *		Allocate an object, with a specific name.
379 *	Conditions:
380 *		Nothing locked.  If successful, the object is returned locked.
381 *		The caller doesn't get a reference for the object.
382 *	Returns:
383 *		KERN_SUCCESS		The object is allocated.
384 *		KERN_INVALID_TASK	The space is dead.
385 *		KERN_NAME_EXISTS	The name already denotes a right.
386 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
387 */
388
389kern_return_t
390ipc_object_alloc_name(
391	ipc_space_t		space,
392	ipc_object_type_t	otype,
393	mach_port_type_t	type,
394	mach_port_urefs_t	urefs,
395	mach_port_name_t	name,
396	ipc_object_t		*objectp)
397{
398	ipc_object_t object;
399	ipc_entry_t entry;
400	kern_return_t kr;
401
402	assert(otype < IOT_NUMBER);
403	assert((type & MACH_PORT_TYPE_ALL_RIGHTS) == type);
404	assert(type != MACH_PORT_TYPE_NONE);
405	assert(urefs <= MACH_PORT_UREFS_MAX);
406
407	object = io_alloc(otype);
408	if (object == IO_NULL)
409		return KERN_RESOURCE_SHORTAGE;
410
411	if (otype == IOT_PORT) {
412		ipc_port_t port = (ipc_port_t)object;
413
414		bzero((char *)port, sizeof(*port));
415#if CONFIG_MACF_MACH
416		mac_port_label_init(&port->ip_label);
417#endif
418	} else if (otype == IOT_PORT_SET) {
419		ipc_pset_t pset = (ipc_pset_t)object;
420
421		bzero((char *)pset, sizeof(*pset));
422	}
423
424	io_lock_init(object);
425	kr = ipc_entry_alloc_name(space, name, &entry);
426	if (kr != KERN_SUCCESS) {
427		io_free(otype, object);
428		return kr;
429	}
430	/* space is write-locked */
431
432	if (ipc_right_inuse(space, name, entry)) {
433		io_free(otype, object);
434		return KERN_NAME_EXISTS;
435	}
436
437	entry->ie_bits |= type | urefs;
438	entry->ie_object = object;
439	ipc_entry_modified(space, name, entry);
440
441	io_lock(object);
442	is_write_unlock(space);
443
444	object->io_references = 1; /* for entry, not caller */
445	object->io_bits = io_makebits(TRUE, otype, 0);
446
447	*objectp = object;
448	return KERN_SUCCESS;
449}
450
451/*
452 *	Routine:	ipc_object_copyin_type
453 *	Purpose:
454 *		Convert a send type name to a received type name.
455 */
456
457mach_msg_type_name_t
458ipc_object_copyin_type(
459	mach_msg_type_name_t	msgt_name)
460{
461	switch (msgt_name) {
462
463	    case MACH_MSG_TYPE_MOVE_RECEIVE:
464	    case MACH_MSG_TYPE_COPY_RECEIVE:
465		return MACH_MSG_TYPE_PORT_RECEIVE;
466
467	    case MACH_MSG_TYPE_MOVE_SEND_ONCE:
468	    case MACH_MSG_TYPE_MAKE_SEND_ONCE:
469		return MACH_MSG_TYPE_PORT_SEND_ONCE;
470
471	    case MACH_MSG_TYPE_MOVE_SEND:
472	    case MACH_MSG_TYPE_MAKE_SEND:
473	    case MACH_MSG_TYPE_COPY_SEND:
474		return MACH_MSG_TYPE_PORT_SEND;
475
476	    default:
477		return MACH_MSG_TYPE_PORT_NONE;
478	}
479}
480
481/*
482 *	Routine:	ipc_object_copyin
483 *	Purpose:
484 *		Copyin a capability from a space.
485 *		If successful, the caller gets a ref
486 *		for the resulting object, unless it is IO_DEAD.
487 *	Conditions:
488 *		Nothing locked.
489 *	Returns:
490 *		KERN_SUCCESS		Acquired an object, possibly IO_DEAD.
491 *		KERN_INVALID_TASK	The space is dead.
492 *		KERN_INVALID_NAME	Name doesn't exist in space.
493 *		KERN_INVALID_RIGHT	Name doesn't denote correct right.
494 */
495
496kern_return_t
497ipc_object_copyin(
498	ipc_space_t		space,
499	mach_port_name_t	name,
500	mach_msg_type_name_t	msgt_name,
501	ipc_object_t		*objectp)
502{
503	ipc_entry_t entry;
504	ipc_port_t soright;
505	ipc_port_t release_port;
506	kern_return_t kr;
507	queue_head_t links_data;
508	queue_t links = &links_data;
509	wait_queue_link_t wql;
510
511	queue_init(links);
512
513	/*
514	 *	Could first try a read lock when doing
515	 *	MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND,
516	 *	and MACH_MSG_TYPE_MAKE_SEND_ONCE.
517	 */
518
519	kr = ipc_right_lookup_write(space, name, &entry);
520	if (kr != KERN_SUCCESS)
521		return kr;
522	/* space is write-locked and active */
523
524	release_port = IP_NULL;
525	kr = ipc_right_copyin(space, name, entry,
526			      msgt_name, TRUE,
527			      objectp, &soright,
528			      &release_port,
529			      links);
530	if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
531		ipc_entry_dealloc(space, name, entry);
532	is_write_unlock(space);
533
534	while(!queue_empty(links)) {
535		wql = (wait_queue_link_t) dequeue(links);
536		wait_queue_link_free(wql);
537	}
538
539	if (release_port != IP_NULL)
540		ip_release(release_port);
541
542	if ((kr == KERN_SUCCESS) && (soright != IP_NULL))
543		ipc_notify_port_deleted(soright, name);
544
545	return kr;
546}
547
548/*
549 *	Routine:	ipc_object_copyin_from_kernel
550 *	Purpose:
551 *		Copyin a naked capability from the kernel.
552 *
553 *		MACH_MSG_TYPE_MOVE_RECEIVE
554 *			The receiver must be ipc_space_kernel
555 *			or the receive right must already be in limbo.
556 *			Consumes the naked receive right.
557 *		MACH_MSG_TYPE_COPY_SEND
558 *			A naked send right must be supplied.
559 *			The port gains a reference, and a send right
560 *			if the port is still active.
561 *		MACH_MSG_TYPE_MAKE_SEND
562 *			The receiver must be ipc_space_kernel.
563 *			The port gains a reference and a send right.
564 *		MACH_MSG_TYPE_MOVE_SEND
565 *			Consumes a naked send right.
566 *		MACH_MSG_TYPE_MAKE_SEND_ONCE
567 *			The port gains a reference and a send-once right.
568 *			Receiver also be the caller of device subsystem,
569 *			so no assertion.
570 *		MACH_MSG_TYPE_MOVE_SEND_ONCE
571 *			Consumes a naked send-once right.
572 *	Conditions:
573 *		Nothing locked.
574 */
575
576void
577ipc_object_copyin_from_kernel(
578	ipc_object_t		object,
579	mach_msg_type_name_t	msgt_name)
580{
581	assert(IO_VALID(object));
582
583	switch (msgt_name) {
584	    case MACH_MSG_TYPE_MOVE_RECEIVE: {
585		ipc_port_t port = (ipc_port_t) object;
586
587		ip_lock(port);
588		assert(ip_active(port));
589		if (port->ip_destination != IP_NULL) {
590			assert(port->ip_receiver == ipc_space_kernel);
591
592			/* relevant part of ipc_port_clear_receiver */
593			ipc_port_set_mscount(port, 0);
594
595			port->ip_receiver_name = MACH_PORT_NULL;
596			port->ip_destination = IP_NULL;
597		}
598		ip_unlock(port);
599		break;
600	    }
601
602	    case MACH_MSG_TYPE_COPY_SEND: {
603		ipc_port_t port = (ipc_port_t) object;
604
605		ip_lock(port);
606		if (ip_active(port)) {
607			assert(port->ip_srights > 0);
608			port->ip_srights++;
609		}
610		ip_reference(port);
611		ip_unlock(port);
612		break;
613	    }
614
615	    case MACH_MSG_TYPE_MAKE_SEND: {
616		ipc_port_t port = (ipc_port_t) object;
617
618		ip_lock(port);
619		assert(ip_active(port));
620		assert(port->ip_receiver_name != MACH_PORT_NULL);
621		assert(port->ip_receiver == ipc_space_kernel);
622
623		ip_reference(port);
624		port->ip_mscount++;
625		port->ip_srights++;
626		ip_unlock(port);
627		break;
628	    }
629
630	    case MACH_MSG_TYPE_MOVE_SEND: {
631		/* move naked send right into the message */
632		assert(((ipc_port_t)object)->ip_srights);
633		break;
634	    }
635
636	    case MACH_MSG_TYPE_MAKE_SEND_ONCE: {
637		ipc_port_t port = (ipc_port_t) object;
638
639		ip_lock(port);
640		assert(ip_active(port));
641		assert(port->ip_receiver_name != MACH_PORT_NULL);
642
643		ip_reference(port);
644		port->ip_sorights++;
645		ip_unlock(port);
646		break;
647	    }
648
649	    case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
650		/* move naked send-once right into the message */
651	    	assert(((ipc_port_t)object)->ip_sorights);
652		break;
653	    }
654
655	    default:
656		panic("ipc_object_copyin_from_kernel: strange rights");
657	}
658}
659
660/*
661 *	Routine:	ipc_object_destroy
662 *	Purpose:
663 *		Destroys a naked capability.
664 *		Consumes a ref for the object.
665 *
666 *		A receive right should be in limbo or in transit.
667 *	Conditions:
668 *		Nothing locked.
669 */
670
671void
672ipc_object_destroy(
673	ipc_object_t		object,
674	mach_msg_type_name_t	msgt_name)
675{
676	assert(IO_VALID(object));
677	assert(io_otype(object) == IOT_PORT);
678
679	switch (msgt_name) {
680	    case MACH_MSG_TYPE_PORT_SEND:
681		ipc_port_release_send((ipc_port_t) object);
682		break;
683
684	    case MACH_MSG_TYPE_PORT_SEND_ONCE:
685		ipc_notify_send_once((ipc_port_t) object);
686		break;
687
688	    case MACH_MSG_TYPE_PORT_RECEIVE:
689		ipc_port_release_receive((ipc_port_t) object);
690		break;
691
692	    default:
693		panic("ipc_object_destroy: strange rights");
694	}
695}
696
697/*
698 *	Routine:	ipc_object_destroy_dest
699 *	Purpose:
700 *		Destroys a naked capability for the destination of
701 *		of a message. Consumes a ref for the object.
702 *
703 *	Conditions:
704 *		Nothing locked.
705 */
706
707void
708ipc_object_destroy_dest(
709	ipc_object_t		object,
710	mach_msg_type_name_t	msgt_name)
711{
712	assert(IO_VALID(object));
713	assert(io_otype(object) == IOT_PORT);
714
715	switch (msgt_name) {
716	    case MACH_MSG_TYPE_PORT_SEND:
717		ipc_port_release_send((ipc_port_t) object);
718		break;
719
720	    case MACH_MSG_TYPE_PORT_SEND_ONCE:
721		if (io_active(object) &&
722		    !ip_full_kernel((ipc_port_t) object))
723			ipc_notify_send_once((ipc_port_t) object);
724		else
725			ipc_port_release_sonce((ipc_port_t) object);
726		break;
727
728	    default:
729		panic("ipc_object_destroy_dest: strange rights");
730	}
731}
732
733/*
734 *	Routine:	ipc_object_copyout
735 *	Purpose:
736 *		Copyout a capability, placing it into a space.
737 *		If successful, consumes a ref for the object.
738 *	Conditions:
739 *		Nothing locked.
740 *	Returns:
741 *		KERN_SUCCESS		Copied out object, consumed ref.
742 *		KERN_INVALID_TASK	The space is dead.
743 *		KERN_INVALID_CAPABILITY	The object is dead.
744 *		KERN_NO_SPACE		No room in space for another right.
745 *		KERN_RESOURCE_SHORTAGE	No memory available.
746 *		KERN_UREFS_OVERFLOW	Urefs limit exceeded
747 *			and overflow wasn't specified.
748 */
749
750kern_return_t
751ipc_object_copyout(
752	ipc_space_t		space,
753	ipc_object_t		object,
754	mach_msg_type_name_t	msgt_name,
755	boolean_t		overflow,
756	mach_port_name_t	*namep)
757{
758	mach_port_name_t name;
759	ipc_entry_t entry;
760	kern_return_t kr;
761
762	assert(IO_VALID(object));
763	assert(io_otype(object) == IOT_PORT);
764
765	is_write_lock(space);
766
767	for (;;) {
768		if (!is_active(space)) {
769			is_write_unlock(space);
770			return KERN_INVALID_TASK;
771		}
772
773		if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
774		    ipc_right_reverse(space, object, &name, &entry)) {
775			/* object is locked and active */
776
777			assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
778			break;
779		}
780
781		name = CAST_MACH_PORT_TO_NAME(object);
782		kr = ipc_entry_get(space, &name, &entry);
783		if (kr != KERN_SUCCESS) {
784			/* unlocks/locks space, so must start again */
785
786			kr = ipc_entry_grow_table(space, ITS_SIZE_NONE);
787			if (kr != KERN_SUCCESS)
788				return kr; /* space is unlocked */
789
790			continue;
791		}
792
793		assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
794		assert(entry->ie_object == IO_NULL);
795
796		io_lock(object);
797		if (!io_active(object)) {
798			io_unlock(object);
799			ipc_entry_dealloc(space, name, entry);
800			is_write_unlock(space);
801			return KERN_INVALID_CAPABILITY;
802		}
803
804		entry->ie_object = object;
805		break;
806	}
807
808	/* space is write-locked and active, object is locked and active */
809
810	kr = ipc_right_copyout(space, name, entry,
811			       msgt_name, overflow, object);
812	/* object is unlocked */
813	is_write_unlock(space);
814
815	if (kr == KERN_SUCCESS)
816		*namep = name;
817	return kr;
818}
819
820/*
821 *	Routine:	ipc_object_copyout_name
822 *	Purpose:
823 *		Copyout a capability, placing it into a space.
824 *		The specified name is used for the capability.
825 *		If successful, consumes a ref for the object.
826 *	Conditions:
827 *		Nothing locked.
828 *	Returns:
829 *		KERN_SUCCESS		Copied out object, consumed ref.
830 *		KERN_INVALID_TASK	The space is dead.
831 *		KERN_INVALID_CAPABILITY	The object is dead.
832 *		KERN_RESOURCE_SHORTAGE	No memory available.
833 *		KERN_UREFS_OVERFLOW	Urefs limit exceeded
834 *			and overflow wasn't specified.
835 *		KERN_RIGHT_EXISTS	Space has rights under another name.
836 *		KERN_NAME_EXISTS	Name is already used.
837 */
838
839kern_return_t
840ipc_object_copyout_name(
841	ipc_space_t		space,
842	ipc_object_t		object,
843	mach_msg_type_name_t	msgt_name,
844	boolean_t		overflow,
845	mach_port_name_t	name)
846{
847	mach_port_name_t oname;
848	ipc_entry_t oentry;
849	ipc_entry_t entry;
850	kern_return_t kr;
851
852	assert(IO_VALID(object));
853	assert(io_otype(object) == IOT_PORT);
854
855	kr = ipc_entry_alloc_name(space, name, &entry);
856	if (kr != KERN_SUCCESS)
857		return kr;
858	/* space is write-locked and active */
859
860	if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
861	    ipc_right_reverse(space, object, &oname, &oentry)) {
862		/* object is locked and active */
863
864		if (name != oname) {
865			io_unlock(object);
866
867			if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
868				ipc_entry_dealloc(space, name, entry);
869
870			is_write_unlock(space);
871			return KERN_RIGHT_EXISTS;
872		}
873
874		assert(entry == oentry);
875		assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
876	} else {
877		if (ipc_right_inuse(space, name, entry))
878			return KERN_NAME_EXISTS;
879
880		assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
881		assert(entry->ie_object == IO_NULL);
882
883		io_lock(object);
884		if (!io_active(object)) {
885			io_unlock(object);
886			ipc_entry_dealloc(space, name, entry);
887			is_write_unlock(space);
888			return KERN_INVALID_CAPABILITY;
889		}
890
891		entry->ie_object = object;
892	}
893
894	/* space is write-locked and active, object is locked and active */
895
896	kr = ipc_right_copyout(space, name, entry,
897			       msgt_name, overflow, object);
898	/* object is unlocked */
899	is_write_unlock(space);
900	return kr;
901}
902
903/*
904 *	Routine:	ipc_object_copyout_dest
905 *	Purpose:
906 *		Translates/consumes the destination right of a message.
907 *		This is unlike normal copyout because the right is consumed
908 *		in a funny way instead of being given to the receiving space.
909 *		The receiver gets his name for the port, if they have receive
910 *		rights, otherwise MACH_PORT_NULL.
911 *	Conditions:
912 *		The object is locked and active.  Nothing else locked.
913 *		The object is unlocked and loses a reference.
914 */
915
916void
917ipc_object_copyout_dest(
918	ipc_space_t		space,
919	ipc_object_t		object,
920	mach_msg_type_name_t	msgt_name,
921	mach_port_name_t	*namep)
922{
923	mach_port_name_t name;
924
925	assert(IO_VALID(object));
926	assert(io_active(object));
927
928	io_release(object);
929
930	/*
931	 *	If the space is the receiver/owner of the object,
932	 *	then we quietly consume the right and return
933	 *	the space's name for the object.  Otherwise
934	 *	we destroy the right and return MACH_PORT_NULL.
935	 */
936
937	switch (msgt_name) {
938	    case MACH_MSG_TYPE_PORT_SEND: {
939		ipc_port_t port = (ipc_port_t) object;
940		ipc_port_t nsrequest = IP_NULL;
941		mach_port_mscount_t mscount;
942
943		if (port->ip_receiver == space)
944			name = port->ip_receiver_name;
945		else
946			name = MACH_PORT_NULL;
947
948		assert(port->ip_srights > 0);
949		if (--port->ip_srights == 0 &&
950		    port->ip_nsrequest != IP_NULL) {
951			nsrequest = port->ip_nsrequest;
952			port->ip_nsrequest = IP_NULL;
953			mscount = port->ip_mscount;
954			ip_unlock(port);
955			ipc_notify_no_senders(nsrequest, mscount);
956		} else
957			ip_unlock(port);
958		break;
959	    }
960
961	    case MACH_MSG_TYPE_PORT_SEND_ONCE: {
962		ipc_port_t port = (ipc_port_t) object;
963
964		assert(port->ip_sorights > 0);
965
966		if (port->ip_receiver == space) {
967			/* quietly consume the send-once right */
968
969			port->ip_sorights--;
970			name = port->ip_receiver_name;
971			ip_unlock(port);
972		} else {
973			/*
974			 *	A very bizarre case.  The message
975			 *	was received, but before this copyout
976			 *	happened the space lost receive rights.
977			 *	We can't quietly consume the soright
978			 *	out from underneath some other task,
979			 *	so generate a send-once notification.
980			 */
981
982			ip_reference(port); /* restore ref */
983			ip_unlock(port);
984
985			ipc_notify_send_once(port);
986			name = MACH_PORT_NULL;
987		}
988
989		break;
990	    }
991
992	    default:
993		panic("ipc_object_copyout_dest: strange rights");
994		name = MACH_PORT_DEAD;
995	}
996
997	*namep = name;
998}
999
1000/*
1001 *	Routine:	ipc_object_rename
1002 *	Purpose:
1003 *		Rename an entry in a space.
1004 *	Conditions:
1005 *		Nothing locked.
1006 *	Returns:
1007 *		KERN_SUCCESS		Renamed the entry.
1008 *		KERN_INVALID_TASK	The space was dead.
1009 *		KERN_INVALID_NAME	oname didn't denote an entry.
1010 *		KERN_NAME_EXISTS	nname already denoted an entry.
1011 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate new entry.
1012 */
1013
1014kern_return_t
1015ipc_object_rename(
1016	ipc_space_t		space,
1017	mach_port_name_t	oname,
1018	mach_port_name_t	nname)
1019{
1020	ipc_entry_t oentry, nentry;
1021	kern_return_t kr;
1022
1023	kr = ipc_entry_alloc_name(space, nname, &nentry);
1024	if (kr != KERN_SUCCESS)
1025		return kr;
1026
1027	/* space is write-locked and active */
1028
1029	if (ipc_right_inuse(space, nname, nentry)) {
1030		/* space is unlocked */
1031		return KERN_NAME_EXISTS;
1032	}
1033
1034	/* don't let ipc_entry_lookup see the uninitialized new entry */
1035
1036	if ((oname == nname) ||
1037	    ((oentry = ipc_entry_lookup(space, oname)) == IE_NULL)) {
1038		ipc_entry_dealloc(space, nname, nentry);
1039		is_write_unlock(space);
1040		return KERN_INVALID_NAME;
1041	}
1042
1043	kr = ipc_right_rename(space, oname, oentry, nname, nentry);
1044	/* space is unlocked */
1045	return kr;
1046}
1047
1048/*
1049 * Get a label out of a port, to be used by a kernel call
1050 * that takes a security label as a parameter. In this case, we want
1051 * to use the label stored in the label handle and not the label on its
1052 * port.
1053 *
1054 * The port should be locked for this call. The lock protecting
1055 * label handle contents should not be necessary, as they can only
1056 * be modified when a label handle with one reference is a task label.
1057 * User allocated label handles can never be modified.
1058 */
1059#if CONFIG_MACF_MACH
1060struct label *io_getlabel (ipc_object_t objp)
1061{
1062	ipc_port_t port = (ipc_port_t)objp;
1063
1064	assert(io_otype(objp) == IOT_PORT);
1065
1066	if (ip_kotype(port) == IKOT_LABELH)
1067		return &((ipc_labelh_t) port->ip_kobject)->lh_label;
1068	else
1069		return &port->ip_label;
1070}
1071#endif
1072
1073/*
1074 *	Check whether the object is a port if so, free it.  But
1075 *	keep track of that fact.
1076 */
1077void
1078io_free(
1079	unsigned int	otype,
1080	ipc_object_t	object)
1081{
1082	ipc_port_t	port;
1083
1084	if (otype == IOT_PORT) {
1085		port = (ipc_port_t) object;
1086		ipc_port_finalize(port);
1087	}
1088	io_lock_destroy(object);
1089	zfree(ipc_object_zones[otype], object);
1090}
1091