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/ipc_kobject.h>
78#include <kern/thread.h>
79#include <kern/misc_protos.h>
80#include <kern/wait_queue.h>
81#include <ipc/ipc_entry.h>
82#include <ipc/ipc_space.h>
83#include <ipc/ipc_object.h>
84#include <ipc/ipc_port.h>
85#include <ipc/ipc_pset.h>
86#include <ipc/ipc_kmsg.h>
87#include <ipc/ipc_mqueue.h>
88#include <ipc/ipc_notify.h>
89#include <ipc/ipc_table.h>
90#include <ipc/ipc_importance.h>
91
92#include <security/mac_mach_internal.h>
93
94#include <string.h>
95
96decl_lck_spin_data(,	ipc_port_multiple_lock_data)
97ipc_port_timestamp_t	ipc_port_timestamp_data;
98int ipc_portbt;
99
100#if	MACH_ASSERT
101void	ipc_port_init_debug(
102		ipc_port_t	port,
103		uintptr_t	*callstack,
104		unsigned int	callstack_max);
105
106void	ipc_port_callstack_init_debug(
107		uintptr_t	*callstack,
108		unsigned int	callstack_max);
109
110#endif	/* MACH_ASSERT */
111
112void
113ipc_port_release(ipc_port_t port)
114{
115	ip_release(port);
116}
117
118void
119ipc_port_reference(ipc_port_t port)
120{
121	ip_reference(port);
122}
123
124/*
125 *	Routine:	ipc_port_timestamp
126 *	Purpose:
127 *		Retrieve a timestamp value.
128 */
129
130ipc_port_timestamp_t
131ipc_port_timestamp(void)
132{
133	return OSIncrementAtomic(&ipc_port_timestamp_data);
134}
135
136/*
137 *	Routine:	ipc_port_request_alloc
138 *	Purpose:
139 *		Try to allocate a request slot.
140 *		If successful, returns the request index.
141 *		Otherwise returns zero.
142 *	Conditions:
143 *		The port is locked and active.
144 *	Returns:
145 *		KERN_SUCCESS		A request index was found.
146 *		KERN_NO_SPACE		No index allocated.
147 */
148
149#if IMPORTANCE_INHERITANCE
150kern_return_t
151ipc_port_request_alloc(
152	ipc_port_t			port,
153	mach_port_name_t		name,
154	ipc_port_t			soright,
155	boolean_t			send_possible,
156	boolean_t			immediate,
157	ipc_port_request_index_t	*indexp,
158	boolean_t			*importantp)
159#else
160kern_return_t
161ipc_port_request_alloc(
162	ipc_port_t			port,
163	mach_port_name_t		name,
164	ipc_port_t			soright,
165	boolean_t			send_possible,
166	boolean_t			immediate,
167	ipc_port_request_index_t	*indexp)
168#endif /* IMPORTANCE_INHERITANCE */
169{
170	ipc_port_request_t ipr, table;
171	ipc_port_request_index_t index;
172	uintptr_t mask = 0;
173
174#if IMPORTANCE_INHERITANCE
175	*importantp = FALSE;
176#endif /* IMPORTANCE_INHERITANCE */
177
178	assert(ip_active(port));
179	assert(name != MACH_PORT_NULL);
180	assert(soright != IP_NULL);
181
182	table = port->ip_requests;
183
184	if (table == IPR_NULL)
185		return KERN_NO_SPACE;
186
187	index = table->ipr_next;
188	if (index == 0)
189		return KERN_NO_SPACE;
190
191	ipr = &table[index];
192	assert(ipr->ipr_name == MACH_PORT_NULL);
193
194	table->ipr_next = ipr->ipr_next;
195	ipr->ipr_name = name;
196
197	if (send_possible) {
198		mask |= IPR_SOR_SPREQ_MASK;
199		if (immediate) {
200			mask |= IPR_SOR_SPARM_MASK;
201			if (port->ip_sprequests == 0) {
202				port->ip_sprequests = 1;
203#if IMPORTANCE_INHERITANCE
204				/* TODO: Live importance support in send-possible */
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
614	port->ip_guarded      = 0;
615	port->ip_strict_guard = 0;
616	port->ip_impcount    = 0;
617
618	port->ip_reserved    = 0;
619
620	ipc_mqueue_init(&port->ip_messages, FALSE /* set */);
621}
622
623/*
624 *	Routine:	ipc_port_alloc
625 *	Purpose:
626 *		Allocate a port.
627 *	Conditions:
628 *		Nothing locked.  If successful, the port is returned
629 *		locked.  (The caller doesn't have a reference.)
630 *	Returns:
631 *		KERN_SUCCESS		The port is allocated.
632 *		KERN_INVALID_TASK	The space is dead.
633 *		KERN_NO_SPACE		No room for an entry in the space.
634 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
635 */
636
637kern_return_t
638ipc_port_alloc(
639	ipc_space_t		space,
640	mach_port_name_t	*namep,
641	ipc_port_t		*portp)
642{
643	ipc_port_t port;
644	mach_port_name_t name;
645	kern_return_t kr;
646
647#if     MACH_ASSERT
648	uintptr_t buf[IP_CALLSTACK_MAX];
649	ipc_port_callstack_init_debug(&buf[0], IP_CALLSTACK_MAX);
650#endif /* MACH_ASSERT */
651
652	kr = ipc_object_alloc(space, IOT_PORT,
653			      MACH_PORT_TYPE_RECEIVE, 0,
654			      &name, (ipc_object_t *) &port);
655	if (kr != KERN_SUCCESS)
656		return kr;
657
658	/* port and space are locked */
659	ipc_port_init(port, space, name);
660
661#if     MACH_ASSERT
662	ipc_port_init_debug(port, &buf[0], IP_CALLSTACK_MAX);
663#endif  /* MACH_ASSERT */
664
665	/* unlock space after init */
666	is_write_unlock(space);
667
668	*namep = name;
669	*portp = port;
670
671	return KERN_SUCCESS;
672}
673
674/*
675 *	Routine:	ipc_port_alloc_name
676 *	Purpose:
677 *		Allocate a port, with a specific name.
678 *	Conditions:
679 *		Nothing locked.  If successful, the port is returned
680 *		locked.  (The caller doesn't have a reference.)
681 *	Returns:
682 *		KERN_SUCCESS		The port is allocated.
683 *		KERN_INVALID_TASK	The space is dead.
684 *		KERN_NAME_EXISTS	The name already denotes a right.
685 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
686 */
687
688kern_return_t
689ipc_port_alloc_name(
690	ipc_space_t		space,
691	mach_port_name_t	name,
692	ipc_port_t		*portp)
693{
694	ipc_port_t port;
695	kern_return_t kr;
696
697#if     MACH_ASSERT
698	uintptr_t buf[IP_CALLSTACK_MAX];
699	ipc_port_callstack_init_debug(&buf[0], IP_CALLSTACK_MAX);
700#endif /* MACH_ASSERT */
701
702	kr = ipc_object_alloc_name(space, IOT_PORT,
703				   MACH_PORT_TYPE_RECEIVE, 0,
704				   name, (ipc_object_t *) &port);
705	if (kr != KERN_SUCCESS)
706		return kr;
707
708	/* port is locked */
709
710	ipc_port_init(port, space, name);
711
712#if     MACH_ASSERT
713	ipc_port_init_debug(port, &buf[0], IP_CALLSTACK_MAX);
714#endif  /* MACH_ASSERT */
715
716	*portp = port;
717
718	return KERN_SUCCESS;
719}
720
721/*
722 * 	Routine:	ipc_port_spnotify
723 *	Purpose:
724 *		Generate send-possible port notifications.
725 *	Conditions:
726 *		Nothing locked, reference held on port.
727 */
728void
729ipc_port_spnotify(
730	ipc_port_t	port)
731{
732	ipc_port_request_index_t index = 0;
733	ipc_table_elems_t size = 0;
734#if IMPORTANCE_INHERITANCE
735	boolean_t dropassert = FALSE;
736#endif /* IMPORTANCE_INHERITANCE */
737
738	/*
739	 * If the port has no send-possible request
740	 * armed, don't bother to lock the port.
741	 */
742	if (port->ip_sprequests == 0)
743		return;
744
745	ip_lock(port);
746
747#if IMPORTANCE_INHERITANCE
748	if (port->ip_spimportant != 0) {
749		port->ip_spimportant = 0;
750		if (ipc_port_impcount_delta(port, -1, IP_NULL) == -1) {
751			dropassert = TRUE;
752		}
753	}
754#endif /* IMPORTANCE_INHERITANCE */
755
756	if (port->ip_sprequests == 0) {
757		ip_unlock(port);
758		goto out;
759	}
760	port->ip_sprequests = 0;
761
762revalidate:
763	if (ip_active(port)) {
764		ipc_port_request_t requests;
765
766		/* table may change each time port unlocked (reload) */
767		requests = port->ip_requests;
768		assert(requests != IPR_NULL);
769
770		/*
771		 * no need to go beyond table size when first
772		 * we entered - those are future notifications.
773		 */
774		if (size == 0)
775			size = requests->ipr_size->its_size;
776
777		/* no need to backtrack either */
778		while (++index < size) {
779			ipc_port_request_t ipr = &requests[index];
780			mach_port_name_t name = ipr->ipr_name;
781			ipc_port_t soright = IPR_SOR_PORT(ipr->ipr_soright);
782			boolean_t armed = IPR_SOR_SPARMED(ipr->ipr_soright);
783
784			if (MACH_PORT_VALID(name) && armed && IP_VALID(soright)) {
785				/* claim send-once right - slot still inuse */
786				ipr->ipr_soright = IP_NULL;
787				ip_unlock(port);
788
789				ipc_notify_send_possible(soright, name);
790
791				ip_lock(port);
792				goto revalidate;
793			}
794		}
795	}
796	ip_unlock(port);
797out:
798#if IMPORTANCE_INHERITANCE
799	if (dropassert == TRUE && ipc_importance_task_is_any_receiver_type(current_task()->task_imp_base)) {
800		/* drop internal assertion */
801		ipc_importance_task_drop_internal_assertion(current_task()->task_imp_base, 1);
802	}
803#endif /* IMPORTANCE_INHERITANCE */
804	return;
805}
806
807/*
808 * 	Routine:	ipc_port_dnnotify
809 *	Purpose:
810 *		Generate dead name notifications for
811 *		all outstanding dead-name and send-
812 *		possible requests.
813 *	Conditions:
814 *		Nothing locked.
815 *		Port must be inactive.
816 *		Reference held on port.
817 */
818void
819ipc_port_dnnotify(
820	ipc_port_t	port)
821{
822	ipc_port_request_t requests = port->ip_requests;
823
824	assert(!ip_active(port));
825	if (requests != IPR_NULL) {
826		ipc_table_size_t its = requests->ipr_size;
827		ipc_table_elems_t size = its->its_size;
828		ipc_port_request_index_t index;
829		for (index = 1; index < size; index++) {
830			ipc_port_request_t ipr = &requests[index];
831			mach_port_name_t name = ipr->ipr_name;
832			ipc_port_t soright = IPR_SOR_PORT(ipr->ipr_soright);
833
834			if (MACH_PORT_VALID(name) && IP_VALID(soright)) {
835				ipc_notify_dead_name(soright, name);
836			}
837		}
838	}
839}
840
841
842/*
843 *	Routine:	ipc_port_destroy
844 *	Purpose:
845 *		Destroys a port.  Cleans up queued messages.
846 *
847 *		If the port has a backup, it doesn't get destroyed,
848 *		but is sent in a port-destroyed notification to the backup.
849 *	Conditions:
850 *		The port is locked and alive; nothing else locked.
851 *		The caller has a reference, which is consumed.
852 *		Afterwards, the port is unlocked and dead.
853 */
854
855void
856ipc_port_destroy(
857	ipc_port_t	port)
858{
859	ipc_port_t pdrequest, nsrequest;
860	ipc_mqueue_t mqueue;
861	ipc_kmsg_t kmsg;
862
863#if IMPORTANCE_INHERITANCE
864	ipc_importance_task_t release_imp_task = IIT_NULL;
865	thread_t self = current_thread();
866	boolean_t top = (self->ith_assertions == 0);
867	natural_t assertcnt = 0;
868#endif /* IMPORTANCE_INHERITANCE */
869
870	assert(ip_active(port));
871	/* port->ip_receiver_name is garbage */
872	/* port->ip_receiver/port->ip_destination is garbage */
873	assert(port->ip_pset_count == 0);
874	assert(port->ip_mscount == 0);
875
876	/* check for a backup port */
877	pdrequest = port->ip_pdrequest;
878
879#if IMPORTANCE_INHERITANCE
880	/* determine how many assertions to drop and from whom */
881	if (port->ip_tempowner != 0) {
882		assert(top);
883		release_imp_task = port->ip_imp_task;
884		if (IIT_NULL != release_imp_task) {
885			port->ip_imp_task = IIT_NULL;
886			assertcnt = port->ip_impcount;
887		}
888		/* Otherwise, nothing to drop */
889	} else {
890		assertcnt = port->ip_impcount;
891		if (pdrequest != IP_NULL)
892			/* mark in limbo for the journey */
893			port->ip_tempowner = 1;
894	}
895
896	if (top)
897		self->ith_assertions = assertcnt;
898#endif /* IMPORTANCE_INHERITANCE */
899
900	if (pdrequest != IP_NULL) {
901		/* we assume the ref for pdrequest */
902		port->ip_pdrequest = IP_NULL;
903
904		/* make port be in limbo */
905		port->ip_receiver_name = MACH_PORT_NULL;
906		port->ip_destination = IP_NULL;
907		ip_unlock(port);
908
909		/* consumes our refs for port and pdrequest */
910		ipc_notify_port_destroyed(pdrequest, port);
911
912		goto drop_assertions;
913	}
914
915	/* once port is dead, we don't need to keep it locked */
916
917	port->ip_object.io_bits &= ~IO_BITS_ACTIVE;
918	port->ip_timestamp = ipc_port_timestamp();
919	nsrequest = port->ip_nsrequest;
920
921	/*
922	 * If the port has a preallocated message buffer and that buffer
923	 * is not inuse, free it.  If it has an inuse one, then the kmsg
924	 * free will detect that we freed the association and it can free it
925	 * like a normal buffer.
926	 */
927	if (IP_PREALLOC(port)) {
928		ipc_port_t inuse_port;
929
930		kmsg = port->ip_premsg;
931		assert(kmsg != IKM_NULL);
932		inuse_port = ikm_prealloc_inuse_port(kmsg);
933		IP_CLEAR_PREALLOC(port, kmsg);
934		ip_unlock(port);
935		if (inuse_port != IP_NULL) {
936			assert(inuse_port == port);
937		} else {
938			ipc_kmsg_free(kmsg);
939		}
940	} else {
941		ip_unlock(port);
942	}
943
944	/* throw away no-senders request */
945	if (nsrequest != IP_NULL)
946		ipc_notify_send_once(nsrequest); /* consumes ref */
947
948	/* destroy any queued messages */
949	mqueue = &port->ip_messages;
950	ipc_mqueue_destroy(mqueue);
951
952	/* generate dead-name notifications */
953	ipc_port_dnnotify(port);
954
955	ipc_kobject_destroy(port);
956
957	ip_release(port); /* consume caller's ref */
958
959 drop_assertions:
960#if IMPORTANCE_INHERITANCE
961	if (release_imp_task != IIT_NULL) {
962		if (assertcnt > 0) {
963			assert(top);
964			self->ith_assertions = 0;
965			assert(ipc_importance_task_is_any_receiver_type(release_imp_task));
966			ipc_importance_task_drop_internal_assertion(release_imp_task, assertcnt);
967		}
968		ipc_importance_task_release(release_imp_task);
969
970	} else if (assertcnt > 0) {
971		if (top) {
972			self->ith_assertions = 0;
973			release_imp_task = current_task()->task_imp_base;
974			if (ipc_importance_task_is_any_receiver_type(release_imp_task)) {
975				ipc_importance_task_drop_internal_assertion(release_imp_task, assertcnt);
976			}
977		}
978	}
979#endif /* IMPORTANCE_INHERITANCE */
980}
981
982/*
983 *	Routine:	ipc_port_check_circularity
984 *	Purpose:
985 *		Check if queueing "port" in a message for "dest"
986 *		would create a circular group of ports and messages.
987 *
988 *		If no circularity (FALSE returned), then "port"
989 *		is changed from "in limbo" to "in transit".
990 *
991 *		That is, we want to set port->ip_destination == dest,
992 *		but guaranteeing that this doesn't create a circle
993 *		port->ip_destination->ip_destination->... == port
994 *
995 *		Additionally, if port was successfully changed to "in transit",
996 *		propagate boost assertions from the "in limbo" port to all
997 *		the ports in the chain, and, if the destination task accepts
998 *		boosts, to the destination task.
999 *
1000 *	Conditions:
1001 *		No ports locked.  References held for "port" and "dest".
1002 */
1003
1004boolean_t
1005ipc_port_check_circularity(
1006	ipc_port_t	port,
1007	ipc_port_t	dest)
1008{
1009	ipc_port_t base;
1010
1011#if IMPORTANCE_INHERITANCE
1012	ipc_importance_task_t imp_task = IIT_NULL;
1013	ipc_importance_task_t release_imp_task = IIT_NULL;
1014	int assertcnt = 0;
1015#endif /* IMPORTANCE_INHERITANCE */
1016
1017	assert(port != IP_NULL);
1018	assert(dest != IP_NULL);
1019
1020	if (port == dest)
1021		return TRUE;
1022	base = dest;
1023
1024	/*
1025	 *	First try a quick check that can run in parallel.
1026	 *	No circularity if dest is not in transit.
1027	 */
1028
1029	ip_lock(port);
1030	if (ip_lock_try(dest)) {
1031		if (!ip_active(dest) ||
1032		    (dest->ip_receiver_name != MACH_PORT_NULL) ||
1033		    (dest->ip_destination == IP_NULL))
1034			goto not_circular;
1035
1036		/* dest is in transit; further checking necessary */
1037
1038		ip_unlock(dest);
1039	}
1040	ip_unlock(port);
1041
1042	ipc_port_multiple_lock(); /* massive serialization */
1043
1044	/*
1045	 *	Search for the end of the chain (a port not in transit),
1046	 *	acquiring locks along the way.
1047	 */
1048
1049	for (;;) {
1050		ip_lock(base);
1051
1052		if (!ip_active(base) ||
1053		    (base->ip_receiver_name != MACH_PORT_NULL) ||
1054		    (base->ip_destination == IP_NULL))
1055			break;
1056
1057		base = base->ip_destination;
1058	}
1059
1060	/* all ports in chain from dest to base, inclusive, are locked */
1061
1062	if (port == base) {
1063		/* circularity detected! */
1064
1065		ipc_port_multiple_unlock();
1066
1067		/* port (== base) is in limbo */
1068
1069		assert(ip_active(port));
1070		assert(port->ip_receiver_name == MACH_PORT_NULL);
1071		assert(port->ip_destination == IP_NULL);
1072
1073		while (dest != IP_NULL) {
1074			ipc_port_t next;
1075
1076			/* dest is in transit or in limbo */
1077
1078			assert(ip_active(dest));
1079			assert(dest->ip_receiver_name == MACH_PORT_NULL);
1080
1081			next = dest->ip_destination;
1082			ip_unlock(dest);
1083			dest = next;
1084		}
1085
1086		return TRUE;
1087	}
1088
1089	/*
1090	 *	The guarantee:  lock port while the entire chain is locked.
1091	 *	Once port is locked, we can take a reference to dest,
1092	 *	add port to the chain, and unlock everything.
1093	 */
1094
1095	ip_lock(port);
1096	ipc_port_multiple_unlock();
1097
1098    not_circular:
1099
1100	/* port is in limbo */
1101
1102	assert(ip_active(port));
1103	assert(port->ip_receiver_name == MACH_PORT_NULL);
1104	assert(port->ip_destination == IP_NULL);
1105
1106	ip_reference(dest);
1107	port->ip_destination = dest;
1108
1109#if IMPORTANCE_INHERITANCE
1110	/* must have been in limbo or still bound to a task */
1111	assert(port->ip_tempowner != 0);
1112
1113	/*
1114	 * We delayed dropping assertions from a specific task.
1115	 * Cache that info now (we'll drop assertions and the
1116	 * task reference below).
1117	 */
1118	release_imp_task = port->ip_imp_task;
1119	if (IIT_NULL != release_imp_task) {
1120		port->ip_imp_task = IIT_NULL;
1121	}
1122	assertcnt = port->ip_impcount;
1123
1124	/* take the port out of limbo w.r.t. assertions */
1125	port->ip_tempowner = 0;
1126
1127#endif /* IMPORTANCE_INHERITANCE */
1128
1129	/* now unlock chain */
1130
1131	ip_unlock(port);
1132
1133	for (;;) {
1134
1135#if IMPORTANCE_INHERITANCE
1136		/* every port along chain track assertions behind it */
1137		dest->ip_impcount += assertcnt;
1138#endif /* IMPORTANCE_INHERITANCE */
1139
1140		if (dest == base)
1141			break;
1142
1143		/* port is in transit */
1144
1145		assert(ip_active(dest));
1146		assert(dest->ip_receiver_name == MACH_PORT_NULL);
1147		assert(dest->ip_destination != IP_NULL);
1148
1149#if IMPORTANCE_INHERITANCE
1150		assert(dest->ip_tempowner == 0);
1151#endif /* IMPORTANCE_INHERITANCE */
1152
1153		port = dest->ip_destination;
1154		ip_unlock(dest);
1155		dest = port;
1156	}
1157
1158	/* base is not in transit */
1159	assert(!ip_active(base) ||
1160	       (base->ip_receiver_name != MACH_PORT_NULL) ||
1161	       (base->ip_destination == IP_NULL));
1162
1163#if IMPORTANCE_INHERITANCE
1164	/*
1165	 * Find the task to boost (if any).
1166	 * We will boost "through" ports that don't know
1167	 * about inheritance to deliver receive rights that
1168	 * do.
1169	 */
1170	if (ip_active(base) && (assertcnt > 0)) {
1171		if (base->ip_tempowner != 0) {
1172			if (IIT_NULL != base->ip_imp_task) {
1173				/* specified tempowner task */
1174				imp_task = base->ip_imp_task;
1175				assert(ipc_importance_task_is_any_receiver_type(imp_task));
1176			}
1177			/* otherwise don't boost current task */
1178
1179		} else if (base->ip_receiver_name != MACH_PORT_NULL) {
1180			ipc_space_t space = base->ip_receiver;
1181
1182			/* only spaces with boost-accepting tasks */
1183			if (space->is_task != TASK_NULL &&
1184			    ipc_importance_task_is_any_receiver_type(space->is_task->task_imp_base))
1185				imp_task = space->is_task->task_imp_base;
1186		}
1187
1188		/* take reference before unlocking base */
1189		if (imp_task != IIT_NULL) {
1190			ipc_importance_task_reference(imp_task);
1191		}
1192	}
1193#endif /* IMPORTANCE_INHERITANCE */
1194
1195	ip_unlock(base);
1196
1197#if IMPORTANCE_INHERITANCE
1198	/*
1199	 * Transfer assertions now that the ports are unlocked.
1200	 * Avoid extra overhead if transferring to/from the same task.
1201	 */
1202	boolean_t transfer_assertions = (imp_task != release_imp_task) ? TRUE : FALSE;
1203
1204	if (imp_task != IIT_NULL) {
1205		if (transfer_assertions)
1206			ipc_importance_task_hold_internal_assertion(imp_task, assertcnt);
1207		ipc_importance_task_release(imp_task);
1208		imp_task = IIT_NULL;
1209	}
1210
1211	if (release_imp_task != IIT_NULL) {
1212		if (transfer_assertions)
1213			ipc_importance_task_drop_internal_assertion(release_imp_task, assertcnt);
1214		ipc_importance_task_release(release_imp_task);
1215		release_imp_task = IIT_NULL;
1216	}
1217#endif /* IMPORTANCE_INHERITANCE */
1218
1219	return FALSE;
1220}
1221
1222/*
1223 *	Routine:	ipc_port_impcount_delta
1224 *	Purpose:
1225 *		Adjust only the importance count associated with a port.
1226 *		If there are any adjustments to be made to receiver task,
1227 *		those are handled elsewhere.
1228 *
1229 *		For now, be defensive during deductions to make sure the
1230 *		impcount for the port doesn't underflow zero.  This will
1231 *		go away when the port boost addition is made atomic (see
1232 *		note in ipc_port_importance_delta()).
1233 *	Conditions:
1234 *		The port is referenced and locked.
1235 *		Nothing else is locked.
1236 */
1237mach_port_delta_t
1238ipc_port_impcount_delta(
1239	ipc_port_t        port,
1240	mach_port_delta_t delta,
1241	ipc_port_t        __unused base)
1242{
1243	mach_port_delta_t absdelta;
1244
1245	if (!ip_active(port)) {
1246		return 0;
1247	}
1248
1249	/* adding/doing nothing is easy */
1250	if (delta >= 0) {
1251		port->ip_impcount += delta;
1252		return delta;
1253	}
1254
1255	absdelta = 0 - delta;
1256	//assert(port->ip_impcount >= absdelta);
1257	/* if we have enough to deduct, we're done */
1258	if (port->ip_impcount >= absdelta) {
1259		port->ip_impcount -= absdelta;
1260		return delta;
1261	}
1262
1263#if DEVELOPMENT || DEBUG
1264	if (port->ip_receiver_name != MACH_PORT_NULL) {
1265		task_t target_task = port->ip_receiver->is_task;
1266		ipc_importance_task_t target_imp = target_task->task_imp_base;
1267		const char *target_procname;
1268		int target_pid;
1269
1270		if (target_imp != IIT_NULL) {
1271			target_procname = target_imp->iit_procname;
1272			target_pid = target_imp->iit_bsd_pid;
1273		} else {
1274			target_procname = "unknown";
1275			target_pid = -1;
1276		}
1277		printf("Over-release of importance assertions for port 0x%x receiver pid %d (%s), "
1278		       "dropping %d assertion(s) but port only has %d remaining.\n",
1279		       port->ip_receiver_name,
1280		       target_imp->iit_bsd_pid, target_imp->iit_procname,
1281		       absdelta, port->ip_impcount);
1282
1283	} else if (base != IP_NULL) {
1284		task_t target_task = base->ip_receiver->is_task;
1285		ipc_importance_task_t target_imp = target_task->task_imp_base;
1286		const char *target_procname;
1287		int target_pid;
1288
1289		if (target_imp != IIT_NULL) {
1290			target_procname = target_imp->iit_procname;
1291			target_pid = target_imp->iit_bsd_pid;
1292		} else {
1293			target_procname = "unknown";
1294			target_pid = -1;
1295		}
1296		printf("Over-release of importance assertions for port %p "
1297		       "enqueued on port 0x%x with receiver pid %d (%s), "
1298		       "dropping %d assertion(s) but port only has %d remaining.\n",
1299		       port, base->ip_receiver_name,
1300		       target_imp->iit_bsd_pid, target_imp->iit_procname,
1301		       absdelta, port->ip_impcount);
1302	}
1303#endif
1304	delta = 0 - port->ip_impcount;
1305	port->ip_impcount = 0;
1306	return delta;
1307}
1308
1309/*
1310 *	Routine:	ipc_port_importance_delta_internal
1311 *	Purpose:
1312 *		Adjust the importance count through the given port.
1313 *		If the port is in transit, apply the delta throughout
1314 *		the chain. Determine if the there is a task at the
1315 *		base of the chain that wants/needs to be adjusted,
1316 *		and if so, apply the delta.
1317 *	Conditions:
1318 *		The port is referenced and locked on entry.
1319 *		Nothing else is locked.
1320 *		The lock may be dropped on exit.
1321 *		Returns TRUE if lock was dropped.
1322 */
1323#if IMPORTANCE_INHERITANCE
1324
1325boolean_t
1326ipc_port_importance_delta_internal(
1327	ipc_port_t 		port,
1328	mach_port_delta_t	*deltap,
1329	ipc_importance_task_t	*imp_task)
1330{
1331	ipc_port_t next, base;
1332	boolean_t dropped = FALSE;
1333
1334	*imp_task = IIT_NULL;
1335
1336	if (*deltap == 0)
1337		return FALSE;
1338
1339	base = port;
1340
1341	/* if port is in transit, have to search for end of chain */
1342	if (ip_active(port) &&
1343	    port->ip_destination != IP_NULL &&
1344	    port->ip_receiver_name == MACH_PORT_NULL) {
1345
1346		dropped = TRUE;
1347
1348		ip_unlock(port);
1349		ipc_port_multiple_lock(); /* massive serialization */
1350		ip_lock(base);
1351
1352		while(ip_active(base) &&
1353		      base->ip_destination != IP_NULL &&
1354		      base->ip_receiver_name == MACH_PORT_NULL) {
1355
1356			base = base->ip_destination;
1357			ip_lock(base);
1358		}
1359		ipc_port_multiple_unlock();
1360	}
1361
1362	/* unlock down to the base, adding a boost at each level */
1363	for (;;) {
1364		/*
1365		 * JMM TODO - because of the port unlock to grab the multiple lock
1366		 * above, a subsequent drop of importance could race and beat
1367		 * the "previous" increase - causing the port impcount to go
1368		 * negative briefly.  The defensive deduction performed by
1369		 * ipc_port_impcount_delta() defeats that, and therefore can
1370		 * cause an importance leak once the increase finally arrives.
1371		 *
1372		 * Need to rework the importance delta logic to be more like
1373		 * ipc_importance_inherit_from() where it locks all it needs in
1374		 * one pass to avoid any lock drops - to keep that race from
1375		 * ever occuring.
1376		 */
1377		*deltap = ipc_port_impcount_delta(port, *deltap, base);
1378
1379		if (port == base) {
1380			break;
1381		}
1382
1383		/* port is in transit */
1384		assert(port->ip_tempowner == 0);
1385		next = port->ip_destination;
1386		ip_unlock(port);
1387		port = next;
1388	}
1389
1390	/* find the task (if any) to boost according to the base */
1391	if (ip_active(base)) {
1392		if (base->ip_tempowner != 0) {
1393			if (IIT_NULL != base->ip_imp_task)
1394				*imp_task = base->ip_imp_task;
1395			/* otherwise don't boost */
1396
1397		} else if (base->ip_receiver_name != MACH_PORT_NULL) {
1398			ipc_space_t space = base->ip_receiver;
1399
1400			/* only spaces with boost-accepting tasks */
1401			if (space->is_task != TASK_NULL &&
1402			    ipc_importance_task_is_any_receiver_type(space->is_task->task_imp_base)) {
1403				*imp_task = space->is_task->task_imp_base;
1404			}
1405		}
1406	}
1407
1408	/*
1409	 * Only the base is locked.  If we have to hold or drop task
1410	 * importance assertions, we'll have to drop that lock as well.
1411	 */
1412	if (*imp_task != IIT_NULL) {
1413		/* take a reference before unlocking base */
1414		ipc_importance_task_reference(*imp_task);
1415	}
1416
1417	if (dropped == TRUE) {
1418		ip_unlock(base);
1419	}
1420
1421	return dropped;
1422}
1423#endif /* IMPORTANCE_INHERITANCE */
1424
1425/*
1426 *	Routine:	ipc_port_importance_delta
1427 *	Purpose:
1428 *		Adjust the importance count through the given port.
1429 *		If the port is in transit, apply the delta throughout
1430 *		the chain.
1431 *
1432 *		If there is a task at the base of the chain that wants/needs
1433 *		to be adjusted, apply the delta.
1434 *	Conditions:
1435 *		The port is referenced and locked on entry.
1436 *		Nothing else is locked.
1437 *		The lock may be dropped on exit.
1438 *		Returns TRUE if lock was dropped.
1439 */
1440#if IMPORTANCE_INHERITANCE
1441
1442boolean_t
1443ipc_port_importance_delta(
1444	ipc_port_t 		port,
1445	mach_port_delta_t	delta)
1446{
1447	ipc_importance_task_t imp_task = IIT_NULL;
1448	boolean_t dropped;
1449
1450	dropped = ipc_port_importance_delta_internal(port, &delta, &imp_task);
1451
1452	if (IIT_NULL == imp_task)
1453		return dropped;
1454
1455	if (!dropped) {
1456		dropped = TRUE;
1457		ip_unlock(port);
1458	}
1459
1460	assert(ipc_importance_task_is_any_receiver_type(imp_task));
1461
1462	if (delta > 0)
1463		ipc_importance_task_hold_internal_assertion(imp_task, delta);
1464	else
1465		ipc_importance_task_drop_internal_assertion(imp_task, -delta);
1466
1467	ipc_importance_task_release(imp_task);
1468	return dropped;
1469}
1470#endif /* IMPORTANCE_INHERITANCE */
1471
1472/*
1473 *	Routine:	ipc_port_lookup_notify
1474 *	Purpose:
1475 *		Make a send-once notify port from a receive right.
1476 *		Returns IP_NULL if name doesn't denote a receive right.
1477 *	Conditions:
1478 *		The space must be locked (read or write) and active.
1479 *  		Being the active space, we can rely on thread server_id
1480 *		context to give us the proper server level sub-order
1481 *		within the space.
1482 */
1483
1484ipc_port_t
1485ipc_port_lookup_notify(
1486	ipc_space_t		space,
1487	mach_port_name_t	name)
1488{
1489	ipc_port_t port;
1490	ipc_entry_t entry;
1491
1492	assert(is_active(space));
1493
1494	entry = ipc_entry_lookup(space, name);
1495	if (entry == IE_NULL)
1496		return IP_NULL;
1497	if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)
1498		return IP_NULL;
1499
1500	port = (ipc_port_t) entry->ie_object;
1501	assert(port != IP_NULL);
1502
1503	ip_lock(port);
1504	assert(ip_active(port));
1505	assert(port->ip_receiver_name == name);
1506	assert(port->ip_receiver == space);
1507
1508	ip_reference(port);
1509	port->ip_sorights++;
1510	ip_unlock(port);
1511
1512	return port;
1513}
1514
1515/*
1516 *	Routine:	ipc_port_make_send_locked
1517 *	Purpose:
1518 *		Make a naked send right from a receive right.
1519 *
1520 *	Conditions:
1521 *		port locked and active.
1522 */
1523ipc_port_t
1524ipc_port_make_send_locked(
1525	ipc_port_t	port)
1526{
1527	assert(ip_active(port));
1528	port->ip_mscount++;
1529	port->ip_srights++;
1530	ip_reference(port);
1531	return port;
1532}
1533
1534/*
1535 *	Routine:	ipc_port_make_send
1536 *	Purpose:
1537 *		Make a naked send right from a receive right.
1538 */
1539
1540ipc_port_t
1541ipc_port_make_send(
1542	ipc_port_t	port)
1543{
1544
1545	if (!IP_VALID(port))
1546		return port;
1547
1548	ip_lock(port);
1549	if (ip_active(port)) {
1550		port->ip_mscount++;
1551		port->ip_srights++;
1552		ip_reference(port);
1553		ip_unlock(port);
1554		return port;
1555	}
1556	ip_unlock(port);
1557	return IP_DEAD;
1558}
1559
1560/*
1561 *	Routine:	ipc_port_copy_send
1562 *	Purpose:
1563 *		Make a naked send right from another naked send right.
1564 *			IP_NULL		-> IP_NULL
1565 *			IP_DEAD		-> IP_DEAD
1566 *			dead port	-> IP_DEAD
1567 *			live port	-> port + ref
1568 *	Conditions:
1569 *		Nothing locked except possibly a space.
1570 */
1571
1572ipc_port_t
1573ipc_port_copy_send(
1574	ipc_port_t	port)
1575{
1576	ipc_port_t sright;
1577
1578	if (!IP_VALID(port))
1579		return port;
1580
1581	ip_lock(port);
1582	if (ip_active(port)) {
1583		assert(port->ip_srights > 0);
1584
1585		ip_reference(port);
1586		port->ip_srights++;
1587		sright = port;
1588	} else
1589		sright = IP_DEAD;
1590	ip_unlock(port);
1591
1592	return sright;
1593}
1594
1595/*
1596 *	Routine:	ipc_port_copyout_send
1597 *	Purpose:
1598 *		Copyout a naked send right (possibly null/dead),
1599 *		or if that fails, destroy the right.
1600 *	Conditions:
1601 *		Nothing locked.
1602 */
1603
1604mach_port_name_t
1605ipc_port_copyout_send(
1606	ipc_port_t	sright,
1607	ipc_space_t	space)
1608{
1609	mach_port_name_t name;
1610
1611	if (IP_VALID(sright)) {
1612		kern_return_t kr;
1613
1614		kr = ipc_object_copyout(space, (ipc_object_t) sright,
1615					MACH_MSG_TYPE_PORT_SEND, TRUE, &name);
1616		if (kr != KERN_SUCCESS) {
1617			ipc_port_release_send(sright);
1618
1619			if (kr == KERN_INVALID_CAPABILITY)
1620				name = MACH_PORT_DEAD;
1621			else
1622				name = MACH_PORT_NULL;
1623		}
1624	} else
1625		name = CAST_MACH_PORT_TO_NAME(sright);
1626
1627	return name;
1628}
1629
1630/*
1631 *	Routine:	ipc_port_release_send
1632 *	Purpose:
1633 *		Release a naked send right.
1634 *		Consumes a ref for the port.
1635 *	Conditions:
1636 *		Nothing locked.
1637 */
1638
1639void
1640ipc_port_release_send(
1641	ipc_port_t	port)
1642{
1643	ipc_port_t nsrequest = IP_NULL;
1644	mach_port_mscount_t mscount;
1645
1646	if (!IP_VALID(port))
1647		return;
1648
1649	ip_lock(port);
1650
1651	assert(port->ip_srights > 0);
1652	port->ip_srights--;
1653
1654	if (!ip_active(port)) {
1655		ip_unlock(port);
1656		ip_release(port);
1657		return;
1658	}
1659
1660	if (port->ip_srights == 0 &&
1661	    port->ip_nsrequest != IP_NULL) {
1662		nsrequest = port->ip_nsrequest;
1663		port->ip_nsrequest = IP_NULL;
1664		mscount = port->ip_mscount;
1665		ip_unlock(port);
1666		ip_release(port);
1667		ipc_notify_no_senders(nsrequest, mscount);
1668	} else {
1669		ip_unlock(port);
1670		ip_release(port);
1671	}
1672}
1673
1674/*
1675 *	Routine:	ipc_port_make_sonce_locked
1676 *	Purpose:
1677 *		Make a naked send-once right from a receive right.
1678 *	Conditions:
1679 *		The port is locked and active.
1680 */
1681
1682ipc_port_t
1683ipc_port_make_sonce_locked(
1684	ipc_port_t	port)
1685{
1686	assert(ip_active(port));
1687	port->ip_sorights++;
1688	ip_reference(port);
1689	return port;
1690}
1691
1692/*
1693 *	Routine:	ipc_port_make_sonce
1694 *	Purpose:
1695 *		Make a naked send-once right from a receive right.
1696 *	Conditions:
1697 *		The port is not locked.
1698 */
1699
1700ipc_port_t
1701ipc_port_make_sonce(
1702	ipc_port_t	port)
1703{
1704	if (!IP_VALID(port))
1705		return port;
1706
1707	ip_lock(port);
1708	if (ip_active(port)) {
1709		port->ip_sorights++;
1710		ip_reference(port);
1711		ip_unlock(port);
1712		return port;
1713	}
1714	ip_unlock(port);
1715	return IP_DEAD;
1716}
1717
1718/*
1719 *	Routine:	ipc_port_release_sonce
1720 *	Purpose:
1721 *		Release a naked send-once right.
1722 *		Consumes a ref for the port.
1723 *
1724 *		In normal situations, this is never used.
1725 *		Send-once rights are only consumed when
1726 *		a message (possibly a send-once notification)
1727 *		is sent to them.
1728 *	Conditions:
1729 *		Nothing locked except possibly a space.
1730 */
1731
1732void
1733ipc_port_release_sonce(
1734	ipc_port_t	port)
1735{
1736	if (!IP_VALID(port))
1737		return;
1738
1739	ip_lock(port);
1740
1741	assert(port->ip_sorights > 0);
1742
1743	port->ip_sorights--;
1744
1745	ip_unlock(port);
1746	ip_release(port);
1747}
1748
1749/*
1750 *	Routine:	ipc_port_release_receive
1751 *	Purpose:
1752 *		Release a naked (in limbo or in transit) receive right.
1753 *		Consumes a ref for the port; destroys the port.
1754 *	Conditions:
1755 *		Nothing locked.
1756 */
1757
1758void
1759ipc_port_release_receive(
1760	ipc_port_t	port)
1761{
1762	ipc_port_t dest;
1763
1764	if (!IP_VALID(port))
1765		return;
1766
1767	ip_lock(port);
1768	assert(ip_active(port));
1769	assert(port->ip_receiver_name == MACH_PORT_NULL);
1770	dest = port->ip_destination;
1771
1772	ipc_port_destroy(port); /* consumes ref, unlocks */
1773
1774	if (dest != IP_NULL)
1775		ip_release(dest);
1776}
1777
1778/*
1779 *	Routine:	ipc_port_alloc_special
1780 *	Purpose:
1781 *		Allocate a port in a special space.
1782 *		The new port is returned with one ref.
1783 *		If unsuccessful, IP_NULL is returned.
1784 *	Conditions:
1785 *		Nothing locked.
1786 */
1787
1788ipc_port_t
1789ipc_port_alloc_special(
1790	ipc_space_t	space)
1791{
1792	ipc_port_t port;
1793
1794	port = (ipc_port_t) io_alloc(IOT_PORT);
1795	if (port == IP_NULL)
1796		return IP_NULL;
1797
1798#if     MACH_ASSERT
1799	uintptr_t buf[IP_CALLSTACK_MAX];
1800	ipc_port_callstack_init_debug(&buf[0], IP_CALLSTACK_MAX);
1801#endif /* MACH_ASSERT */
1802
1803	bzero((char *)port, sizeof(*port));
1804	io_lock_init(&port->ip_object);
1805	port->ip_references = 1;
1806	port->ip_object.io_bits = io_makebits(TRUE, IOT_PORT, 0);
1807
1808	ipc_port_init(port, space, 1);
1809
1810#if     MACH_ASSERT
1811	ipc_port_init_debug(port, &buf[0], IP_CALLSTACK_MAX);
1812#endif  /* MACH_ASSERT */
1813
1814	return port;
1815}
1816
1817/*
1818 *	Routine:	ipc_port_dealloc_special
1819 *	Purpose:
1820 *		Deallocate a port in a special space.
1821 *		Consumes one ref for the port.
1822 *	Conditions:
1823 *		Nothing locked.
1824 */
1825
1826void
1827ipc_port_dealloc_special(
1828	ipc_port_t			port,
1829	__assert_only ipc_space_t	space)
1830{
1831	ip_lock(port);
1832	assert(ip_active(port));
1833//	assert(port->ip_receiver_name != MACH_PORT_NULL);
1834	assert(port->ip_receiver == space);
1835
1836	/*
1837	 *	We clear ip_receiver_name and ip_receiver to simplify
1838	 *	the ipc_space_kernel check in ipc_mqueue_send.
1839	 */
1840
1841	port->ip_receiver_name = MACH_PORT_NULL;
1842	port->ip_receiver = IS_NULL;
1843
1844	/* relevant part of ipc_port_clear_receiver */
1845	ipc_port_set_mscount(port, 0);
1846	port->ip_messages.imq_seqno = 0;
1847
1848	ipc_port_destroy(port);
1849}
1850
1851/*
1852 *	Routine:	ipc_port_finalize
1853 *	Purpose:
1854 *		Called on last reference deallocate to
1855 *		free any remaining data associated with the
1856 *		port.
1857 *	Conditions:
1858 *		Nothing locked.
1859 */
1860void
1861ipc_port_finalize(
1862	ipc_port_t		port)
1863{
1864	ipc_port_request_t requests = port->ip_requests;
1865
1866	assert(!ip_active(port));
1867	if (requests != IPR_NULL) {
1868		ipc_table_size_t its = requests->ipr_size;
1869		it_requests_free(its, requests);
1870		port->ip_requests = IPR_NULL;
1871	}
1872
1873#if	MACH_ASSERT
1874	ipc_port_track_dealloc(port);
1875#endif	/* MACH_ASSERT */
1876}
1877
1878#if	MACH_ASSERT
1879#include <kern/machine.h>
1880
1881/*
1882 *	Keep a list of all allocated ports.
1883 *	Allocation is intercepted via ipc_port_init;
1884 *	deallocation is intercepted via io_free.
1885 */
1886queue_head_t	port_alloc_queue;
1887lck_spin_t	port_alloc_queue_lock;
1888
1889unsigned long	port_count = 0;
1890unsigned long	port_count_warning = 20000;
1891unsigned long	port_timestamp = 0;
1892
1893void		db_port_stack_trace(
1894			ipc_port_t	port);
1895void		db_ref(
1896			int		refs);
1897int		db_port_walk(
1898			unsigned int	verbose,
1899			unsigned int	display,
1900			unsigned int	ref_search,
1901			unsigned int	ref_target);
1902
1903/*
1904 *	Initialize global state needed for run-time
1905 *	port debugging.
1906 */
1907void
1908ipc_port_debug_init(void)
1909{
1910	queue_init(&port_alloc_queue);
1911
1912	lck_spin_init(&port_alloc_queue_lock, &ipc_lck_grp, &ipc_lck_attr);
1913
1914	if (!PE_parse_boot_argn("ipc_portbt", &ipc_portbt, sizeof (ipc_portbt)))
1915		ipc_portbt = 0;
1916}
1917
1918#ifdef MACH_BSD
1919extern int proc_pid(struct proc*);
1920#endif /* MACH_BSD */
1921
1922/*
1923 *	Initialize all of the debugging state in a port.
1924 *	Insert the port into a global list of all allocated ports.
1925 */
1926void
1927ipc_port_init_debug(
1928	ipc_port_t	port,
1929	uintptr_t 	*callstack,
1930	unsigned int	callstack_max)
1931{
1932	unsigned int	i;
1933
1934	port->ip_thread = current_thread();
1935	port->ip_timetrack = port_timestamp++;
1936	for (i = 0; i < callstack_max; ++i)
1937		port->ip_callstack[i] = callstack[i];
1938	for (i = 0; i < IP_NSPARES; ++i)
1939		port->ip_spares[i] = 0;
1940
1941#ifdef MACH_BSD
1942	task_t task = current_task();
1943	if (task != TASK_NULL) {
1944		struct proc* proc = (struct proc*) get_bsdtask_info(task);
1945		if (proc)
1946			port->ip_spares[0] = proc_pid(proc);
1947	}
1948#endif /* MACH_BSD */
1949
1950#if 0
1951	lck_spin_lock(&port_alloc_queue_lock);
1952	++port_count;
1953	if (port_count_warning > 0 && port_count >= port_count_warning)
1954		assert(port_count < port_count_warning);
1955	queue_enter(&port_alloc_queue, port, ipc_port_t, ip_port_links);
1956	lck_spin_unlock(&port_alloc_queue_lock);
1957#endif
1958}
1959
1960/*
1961 *	Routine:	ipc_port_callstack_init_debug
1962 *	Purpose:
1963 *		Calls the machine-dependent routine to
1964 *		fill in an array with up to IP_CALLSTACK_MAX
1965 *		levels of return pc information
1966 *	Conditions:
1967 *		May block (via copyin)
1968 */
1969void
1970ipc_port_callstack_init_debug(
1971	uintptr_t	*callstack,
1972	unsigned int	callstack_max)
1973{
1974	unsigned int	i;
1975
1976	/* guarantee the callstack is initialized */
1977	for (i=0; i < callstack_max; i++)
1978		callstack[i] = 0;
1979
1980	if (ipc_portbt)
1981		machine_callstack(callstack, callstack_max);
1982}
1983
1984/*
1985 *	Remove a port from the queue of allocated ports.
1986 *	This routine should be invoked JUST prior to
1987 *	deallocating the actual memory occupied by the port.
1988 */
1989#if 1
1990void
1991ipc_port_track_dealloc(
1992	__unused ipc_port_t	port)
1993{
1994}
1995#else
1996void
1997ipc_port_track_dealloc(
1998	ipc_port_t		port)
1999{
2000	lck_spin_lock(&port_alloc_queue_lock);
2001	assert(port_count > 0);
2002	--port_count;
2003	queue_remove(&port_alloc_queue, port, ipc_port_t, ip_port_links);
2004	lck_spin_unlock(&port_alloc_queue_lock);
2005}
2006#endif
2007
2008
2009#endif	/* MACH_ASSERT */
2010