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#if IMPORTANCE_INHERITANCE
512	int assertcnt = 0;
513#endif
514
515	queue_init(links);
516
517	/*
518	 *	Could first try a read lock when doing
519	 *	MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND,
520	 *	and MACH_MSG_TYPE_MAKE_SEND_ONCE.
521	 */
522
523	kr = ipc_right_lookup_write(space, name, &entry);
524	if (kr != KERN_SUCCESS)
525		return kr;
526	/* space is write-locked and active */
527
528	release_port = IP_NULL;
529	kr = ipc_right_copyin(space, name, entry,
530			      msgt_name, TRUE,
531			      objectp, &soright,
532			      &release_port,
533#if IMPORTANCE_INHERITANCE
534			      &assertcnt,
535#endif /* IMPORTANCE_INHERITANCE */
536			      links);
537	if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
538		ipc_entry_dealloc(space, name, entry);
539	is_write_unlock(space);
540
541	while(!queue_empty(links)) {
542		wql = (wait_queue_link_t) dequeue(links);
543		wait_queue_link_free(wql);
544	}
545
546#if IMPORTANCE_INHERITANCE
547	if (assertcnt > 0 && current_task()->imp_receiver != 0) {
548		task_importance_drop_internal_assertion(current_task(), assertcnt);
549	}
550#endif /* IMPORTANCE_INHERITANCE */
551
552	if (release_port != IP_NULL)
553		ip_release(release_port);
554
555	if ((kr == KERN_SUCCESS) && (soright != IP_NULL))
556		ipc_notify_port_deleted(soright, name);
557
558	return kr;
559}
560
561/*
562 *	Routine:	ipc_object_copyin_from_kernel
563 *	Purpose:
564 *		Copyin a naked capability from the kernel.
565 *
566 *		MACH_MSG_TYPE_MOVE_RECEIVE
567 *			The receiver must be ipc_space_kernel
568 *			or the receive right must already be in limbo.
569 *			Consumes the naked receive right.
570 *		MACH_MSG_TYPE_COPY_SEND
571 *			A naked send right must be supplied.
572 *			The port gains a reference, and a send right
573 *			if the port is still active.
574 *		MACH_MSG_TYPE_MAKE_SEND
575 *			The receiver must be ipc_space_kernel.
576 *			The port gains a reference and a send right.
577 *		MACH_MSG_TYPE_MOVE_SEND
578 *			Consumes a naked send right.
579 *		MACH_MSG_TYPE_MAKE_SEND_ONCE
580 *			The port gains a reference and a send-once right.
581 *			Receiver also be the caller of device subsystem,
582 *			so no assertion.
583 *		MACH_MSG_TYPE_MOVE_SEND_ONCE
584 *			Consumes a naked send-once right.
585 *	Conditions:
586 *		Nothing locked.
587 */
588
589void
590ipc_object_copyin_from_kernel(
591	ipc_object_t		object,
592	mach_msg_type_name_t	msgt_name)
593{
594	assert(IO_VALID(object));
595
596	switch (msgt_name) {
597	    case MACH_MSG_TYPE_MOVE_RECEIVE: {
598		ipc_port_t port = (ipc_port_t) object;
599
600		ip_lock(port);
601		assert(ip_active(port));
602		if (port->ip_destination != IP_NULL) {
603			assert(port->ip_receiver == ipc_space_kernel);
604
605			/* relevant part of ipc_port_clear_receiver */
606			ipc_port_set_mscount(port, 0);
607
608			port->ip_receiver_name = MACH_PORT_NULL;
609			port->ip_destination = IP_NULL;
610		}
611		ip_unlock(port);
612		break;
613	    }
614
615	    case MACH_MSG_TYPE_COPY_SEND: {
616		ipc_port_t port = (ipc_port_t) object;
617
618		ip_lock(port);
619		if (ip_active(port)) {
620			assert(port->ip_srights > 0);
621			port->ip_srights++;
622		}
623		ip_reference(port);
624		ip_unlock(port);
625		break;
626	    }
627
628	    case MACH_MSG_TYPE_MAKE_SEND: {
629		ipc_port_t port = (ipc_port_t) object;
630
631		ip_lock(port);
632		if (ip_active(port)) {
633			assert(port->ip_receiver_name != MACH_PORT_NULL);
634			assert(port->ip_receiver == ipc_space_kernel);
635			port->ip_mscount++;
636		}
637
638		port->ip_srights++;
639		ip_reference(port);
640		ip_unlock(port);
641		break;
642	    }
643
644	    case MACH_MSG_TYPE_MOVE_SEND: {
645		/* move naked send right into the message */
646		assert(((ipc_port_t)object)->ip_srights);
647		break;
648	    }
649
650	    case MACH_MSG_TYPE_MAKE_SEND_ONCE: {
651		ipc_port_t port = (ipc_port_t) object;
652
653		ip_lock(port);
654		if (ip_active(port)) {
655			assert(port->ip_receiver_name != MACH_PORT_NULL);
656		}
657		port->ip_sorights++;
658		ip_reference(port);
659		ip_unlock(port);
660		break;
661	    }
662
663	    case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
664		/* move naked send-once right into the message */
665	    	assert(((ipc_port_t)object)->ip_sorights);
666		break;
667	    }
668
669	    default:
670		panic("ipc_object_copyin_from_kernel: strange rights");
671	}
672}
673
674/*
675 *	Routine:	ipc_object_destroy
676 *	Purpose:
677 *		Destroys a naked capability.
678 *		Consumes a ref for the object.
679 *
680 *		A receive right should be in limbo or in transit.
681 *	Conditions:
682 *		Nothing locked.
683 */
684
685void
686ipc_object_destroy(
687	ipc_object_t		object,
688	mach_msg_type_name_t	msgt_name)
689{
690	assert(IO_VALID(object));
691	assert(io_otype(object) == IOT_PORT);
692
693	switch (msgt_name) {
694	    case MACH_MSG_TYPE_PORT_SEND:
695		ipc_port_release_send((ipc_port_t) object);
696		break;
697
698	    case MACH_MSG_TYPE_PORT_SEND_ONCE:
699		ipc_notify_send_once((ipc_port_t) object);
700		break;
701
702	    case MACH_MSG_TYPE_PORT_RECEIVE:
703		ipc_port_release_receive((ipc_port_t) object);
704		break;
705
706	    default:
707		panic("ipc_object_destroy: strange rights");
708	}
709}
710
711/*
712 *	Routine:	ipc_object_destroy_dest
713 *	Purpose:
714 *		Destroys a naked capability for the destination of
715 *		of a message. Consumes a ref for the object.
716 *
717 *	Conditions:
718 *		Nothing locked.
719 */
720
721void
722ipc_object_destroy_dest(
723	ipc_object_t		object,
724	mach_msg_type_name_t	msgt_name)
725{
726	assert(IO_VALID(object));
727	assert(io_otype(object) == IOT_PORT);
728
729	switch (msgt_name) {
730	    case MACH_MSG_TYPE_PORT_SEND:
731		ipc_port_release_send((ipc_port_t) object);
732		break;
733
734	    case MACH_MSG_TYPE_PORT_SEND_ONCE:
735		if (io_active(object) &&
736		    !ip_full_kernel((ipc_port_t) object))
737			ipc_notify_send_once((ipc_port_t) object);
738		else
739			ipc_port_release_sonce((ipc_port_t) object);
740		break;
741
742	    default:
743		panic("ipc_object_destroy_dest: strange rights");
744	}
745}
746
747/*
748 *	Routine:	ipc_object_copyout
749 *	Purpose:
750 *		Copyout a capability, placing it into a space.
751 *		If successful, consumes a ref for the object.
752 *	Conditions:
753 *		Nothing locked.
754 *	Returns:
755 *		KERN_SUCCESS		Copied out object, consumed ref.
756 *		KERN_INVALID_TASK	The space is dead.
757 *		KERN_INVALID_CAPABILITY	The object is dead.
758 *		KERN_NO_SPACE		No room in space for another right.
759 *		KERN_RESOURCE_SHORTAGE	No memory available.
760 *		KERN_UREFS_OVERFLOW	Urefs limit exceeded
761 *			and overflow wasn't specified.
762 */
763
764kern_return_t
765ipc_object_copyout(
766	ipc_space_t		space,
767	ipc_object_t		object,
768	mach_msg_type_name_t	msgt_name,
769	boolean_t		overflow,
770	mach_port_name_t	*namep)
771{
772	mach_port_name_t name;
773	ipc_entry_t entry;
774	kern_return_t kr;
775
776	assert(IO_VALID(object));
777	assert(io_otype(object) == IOT_PORT);
778
779	is_write_lock(space);
780
781	for (;;) {
782		if (!is_active(space)) {
783			is_write_unlock(space);
784			return KERN_INVALID_TASK;
785		}
786
787		if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
788		    ipc_right_reverse(space, object, &name, &entry)) {
789			/* object is locked and active */
790
791			assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
792			break;
793		}
794
795		name = CAST_MACH_PORT_TO_NAME(object);
796		kr = ipc_entry_get(space, &name, &entry);
797		if (kr != KERN_SUCCESS) {
798			/* unlocks/locks space, so must start again */
799
800			kr = ipc_entry_grow_table(space, ITS_SIZE_NONE);
801			if (kr != KERN_SUCCESS)
802				return kr; /* space is unlocked */
803
804			continue;
805		}
806
807		assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
808		assert(entry->ie_object == IO_NULL);
809
810		io_lock(object);
811		if (!io_active(object)) {
812			io_unlock(object);
813			ipc_entry_dealloc(space, name, entry);
814			is_write_unlock(space);
815			return KERN_INVALID_CAPABILITY;
816		}
817
818		entry->ie_object = object;
819		break;
820	}
821
822	/* space is write-locked and active, object is locked and active */
823
824	kr = ipc_right_copyout(space, name, entry,
825			       msgt_name, overflow, object);
826
827	/* object is unlocked */
828	is_write_unlock(space);
829
830	if (kr == KERN_SUCCESS)
831		*namep = name;
832	return kr;
833}
834
835/*
836 *	Routine:	ipc_object_copyout_name
837 *	Purpose:
838 *		Copyout a capability, placing it into a space.
839 *		The specified name is used for the capability.
840 *		If successful, consumes a ref for the object.
841 *	Conditions:
842 *		Nothing locked.
843 *	Returns:
844 *		KERN_SUCCESS		Copied out object, consumed ref.
845 *		KERN_INVALID_TASK	The space is dead.
846 *		KERN_INVALID_CAPABILITY	The object is dead.
847 *		KERN_RESOURCE_SHORTAGE	No memory available.
848 *		KERN_UREFS_OVERFLOW	Urefs limit exceeded
849 *			and overflow wasn't specified.
850 *		KERN_RIGHT_EXISTS	Space has rights under another name.
851 *		KERN_NAME_EXISTS	Name is already used.
852 */
853
854kern_return_t
855ipc_object_copyout_name(
856	ipc_space_t		space,
857	ipc_object_t		object,
858	mach_msg_type_name_t	msgt_name,
859	boolean_t		overflow,
860	mach_port_name_t	name)
861{
862	mach_port_name_t oname;
863	ipc_entry_t oentry;
864	ipc_entry_t entry;
865	kern_return_t kr;
866
867#if IMPORTANCE_INHERITANCE
868	int assertcnt = 0;
869	task_t task = TASK_NULL;
870#endif /* IMPORTANCE_INHERITANCE */
871
872	assert(IO_VALID(object));
873	assert(io_otype(object) == IOT_PORT);
874
875	kr = ipc_entry_alloc_name(space, name, &entry);
876	if (kr != KERN_SUCCESS)
877		return kr;
878	/* space is write-locked and active */
879
880	if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
881	    ipc_right_reverse(space, object, &oname, &oentry)) {
882		/* object is locked and active */
883
884		if (name != oname) {
885			io_unlock(object);
886
887			if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
888				ipc_entry_dealloc(space, name, entry);
889
890			is_write_unlock(space);
891			return KERN_RIGHT_EXISTS;
892		}
893
894		assert(entry == oentry);
895		assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
896	} else {
897		if (ipc_right_inuse(space, name, entry))
898			return KERN_NAME_EXISTS;
899
900		assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
901		assert(entry->ie_object == IO_NULL);
902
903		io_lock(object);
904		if (!io_active(object)) {
905			io_unlock(object);
906			ipc_entry_dealloc(space, name, entry);
907			is_write_unlock(space);
908			return KERN_INVALID_CAPABILITY;
909		}
910
911		entry->ie_object = object;
912	}
913
914	/* space is write-locked and active, object is locked and active */
915
916#if IMPORTANCE_INHERITANCE
917	/*
918	 * We are slamming a receive right into the space, without
919	 * first having been enqueued on a port destined there.  So,
920	 * we have to arrange to boost the task appropriately if this
921	 * port has assertions (and the task wants them).
922	 */
923	if (msgt_name == MACH_MSG_TYPE_PORT_RECEIVE) {
924		ipc_port_t port = (ipc_port_t)object;
925
926		if ((space->is_task != TASK_NULL) &&
927		    (space->is_task->imp_receiver != 0)) {
928			assertcnt = port->ip_impcount;
929			task = space->is_task;
930			task_reference(task);
931		}
932
933		/* take port out of limbo */
934		assert(port->ip_tempowner != 0);
935		port->ip_tempowner = 0;
936	}
937
938#endif /* IMPORTANCE_INHERITANCE */
939
940	kr = ipc_right_copyout(space, name, entry,
941			       msgt_name, overflow, object);
942
943	/* object is unlocked */
944	is_write_unlock(space);
945
946#if IMPORTANCE_INHERITANCE
947	/*
948	 * Add the assertions to the task that we captured before
949	 */
950	if (task != TASK_NULL) {
951		if (assertcnt > 0)
952			task_importance_hold_internal_assertion(task, assertcnt);
953		task_deallocate(task);
954	}
955#endif /* IMPORTANCE_INHERITANCE */
956
957	return kr;
958}
959
960/*
961 *	Routine:	ipc_object_copyout_dest
962 *	Purpose:
963 *		Translates/consumes the destination right of a message.
964 *		This is unlike normal copyout because the right is consumed
965 *		in a funny way instead of being given to the receiving space.
966 *		The receiver gets his name for the port, if he has receive
967 *		rights, otherwise MACH_PORT_NULL.
968 *	Conditions:
969 *		The object is locked and active.  Nothing else locked.
970 *		The object is unlocked and loses a reference.
971 */
972
973void
974ipc_object_copyout_dest(
975	ipc_space_t		space,
976	ipc_object_t		object,
977	mach_msg_type_name_t	msgt_name,
978	mach_port_name_t	*namep)
979{
980	mach_port_name_t name;
981
982	assert(IO_VALID(object));
983	assert(io_active(object));
984
985	io_release(object);
986
987	/*
988	 *	If the space is the receiver/owner of the object,
989	 *	then we quietly consume the right and return
990	 *	the space's name for the object.  Otherwise
991	 *	we destroy the right and return MACH_PORT_NULL.
992	 */
993
994	switch (msgt_name) {
995	    case MACH_MSG_TYPE_PORT_SEND: {
996		ipc_port_t port = (ipc_port_t) object;
997		ipc_port_t nsrequest = IP_NULL;
998		mach_port_mscount_t mscount;
999
1000		if (port->ip_receiver == space)
1001			name = port->ip_receiver_name;
1002		else
1003			name = MACH_PORT_NULL;
1004
1005		assert(port->ip_srights > 0);
1006		if (--port->ip_srights == 0 &&
1007		    port->ip_nsrequest != IP_NULL) {
1008			nsrequest = port->ip_nsrequest;
1009			port->ip_nsrequest = IP_NULL;
1010			mscount = port->ip_mscount;
1011			ip_unlock(port);
1012			ipc_notify_no_senders(nsrequest, mscount);
1013		} else
1014			ip_unlock(port);
1015		break;
1016	    }
1017
1018	    case MACH_MSG_TYPE_PORT_SEND_ONCE: {
1019		ipc_port_t port = (ipc_port_t) object;
1020
1021		assert(port->ip_sorights > 0);
1022
1023		if (port->ip_receiver == space) {
1024			/* quietly consume the send-once right */
1025
1026			port->ip_sorights--;
1027			name = port->ip_receiver_name;
1028			ip_unlock(port);
1029		} else {
1030			/*
1031			 *	A very bizarre case.  The message
1032			 *	was received, but before this copyout
1033			 *	happened the space lost receive rights.
1034			 *	We can't quietly consume the soright
1035			 *	out from underneath some other task,
1036			 *	so generate a send-once notification.
1037			 */
1038
1039			ip_reference(port); /* restore ref */
1040			ip_unlock(port);
1041
1042			ipc_notify_send_once(port);
1043			name = MACH_PORT_NULL;
1044		}
1045
1046		break;
1047	    }
1048
1049	    default:
1050		panic("ipc_object_copyout_dest: strange rights");
1051		name = MACH_PORT_DEAD;
1052	}
1053
1054	*namep = name;
1055}
1056
1057/*
1058 *	Routine:	ipc_object_rename
1059 *	Purpose:
1060 *		Rename an entry in a space.
1061 *	Conditions:
1062 *		Nothing locked.
1063 *	Returns:
1064 *		KERN_SUCCESS		Renamed the entry.
1065 *		KERN_INVALID_TASK	The space was dead.
1066 *		KERN_INVALID_NAME	oname didn't denote an entry.
1067 *		KERN_NAME_EXISTS	nname already denoted an entry.
1068 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate new entry.
1069 */
1070
1071kern_return_t
1072ipc_object_rename(
1073	ipc_space_t		space,
1074	mach_port_name_t	oname,
1075	mach_port_name_t	nname)
1076{
1077	ipc_entry_t oentry, nentry;
1078	kern_return_t kr;
1079
1080	kr = ipc_entry_alloc_name(space, nname, &nentry);
1081	if (kr != KERN_SUCCESS)
1082		return kr;
1083
1084	/* space is write-locked and active */
1085
1086	if (ipc_right_inuse(space, nname, nentry)) {
1087		/* space is unlocked */
1088		return KERN_NAME_EXISTS;
1089	}
1090
1091	/* don't let ipc_entry_lookup see the uninitialized new entry */
1092
1093	if ((oname == nname) ||
1094	    ((oentry = ipc_entry_lookup(space, oname)) == IE_NULL)) {
1095		ipc_entry_dealloc(space, nname, nentry);
1096		is_write_unlock(space);
1097		return KERN_INVALID_NAME;
1098	}
1099
1100	kr = ipc_right_rename(space, oname, oentry, nname, nentry);
1101	/* space is unlocked */
1102	return kr;
1103}
1104
1105/*
1106 * Get a label out of a port, to be used by a kernel call
1107 * that takes a security label as a parameter. In this case, we want
1108 * to use the label stored in the label handle and not the label on its
1109 * port.
1110 *
1111 * The port should be locked for this call. The lock protecting
1112 * label handle contents should not be necessary, as they can only
1113 * be modified when a label handle with one reference is a task label.
1114 * User allocated label handles can never be modified.
1115 */
1116#if CONFIG_MACF_MACH
1117struct label *io_getlabel (ipc_object_t objp)
1118{
1119	ipc_port_t port = (ipc_port_t)objp;
1120
1121	assert(io_otype(objp) == IOT_PORT);
1122
1123	if (ip_kotype(port) == IKOT_LABELH)
1124		return &((ipc_labelh_t) port->ip_kobject)->lh_label;
1125	else
1126		return &port->ip_label;
1127}
1128#endif
1129
1130/*
1131 *	Check whether the object is a port if so, free it.  But
1132 *	keep track of that fact.
1133 */
1134void
1135io_free(
1136	unsigned int	otype,
1137	ipc_object_t	object)
1138{
1139	ipc_port_t	port;
1140
1141	if (otype == IOT_PORT) {
1142		port = (ipc_port_t) object;
1143		ipc_port_finalize(port);
1144	}
1145	io_lock_destroy(object);
1146	zfree(ipc_object_zones[otype], object);
1147}
1148