1/*
2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*
29 * @OSF_FREE_COPYRIGHT@
30 */
31/*
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
34 * All Rights Reserved.
35 *
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
41 *
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
49 *  School of Computer Science
50 *  Carnegie Mellon University
51 *  Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56/*
57 * NOTICE: This file was modified by McAfee Research in 2004 to introduce
58 * support for mandatory and extensible security protections.  This notice
59 * is included in support of clause 2.2 (b) of the Apple Public License,
60 * Version 2.0.
61 */
62/*
63 */
64/*
65 *	File:	ipc/ipc_port.c
66 *	Author:	Rich Draves
67 *	Date:	1989
68 *
69 *	Functions to manipulate IPC ports.
70 */
71
72#include <zone_debug.h>
73#include <mach_assert.h>
74
75#include <mach/port.h>
76#include <mach/kern_return.h>
77#include <kern/lock.h>
78#include <kern/ipc_kobject.h>
79#include <kern/thread.h>
80#include <kern/misc_protos.h>
81#include <kern/wait_queue.h>
82#include <ipc/ipc_entry.h>
83#include <ipc/ipc_space.h>
84#include <ipc/ipc_object.h>
85#include <ipc/ipc_port.h>
86#include <ipc/ipc_pset.h>
87#include <ipc/ipc_kmsg.h>
88#include <ipc/ipc_mqueue.h>
89#include <ipc/ipc_notify.h>
90#include <ipc/ipc_table.h>
91
92#include <security/mac_mach_internal.h>
93
94#include <string.h>
95
96decl_lck_mtx_data(,	ipc_port_multiple_lock_data)
97lck_mtx_ext_t	ipc_port_multiple_lock_data_ext;
98ipc_port_timestamp_t	ipc_port_timestamp_data;
99int ipc_portbt;
100
101#if	MACH_ASSERT
102void	ipc_port_init_debug(
103		ipc_port_t	port,
104		uintptr_t	*callstack,
105		unsigned int	callstack_max);
106
107void	ipc_port_callstack_init_debug(
108		uintptr_t	*callstack,
109		unsigned int	callstack_max);
110
111#endif	/* MACH_ASSERT */
112
113void
114ipc_port_release(ipc_port_t port)
115{
116	ip_release(port);
117}
118
119void
120ipc_port_reference(ipc_port_t port)
121{
122	ip_reference(port);
123}
124
125/*
126 *	Routine:	ipc_port_timestamp
127 *	Purpose:
128 *		Retrieve a timestamp value.
129 */
130
131ipc_port_timestamp_t
132ipc_port_timestamp(void)
133{
134	return OSIncrementAtomic(&ipc_port_timestamp_data);
135}
136
137/*
138 *	Routine:	ipc_port_request_alloc
139 *	Purpose:
140 *		Try to allocate a request slot.
141 *		If successful, returns the request index.
142 *		Otherwise returns zero.
143 *	Conditions:
144 *		The port is locked and active.
145 *	Returns:
146 *		KERN_SUCCESS		A request index was found.
147 *		KERN_NO_SPACE		No index allocated.
148 */
149
150#if IMPORTANCE_INHERITANCE
151kern_return_t
152ipc_port_request_alloc(
153	ipc_port_t			port,
154	mach_port_name_t		name,
155	ipc_port_t			soright,
156	boolean_t			send_possible,
157	boolean_t			immediate,
158	ipc_port_request_index_t	*indexp,
159	boolean_t			*importantp)
160#else
161kern_return_t
162ipc_port_request_alloc(
163	ipc_port_t			port,
164	mach_port_name_t		name,
165	ipc_port_t			soright,
166	boolean_t			send_possible,
167	boolean_t			immediate,
168	ipc_port_request_index_t	*indexp)
169#endif /* IMPORTANCE_INHERITANCE */
170{
171	ipc_port_request_t ipr, table;
172	ipc_port_request_index_t index;
173	uintptr_t mask = 0;
174
175#if IMPORTANCE_INHERITANCE
176	*importantp = FALSE;
177#endif /* IMPORTANCE_INHERITANCE */
178
179	assert(ip_active(port));
180	assert(name != MACH_PORT_NULL);
181	assert(soright != IP_NULL);
182
183	table = port->ip_requests;
184
185	if (table == IPR_NULL)
186		return KERN_NO_SPACE;
187
188	index = table->ipr_next;
189	if (index == 0)
190		return KERN_NO_SPACE;
191
192	ipr = &table[index];
193	assert(ipr->ipr_name == MACH_PORT_NULL);
194
195	table->ipr_next = ipr->ipr_next;
196	ipr->ipr_name = name;
197
198	if (send_possible) {
199		mask |= IPR_SOR_SPREQ_MASK;
200		if (immediate) {
201			mask |= IPR_SOR_SPARM_MASK;
202			if (port->ip_sprequests == 0) {
203				port->ip_sprequests = 1;
204#if IMPORTANCE_INHERITANCE
205				if (port->ip_impdonation != 0 &&
206				    port->ip_spimportant == 0 &&
207				    (task_is_importance_donor(current_task()))) {
208					port->ip_spimportant = 1;
209					*importantp = TRUE;
210				}
211#endif /* IMPORTANCE_INHERTANCE */
212			}
213		}
214	}
215	ipr->ipr_soright = IPR_SOR_MAKE(soright, mask);
216
217	*indexp = index;
218
219	return KERN_SUCCESS;
220}
221
222/*
223 *	Routine:	ipc_port_request_grow
224 *	Purpose:
225 *		Grow a port's table of requests.
226 *	Conditions:
227 *		The port must be locked and active.
228 *		Nothing else locked; will allocate memory.
229 *		Upon return the port is unlocked.
230 *	Returns:
231 *		KERN_SUCCESS		Grew the table.
232 *		KERN_SUCCESS		Somebody else grew the table.
233 *		KERN_SUCCESS		The port died.
234 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate new table.
235 *		KERN_NO_SPACE		Couldn't grow to desired size
236 */
237
238kern_return_t
239ipc_port_request_grow(
240	ipc_port_t		port,
241	ipc_table_elems_t 	target_size)
242{
243	ipc_table_size_t its;
244	ipc_port_request_t otable, ntable;
245
246	assert(ip_active(port));
247
248	otable = port->ip_requests;
249	if (otable == IPR_NULL)
250		its = &ipc_table_requests[0];
251	else
252		its = otable->ipr_size + 1;
253
254	if (target_size != ITS_SIZE_NONE) {
255		if ((otable != IPR_NULL) &&
256		    (target_size <= otable->ipr_size->its_size)) {
257			ip_unlock(port);
258			return KERN_SUCCESS;
259	        }
260		while ((its->its_size) && (its->its_size < target_size)) {
261			its++;
262		}
263		if (its->its_size == 0) {
264			ip_unlock(port);
265			return KERN_NO_SPACE;
266		}
267	}
268
269	ip_reference(port);
270	ip_unlock(port);
271
272	if ((its->its_size == 0) ||
273	    ((ntable = it_requests_alloc(its)) == IPR_NULL)) {
274		ip_release(port);
275		return KERN_RESOURCE_SHORTAGE;
276	}
277
278	ip_lock(port);
279
280	/*
281	 *	Check that port is still active and that nobody else
282	 *	has slipped in and grown the table on us.  Note that
283	 *	just checking if the current table pointer == otable
284	 *	isn't sufficient; must check ipr_size.
285	 */
286
287	if (ip_active(port) && (port->ip_requests == otable) &&
288	    ((otable == IPR_NULL) || (otable->ipr_size+1 == its))) {
289		ipc_table_size_t oits;
290		ipc_table_elems_t osize, nsize;
291		ipc_port_request_index_t free, i;
292
293		/* copy old table to new table */
294
295		if (otable != IPR_NULL) {
296			oits = otable->ipr_size;
297			osize = oits->its_size;
298			free = otable->ipr_next;
299
300			(void) memcpy((void *)(ntable + 1),
301			      (const void *)(otable + 1),
302			      (osize - 1) * sizeof(struct ipc_port_request));
303		} else {
304			osize = 1;
305			oits = 0;
306			free = 0;
307		}
308
309		nsize = its->its_size;
310		assert(nsize > osize);
311
312		/* add new elements to the new table's free list */
313
314		for (i = osize; i < nsize; i++) {
315			ipc_port_request_t ipr = &ntable[i];
316
317			ipr->ipr_name = MACH_PORT_NULL;
318			ipr->ipr_next = free;
319			free = i;
320		}
321
322		ntable->ipr_next = free;
323		ntable->ipr_size = its;
324		port->ip_requests = ntable;
325		ip_unlock(port);
326		ip_release(port);
327
328		if (otable != IPR_NULL) {
329			it_requests_free(oits, otable);
330	        }
331	} else {
332		ip_unlock(port);
333		ip_release(port);
334		it_requests_free(its, ntable);
335	}
336
337	return KERN_SUCCESS;
338}
339
340/*
341 *	Routine:	ipc_port_request_sparm
342 *	Purpose:
343 *		Arm delayed send-possible request.
344 *	Conditions:
345 *		The port must be locked and active.
346 *
347 *		Returns TRUE if the request was armed
348 *		(or armed with importance in that version).
349 */
350
351#if IMPORTANCE_INHERITANCE
352boolean_t
353ipc_port_request_sparm(
354	ipc_port_t			port,
355	__assert_only mach_port_name_t	name,
356	ipc_port_request_index_t	index,
357	mach_msg_option_t		option)
358#else
359boolean_t
360ipc_port_request_sparm(
361	ipc_port_t			port,
362	__assert_only mach_port_name_t	name,
363	ipc_port_request_index_t	index)
364#endif /* IMPORTANCE_INHERITANCE */
365{
366	if (index != IE_REQ_NONE) {
367		ipc_port_request_t ipr, table;
368
369		assert(ip_active(port));
370
371		table = port->ip_requests;
372		assert(table != IPR_NULL);
373
374		ipr = &table[index];
375		assert(ipr->ipr_name == name);
376
377		if (IPR_SOR_SPREQ(ipr->ipr_soright)) {
378			ipr->ipr_soright = IPR_SOR_MAKE(ipr->ipr_soright, IPR_SOR_SPARM_MASK);
379			port->ip_sprequests = 1;
380#if IMPORTANCE_INHERITANCE
381			if (((option & MACH_SEND_NOIMPORTANCE) == 0) &&
382			    (port->ip_impdonation != 0) &&
383			    (port->ip_spimportant == 0) &&
384			    (((option & MACH_SEND_IMPORTANCE) != 0) ||
385			     (task_is_importance_donor(current_task())))) {
386				port->ip_spimportant = 1;
387				return TRUE;
388			}
389#else
390			return TRUE;
391#endif /* IMPORTANCE_INHERITANCE */
392		}
393	}
394	return FALSE;
395}
396
397/*
398 *	Routine:	ipc_port_request_type
399 *	Purpose:
400 *		Determine the type(s) of port requests enabled for a name.
401 *	Conditions:
402 *		The port must be locked or inactive (to avoid table growth).
403 *		The index must not be IE_REQ_NONE and for the name in question.
404 */
405mach_port_type_t
406ipc_port_request_type(
407	ipc_port_t			port,
408	__assert_only mach_port_name_t	name,
409	ipc_port_request_index_t	index)
410{
411	ipc_port_request_t ipr, table;
412	mach_port_type_t type = 0;
413
414	table = port->ip_requests;
415	assert (table != IPR_NULL);
416
417	assert(index != IE_REQ_NONE);
418	ipr = &table[index];
419	assert(ipr->ipr_name == name);
420
421	if (IP_VALID(IPR_SOR_PORT(ipr->ipr_soright))) {
422		type |= MACH_PORT_TYPE_DNREQUEST;
423
424		if (IPR_SOR_SPREQ(ipr->ipr_soright)) {
425			type |= MACH_PORT_TYPE_SPREQUEST;
426
427			if (!IPR_SOR_SPARMED(ipr->ipr_soright)) {
428				type |= MACH_PORT_TYPE_SPREQUEST_DELAYED;
429			}
430		}
431	}
432	return type;
433}
434
435/*
436 *	Routine:	ipc_port_request_cancel
437 *	Purpose:
438 *		Cancel a dead-name/send-possible request and return the send-once right.
439 *	Conditions:
440 *		The port must be locked and active.
441 *		The index must not be IPR_REQ_NONE and must correspond with name.
442 */
443
444ipc_port_t
445ipc_port_request_cancel(
446	ipc_port_t			port,
447	__assert_only mach_port_name_t	name,
448	ipc_port_request_index_t	index)
449{
450	ipc_port_request_t ipr, table;
451	ipc_port_t request = IP_NULL;
452
453	assert(ip_active(port));
454	table = port->ip_requests;
455	assert(table != IPR_NULL);
456
457	assert (index != IE_REQ_NONE);
458	ipr = &table[index];
459	assert(ipr->ipr_name == name);
460	request = IPR_SOR_PORT(ipr->ipr_soright);
461
462	/* return ipr to the free list inside the table */
463	ipr->ipr_name = MACH_PORT_NULL;
464	ipr->ipr_next = table->ipr_next;
465	table->ipr_next = index;
466
467	return request;
468}
469
470/*
471 *	Routine:	ipc_port_pdrequest
472 *	Purpose:
473 *		Make a port-deleted request, returning the
474 *		previously registered send-once right.
475 *		Just cancels the previous request if notify is IP_NULL.
476 *	Conditions:
477 *		The port is locked and active.  It is unlocked.
478 *		Consumes a ref for notify (if non-null), and
479 *		returns previous with a ref (if non-null).
480 */
481
482void
483ipc_port_pdrequest(
484	ipc_port_t	port,
485	ipc_port_t	notify,
486	ipc_port_t	*previousp)
487{
488	ipc_port_t previous;
489
490	assert(ip_active(port));
491
492	previous = port->ip_pdrequest;
493	port->ip_pdrequest = notify;
494	ip_unlock(port);
495
496	*previousp = previous;
497}
498
499/*
500 *	Routine:	ipc_port_nsrequest
501 *	Purpose:
502 *		Make a no-senders request, returning the
503 *		previously registered send-once right.
504 *		Just cancels the previous request if notify is IP_NULL.
505 *	Conditions:
506 *		The port is locked and active.  It is unlocked.
507 *		Consumes a ref for notify (if non-null), and
508 *		returns previous with a ref (if non-null).
509 */
510
511void
512ipc_port_nsrequest(
513	ipc_port_t		port,
514	mach_port_mscount_t	sync,
515	ipc_port_t		notify,
516	ipc_port_t		*previousp)
517{
518	ipc_port_t previous;
519	mach_port_mscount_t mscount;
520
521	assert(ip_active(port));
522
523	previous = port->ip_nsrequest;
524	mscount = port->ip_mscount;
525
526	if ((port->ip_srights == 0) && (sync <= mscount) &&
527	    (notify != IP_NULL)) {
528		port->ip_nsrequest = IP_NULL;
529		ip_unlock(port);
530		ipc_notify_no_senders(notify, mscount);
531	} else {
532		port->ip_nsrequest = notify;
533		ip_unlock(port);
534	}
535
536	*previousp = previous;
537}
538
539
540/*
541 *	Routine:	ipc_port_clear_receiver
542 *	Purpose:
543 *		Prepares a receive right for transmission/destruction.
544 *	Conditions:
545 *		The port is locked and active.
546 */
547
548void
549ipc_port_clear_receiver(
550	ipc_port_t	port,
551	queue_t		links)
552{
553	spl_t		s;
554
555	assert(ip_active(port));
556
557	/*
558	 * pull ourselves from any sets.
559	 */
560	if (port->ip_pset_count != 0) {
561		ipc_pset_remove_from_all(port, links);
562		assert(port->ip_pset_count == 0);
563	}
564
565	/*
566	 * Send anyone waiting on the port's queue directly away.
567	 * Also clear the mscount and seqno.
568	 */
569	s = splsched();
570	imq_lock(&port->ip_messages);
571	ipc_mqueue_changed(&port->ip_messages);
572	ipc_port_set_mscount(port, 0);
573	port->ip_messages.imq_seqno = 0;
574	port->ip_context = port->ip_guarded = port->ip_strict_guard = 0;
575	imq_unlock(&port->ip_messages);
576	splx(s);
577}
578
579/*
580 *	Routine:	ipc_port_init
581 *	Purpose:
582 *		Initializes a newly-allocated port.
583 *		Doesn't touch the ip_object fields.
584 */
585
586void
587ipc_port_init(
588	ipc_port_t		port,
589	ipc_space_t		space,
590	mach_port_name_t	name)
591{
592	/* port->ip_kobject doesn't have to be initialized */
593
594	port->ip_receiver = space;
595	port->ip_receiver_name = name;
596
597	port->ip_mscount = 0;
598	port->ip_srights = 0;
599	port->ip_sorights = 0;
600
601	port->ip_nsrequest = IP_NULL;
602	port->ip_pdrequest = IP_NULL;
603	port->ip_requests = IPR_NULL;
604
605	port->ip_pset_count = 0;
606	port->ip_premsg = IKM_NULL;
607	port->ip_context = 0;
608
609	port->ip_sprequests  = 0;
610	port->ip_spimportant = 0;
611	port->ip_impdonation = 0;
612	port->ip_tempowner   = 0;
613	port->ip_taskptr     = 0;
614
615	port->ip_guarded      = 0;
616	port->ip_strict_guard = 0;
617	port->ip_impcount    = 0;
618
619	port->ip_reserved    = 0;
620
621	ipc_mqueue_init(&port->ip_messages, FALSE /* set */);
622}
623
624/*
625 *	Routine:	ipc_port_alloc
626 *	Purpose:
627 *		Allocate a port.
628 *	Conditions:
629 *		Nothing locked.  If successful, the port is returned
630 *		locked.  (The caller doesn't have a reference.)
631 *	Returns:
632 *		KERN_SUCCESS		The port is allocated.
633 *		KERN_INVALID_TASK	The space is dead.
634 *		KERN_NO_SPACE		No room for an entry in the space.
635 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
636 */
637
638kern_return_t
639ipc_port_alloc(
640	ipc_space_t		space,
641	mach_port_name_t	*namep,
642	ipc_port_t		*portp)
643{
644	ipc_port_t port;
645	mach_port_name_t name;
646	kern_return_t kr;
647
648#if     MACH_ASSERT
649	uintptr_t buf[IP_CALLSTACK_MAX];
650	ipc_port_callstack_init_debug(&buf[0], IP_CALLSTACK_MAX);
651#endif /* MACH_ASSERT */
652
653	kr = ipc_object_alloc(space, IOT_PORT,
654			      MACH_PORT_TYPE_RECEIVE, 0,
655			      &name, (ipc_object_t *) &port);
656	if (kr != KERN_SUCCESS)
657		return kr;
658
659	/* port and space are locked */
660	ipc_port_init(port, space, name);
661
662#if     MACH_ASSERT
663	ipc_port_init_debug(port, &buf[0], IP_CALLSTACK_MAX);
664#endif  /* MACH_ASSERT */
665
666	/* unlock space after init */
667	is_write_unlock(space);
668
669#if CONFIG_MACF_MACH
670	task_t issuer = current_task();
671	tasklabel_lock2 (issuer, space->is_task);
672	mac_port_label_associate(&issuer->maclabel, &space->is_task->maclabel,
673			 &port->ip_label);
674	tasklabel_unlock2 (issuer, space->is_task);
675#endif
676
677	*namep = name;
678	*portp = port;
679
680	return KERN_SUCCESS;
681}
682
683/*
684 *	Routine:	ipc_port_alloc_name
685 *	Purpose:
686 *		Allocate a port, with a specific name.
687 *	Conditions:
688 *		Nothing locked.  If successful, the port is returned
689 *		locked.  (The caller doesn't have a reference.)
690 *	Returns:
691 *		KERN_SUCCESS		The port is allocated.
692 *		KERN_INVALID_TASK	The space is dead.
693 *		KERN_NAME_EXISTS	The name already denotes a right.
694 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
695 */
696
697kern_return_t
698ipc_port_alloc_name(
699	ipc_space_t		space,
700	mach_port_name_t	name,
701	ipc_port_t		*portp)
702{
703	ipc_port_t port;
704	kern_return_t kr;
705
706#if     MACH_ASSERT
707	uintptr_t buf[IP_CALLSTACK_MAX];
708	ipc_port_callstack_init_debug(&buf[0], IP_CALLSTACK_MAX);
709#endif /* MACH_ASSERT */
710
711	kr = ipc_object_alloc_name(space, IOT_PORT,
712				   MACH_PORT_TYPE_RECEIVE, 0,
713				   name, (ipc_object_t *) &port);
714	if (kr != KERN_SUCCESS)
715		return kr;
716
717	/* port is locked */
718
719	ipc_port_init(port, space, name);
720
721#if     MACH_ASSERT
722	ipc_port_init_debug(port, &buf[0], IP_CALLSTACK_MAX);
723#endif  /* MACH_ASSERT */
724
725#if CONFIG_MACF_MACH
726	task_t issuer = current_task();
727	tasklabel_lock2 (issuer, space->is_task);
728	mac_port_label_associate(&issuer->maclabel, &space->is_task->maclabel,
729			 &port->ip_label);
730	tasklabel_unlock2 (issuer, space->is_task);
731#endif
732
733	*portp = port;
734
735	return KERN_SUCCESS;
736}
737
738/*
739 * 	Routine:	ipc_port_spnotify
740 *	Purpose:
741 *		Generate send-possible port notifications.
742 *	Conditions:
743 *		Nothing locked, reference held on port.
744 */
745void
746ipc_port_spnotify(
747	ipc_port_t	port)
748{
749	ipc_port_request_index_t index = 0;
750	ipc_table_elems_t size = 0;
751#if IMPORTANCE_INHERITANCE
752	boolean_t dropassert = FALSE;
753#endif /* IMPORTANCE_INHERITANCE */
754
755	/*
756	 * If the port has no send-possible request
757	 * armed, don't bother to lock the port.
758	 */
759	if (port->ip_sprequests == 0)
760		return;
761
762	ip_lock(port);
763
764#if IMPORTANCE_INHERITANCE
765	if (port->ip_spimportant != 0) {
766		port->ip_spimportant = 0;
767		port->ip_impcount--;
768		dropassert = TRUE;
769	}
770#endif /* IMPORTANCE_INHERITANCE */
771
772	if (port->ip_sprequests == 0) {
773		ip_unlock(port);
774		goto out;
775	}
776	port->ip_sprequests = 0;
777
778revalidate:
779	if (ip_active(port)) {
780		ipc_port_request_t requests;
781
782		/* table may change each time port unlocked (reload) */
783		requests = port->ip_requests;
784		assert(requests != IPR_NULL);
785
786		/*
787		 * no need to go beyond table size when first
788		 * we entered - those are future notifications.
789		 */
790		if (size == 0)
791			size = requests->ipr_size->its_size;
792
793		/* no need to backtrack either */
794		while (++index < size) {
795			ipc_port_request_t ipr = &requests[index];
796			mach_port_name_t name = ipr->ipr_name;
797			ipc_port_t soright = IPR_SOR_PORT(ipr->ipr_soright);
798			boolean_t armed = IPR_SOR_SPARMED(ipr->ipr_soright);
799
800			if (MACH_PORT_VALID(name) && armed && IP_VALID(soright)) {
801				/* claim send-once right - slot still inuse */
802				ipr->ipr_soright = IP_NULL;
803				ip_unlock(port);
804
805				ipc_notify_send_possible(soright, name);
806
807				ip_lock(port);
808				goto revalidate;
809			}
810		}
811	}
812	ip_unlock(port);
813out:
814#if IMPORTANCE_INHERITANCE
815	if ((dropassert == TRUE) && (current_task()->imp_receiver != 0)) {
816		/* drop internal assertion and no task lock held */
817		task_importance_drop_internal_assertion(current_task(), 1);
818	}
819#endif /* IMPORTANCE_INHERITANCE */
820	return;
821}
822
823/*
824 * 	Routine:	ipc_port_dnnotify
825 *	Purpose:
826 *		Generate dead name notifications for
827 *		all outstanding dead-name and send-
828 *		possible requests.
829 *	Conditions:
830 *		Nothing locked.
831 *		Port must be inactive.
832 *		Reference held on port.
833 */
834void
835ipc_port_dnnotify(
836	ipc_port_t	port)
837{
838	ipc_port_request_t requests = port->ip_requests;
839
840	assert(!ip_active(port));
841	if (requests != IPR_NULL) {
842		ipc_table_size_t its = requests->ipr_size;
843		ipc_table_elems_t size = its->its_size;
844		ipc_port_request_index_t index;
845		for (index = 1; index < size; index++) {
846			ipc_port_request_t ipr = &requests[index];
847			mach_port_name_t name = ipr->ipr_name;
848			ipc_port_t soright = IPR_SOR_PORT(ipr->ipr_soright);
849
850			if (MACH_PORT_VALID(name) && IP_VALID(soright)) {
851				ipc_notify_dead_name(soright, name);
852			}
853		}
854	}
855}
856
857
858/*
859 *	Routine:	ipc_port_destroy
860 *	Purpose:
861 *		Destroys a port.  Cleans up queued messages.
862 *
863 *		If the port has a backup, it doesn't get destroyed,
864 *		but is sent in a port-destroyed notification to the backup.
865 *	Conditions:
866 *		The port is locked and alive; nothing else locked.
867 *		The caller has a reference, which is consumed.
868 *		Afterwards, the port is unlocked and dead.
869 */
870
871void
872ipc_port_destroy(
873	ipc_port_t	port)
874{
875	ipc_port_t pdrequest, nsrequest;
876	ipc_mqueue_t mqueue;
877	ipc_kmsg_t kmsg;
878
879#if IMPORTANCE_INHERITANCE
880	task_t release_imp_task = TASK_NULL;
881	thread_t self = current_thread();
882	boolean_t top = (self->ith_assertions == 0);
883	natural_t assertcnt = 0;
884#endif /* IMPORTANCE_INHERITANCE */
885
886	assert(ip_active(port));
887	/* port->ip_receiver_name is garbage */
888	/* port->ip_receiver/port->ip_destination is garbage */
889	assert(port->ip_pset_count == 0);
890	assert(port->ip_mscount == 0);
891
892	/* check for a backup port */
893	pdrequest = port->ip_pdrequest;
894
895#if IMPORTANCE_INHERITANCE
896	/* determine how may assertions to drop and from whom */
897	if (port->ip_tempowner != 0) {
898		assert(top);
899		if (port->ip_taskptr != 0) {
900			release_imp_task = port->ip_imp_task;
901			port->ip_imp_task = TASK_NULL;
902			port->ip_taskptr = 0;
903			assertcnt = port->ip_impcount;
904		}
905		/* Otherwise, nothing to drop */
906	} else {
907		assert(port->ip_taskptr == 0);
908		assertcnt = port->ip_impcount;
909		if (pdrequest != IP_NULL)
910			/* mark in limbo for the journey */
911			port->ip_tempowner = 1;
912	}
913
914	if (top)
915		self->ith_assertions = assertcnt;
916#endif /* IMPORTANCE_INHERITANCE */
917
918	if (pdrequest != IP_NULL) {
919		/* we assume the ref for pdrequest */
920		port->ip_pdrequest = IP_NULL;
921
922		/* make port be in limbo */
923		port->ip_receiver_name = MACH_PORT_NULL;
924		port->ip_destination = IP_NULL;
925		ip_unlock(port);
926
927		/* consumes our refs for port and pdrequest */
928		ipc_notify_port_destroyed(pdrequest, port);
929
930		goto drop_assertions;
931	}
932
933	/* once port is dead, we don't need to keep it locked */
934
935	port->ip_object.io_bits &= ~IO_BITS_ACTIVE;
936	port->ip_timestamp = ipc_port_timestamp();
937
938	/*
939	 * If the port has a preallocated message buffer and that buffer
940	 * is not inuse, free it.  If it has an inuse one, then the kmsg
941	 * free will detect that we freed the association and it can free it
942	 * like a normal buffer.
943	 */
944	if (IP_PREALLOC(port)) {
945		ipc_port_t inuse_port;
946
947		kmsg = port->ip_premsg;
948		assert(kmsg != IKM_NULL);
949		inuse_port = ikm_prealloc_inuse_port(kmsg);
950		IP_CLEAR_PREALLOC(port, kmsg);
951		ip_unlock(port);
952		if (inuse_port != IP_NULL) {
953			assert(inuse_port == port);
954		} else {
955			ipc_kmsg_free(kmsg);
956		}
957	} else {
958		ip_unlock(port);
959	}
960
961	/* throw away no-senders request */
962	nsrequest = port->ip_nsrequest;
963	if (nsrequest != IP_NULL)
964		ipc_notify_send_once(nsrequest); /* consumes ref */
965
966	/* destroy any queued messages */
967	mqueue = &port->ip_messages;
968	ipc_mqueue_destroy(mqueue);
969
970	/* generate dead-name notifications */
971	ipc_port_dnnotify(port);
972
973	ipc_kobject_destroy(port);
974
975	ip_release(port); /* consume caller's ref */
976
977 drop_assertions:
978#if IMPORTANCE_INHERITANCE
979	if (release_imp_task != TASK_NULL) {
980		if (assertcnt > 0) {
981			assert(top);
982			self->ith_assertions = 0;
983			assert(release_imp_task->imp_receiver != 0);
984			task_importance_drop_internal_assertion(release_imp_task, assertcnt);
985		}
986		task_deallocate(release_imp_task);
987
988	} else if (assertcnt > 0) {
989		if (top) {
990			self->ith_assertions = 0;
991			release_imp_task = current_task();
992			if (release_imp_task->imp_receiver != 0) {
993				task_importance_drop_internal_assertion(release_imp_task, assertcnt);
994			}
995		} else {
996			/* the port chain we are enqueued on should cover our assertions */
997			assert(assertcnt <= self->ith_assertions);
998		}
999	}
1000#endif /* IMPORTANCE_INHERITANCE */
1001}
1002
1003/*
1004 *	Routine:	ipc_port_check_circularity
1005 *	Purpose:
1006 *		Check if queueing "port" in a message for "dest"
1007 *		would create a circular group of ports and messages.
1008 *
1009 *		If no circularity (FALSE returned), then "port"
1010 *		is changed from "in limbo" to "in transit".
1011 *
1012 *		That is, we want to set port->ip_destination == dest,
1013 *		but guaranteeing that this doesn't create a circle
1014 *		port->ip_destination->ip_destination->... == port
1015 *
1016 *		Additionally, if port was successfully changed to "in transit",
1017 *		propagate boost assertions from the "in limbo" port to all
1018 *		the ports in the chain, and, if the destination task accepts
1019 *		boosts, to the destination task.
1020 *
1021 *	Conditions:
1022 *		No ports locked.  References held for "port" and "dest".
1023 */
1024
1025boolean_t
1026ipc_port_check_circularity(
1027	ipc_port_t	port,
1028	ipc_port_t	dest)
1029{
1030	ipc_port_t base;
1031
1032#if IMPORTANCE_INHERITANCE
1033	task_t task = TASK_NULL;
1034	task_t release_task = TASK_NULL;
1035	int assertcnt = 0;
1036#endif /* IMPORTANCE_INHERITANCE */
1037
1038	assert(port != IP_NULL);
1039	assert(dest != IP_NULL);
1040
1041	if (port == dest)
1042		return TRUE;
1043	base = dest;
1044
1045	/*
1046	 *	First try a quick check that can run in parallel.
1047	 *	No circularity if dest is not in transit.
1048	 */
1049
1050	ip_lock(port);
1051	if (ip_lock_try(dest)) {
1052		if (!ip_active(dest) ||
1053		    (dest->ip_receiver_name != MACH_PORT_NULL) ||
1054		    (dest->ip_destination == IP_NULL))
1055			goto not_circular;
1056
1057		/* dest is in transit; further checking necessary */
1058
1059		ip_unlock(dest);
1060	}
1061	ip_unlock(port);
1062
1063	ipc_port_multiple_lock(); /* massive serialization */
1064
1065	/*
1066	 *	Search for the end of the chain (a port not in transit),
1067	 *	acquiring locks along the way.
1068	 */
1069
1070	for (;;) {
1071		ip_lock(base);
1072
1073		if (!ip_active(base) ||
1074		    (base->ip_receiver_name != MACH_PORT_NULL) ||
1075		    (base->ip_destination == IP_NULL))
1076			break;
1077
1078		base = base->ip_destination;
1079	}
1080
1081	/* all ports in chain from dest to base, inclusive, are locked */
1082
1083	if (port == base) {
1084		/* circularity detected! */
1085
1086		ipc_port_multiple_unlock();
1087
1088		/* port (== base) is in limbo */
1089
1090		assert(ip_active(port));
1091		assert(port->ip_receiver_name == MACH_PORT_NULL);
1092		assert(port->ip_destination == IP_NULL);
1093
1094		while (dest != IP_NULL) {
1095			ipc_port_t next;
1096
1097			/* dest is in transit or in limbo */
1098
1099			assert(ip_active(dest));
1100			assert(dest->ip_receiver_name == MACH_PORT_NULL);
1101
1102			next = dest->ip_destination;
1103			ip_unlock(dest);
1104			dest = next;
1105		}
1106
1107		return TRUE;
1108	}
1109
1110	/*
1111	 *	The guarantee:  lock port while the entire chain is locked.
1112	 *	Once port is locked, we can take a reference to dest,
1113	 *	add port to the chain, and unlock everything.
1114	 */
1115
1116	ip_lock(port);
1117	ipc_port_multiple_unlock();
1118
1119    not_circular:
1120
1121	/* port is in limbo */
1122
1123	assert(ip_active(port));
1124	assert(port->ip_receiver_name == MACH_PORT_NULL);
1125	assert(port->ip_destination == IP_NULL);
1126
1127	ip_reference(dest);
1128	port->ip_destination = dest;
1129
1130#if IMPORTANCE_INHERITANCE
1131	/* must have been in limbo or still bound to a task */
1132	assert(port->ip_tempowner != 0);
1133
1134	if (port->ip_taskptr != 0) {
1135		/*
1136		 * We delayed dropping assertions from a specific task.
1137		 * Cache that info now (we'll drop assertions and the
1138		 * task reference below).
1139		 */
1140		release_task = port->ip_imp_task;
1141		port->ip_imp_task = TASK_NULL;
1142		port->ip_taskptr = 0;
1143	}
1144	assertcnt = port->ip_impcount;
1145
1146	/* take the port out of limbo w.r.t. assertions */
1147	port->ip_tempowner = 0;
1148
1149#endif /* IMPORTANCE_INHERITANCE */
1150
1151	/* now unlock chain */
1152
1153	ip_unlock(port);
1154
1155	for (;;) {
1156
1157#if IMPORTANCE_INHERITANCE
1158		/* every port along chain track assertions behind it */
1159		dest->ip_impcount += assertcnt;
1160#endif /* IMPORTANCE_INHERITANCE */
1161
1162		if (dest == base)
1163			break;
1164
1165		/* port is in transit */
1166
1167		assert(ip_active(dest));
1168		assert(dest->ip_receiver_name == MACH_PORT_NULL);
1169		assert(dest->ip_destination != IP_NULL);
1170
1171#if IMPORTANCE_INHERITANCE
1172		assert(dest->ip_tempowner == 0);
1173#endif /* IMPORTANCE_INHERITANCE */
1174
1175		port = dest->ip_destination;
1176		ip_unlock(dest);
1177		dest = port;
1178	}
1179
1180	/* base is not in transit */
1181	assert(!ip_active(base) ||
1182	       (base->ip_receiver_name != MACH_PORT_NULL) ||
1183	       (base->ip_destination == IP_NULL));
1184
1185#if IMPORTANCE_INHERITANCE
1186	/*
1187	 * Find the task to boost (if any).
1188	 * We will boost "through" ports that don't know
1189	 * about inheritance to deliver receive rights that
1190	 * do.
1191	 */
1192	if (ip_active(base) && (assertcnt > 0)) {
1193		if (base->ip_tempowner != 0) {
1194			if (base->ip_taskptr != 0)
1195				/* specified tempowner task */
1196				task = base->ip_imp_task;
1197			/* otherwise don't boost current task */
1198
1199		} else if (base->ip_receiver_name != MACH_PORT_NULL) {
1200			ipc_space_t space = base->ip_receiver;
1201
1202			/* only spaces with boost-accepting tasks */
1203			if (space->is_task != TASK_NULL &&
1204			    space->is_task->imp_receiver != 0)
1205				task = space->is_task;
1206		}
1207
1208		/* take reference before unlocking base */
1209		if (task != TASK_NULL) {
1210			assert(task->imp_receiver != 0);
1211			task_reference(task);
1212		}
1213	}
1214#endif /* IMPORTANCE_INHERITANCE */
1215
1216	ip_unlock(base);
1217
1218#if IMPORTANCE_INHERITANCE
1219	/*
1220	 * Transfer assertions now that the ports are unlocked.
1221	 * Avoid extra overhead if transferring to/from the same task.
1222	 */
1223	boolean_t transfer_assertions = (task != release_task) ? TRUE : FALSE;
1224
1225	if (task != TASK_NULL) {
1226		if (transfer_assertions)
1227			task_importance_hold_internal_assertion(task, assertcnt);
1228		task_deallocate(task);
1229		task = TASK_NULL;
1230	}
1231
1232	if (release_task != TASK_NULL) {
1233		if (transfer_assertions)
1234			task_importance_drop_internal_assertion(release_task, assertcnt);
1235		task_deallocate(release_task);
1236		release_task = TASK_NULL;
1237	}
1238#endif /* IMPORTANCE_INHERITANCE */
1239
1240	return FALSE;
1241}
1242
1243/*
1244 *	Routine:	ipc_port_importance_delta
1245 *	Purpose:
1246 *		Adjust the importance count through the given port.
1247 *		If the port is in transit, apply the delta throughout
1248 *		the chain. Determine if the there is a task at the
1249 *		base of the chain that wants/needs to be adjusted,
1250 *		and if so, apply the delta.
1251 *	Conditions:
1252 *		The port is referenced and locked on entry.
1253 *		Nothing else is locked.
1254 *		The lock may be dropped on exit.
1255 *		Returns TRUE if lock was dropped.
1256 */
1257#if IMPORTANCE_INHERITANCE
1258
1259boolean_t
1260ipc_port_importance_delta(
1261	ipc_port_t 		port,
1262	mach_port_delta_t	delta)
1263{
1264	ipc_port_t next, base;
1265	task_t task = TASK_NULL;
1266	boolean_t dropped = FALSE;
1267
1268	if (delta == 0)
1269		return FALSE;
1270
1271	base = port;
1272
1273	/* if port is in transit, have to search for end of chain */
1274	if (ip_active(port) &&
1275	    port->ip_destination != IP_NULL &&
1276	    port->ip_receiver_name == MACH_PORT_NULL) {
1277
1278		dropped = TRUE;
1279
1280		ip_unlock(port);
1281		ipc_port_multiple_lock(); /* massive serialization */
1282		ip_lock(base);
1283
1284		while(ip_active(base) &&
1285		      base->ip_destination != IP_NULL &&
1286		      base->ip_receiver_name == MACH_PORT_NULL) {
1287
1288			base = base->ip_destination;
1289			ip_lock(base);
1290		}
1291		ipc_port_multiple_unlock();
1292	}
1293
1294	/* unlock down to the base, adding a boost at each level */
1295	for (;;) {
1296		port->ip_impcount += delta;
1297
1298		if (port == base)
1299			break;
1300
1301		/* port is in transit */
1302		assert(port->ip_tempowner == 0);
1303		next = port->ip_destination;
1304		ip_unlock(port);
1305		port = next;
1306	}
1307
1308	/* find the task (if any) to boost according to the base */
1309	if (ip_active(base)) {
1310		if (base->ip_tempowner != 0) {
1311			if (base->ip_taskptr != 0)
1312				task = base->ip_imp_task;
1313			/* otherwise don't boost */
1314
1315		} else if (base->ip_receiver_name != MACH_PORT_NULL) {
1316			ipc_space_t space = base->ip_receiver;
1317
1318			/* only spaces with boost-accepting tasks */
1319			if (space->is_task != TASK_NULL &&
1320			    space->is_task->imp_receiver != 0)
1321				task = space->is_task;
1322		}
1323	}
1324
1325	/*
1326	 * Only the base is locked.  If we have to hold or drop task
1327	 * importance assertions, we'll have to drop that lock as well.
1328	 */
1329	if (task != TASK_NULL) {
1330		/* take a reference before unlocking base */
1331		assert(task->imp_receiver != 0);
1332		task_reference(task);
1333
1334		ip_unlock(base);
1335		dropped = TRUE;
1336
1337		if (delta > 0)
1338			task_importance_hold_internal_assertion(task, delta);
1339		else
1340			task_importance_drop_internal_assertion(task, -delta);
1341
1342		task_deallocate(task);
1343	} else if (dropped == TRUE) {
1344		ip_unlock(base);
1345	}
1346
1347	return dropped;
1348}
1349#endif /* IMPORTANCE_INHERITANCE */
1350
1351/*
1352 *	Routine:	ipc_port_lookup_notify
1353 *	Purpose:
1354 *		Make a send-once notify port from a receive right.
1355 *		Returns IP_NULL if name doesn't denote a receive right.
1356 *	Conditions:
1357 *		The space must be locked (read or write) and active.
1358 *  		Being the active space, we can rely on thread server_id
1359 *		context to give us the proper server level sub-order
1360 *		within the space.
1361 */
1362
1363ipc_port_t
1364ipc_port_lookup_notify(
1365	ipc_space_t		space,
1366	mach_port_name_t	name)
1367{
1368	ipc_port_t port;
1369	ipc_entry_t entry;
1370
1371	assert(is_active(space));
1372
1373	entry = ipc_entry_lookup(space, name);
1374	if (entry == IE_NULL)
1375		return IP_NULL;
1376	if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)
1377		return IP_NULL;
1378
1379	port = (ipc_port_t) entry->ie_object;
1380	assert(port != IP_NULL);
1381
1382	ip_lock(port);
1383	assert(ip_active(port));
1384	assert(port->ip_receiver_name == name);
1385	assert(port->ip_receiver == space);
1386
1387	ip_reference(port);
1388	port->ip_sorights++;
1389	ip_unlock(port);
1390
1391	return port;
1392}
1393
1394/*
1395 *	Routine:	ipc_port_make_send_locked
1396 *	Purpose:
1397 *		Make a naked send right from a receive right.
1398 *
1399 *	Conditions:
1400 *		port locked and active.
1401 */
1402ipc_port_t
1403ipc_port_make_send_locked(
1404	ipc_port_t	port)
1405{
1406	assert(ip_active(port));
1407	port->ip_mscount++;
1408	port->ip_srights++;
1409	ip_reference(port);
1410	return port;
1411}
1412
1413/*
1414 *	Routine:	ipc_port_make_send
1415 *	Purpose:
1416 *		Make a naked send right from a receive right.
1417 */
1418
1419ipc_port_t
1420ipc_port_make_send(
1421	ipc_port_t	port)
1422{
1423
1424	if (!IP_VALID(port))
1425		return port;
1426
1427	ip_lock(port);
1428	if (ip_active(port)) {
1429		port->ip_mscount++;
1430		port->ip_srights++;
1431		ip_reference(port);
1432		ip_unlock(port);
1433		return port;
1434	}
1435	ip_unlock(port);
1436	return IP_DEAD;
1437}
1438
1439/*
1440 *	Routine:	ipc_port_copy_send
1441 *	Purpose:
1442 *		Make a naked send right from another naked send right.
1443 *			IP_NULL		-> IP_NULL
1444 *			IP_DEAD		-> IP_DEAD
1445 *			dead port	-> IP_DEAD
1446 *			live port	-> port + ref
1447 *	Conditions:
1448 *		Nothing locked except possibly a space.
1449 */
1450
1451ipc_port_t
1452ipc_port_copy_send(
1453	ipc_port_t	port)
1454{
1455	ipc_port_t sright;
1456
1457	if (!IP_VALID(port))
1458		return port;
1459
1460	ip_lock(port);
1461	if (ip_active(port)) {
1462		assert(port->ip_srights > 0);
1463
1464		ip_reference(port);
1465		port->ip_srights++;
1466		sright = port;
1467	} else
1468		sright = IP_DEAD;
1469	ip_unlock(port);
1470
1471	return sright;
1472}
1473
1474/*
1475 *	Routine:	ipc_port_copyout_send
1476 *	Purpose:
1477 *		Copyout a naked send right (possibly null/dead),
1478 *		or if that fails, destroy the right.
1479 *	Conditions:
1480 *		Nothing locked.
1481 */
1482
1483mach_port_name_t
1484ipc_port_copyout_send(
1485	ipc_port_t	sright,
1486	ipc_space_t	space)
1487{
1488	mach_port_name_t name;
1489
1490	if (IP_VALID(sright)) {
1491		kern_return_t kr;
1492
1493		kr = ipc_object_copyout(space, (ipc_object_t) sright,
1494					MACH_MSG_TYPE_PORT_SEND, TRUE, &name);
1495		if (kr != KERN_SUCCESS) {
1496			ipc_port_release_send(sright);
1497
1498			if (kr == KERN_INVALID_CAPABILITY)
1499				name = MACH_PORT_DEAD;
1500			else
1501				name = MACH_PORT_NULL;
1502		}
1503	} else
1504		name = CAST_MACH_PORT_TO_NAME(sright);
1505
1506	return name;
1507}
1508
1509/*
1510 *	Routine:	ipc_port_release_send
1511 *	Purpose:
1512 *		Release a naked send right.
1513 *		Consumes a ref for the port.
1514 *	Conditions:
1515 *		Nothing locked.
1516 */
1517
1518void
1519ipc_port_release_send(
1520	ipc_port_t	port)
1521{
1522	ipc_port_t nsrequest = IP_NULL;
1523	mach_port_mscount_t mscount;
1524
1525	if (!IP_VALID(port))
1526		return;
1527
1528	ip_lock(port);
1529
1530	if (!ip_active(port)) {
1531		ip_unlock(port);
1532		ip_release(port);
1533		return;
1534	}
1535
1536	assert(port->ip_srights > 0);
1537
1538	if (--port->ip_srights == 0 &&
1539	    port->ip_nsrequest != IP_NULL) {
1540		nsrequest = port->ip_nsrequest;
1541		port->ip_nsrequest = IP_NULL;
1542		mscount = port->ip_mscount;
1543		ip_unlock(port);
1544		ip_release(port);
1545		ipc_notify_no_senders(nsrequest, mscount);
1546	} else {
1547		ip_unlock(port);
1548		ip_release(port);
1549	}
1550}
1551
1552/*
1553 *	Routine:	ipc_port_make_sonce_locked
1554 *	Purpose:
1555 *		Make a naked send-once right from a receive right.
1556 *	Conditions:
1557 *		The port is locked and active.
1558 */
1559
1560ipc_port_t
1561ipc_port_make_sonce_locked(
1562	ipc_port_t	port)
1563{
1564	assert(ip_active(port));
1565	port->ip_sorights++;
1566	ip_reference(port);
1567	return port;
1568}
1569
1570/*
1571 *	Routine:	ipc_port_make_sonce
1572 *	Purpose:
1573 *		Make a naked send-once right from a receive right.
1574 *	Conditions:
1575 *		The port is not locked.
1576 */
1577
1578ipc_port_t
1579ipc_port_make_sonce(
1580	ipc_port_t	port)
1581{
1582	if (!IP_VALID(port))
1583		return port;
1584
1585	ip_lock(port);
1586	if (ip_active(port)) {
1587		port->ip_sorights++;
1588		ip_reference(port);
1589		ip_unlock(port);
1590		return port;
1591	}
1592	ip_unlock(port);
1593	return IP_DEAD;
1594}
1595
1596/*
1597 *	Routine:	ipc_port_release_sonce
1598 *	Purpose:
1599 *		Release a naked send-once right.
1600 *		Consumes a ref for the port.
1601 *
1602 *		In normal situations, this is never used.
1603 *		Send-once rights are only consumed when
1604 *		a message (possibly a send-once notification)
1605 *		is sent to them.
1606 *	Conditions:
1607 *		Nothing locked except possibly a space.
1608 */
1609
1610void
1611ipc_port_release_sonce(
1612	ipc_port_t	port)
1613{
1614	if (!IP_VALID(port))
1615		return;
1616
1617	ip_lock(port);
1618
1619	assert(port->ip_sorights > 0);
1620
1621	port->ip_sorights--;
1622
1623	ip_unlock(port);
1624	ip_release(port);
1625}
1626
1627/*
1628 *	Routine:	ipc_port_release_receive
1629 *	Purpose:
1630 *		Release a naked (in limbo or in transit) receive right.
1631 *		Consumes a ref for the port; destroys the port.
1632 *	Conditions:
1633 *		Nothing locked.
1634 */
1635
1636void
1637ipc_port_release_receive(
1638	ipc_port_t	port)
1639{
1640	ipc_port_t dest;
1641
1642	if (!IP_VALID(port))
1643		return;
1644
1645	ip_lock(port);
1646	assert(ip_active(port));
1647	assert(port->ip_receiver_name == MACH_PORT_NULL);
1648	dest = port->ip_destination;
1649
1650	ipc_port_destroy(port); /* consumes ref, unlocks */
1651
1652	if (dest != IP_NULL)
1653		ip_release(dest);
1654}
1655
1656/*
1657 *	Routine:	ipc_port_alloc_special
1658 *	Purpose:
1659 *		Allocate a port in a special space.
1660 *		The new port is returned with one ref.
1661 *		If unsuccessful, IP_NULL is returned.
1662 *	Conditions:
1663 *		Nothing locked.
1664 */
1665
1666ipc_port_t
1667ipc_port_alloc_special(
1668	ipc_space_t	space)
1669{
1670	ipc_port_t port;
1671
1672	port = (ipc_port_t) io_alloc(IOT_PORT);
1673	if (port == IP_NULL)
1674		return IP_NULL;
1675
1676#if     MACH_ASSERT
1677	uintptr_t buf[IP_CALLSTACK_MAX];
1678	ipc_port_callstack_init_debug(&buf[0], IP_CALLSTACK_MAX);
1679#endif /* MACH_ASSERT */
1680
1681	bzero((char *)port, sizeof(*port));
1682	io_lock_init(&port->ip_object);
1683	port->ip_references = 1;
1684	port->ip_object.io_bits = io_makebits(TRUE, IOT_PORT, 0);
1685
1686	ipc_port_init(port, space, 1);
1687
1688#if     MACH_ASSERT
1689	ipc_port_init_debug(port, &buf[0], IP_CALLSTACK_MAX);
1690#endif  /* MACH_ASSERT */
1691
1692#if CONFIG_MACF_MACH
1693	/* Currently, ipc_port_alloc_special is used for two things:
1694	 * - Reply ports for messages from the kernel
1695	 * - Ports for communication with the kernel (e.g. task ports)
1696	 * Since both of these would typically be labelled as kernel objects,
1697	 * we will use a new entry point for this purpose, as current_task()
1698	 * is often wrong (i.e. not kernel_task) or null.
1699	 */
1700	mac_port_label_init(&port->ip_label);
1701	mac_port_label_associate_kernel(&port->ip_label, space == ipc_space_reply);
1702#endif
1703
1704	return port;
1705}
1706
1707/*
1708 *	Routine:	ipc_port_dealloc_special
1709 *	Purpose:
1710 *		Deallocate a port in a special space.
1711 *		Consumes one ref for the port.
1712 *	Conditions:
1713 *		Nothing locked.
1714 */
1715
1716void
1717ipc_port_dealloc_special(
1718	ipc_port_t			port,
1719	__assert_only ipc_space_t	space)
1720{
1721	ip_lock(port);
1722	assert(ip_active(port));
1723//	assert(port->ip_receiver_name != MACH_PORT_NULL);
1724	assert(port->ip_receiver == space);
1725
1726	/*
1727	 *	We clear ip_receiver_name and ip_receiver to simplify
1728	 *	the ipc_space_kernel check in ipc_mqueue_send.
1729	 */
1730
1731	port->ip_receiver_name = MACH_PORT_NULL;
1732	port->ip_receiver = IS_NULL;
1733
1734	/* relevant part of ipc_port_clear_receiver */
1735	ipc_port_set_mscount(port, 0);
1736	port->ip_messages.imq_seqno = 0;
1737
1738	ipc_port_destroy(port);
1739}
1740
1741/*
1742 *	Routine:	ipc_port_finalize
1743 *	Purpose:
1744 *		Called on last reference deallocate to
1745 *		free any remaining data associated with the
1746 *		port.
1747 *	Conditions:
1748 *		Nothing locked.
1749 */
1750void
1751ipc_port_finalize(
1752	ipc_port_t		port)
1753{
1754	ipc_port_request_t requests = port->ip_requests;
1755
1756	assert(!ip_active(port));
1757	if (requests != IPR_NULL) {
1758		ipc_table_size_t its = requests->ipr_size;
1759		it_requests_free(its, requests);
1760		port->ip_requests = IPR_NULL;
1761	}
1762
1763#if	MACH_ASSERT
1764	ipc_port_track_dealloc(port);
1765#endif	/* MACH_ASSERT */
1766
1767#if CONFIG_MACF_MACH
1768	/* Port label should have been initialized after creation. */
1769	mac_port_label_destroy(&port->ip_label);
1770#endif
1771}
1772
1773#if	MACH_ASSERT
1774#include <kern/machine.h>
1775
1776/*
1777 *	Keep a list of all allocated ports.
1778 *	Allocation is intercepted via ipc_port_init;
1779 *	deallocation is intercepted via io_free.
1780 */
1781queue_head_t	port_alloc_queue;
1782lck_spin_t	port_alloc_queue_lock;
1783
1784unsigned long	port_count = 0;
1785unsigned long	port_count_warning = 20000;
1786unsigned long	port_timestamp = 0;
1787
1788void		db_port_stack_trace(
1789			ipc_port_t	port);
1790void		db_ref(
1791			int		refs);
1792int		db_port_walk(
1793			unsigned int	verbose,
1794			unsigned int	display,
1795			unsigned int	ref_search,
1796			unsigned int	ref_target);
1797
1798/*
1799 *	Initialize global state needed for run-time
1800 *	port debugging.
1801 */
1802void
1803ipc_port_debug_init(void)
1804{
1805	queue_init(&port_alloc_queue);
1806
1807	lck_spin_init(&port_alloc_queue_lock, &ipc_lck_grp, &ipc_lck_attr);
1808
1809	if (!PE_parse_boot_argn("ipc_portbt", &ipc_portbt, sizeof (ipc_portbt)))
1810		ipc_portbt = 0;
1811}
1812
1813#ifdef MACH_BSD
1814extern int proc_pid(struct proc*);
1815#endif /* MACH_BSD */
1816
1817/*
1818 *	Initialize all of the debugging state in a port.
1819 *	Insert the port into a global list of all allocated ports.
1820 */
1821void
1822ipc_port_init_debug(
1823	ipc_port_t	port,
1824	uintptr_t 	*callstack,
1825	unsigned int	callstack_max)
1826{
1827	unsigned int	i;
1828
1829	port->ip_thread = current_thread();
1830	port->ip_timetrack = port_timestamp++;
1831	for (i = 0; i < callstack_max; ++i)
1832		port->ip_callstack[i] = callstack[i];
1833	for (i = 0; i < IP_NSPARES; ++i)
1834		port->ip_spares[i] = 0;
1835
1836#ifdef MACH_BSD
1837	task_t task = current_task();
1838	if (task != TASK_NULL) {
1839		struct proc* proc = (struct proc*) get_bsdtask_info(task);
1840		if (proc)
1841			port->ip_spares[0] = proc_pid(proc);
1842	}
1843#endif /* MACH_BSD */
1844
1845#if 0
1846	lck_spin_lock(&port_alloc_queue_lock);
1847	++port_count;
1848	if (port_count_warning > 0 && port_count >= port_count_warning)
1849		assert(port_count < port_count_warning);
1850	queue_enter(&port_alloc_queue, port, ipc_port_t, ip_port_links);
1851	lck_spin_unlock(&port_alloc_queue_lock);
1852#endif
1853}
1854
1855/*
1856 *	Routine:	ipc_port_callstack_init_debug
1857 *	Purpose:
1858 *		Calls the machine-dependent routine to
1859 *		fill in an array with up to IP_CALLSTACK_MAX
1860 *		levels of return pc information
1861 *	Conditions:
1862 *		May block (via copyin)
1863 */
1864void
1865ipc_port_callstack_init_debug(
1866	uintptr_t	*callstack,
1867	unsigned int	callstack_max)
1868{
1869	unsigned int	i;
1870
1871	/* guarantee the callstack is initialized */
1872	for (i=0; i < callstack_max; i++)
1873		callstack[i] = 0;
1874
1875	if (ipc_portbt)
1876		machine_callstack(callstack, callstack_max);
1877}
1878
1879/*
1880 *	Remove a port from the queue of allocated ports.
1881 *	This routine should be invoked JUST prior to
1882 *	deallocating the actual memory occupied by the port.
1883 */
1884#if 1
1885void
1886ipc_port_track_dealloc(
1887	__unused ipc_port_t	port)
1888{
1889}
1890#else
1891void
1892ipc_port_track_dealloc(
1893	ipc_port_t		port)
1894{
1895	lck_spin_lock(&port_alloc_queue_lock);
1896	assert(port_count > 0);
1897	--port_count;
1898	queue_remove(&port_alloc_queue, port, ipc_port_t, ip_port_links);
1899	lck_spin_unlock(&port_alloc_queue_lock);
1900}
1901#endif
1902
1903
1904#endif	/* MACH_ASSERT */
1905