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