1/*
2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*
29 * @OSF_COPYRIGHT@
30 */
31/*
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
34 * All Rights Reserved.
35 *
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
41 *
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
49 *  School of Computer Science
50 *  Carnegie Mellon University
51 *  Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56/*
57 * NOTICE: This file was modified by McAfee Research in 2004 to introduce
58 * support for mandatory and extensible security protections.  This notice
59 * is included in support of clause 2.2 (b) of the Apple Public License,
60 * Version 2.0.
61 * Copyright (c) 2005-2006 SPARTA, Inc.
62 */
63/*
64 */
65/*
66 *	File:	ipc/mach_port.c
67 *	Author:	Rich Draves
68 *	Date: 	1989
69 *
70 *	Exported kernel calls.  See mach/mach_port.defs.
71 */
72
73#include <mach_debug.h>
74#include <mach_rt.h>
75
76#include <mach/port.h>
77#include <mach/kern_return.h>
78#include <mach/notify.h>
79#include <mach/mach_param.h>
80#include <mach/vm_param.h>
81#include <mach/vm_prot.h>
82#include <mach/vm_map.h>
83#include <kern/task.h>
84#include <kern/counters.h>
85#include <kern/thread.h>
86#include <kern/kalloc.h>
87#include <mach/mach_port_server.h>
88#include <vm/vm_map.h>
89#include <vm/vm_kern.h>
90#include <ipc/ipc_entry.h>
91#include <ipc/ipc_space.h>
92#include <ipc/ipc_object.h>
93#include <ipc/ipc_notify.h>
94#include <ipc/ipc_port.h>
95#include <ipc/ipc_pset.h>
96#include <ipc/ipc_right.h>
97#include <ipc/ipc_kmsg.h>
98#include <kern/misc_protos.h>
99#include <security/mac_mach_internal.h>
100
101#if IMPORTANCE_INHERITANCE
102#include <ipc/ipc_importance.h>
103#endif
104
105/*
106 * Forward declarations
107 */
108void mach_port_names_helper(
109	ipc_port_timestamp_t	timestamp,
110	ipc_entry_t		entry,
111	mach_port_name_t	name,
112	mach_port_name_t	*names,
113	mach_port_type_t	*types,
114	ipc_entry_num_t		*actualp);
115
116void mach_port_gst_helper(
117	ipc_pset_t		pset,
118	ipc_entry_num_t		maxnames,
119	mach_port_name_t	*names,
120	ipc_entry_num_t		*actualp);
121
122
123kern_return_t
124mach_port_guard_exception(
125	mach_port_name_t	name,
126	uint64_t		inguard,
127	uint64_t		portguard,
128	unsigned		reason);
129
130/* Needs port locked */
131void mach_port_get_status_helper(
132	ipc_port_t		port,
133	mach_port_status_t	*status);
134
135/* Zeroed template of qos flags */
136
137static mach_port_qos_t	qos_template;
138
139/*
140 *	Routine:	mach_port_names_helper
141 *	Purpose:
142 *		A helper function for mach_port_names.
143 *
144 *	Conditions:
145 *		Space containing entry is [at least] read-locked.
146 */
147
148void
149mach_port_names_helper(
150	ipc_port_timestamp_t	timestamp,
151	ipc_entry_t		entry,
152	mach_port_name_t	name,
153	mach_port_name_t	*names,
154	mach_port_type_t	*types,
155	ipc_entry_num_t		*actualp)
156{
157	ipc_entry_bits_t bits;
158	ipc_port_request_index_t request;
159	mach_port_type_t type = 0;
160	ipc_entry_num_t actual;
161	ipc_port_t port;
162
163	bits = entry->ie_bits;
164	request = entry->ie_request;
165	port = (ipc_port_t) entry->ie_object;
166
167	if (bits & MACH_PORT_TYPE_RECEIVE) {
168		assert(IP_VALID(port));
169
170		if (request != IE_REQ_NONE) {
171			ip_lock(port);
172			assert(ip_active(port));
173			type |= ipc_port_request_type(port, name, request);
174			ip_unlock(port);
175		}
176
177	} else if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
178		mach_port_type_t reqtype;
179
180		assert(IP_VALID(port));
181		ip_lock(port);
182
183		reqtype = (request != IE_REQ_NONE) ?
184			  ipc_port_request_type(port, name, request) : 0;
185
186		/*
187		 * If the port is alive, or was alive when the mach_port_names
188		 * started, then return that fact.  Otherwise, pretend we found
189		 * a dead name entry.
190		 */
191		if (ip_active(port) || IP_TIMESTAMP_ORDER(timestamp, port->ip_timestamp)) {
192			type |= reqtype;
193		} else {
194			bits &= ~(IE_BITS_TYPE_MASK);
195			bits |= MACH_PORT_TYPE_DEAD_NAME;
196			/* account for additional reference for dead-name notification */
197			if (reqtype != 0)
198				bits++;
199		}
200		ip_unlock(port);
201	}
202
203	type |= IE_BITS_TYPE(bits);
204
205	actual = *actualp;
206	names[actual] = name;
207	types[actual] = type;
208	*actualp = actual+1;
209}
210
211/*
212 *	Routine:	mach_port_names [kernel call]
213 *	Purpose:
214 *		Retrieves a list of the rights present in the space,
215 *		along with type information.  (Same as returned
216 *		by mach_port_type.)  The names are returned in
217 *		no particular order, but they (and the type info)
218 *		are an accurate snapshot of the space.
219 *	Conditions:
220 *		Nothing locked.
221 *	Returns:
222 *		KERN_SUCCESS		Arrays of names and types returned.
223 *		KERN_INVALID_TASK	The space is null.
224 *		KERN_INVALID_TASK	The space is dead.
225 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
226 */
227
228kern_return_t
229mach_port_names(
230	ipc_space_t		space,
231	mach_port_name_t	**namesp,
232	mach_msg_type_number_t	*namesCnt,
233	mach_port_type_t	**typesp,
234	mach_msg_type_number_t	*typesCnt)
235{
236	ipc_entry_t table;
237	ipc_entry_num_t tsize;
238	mach_port_index_t index;
239	ipc_entry_num_t actual;	/* this many names */
240	ipc_port_timestamp_t timestamp;	/* logical time of this operation */
241	mach_port_name_t *names;
242	mach_port_type_t *types;
243	kern_return_t kr;
244
245	vm_size_t size;		/* size of allocated memory */
246	vm_offset_t addr1;	/* allocated memory, for names */
247	vm_offset_t addr2;	/* allocated memory, for types */
248	vm_map_copy_t memory1;	/* copied-in memory, for names */
249	vm_map_copy_t memory2;	/* copied-in memory, for types */
250
251	/* safe simplifying assumption */
252	assert_static(sizeof(mach_port_name_t) == sizeof(mach_port_type_t));
253
254	if (space == IS_NULL)
255		return KERN_INVALID_TASK;
256
257	size = 0;
258
259	for (;;) {
260		ipc_entry_num_t bound;
261		vm_size_t size_needed;
262
263		is_read_lock(space);
264		if (!is_active(space)) {
265			is_read_unlock(space);
266			if (size != 0) {
267				kmem_free(ipc_kernel_map, addr1, size);
268				kmem_free(ipc_kernel_map, addr2, size);
269			}
270			return KERN_INVALID_TASK;
271		}
272
273		/* upper bound on number of names in the space */
274		bound = space->is_table_size;
275		size_needed = vm_map_round_page(
276			(bound * sizeof(mach_port_name_t)),
277			VM_MAP_PAGE_MASK(ipc_kernel_map));
278
279		if (size_needed <= size)
280			break;
281
282		is_read_unlock(space);
283
284		if (size != 0) {
285			kmem_free(ipc_kernel_map, addr1, size);
286			kmem_free(ipc_kernel_map, addr2, size);
287		}
288		size = size_needed;
289
290		kr = vm_allocate(ipc_kernel_map, &addr1, size, VM_FLAGS_ANYWHERE);
291		if (kr != KERN_SUCCESS)
292			return KERN_RESOURCE_SHORTAGE;
293
294		kr = vm_allocate(ipc_kernel_map, &addr2, size, VM_FLAGS_ANYWHERE);
295		if (kr != KERN_SUCCESS) {
296			kmem_free(ipc_kernel_map, addr1, size);
297			return KERN_RESOURCE_SHORTAGE;
298		}
299
300		/* can't fault while we hold locks */
301
302		kr = vm_map_wire(
303			ipc_kernel_map,
304			vm_map_trunc_page(addr1,
305					  VM_MAP_PAGE_MASK(ipc_kernel_map)),
306			vm_map_round_page(addr1 + size,
307					  VM_MAP_PAGE_MASK(ipc_kernel_map)),
308			VM_PROT_READ|VM_PROT_WRITE,
309			FALSE);
310		if (kr != KERN_SUCCESS) {
311			kmem_free(ipc_kernel_map, addr1, size);
312			kmem_free(ipc_kernel_map, addr2, size);
313			return KERN_RESOURCE_SHORTAGE;
314		}
315
316		kr = vm_map_wire(
317			ipc_kernel_map,
318			vm_map_trunc_page(addr2,
319					  VM_MAP_PAGE_MASK(ipc_kernel_map)),
320			vm_map_round_page(addr2 + size,
321					  VM_MAP_PAGE_MASK(ipc_kernel_map)),
322			VM_PROT_READ|VM_PROT_WRITE,
323			FALSE);
324		if (kr != KERN_SUCCESS) {
325			kmem_free(ipc_kernel_map, addr1, size);
326			kmem_free(ipc_kernel_map, addr2, size);
327			return KERN_RESOURCE_SHORTAGE;
328		}
329
330	}
331	/* space is read-locked and active */
332
333	names = (mach_port_name_t *) addr1;
334	types = (mach_port_type_t *) addr2;
335	actual = 0;
336
337	timestamp = ipc_port_timestamp();
338
339	table = space->is_table;
340	tsize = space->is_table_size;
341
342	for (index = 0; index < tsize; index++) {
343		ipc_entry_t entry = &table[index];
344		ipc_entry_bits_t bits = entry->ie_bits;
345
346		if (IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE) {
347			mach_port_name_t name;
348
349			name = MACH_PORT_MAKE(index, IE_BITS_GEN(bits));
350			mach_port_names_helper(timestamp, entry, name, names,
351					       types, &actual);
352		}
353	}
354
355	is_read_unlock(space);
356
357	if (actual == 0) {
358		memory1 = VM_MAP_COPY_NULL;
359		memory2 = VM_MAP_COPY_NULL;
360
361		if (size != 0) {
362			kmem_free(ipc_kernel_map, addr1, size);
363			kmem_free(ipc_kernel_map, addr2, size);
364		}
365	} else {
366		vm_size_t size_used;
367		vm_size_t vm_size_used;
368
369		size_used = actual * sizeof(mach_port_name_t);
370		vm_size_used =
371			vm_map_round_page(size_used,
372					  VM_MAP_PAGE_MASK(ipc_kernel_map));
373
374		/*
375		 *	Make used memory pageable and get it into
376		 *	copied-in form.  Free any unused memory.
377		 */
378
379		kr = vm_map_unwire(
380			ipc_kernel_map,
381			vm_map_trunc_page(addr1,
382					  VM_MAP_PAGE_MASK(ipc_kernel_map)),
383			vm_map_round_page(addr1 + vm_size_used,
384					  VM_MAP_PAGE_MASK(ipc_kernel_map)),
385			FALSE);
386		assert(kr == KERN_SUCCESS);
387
388		kr = vm_map_unwire(
389			ipc_kernel_map,
390			vm_map_trunc_page(addr2,
391					  VM_MAP_PAGE_MASK(ipc_kernel_map)),
392			vm_map_round_page(addr2 + vm_size_used,
393					  VM_MAP_PAGE_MASK(ipc_kernel_map)),
394			FALSE);
395		assert(kr == KERN_SUCCESS);
396
397		kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr1,
398				   (vm_map_size_t)size_used, TRUE, &memory1);
399		assert(kr == KERN_SUCCESS);
400
401		kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr2,
402				   (vm_map_size_t)size_used, TRUE, &memory2);
403		assert(kr == KERN_SUCCESS);
404
405		if (vm_size_used != size) {
406			kmem_free(ipc_kernel_map,
407				  addr1 + vm_size_used, size - vm_size_used);
408			kmem_free(ipc_kernel_map,
409				  addr2 + vm_size_used, size - vm_size_used);
410		}
411	}
412
413	*namesp = (mach_port_name_t *) memory1;
414	*namesCnt = actual;
415	*typesp = (mach_port_type_t *) memory2;
416	*typesCnt = actual;
417	return KERN_SUCCESS;
418}
419
420/*
421 *	Routine:	mach_port_type [kernel call]
422 *	Purpose:
423 *		Retrieves the type of a right in the space.
424 *		The type is a bitwise combination of one or more
425 *		of the following type bits:
426 *			MACH_PORT_TYPE_SEND
427 *			MACH_PORT_TYPE_RECEIVE
428 *			MACH_PORT_TYPE_SEND_ONCE
429 *			MACH_PORT_TYPE_PORT_SET
430 *			MACH_PORT_TYPE_DEAD_NAME
431 *		In addition, the following pseudo-type bits may be present:
432 *			MACH_PORT_TYPE_DNREQUEST
433 *				A dead-name notification is requested.
434 *	Conditions:
435 *		Nothing locked.
436 *	Returns:
437 *		KERN_SUCCESS		Type is returned.
438 *		KERN_INVALID_TASK	The space is null.
439 *		KERN_INVALID_TASK	The space is dead.
440 *		KERN_INVALID_NAME	The name doesn't denote a right.
441 */
442
443kern_return_t
444mach_port_type(
445	ipc_space_t		space,
446	mach_port_name_t	name,
447	mach_port_type_t	*typep)
448{
449	mach_port_urefs_t urefs;
450	ipc_entry_t entry;
451	kern_return_t kr;
452
453	if (space == IS_NULL)
454		return KERN_INVALID_TASK;
455
456	if (name == MACH_PORT_NULL)
457		return KERN_INVALID_NAME;
458
459	if (name == MACH_PORT_DEAD) {
460		*typep = MACH_PORT_TYPE_DEAD_NAME;
461		return KERN_SUCCESS;
462	}
463
464	kr = ipc_right_lookup_write(space, name, &entry);
465	if (kr != KERN_SUCCESS)
466		return kr;
467
468	/* space is write-locked and active */
469	kr = ipc_right_info(space, name, entry, typep, &urefs);
470	/* space is unlocked */
471
472#if 1
473        /* JMM - workaround rdar://problem/9121297 (CF being too picky on these bits). */
474        *typep &= ~(MACH_PORT_TYPE_SPREQUEST | MACH_PORT_TYPE_SPREQUEST_DELAYED);
475#endif
476
477	return kr;
478}
479
480/*
481 *	Routine:	mach_port_rename [kernel call]
482 *	Purpose:
483 *		Changes the name denoting a right,
484 *		from oname to nname.
485 *	Conditions:
486 *		Nothing locked.
487 *	Returns:
488 *		KERN_SUCCESS		The right is renamed.
489 *		KERN_INVALID_TASK	The space is null.
490 *		KERN_INVALID_TASK	The space is dead.
491 *		KERN_INVALID_NAME	The oname doesn't denote a right.
492 *		KERN_INVALID_VALUE	The nname isn't a legal name.
493 *		KERN_NAME_EXISTS	The nname already denotes a right.
494 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
495 *
496 *      This interface is obsolete and always returns
497 *      KERN_NOT_SUPPORTED.
498 */
499
500kern_return_t
501mach_port_rename(
502	__unused ipc_space_t		space,
503	__unused mach_port_name_t	oname,
504	__unused mach_port_name_t	nname)
505{
506	return KERN_NOT_SUPPORTED;
507}
508
509
510/*
511 *	Routine:	mach_port_allocate_name [kernel call]
512 *	Purpose:
513 *		Allocates a right in a space, using a specific name
514 *		for the new right.  Possible rights:
515 *			MACH_PORT_RIGHT_RECEIVE
516 *			MACH_PORT_RIGHT_PORT_SET
517 *			MACH_PORT_RIGHT_DEAD_NAME
518 *
519 *		A new port (allocated with MACH_PORT_RIGHT_RECEIVE)
520 *		has no extant send or send-once rights and no queued
521 *		messages.  Its queue limit is MACH_PORT_QLIMIT_DEFAULT
522 *		and its make-send count is 0.  It is not a member of
523 *		a port set.  It has no registered no-senders or
524 *		port-destroyed notification requests.
525 *
526 *		A new port set has no members.
527 *
528 *		A new dead name has one user reference.
529 *	Conditions:
530 *		Nothing locked.
531 *	Returns:
532 *		KERN_SUCCESS		The right is allocated.
533 *		KERN_INVALID_TASK	The space is null.
534 *		KERN_INVALID_TASK	The space is dead.
535 *		KERN_INVALID_VALUE	The name isn't a legal name.
536 *		KERN_INVALID_VALUE	"right" isn't a legal kind of right.
537 *		KERN_NAME_EXISTS	The name already denotes a right.
538 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
539 *
540 *	Restrictions on name allocation:  NT bits are reserved by kernel,
541 *	must be set on any chosen name.  Can't do this at all in kernel
542 *	loaded server.
543 */
544
545kern_return_t
546mach_port_allocate_name(
547	ipc_space_t		space,
548	mach_port_right_t	right,
549	mach_port_name_t	name)
550{
551	kern_return_t		kr;
552	mach_port_qos_t		qos = qos_template;
553
554	qos.name = TRUE;
555
556	if (!MACH_PORT_VALID(name))
557		return KERN_INVALID_VALUE;
558
559	kr = mach_port_allocate_full (space, right, MACH_PORT_NULL,
560					&qos, &name);
561	return (kr);
562}
563
564/*
565 *	Routine:	mach_port_allocate [kernel call]
566 *	Purpose:
567 *		Allocates a right in a space.  Like mach_port_allocate_name,
568 *		except that the implementation picks a name for the right.
569 *		The name may be any legal name in the space that doesn't
570 *		currently denote a right.
571 *	Conditions:
572 *		Nothing locked.
573 *	Returns:
574 *		KERN_SUCCESS		The right is allocated.
575 *		KERN_INVALID_TASK	The space is null.
576 *		KERN_INVALID_TASK	The space is dead.
577 *		KERN_INVALID_VALUE	"right" isn't a legal kind of right.
578 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
579 *		KERN_NO_SPACE		No room in space for another right.
580 */
581
582kern_return_t
583mach_port_allocate(
584	ipc_space_t		space,
585	mach_port_right_t	right,
586	mach_port_name_t	*namep)
587{
588	kern_return_t		kr;
589	mach_port_qos_t		qos = qos_template;
590
591	kr = mach_port_allocate_full (space, right, MACH_PORT_NULL,
592					&qos, namep);
593	return (kr);
594}
595
596/*
597 *	Routine:	mach_port_allocate_qos [kernel call]
598 *	Purpose:
599 *		Allocates a right, with qos options, in a space.  Like
600 *		mach_port_allocate_name, except that the implementation
601 *		picks a name for the right. The name may be any legal name
602 *		in the space that doesn't currently denote a right.
603 *	Conditions:
604 *		Nothing locked.
605 *	Returns:
606 *		KERN_SUCCESS		The right is allocated.
607 *		KERN_INVALID_TASK	The space is null.
608 *		KERN_INVALID_TASK	The space is dead.
609 *		KERN_INVALID_VALUE	"right" isn't a legal kind of right.
610 *		KERN_INVALID_ARGUMENT   The qos request was invalid.
611 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
612 *		KERN_NO_SPACE		No room in space for another right.
613 */
614
615kern_return_t
616mach_port_allocate_qos(
617	ipc_space_t		space,
618	mach_port_right_t	right,
619	mach_port_qos_t		*qosp,
620	mach_port_name_t	*namep)
621{
622	kern_return_t		kr;
623
624	if (qosp->name)
625		return KERN_INVALID_ARGUMENT;
626	kr = mach_port_allocate_full (space, right, MACH_PORT_NULL,
627					qosp, namep);
628	return (kr);
629}
630
631/*
632 *	Routine:	mach_port_allocate_full [kernel call]
633 *	Purpose:
634 *		Allocates a right in a space.  Supports all of the
635 *		special cases, such as specifying a subsystem,
636 *		a specific name, a real-time port, etc.
637 *		The name may be any legal name in the space that doesn't
638 *		currently denote a right.
639 *	Conditions:
640 *		Nothing locked.
641 *	Returns:
642 *		KERN_SUCCESS		The right is allocated.
643 *		KERN_INVALID_TASK	The space is null.
644 *		KERN_INVALID_TASK	The space is dead.
645 *		KERN_INVALID_VALUE	"right" isn't a legal kind of right.
646 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
647 *		KERN_NO_SPACE		No room in space for another right.
648 */
649
650kern_return_t
651mach_port_allocate_full(
652	ipc_space_t		space,
653	mach_port_right_t	right,
654	mach_port_t		proto,
655	mach_port_qos_t		*qosp,
656	mach_port_name_t	*namep)
657{
658	ipc_kmsg_t		kmsg = IKM_NULL;
659	kern_return_t		kr;
660
661	if (space == IS_NULL)
662		return (KERN_INVALID_TASK);
663
664	if (proto != MACH_PORT_NULL)
665		return (KERN_INVALID_VALUE);
666
667	if (qosp->name) {
668		if (!MACH_PORT_VALID (*namep))
669			return (KERN_INVALID_VALUE);
670	}
671
672	if (qosp->prealloc) {
673		if (qosp->len > MACH_MSG_SIZE_MAX - MAX_TRAILER_SIZE) {
674			return KERN_RESOURCE_SHORTAGE;
675		} else {
676			mach_msg_size_t size = qosp->len + MAX_TRAILER_SIZE;
677
678			if (right != MACH_PORT_RIGHT_RECEIVE)
679				return (KERN_INVALID_VALUE);
680
681			kmsg = (ipc_kmsg_t)ipc_kmsg_prealloc(size);
682			if (kmsg == IKM_NULL)
683				return (KERN_RESOURCE_SHORTAGE);
684		}
685	}
686
687	switch (right) {
688	    case MACH_PORT_RIGHT_RECEIVE:
689	    {
690		ipc_port_t	port;
691
692		if (qosp->name)
693			kr = ipc_port_alloc_name(space, *namep, &port);
694		else
695			kr = ipc_port_alloc(space, namep, &port);
696		if (kr == KERN_SUCCESS) {
697			if (kmsg != IKM_NULL)
698				ipc_kmsg_set_prealloc(kmsg, port);
699
700			ip_unlock(port);
701
702		} else if (kmsg != IKM_NULL)
703			ipc_kmsg_free(kmsg);
704		break;
705	    }
706
707	    case MACH_PORT_RIGHT_PORT_SET:
708	    {
709		ipc_pset_t	pset;
710
711		if (qosp->name)
712			kr = ipc_pset_alloc_name(space, *namep, &pset);
713		else
714			kr = ipc_pset_alloc(space, namep, &pset);
715		if (kr == KERN_SUCCESS)
716			ips_unlock(pset);
717		break;
718	    }
719
720	    case MACH_PORT_RIGHT_DEAD_NAME:
721		kr = ipc_object_alloc_dead(space, namep);
722		break;
723
724	    default:
725		kr = KERN_INVALID_VALUE;
726		break;
727	}
728
729	return (kr);
730}
731
732/*
733 *	Routine:	mach_port_destroy [kernel call]
734 *	Purpose:
735 *		Cleans up and destroys all rights denoted by a name
736 *		in a space.  The destruction of a receive right
737 *		destroys the port, unless a port-destroyed request
738 *		has been made for it; the destruction of a port-set right
739 *		destroys the port set.
740 *	Conditions:
741 *		Nothing locked.
742 *	Returns:
743 *		KERN_SUCCESS		The name is destroyed.
744 *		KERN_INVALID_TASK	The space is null.
745 *		KERN_INVALID_TASK	The space is dead.
746 *		KERN_INVALID_NAME	The name doesn't denote a right.
747 */
748
749kern_return_t
750mach_port_destroy(
751	ipc_space_t		space,
752	mach_port_name_t	name)
753{
754	ipc_entry_t entry;
755	kern_return_t kr;
756
757	if (space == IS_NULL)
758		return KERN_INVALID_TASK;
759
760	if (!MACH_PORT_VALID(name))
761		return KERN_SUCCESS;
762
763	kr = ipc_right_lookup_write(space, name, &entry);
764	if (kr != KERN_SUCCESS)
765		return kr;
766	/* space is write-locked and active */
767
768	kr = ipc_right_destroy(space, name, entry, TRUE, 0); /* unlocks space */
769	return kr;
770}
771
772/*
773 *	Routine:	mach_port_deallocate [kernel call]
774 *	Purpose:
775 *		Deallocates a user reference from a send right,
776 *		send-once right, or a dead-name right.  May
777 *		deallocate the right, if this is the last uref,
778 *		and destroy the name, if it doesn't denote
779 *		other rights.
780 *	Conditions:
781 *		Nothing locked.
782 *	Returns:
783 *		KERN_SUCCESS		The uref is deallocated.
784 *		KERN_INVALID_TASK	The space is null.
785 *		KERN_INVALID_TASK	The space is dead.
786 *		KERN_INVALID_NAME	The name doesn't denote a right.
787 *		KERN_INVALID_RIGHT	The right isn't correct.
788 */
789
790kern_return_t
791mach_port_deallocate(
792	ipc_space_t		space,
793	mach_port_name_t	name)
794{
795	ipc_entry_t entry;
796	kern_return_t kr;
797
798	if (space == IS_NULL)
799		return KERN_INVALID_TASK;
800
801	if (!MACH_PORT_VALID(name))
802		return KERN_SUCCESS;
803
804	kr = ipc_right_lookup_write(space, name, &entry);
805	if (kr != KERN_SUCCESS)
806		return kr;
807	/* space is write-locked */
808
809	kr = ipc_right_dealloc(space, name, entry); /* unlocks space */
810	return kr;
811}
812
813/*
814 *	Routine:	mach_port_get_refs [kernel call]
815 *	Purpose:
816 *		Retrieves the number of user references held by a right.
817 *		Receive rights, port-set rights, and send-once rights
818 *		always have one user reference.  Returns zero if the
819 *		name denotes a right, but not the queried right.
820 *	Conditions:
821 *		Nothing locked.
822 *	Returns:
823 *		KERN_SUCCESS		Number of urefs returned.
824 *		KERN_INVALID_TASK	The space is null.
825 *		KERN_INVALID_TASK	The space is dead.
826 *		KERN_INVALID_VALUE	"right" isn't a legal value.
827 *		KERN_INVALID_NAME	The name doesn't denote a right.
828 */
829
830kern_return_t
831mach_port_get_refs(
832	ipc_space_t		space,
833	mach_port_name_t	name,
834	mach_port_right_t	right,
835	mach_port_urefs_t	*urefsp)
836{
837	mach_port_type_t type;
838	mach_port_urefs_t urefs;
839	ipc_entry_t entry;
840	kern_return_t kr;
841
842	if (space == IS_NULL)
843		return KERN_INVALID_TASK;
844
845	if (right >= MACH_PORT_RIGHT_NUMBER)
846		return KERN_INVALID_VALUE;
847
848	if (!MACH_PORT_VALID(name)) {
849	  	if (right == MACH_PORT_RIGHT_SEND ||
850		    right == MACH_PORT_RIGHT_SEND_ONCE) {
851			*urefsp = 1;
852			return KERN_SUCCESS;
853		}
854		return KERN_INVALID_NAME;
855	}
856
857	kr = ipc_right_lookup_write(space, name, &entry);
858	if (kr != KERN_SUCCESS)
859		return kr;
860
861	/* space is write-locked and active */
862	kr = ipc_right_info(space, name, entry, &type, &urefs);
863	/* space is unlocked */
864
865	if (kr != KERN_SUCCESS)
866		return kr;
867
868	if (type & MACH_PORT_TYPE(right))
869		switch (right) {
870		    case MACH_PORT_RIGHT_SEND_ONCE:
871			assert(urefs == 1);
872			/* fall-through */
873
874		    case MACH_PORT_RIGHT_PORT_SET:
875		    case MACH_PORT_RIGHT_RECEIVE:
876			*urefsp = 1;
877			break;
878
879		    case MACH_PORT_RIGHT_DEAD_NAME:
880		    case MACH_PORT_RIGHT_SEND:
881			assert(urefs > 0);
882			*urefsp = urefs;
883			break;
884
885		    default:
886			panic("mach_port_get_refs: strange rights");
887		}
888	else
889		*urefsp = 0;
890
891	return kr;
892}
893
894/*
895 *	Routine:	mach_port_mod_refs
896 *	Purpose:
897 *		Modifies the number of user references held by a right.
898 *		The resulting number of user references must be non-negative.
899 *		If it is zero, the right is deallocated.  If the name
900 *		doesn't denote other rights, it is destroyed.
901 *	Conditions:
902 *		Nothing locked.
903 *	Returns:
904 *		KERN_SUCCESS		Modified number of urefs.
905 *		KERN_INVALID_TASK	The space is null.
906 *		KERN_INVALID_TASK	The space is dead.
907 *		KERN_INVALID_VALUE	"right" isn't a legal value.
908 *		KERN_INVALID_NAME	The name doesn't denote a right.
909 *		KERN_INVALID_RIGHT	Name doesn't denote specified right.
910 *		KERN_INVALID_VALUE	Impossible modification to urefs.
911 *		KERN_UREFS_OVERFLOW	Urefs would overflow.
912 */
913
914kern_return_t
915mach_port_mod_refs(
916	ipc_space_t		space,
917	mach_port_name_t	name,
918	mach_port_right_t	right,
919	mach_port_delta_t	delta)
920{
921	ipc_entry_t entry;
922	kern_return_t kr;
923
924	if (space == IS_NULL)
925		return KERN_INVALID_TASK;
926
927	if (right >= MACH_PORT_RIGHT_NUMBER)
928		return KERN_INVALID_VALUE;
929
930	if (!MACH_PORT_VALID(name)) {
931		if (right == MACH_PORT_RIGHT_SEND ||
932		    right == MACH_PORT_RIGHT_SEND_ONCE)
933			return KERN_SUCCESS;
934		return KERN_INVALID_NAME;
935	}
936
937	kr = ipc_right_lookup_write(space, name, &entry);
938	if (kr != KERN_SUCCESS)
939		return kr;
940	/* space is write-locked and active */
941
942	kr = ipc_right_delta(space, name, entry, right, delta);	/* unlocks */
943	return kr;
944}
945
946
947/*
948 *	Routine:	mach_port_peek [kernel call]
949 *	Purpose:
950 *		Peek at the message queue for the specified receive
951 *		right and return info about a message in the queue.
952 *
953 *		On input, seqnop points to a sequence number value
954 *		to match the message being peeked. If zero is specified
955 *		as the seqno, the first message in the queue will be
956 *		peeked.
957 *
958 *		Only the following trailer types are currently supported:
959 *			MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)
960 *
961 *				or'ed with one of these element types:
962 *			MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_NULL)
963 *			MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SEQNO)
964 *			MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER)
965 *			MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT)
966 *
967 *		On input, the value pointed to by trailer_sizep must be
968 *		large enough to hold the requested trailer size.
969 *
970 *		The message sequence number, id, size, requested trailer info
971 *		and requested trailer size are returned in their respective
972 *		output parameters upon success.
973 *
974 *	Conditions:
975 *		Nothing locked.
976 *	Returns:
977 *		KERN_SUCCESS		Matching message found, out parameters set.
978 *		KERN_INVALID_TASK	The space is null or dead.
979 *		KERN_INVALID_NAME	The name doesn't denote a right.
980 *		KERN_INVALID_RIGHT	Name doesn't denote receive rights.
981 *		KERN_INVALID_VALUE	The input parameter values are out of bounds.
982 *		KERN_FAILURE		The requested message was not found.
983 */
984
985kern_return_t
986mach_port_peek(
987	ipc_space_t			space,
988	mach_port_name_t		name,
989	mach_msg_trailer_type_t 	trailer_type,
990	mach_port_seqno_t		*seqnop,
991	mach_msg_size_t			*msg_sizep,
992	mach_msg_id_t			*msg_idp,
993	mach_msg_trailer_info_t 	trailer_infop,
994	mach_msg_type_number_t		*trailer_sizep)
995{
996	ipc_port_t port;
997	kern_return_t kr;
998	boolean_t found;
999	mach_msg_max_trailer_t max_trailer;
1000
1001	if (space == IS_NULL)
1002		return KERN_INVALID_TASK;
1003
1004	if (!MACH_PORT_VALID(name))
1005		return KERN_INVALID_RIGHT;
1006
1007	/*
1008	 * We don't allow anything greater than the audit trailer - to avoid
1009	 * leaking the context pointer and to avoid variable-sized context issues.
1010	 */
1011	if (GET_RCV_ELEMENTS(trailer_type) > MACH_RCV_TRAILER_AUDIT ||
1012	    REQUESTED_TRAILER_SIZE(TRUE, trailer_type) > *trailer_sizep)
1013		return KERN_INVALID_VALUE;
1014
1015	*trailer_sizep = REQUESTED_TRAILER_SIZE(TRUE, trailer_type);
1016
1017	kr = ipc_port_translate_receive(space, name, &port);
1018	if (kr != KERN_SUCCESS)
1019		return kr;
1020
1021	/* Port locked and active */
1022
1023	found = ipc_mqueue_peek(&port->ip_messages, seqnop,
1024				msg_sizep, msg_idp, &max_trailer);
1025	ip_unlock(port);
1026
1027	if (found != TRUE)
1028		return KERN_FAILURE;
1029
1030	max_trailer.msgh_seqno = *seqnop;
1031	memcpy(trailer_infop, &max_trailer, *trailer_sizep);
1032
1033	return KERN_SUCCESS;
1034}
1035
1036/*
1037 *	Routine:	mach_port_set_mscount [kernel call]
1038 *	Purpose:
1039 *		Changes a receive right's make-send count.
1040 *	Conditions:
1041 *		Nothing locked.
1042 *	Returns:
1043 *		KERN_SUCCESS		Set make-send count.
1044 *		KERN_INVALID_TASK	The space is null.
1045 *		KERN_INVALID_TASK	The space is dead.
1046 *		KERN_INVALID_NAME	The name doesn't denote a right.
1047 *		KERN_INVALID_RIGHT	Name doesn't denote receive rights.
1048 */
1049
1050kern_return_t
1051mach_port_set_mscount(
1052	ipc_space_t		space,
1053	mach_port_name_t	name,
1054	mach_port_mscount_t	mscount)
1055{
1056	ipc_port_t port;
1057	kern_return_t kr;
1058
1059	if (space == IS_NULL)
1060		return KERN_INVALID_TASK;
1061
1062	if (!MACH_PORT_VALID(name))
1063		return KERN_INVALID_RIGHT;
1064
1065	kr = ipc_port_translate_receive(space, name, &port);
1066	if (kr != KERN_SUCCESS)
1067		return kr;
1068	/* port is locked and active */
1069
1070	ipc_port_set_mscount(port, mscount);
1071
1072	ip_unlock(port);
1073	return KERN_SUCCESS;
1074}
1075
1076/*
1077 *	Routine:	mach_port_set_seqno [kernel call]
1078 *	Purpose:
1079 *		Changes a receive right's sequence number.
1080 *	Conditions:
1081 *		Nothing locked.
1082 *	Returns:
1083 *		KERN_SUCCESS		Set sequence number.
1084 *		KERN_INVALID_TASK	The space is null.
1085 *		KERN_INVALID_TASK	The space is dead.
1086 *		KERN_INVALID_NAME	The name doesn't denote a right.
1087 *		KERN_INVALID_RIGHT	Name doesn't denote receive rights.
1088 */
1089
1090kern_return_t
1091mach_port_set_seqno(
1092	ipc_space_t		space,
1093	mach_port_name_t	name,
1094	mach_port_seqno_t	seqno)
1095{
1096	ipc_port_t port;
1097	kern_return_t kr;
1098
1099	if (space == IS_NULL)
1100		return KERN_INVALID_TASK;
1101
1102	if (!MACH_PORT_VALID(name))
1103		return KERN_INVALID_RIGHT;
1104
1105	kr = ipc_port_translate_receive(space, name, &port);
1106	if (kr != KERN_SUCCESS)
1107		return kr;
1108	/* port is locked and active */
1109
1110	ipc_mqueue_set_seqno(&port->ip_messages, seqno);
1111
1112	ip_unlock(port);
1113	return KERN_SUCCESS;
1114}
1115
1116/*
1117 *	Routine:	mach_port_get_context [kernel call]
1118 *	Purpose:
1119 *		Returns a receive right's context pointer.
1120 *	Conditions:
1121 *		Nothing locked.
1122 *	Returns:
1123 *		KERN_SUCCESS		Set context pointer.
1124 *		KERN_INVALID_TASK	The space is null.
1125 *		KERN_INVALID_TASK	The space is dead.
1126 *		KERN_INVALID_NAME	The name doesn't denote a right.
1127 *		KERN_INVALID_RIGHT	Name doesn't denote receive rights.
1128 */
1129
1130kern_return_t
1131mach_port_get_context(
1132	ipc_space_t		space,
1133	mach_port_name_t	name,
1134	mach_vm_address_t	*context)
1135{
1136	ipc_port_t port;
1137	kern_return_t kr;
1138
1139	if (space == IS_NULL)
1140		return KERN_INVALID_TASK;
1141
1142	if (!MACH_PORT_VALID(name))
1143		return KERN_INVALID_RIGHT;
1144
1145	kr = ipc_port_translate_receive(space, name, &port);
1146	if (kr != KERN_SUCCESS)
1147		return kr;
1148
1149	/* Port locked and active */
1150
1151	/* For strictly guarded ports, return empty context (which acts as guard) */
1152	if (port->ip_strict_guard)
1153		*context = 0;
1154	else
1155		*context = port->ip_context;
1156
1157	ip_unlock(port);
1158	return KERN_SUCCESS;
1159}
1160
1161
1162/*
1163 *	Routine:	mach_port_set_context [kernel call]
1164 *	Purpose:
1165 *		Changes a receive right's context pointer.
1166 *	Conditions:
1167 *		Nothing locked.
1168 *	Returns:
1169 *		KERN_SUCCESS		Set context pointer.
1170 *		KERN_INVALID_TASK	The space is null.
1171 *		KERN_INVALID_TASK	The space is dead.
1172 *		KERN_INVALID_NAME	The name doesn't denote a right.
1173 *		KERN_INVALID_RIGHT	Name doesn't denote receive rights.
1174 */
1175
1176kern_return_t
1177mach_port_set_context(
1178	ipc_space_t		space,
1179	mach_port_name_t	name,
1180	mach_vm_address_t	context)
1181{
1182	ipc_port_t port;
1183	kern_return_t kr;
1184
1185	if (space == IS_NULL)
1186		return KERN_INVALID_TASK;
1187
1188	if (!MACH_PORT_VALID(name))
1189		return KERN_INVALID_RIGHT;
1190
1191	kr = ipc_port_translate_receive(space, name, &port);
1192	if (kr != KERN_SUCCESS)
1193		return kr;
1194
1195	/* port is locked and active */
1196	if(port->ip_strict_guard) {
1197		uint64_t portguard = port->ip_context;
1198		ip_unlock(port);
1199		/* For strictly guarded ports, disallow overwriting context; Raise Exception */
1200		mach_port_guard_exception(name, context, portguard, kGUARD_EXC_SET_CONTEXT);
1201		return KERN_INVALID_ARGUMENT;
1202	}
1203
1204	port->ip_context = context;
1205
1206	ip_unlock(port);
1207	return KERN_SUCCESS;
1208}
1209
1210
1211/*
1212 *	Routine:	mach_port_get_set_status [kernel call]
1213 *	Purpose:
1214 *		Retrieves a list of members in a port set.
1215 *		Returns the space's name for each receive right member.
1216 *	Conditions:
1217 *		Nothing locked.
1218 *	Returns:
1219 *		KERN_SUCCESS		Retrieved list of members.
1220 *		KERN_INVALID_TASK	The space is null.
1221 *		KERN_INVALID_TASK	The space is dead.
1222 *		KERN_INVALID_NAME	The name doesn't denote a right.
1223 *		KERN_INVALID_RIGHT	Name doesn't denote a port set.
1224 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
1225 */
1226
1227kern_return_t
1228mach_port_get_set_status(
1229	ipc_space_t			space,
1230	mach_port_name_t		name,
1231	mach_port_name_t		**members,
1232	mach_msg_type_number_t		*membersCnt)
1233{
1234	ipc_entry_num_t actual;		/* this many members */
1235	ipc_entry_num_t maxnames;	/* space for this many members */
1236	kern_return_t kr;
1237
1238	vm_size_t size;		/* size of allocated memory */
1239	vm_offset_t addr;	/* allocated memory */
1240	vm_map_copy_t memory;	/* copied-in memory */
1241
1242	if (space == IS_NULL)
1243		return KERN_INVALID_TASK;
1244
1245	if (!MACH_PORT_VALID(name))
1246		return KERN_INVALID_RIGHT;
1247
1248	size = VM_MAP_PAGE_SIZE(ipc_kernel_map);	/* initial guess */
1249
1250	for (;;) {
1251		mach_port_name_t *names;
1252		ipc_object_t psobj;
1253		ipc_pset_t pset;
1254
1255		kr = vm_allocate(ipc_kernel_map, &addr, size, VM_FLAGS_ANYWHERE);
1256		if (kr != KERN_SUCCESS)
1257			return KERN_RESOURCE_SHORTAGE;
1258
1259		/* can't fault while we hold locks */
1260
1261		kr = vm_map_wire(ipc_kernel_map, addr, addr + size,
1262				     VM_PROT_READ|VM_PROT_WRITE, FALSE);
1263		assert(kr == KERN_SUCCESS);
1264
1265		kr = ipc_object_translate(space, name, MACH_PORT_RIGHT_PORT_SET, &psobj);
1266		if (kr != KERN_SUCCESS) {
1267			kmem_free(ipc_kernel_map, addr, size);
1268			return kr;
1269		}
1270
1271		/* just use a portset reference from here on out */
1272		pset = (ipc_pset_t) psobj;
1273		ips_reference(pset);
1274		ips_unlock(pset);
1275
1276		names = (mach_port_name_t *) addr;
1277		maxnames = (ipc_entry_num_t)(size / sizeof(mach_port_name_t));
1278
1279		ipc_mqueue_set_gather_member_names(&pset->ips_messages, maxnames, names, &actual);
1280
1281		/* release the portset reference */
1282		ips_release(pset);
1283
1284		if (actual <= maxnames)
1285			break;
1286
1287		/* didn't have enough memory; allocate more */
1288		kmem_free(ipc_kernel_map, addr, size);
1289		size = vm_map_round_page(
1290			(actual * sizeof(mach_port_name_t)),
1291			 VM_MAP_PAGE_MASK(ipc_kernel_map)) +
1292			VM_MAP_PAGE_SIZE(ipc_kernel_map);
1293	}
1294
1295	if (actual == 0) {
1296		memory = VM_MAP_COPY_NULL;
1297
1298		kmem_free(ipc_kernel_map, addr, size);
1299	} else {
1300		vm_size_t size_used;
1301		vm_size_t vm_size_used;
1302
1303		size_used = actual * sizeof(mach_port_name_t);
1304		vm_size_used = vm_map_round_page(
1305			size_used,
1306			VM_MAP_PAGE_MASK(ipc_kernel_map));
1307
1308		/*
1309		 *	Make used memory pageable and get it into
1310		 *	copied-in form.  Free any unused memory.
1311		 */
1312
1313		kr = vm_map_unwire(
1314			ipc_kernel_map,
1315			vm_map_trunc_page(addr,
1316					  VM_MAP_PAGE_MASK(ipc_kernel_map)),
1317			vm_map_round_page(addr + vm_size_used,
1318					  VM_MAP_PAGE_MASK(ipc_kernel_map)),
1319			FALSE);
1320		assert(kr == KERN_SUCCESS);
1321
1322		kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr,
1323				   (vm_map_size_t)size_used, TRUE, &memory);
1324		assert(kr == KERN_SUCCESS);
1325
1326		if (vm_size_used != size)
1327			kmem_free(ipc_kernel_map,
1328				  addr + vm_size_used, size - vm_size_used);
1329	}
1330
1331	*members = (mach_port_name_t *) memory;
1332	*membersCnt = actual;
1333	return KERN_SUCCESS;
1334}
1335
1336/*
1337 *	Routine:	mach_port_move_member [kernel call]
1338 *	Purpose:
1339 *		If after is MACH_PORT_NULL, removes member
1340 *		from the port set it is in.  Otherwise, adds
1341 *		member to after, removing it from any set
1342 *		it might already be in.
1343 *	Conditions:
1344 *		Nothing locked.
1345 *	Returns:
1346 *		KERN_SUCCESS		Moved the port.
1347 *		KERN_INVALID_TASK	The space is null.
1348 *		KERN_INVALID_TASK	The space is dead.
1349 *		KERN_INVALID_NAME	Member didn't denote a right.
1350 *		KERN_INVALID_RIGHT	Member didn't denote a receive right.
1351 *		KERN_INVALID_NAME	After didn't denote a right.
1352 *		KERN_INVALID_RIGHT	After didn't denote a port set right.
1353 *		KERN_NOT_IN_SET
1354 *			After is MACH_PORT_NULL and Member isn't in a port set.
1355 */
1356
1357kern_return_t
1358mach_port_move_member(
1359	ipc_space_t		space,
1360	mach_port_name_t	member,
1361	mach_port_name_t	after)
1362{
1363	ipc_entry_t entry;
1364	ipc_port_t port;
1365	ipc_pset_t nset;
1366	kern_return_t kr;
1367	wait_queue_link_t wql;
1368	queue_head_t links_data;
1369	queue_t links = &links_data;
1370
1371	if (space == IS_NULL)
1372		return KERN_INVALID_TASK;
1373
1374	if (!MACH_PORT_VALID(member))
1375		return KERN_INVALID_RIGHT;
1376
1377	if (after == MACH_PORT_DEAD)
1378		return KERN_INVALID_RIGHT;
1379	else if (after == MACH_PORT_NULL)
1380		wql = WAIT_QUEUE_LINK_NULL;
1381	else
1382		wql = wait_queue_link_allocate();
1383
1384	queue_init(links);
1385
1386	kr = ipc_right_lookup_read(space, member, &entry);
1387	if (kr != KERN_SUCCESS)
1388		goto done;
1389	/* space is read-locked and active */
1390
1391	if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0) {
1392		is_read_unlock(space);
1393		kr = KERN_INVALID_RIGHT;
1394		goto done;
1395	}
1396
1397	port = (ipc_port_t) entry->ie_object;
1398	assert(port != IP_NULL);
1399
1400	if (after == MACH_PORT_NULL)
1401		nset = IPS_NULL;
1402	else {
1403		entry = ipc_entry_lookup(space, after);
1404		if (entry == IE_NULL) {
1405			is_read_unlock(space);
1406			kr = KERN_INVALID_NAME;
1407			goto done;
1408		}
1409
1410		if ((entry->ie_bits & MACH_PORT_TYPE_PORT_SET) == 0) {
1411			is_read_unlock(space);
1412			kr = KERN_INVALID_RIGHT;
1413			goto done;
1414		}
1415
1416		nset = (ipc_pset_t) entry->ie_object;
1417		assert(nset != IPS_NULL);
1418	}
1419	ip_lock(port);
1420	ipc_pset_remove_from_all(port, links);
1421
1422	if (nset != IPS_NULL) {
1423		ips_lock(nset);
1424		kr = ipc_pset_add(nset, port, wql);
1425		ips_unlock(nset);
1426	}
1427	ip_unlock(port);
1428	is_read_unlock(space);
1429
1430 done:
1431	if (kr != KERN_SUCCESS && wql != WAIT_QUEUE_LINK_NULL)
1432		wait_queue_link_free(wql);
1433	while(!queue_empty(links)) {
1434		wql = (wait_queue_link_t) dequeue(links);
1435		wait_queue_link_free(wql);
1436	}
1437
1438	return kr;
1439}
1440
1441/*
1442 *	Routine:	mach_port_request_notification [kernel call]
1443 *	Purpose:
1444 *		Requests a notification.  The caller supplies
1445 *		a send-once right for the notification to use,
1446 *		and the call returns the previously registered
1447 *		send-once right, if any.  Possible types:
1448 *
1449 *		MACH_NOTIFY_PORT_DESTROYED
1450 *			Requests a port-destroyed notification
1451 *			for a receive right.  Sync should be zero.
1452 *		MACH_NOTIFY_NO_SENDERS
1453 *			Requests a no-senders notification for a
1454 *			receive right.  If there are currently no
1455 *			senders, sync is less than or equal to the
1456 *			current make-send count, and a send-once right
1457 *			is supplied, then an immediate no-senders
1458 *			notification is generated.
1459 *		MACH_NOTIFY_DEAD_NAME
1460 *			Requests a dead-name notification for a send
1461 *			or receive right.  If the name is already a
1462 *			dead name, sync is non-zero, and a send-once
1463 *			right is supplied, then an immediate dead-name
1464 *			notification is generated.
1465 *	Conditions:
1466 *		Nothing locked.
1467 *	Returns:
1468 *		KERN_SUCCESS		Requested a notification.
1469 *		KERN_INVALID_TASK	The space is null.
1470 *		KERN_INVALID_TASK	The space is dead.
1471 *		KERN_INVALID_VALUE	Bad id value.
1472 *		KERN_INVALID_NAME	Name doesn't denote a right.
1473 *		KERN_INVALID_RIGHT	Name doesn't denote appropriate right.
1474 *		KERN_INVALID_CAPABILITY	The notify port is dead.
1475 *	MACH_NOTIFY_PORT_DESTROYED:
1476 *		KERN_INVALID_VALUE	Sync isn't zero.
1477 *	MACH_NOTIFY_DEAD_NAME:
1478 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
1479 *		KERN_INVALID_ARGUMENT	Name denotes dead name, but
1480 *			sync is zero or notify is IP_NULL.
1481 *		KERN_UREFS_OVERFLOW	Name denotes dead name, but
1482 *			generating immediate notif. would overflow urefs.
1483 */
1484
1485kern_return_t
1486mach_port_request_notification(
1487	ipc_space_t		space,
1488	mach_port_name_t	name,
1489	mach_msg_id_t		id,
1490	mach_port_mscount_t	sync,
1491	ipc_port_t		notify,
1492	ipc_port_t		*previousp)
1493{
1494	kern_return_t kr;
1495
1496	if (space == IS_NULL)
1497		return KERN_INVALID_TASK;
1498
1499	if (notify == IP_DEAD)
1500		return KERN_INVALID_CAPABILITY;
1501
1502#if	NOTYET
1503	/*
1504	 *	Requesting notifications on RPC ports is an error.
1505	 */
1506	{
1507		ipc_port_t port;
1508		ipc_entry_t entry;
1509
1510		kr = ipc_right_lookup_write(space, name, &entry);
1511		if (kr != KERN_SUCCESS)
1512			return kr;
1513
1514		port = (ipc_port_t) entry->ie_object;
1515
1516		if (port->ip_subsystem != NULL) {
1517			is_write_unlock(space);
1518			panic("mach_port_request_notification: on RPC port!!");
1519			return KERN_INVALID_CAPABILITY;
1520		}
1521		is_write_unlock(space);
1522	}
1523#endif 	/* NOTYET */
1524
1525
1526	switch (id) {
1527	    case MACH_NOTIFY_PORT_DESTROYED: {
1528		ipc_port_t port, previous;
1529
1530		if (sync != 0)
1531			return KERN_INVALID_VALUE;
1532
1533		if (!MACH_PORT_VALID(name))
1534			return KERN_INVALID_RIGHT;
1535
1536		kr = ipc_port_translate_receive(space, name, &port);
1537		if (kr != KERN_SUCCESS)
1538			return kr;
1539		/* port is locked and active */
1540
1541		ipc_port_pdrequest(port, notify, &previous);
1542		/* port is unlocked */
1543
1544		*previousp = previous;
1545		break;
1546	    }
1547
1548	    case MACH_NOTIFY_NO_SENDERS: {
1549		ipc_port_t port;
1550
1551		if (!MACH_PORT_VALID(name))
1552			return KERN_INVALID_RIGHT;
1553
1554		kr = ipc_port_translate_receive(space, name, &port);
1555		if (kr != KERN_SUCCESS)
1556			return kr;
1557		/* port is locked and active */
1558
1559		ipc_port_nsrequest(port, sync, notify, previousp);
1560		/* port is unlocked */
1561		break;
1562	    }
1563
1564	    case MACH_NOTIFY_SEND_POSSIBLE:
1565
1566	    	if (!MACH_PORT_VALID(name)) {
1567	      		return KERN_INVALID_ARGUMENT;
1568		}
1569
1570		kr = ipc_right_request_alloc(space, name, sync != 0,
1571					     TRUE, notify, previousp);
1572		if (kr != KERN_SUCCESS)
1573			return kr;
1574		break;
1575
1576	    case MACH_NOTIFY_DEAD_NAME:
1577
1578	    	if (!MACH_PORT_VALID(name)) {
1579			/*
1580			 * Already dead.
1581			 * Should do immediate delivery check -
1582			 * will do that in the near future.
1583			 */
1584	      		return KERN_INVALID_ARGUMENT;
1585		}
1586
1587		kr = ipc_right_request_alloc(space, name, sync != 0,
1588					     FALSE, notify, previousp);
1589		if (kr != KERN_SUCCESS)
1590			return kr;
1591		break;
1592
1593	    default:
1594		return KERN_INVALID_VALUE;
1595	}
1596
1597	return KERN_SUCCESS;
1598}
1599
1600/*
1601 *	Routine:	mach_port_insert_right [kernel call]
1602 *	Purpose:
1603 *		Inserts a right into a space, as if the space
1604 *		voluntarily received the right in a message,
1605 *		except that the right gets the specified name.
1606 *	Conditions:
1607 *		Nothing locked.
1608 *	Returns:
1609 *		KERN_SUCCESS		Inserted the right.
1610 *		KERN_INVALID_TASK	The space is null.
1611 *		KERN_INVALID_TASK	The space is dead.
1612 *		KERN_INVALID_VALUE	The name isn't a legal name.
1613 *		KERN_NAME_EXISTS	The name already denotes a right.
1614 *		KERN_INVALID_VALUE	Message doesn't carry a port right.
1615 *		KERN_INVALID_CAPABILITY	Port is null or dead.
1616 *		KERN_UREFS_OVERFLOW	Urefs limit would be exceeded.
1617 *		KERN_RIGHT_EXISTS	Space has rights under another name.
1618 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
1619 */
1620
1621kern_return_t
1622mach_port_insert_right(
1623	ipc_space_t			space,
1624	mach_port_name_t		name,
1625	ipc_port_t			poly,
1626	mach_msg_type_name_t		polyPoly)
1627{
1628	if (space == IS_NULL)
1629		return KERN_INVALID_TASK;
1630
1631	if (!MACH_PORT_VALID(name) ||
1632	    !MACH_MSG_TYPE_PORT_ANY_RIGHT(polyPoly))
1633		return KERN_INVALID_VALUE;
1634
1635	if (!IO_VALID((ipc_object_t) poly))
1636		return KERN_INVALID_CAPABILITY;
1637
1638	return ipc_object_copyout_name(space, (ipc_object_t) poly,
1639				       polyPoly, FALSE, name);
1640}
1641
1642/*
1643 *	Routine:	mach_port_extract_right [kernel call]
1644 *	Purpose:
1645 *		Extracts a right from a space, as if the space
1646 *		voluntarily sent the right to the caller.
1647 *	Conditions:
1648 *		Nothing locked.
1649 *	Returns:
1650 *		KERN_SUCCESS		Extracted the right.
1651 *		KERN_INVALID_TASK	The space is null.
1652 *		KERN_INVALID_TASK	The space is dead.
1653 *		KERN_INVALID_VALUE	Requested type isn't a port right.
1654 *		KERN_INVALID_NAME	Name doesn't denote a right.
1655 *		KERN_INVALID_RIGHT	Name doesn't denote appropriate right.
1656 */
1657
1658kern_return_t
1659mach_port_extract_right(
1660	ipc_space_t		space,
1661	mach_port_name_t	name,
1662	mach_msg_type_name_t	msgt_name,
1663	ipc_port_t		*poly,
1664	mach_msg_type_name_t	*polyPoly)
1665{
1666	kern_return_t kr;
1667
1668	if (space == IS_NULL)
1669		return KERN_INVALID_TASK;
1670
1671	if (!MACH_MSG_TYPE_PORT_ANY(msgt_name))
1672		return KERN_INVALID_VALUE;
1673
1674	if (!MACH_PORT_VALID(name)) {
1675		/*
1676		 * really should copy out a dead name, if it is a send or
1677		 * send-once right being copied, but instead return an
1678		 * error for now.
1679		 */
1680		return KERN_INVALID_RIGHT;
1681	}
1682
1683	kr = ipc_object_copyin(space, name, msgt_name, (ipc_object_t *) poly);
1684
1685	if (kr == KERN_SUCCESS)
1686		*polyPoly = ipc_object_copyin_type(msgt_name);
1687	return kr;
1688}
1689
1690/*
1691 *	Routine:	mach_port_get_status_helper [helper]
1692 *	Purpose:
1693 *		Populates a mach_port_status_t structure with
1694 *		port information.
1695 *	Conditions:
1696 *		Port needs to be locked
1697 *	Returns:
1698 *		None.
1699 */
1700void mach_port_get_status_helper(
1701	ipc_port_t		port,
1702	mach_port_status_t	*statusp)
1703{
1704	spl_t s;
1705	statusp->mps_pset = port->ip_pset_count;
1706
1707	s = splsched();
1708	imq_lock(&port->ip_messages);
1709	statusp->mps_seqno = port->ip_messages.imq_seqno;
1710	statusp->mps_qlimit = port->ip_messages.imq_qlimit;
1711	statusp->mps_msgcount = port->ip_messages.imq_msgcount;
1712	imq_unlock(&port->ip_messages);
1713	splx(s);
1714
1715	statusp->mps_mscount = port->ip_mscount;
1716	statusp->mps_sorights = port->ip_sorights;
1717	statusp->mps_srights = port->ip_srights > 0;
1718	statusp->mps_pdrequest = port->ip_pdrequest != IP_NULL;
1719	statusp->mps_nsrequest = port->ip_nsrequest != IP_NULL;
1720	statusp->mps_flags = 0;
1721	if (port->ip_impdonation) {
1722		statusp->mps_flags |= MACH_PORT_STATUS_FLAG_IMP_DONATION;
1723		if (port->ip_tempowner) {
1724			statusp->mps_flags |= MACH_PORT_STATUS_FLAG_TEMPOWNER;
1725			if (IIT_NULL != port->ip_imp_task) {
1726				statusp->mps_flags |= MACH_PORT_STATUS_FLAG_TASKPTR;
1727			}
1728		}
1729	}
1730	if (port->ip_guarded) {
1731		statusp->mps_flags |= MACH_PORT_STATUS_FLAG_GUARDED;
1732		if (port->ip_strict_guard) {
1733			statusp->mps_flags |= MACH_PORT_STATUS_FLAG_STRICT_GUARD;
1734		}
1735	}
1736	return;
1737}
1738
1739
1740
1741kern_return_t
1742mach_port_get_attributes(
1743	ipc_space_t		space,
1744	mach_port_name_t	name,
1745	int			flavor,
1746        mach_port_info_t	info,
1747        mach_msg_type_number_t	*count)
1748{
1749	ipc_port_t port;
1750	kern_return_t kr;
1751
1752	if (space == IS_NULL)
1753		return KERN_INVALID_TASK;
1754
1755        switch (flavor) {
1756        case MACH_PORT_LIMITS_INFO: {
1757                mach_port_limits_t *lp = (mach_port_limits_t *)info;
1758
1759                if (*count < MACH_PORT_LIMITS_INFO_COUNT)
1760                        return KERN_FAILURE;
1761
1762                if (!MACH_PORT_VALID(name)) {
1763			*count = 0;
1764			break;
1765		}
1766
1767                kr = ipc_port_translate_receive(space, name, &port);
1768                if (kr != KERN_SUCCESS)
1769                        return kr;
1770                /* port is locked and active */
1771
1772                lp->mpl_qlimit = port->ip_messages.imq_qlimit;
1773                *count = MACH_PORT_LIMITS_INFO_COUNT;
1774                ip_unlock(port);
1775                break;
1776        }
1777
1778        case MACH_PORT_RECEIVE_STATUS: {
1779		mach_port_status_t *statusp = (mach_port_status_t *)info;
1780
1781		if (*count < MACH_PORT_RECEIVE_STATUS_COUNT)
1782			return KERN_FAILURE;
1783
1784		if (!MACH_PORT_VALID(name))
1785			return KERN_INVALID_RIGHT;
1786
1787		kr = ipc_port_translate_receive(space, name, &port);
1788		if (kr != KERN_SUCCESS)
1789			return kr;
1790		/* port is locked and active */
1791		mach_port_get_status_helper(port, statusp);
1792		*count = MACH_PORT_RECEIVE_STATUS_COUNT;
1793		ip_unlock(port);
1794		break;
1795	}
1796
1797	case MACH_PORT_DNREQUESTS_SIZE: {
1798		ipc_port_request_t	table;
1799
1800                if (*count < MACH_PORT_DNREQUESTS_SIZE_COUNT)
1801                        return KERN_FAILURE;
1802
1803		if (!MACH_PORT_VALID(name)) {
1804			*(int *)info = 0;
1805			break;
1806		}
1807
1808                kr = ipc_port_translate_receive(space, name, &port);
1809                if (kr != KERN_SUCCESS)
1810                        return kr;
1811                /* port is locked and active */
1812
1813		table = port->ip_requests;
1814		if (table == IPR_NULL)
1815			*(int *)info = 0;
1816		else
1817			*(int *)info = table->ipr_size->its_size;
1818                *count = MACH_PORT_DNREQUESTS_SIZE_COUNT;
1819                ip_unlock(port);
1820		break;
1821	}
1822
1823	case MACH_PORT_INFO_EXT: {
1824		mach_port_info_ext_t *mp_info = (mach_port_info_ext_t *)info;
1825		if (*count < MACH_PORT_INFO_EXT_COUNT)
1826			return KERN_FAILURE;
1827
1828		if (!MACH_PORT_VALID(name))
1829			return KERN_INVALID_RIGHT;
1830
1831		kr = ipc_port_translate_receive(space, name, &port);
1832		if (kr != KERN_SUCCESS)
1833			return kr;
1834		/* port is locked and active */
1835		mach_port_get_status_helper(port, &mp_info->mpie_status);
1836		mp_info->mpie_boost_cnt = port->ip_impcount;
1837		*count = MACH_PORT_INFO_EXT_COUNT;
1838		ip_unlock(port);
1839		break;
1840	}
1841
1842        default:
1843		return KERN_INVALID_ARGUMENT;
1844                /*NOTREACHED*/
1845        }
1846
1847	return KERN_SUCCESS;
1848}
1849
1850kern_return_t
1851mach_port_set_attributes(
1852	ipc_space_t		space,
1853	mach_port_name_t	name,
1854	int			flavor,
1855        mach_port_info_t	info,
1856        mach_msg_type_number_t	count)
1857{
1858	ipc_port_t port;
1859	kern_return_t kr;
1860
1861	if (space == IS_NULL)
1862		return KERN_INVALID_TASK;
1863
1864        switch (flavor) {
1865
1866        case MACH_PORT_LIMITS_INFO: {
1867                mach_port_limits_t *mplp = (mach_port_limits_t *)info;
1868
1869                if (count < MACH_PORT_LIMITS_INFO_COUNT)
1870                        return KERN_FAILURE;
1871
1872                if (mplp->mpl_qlimit > MACH_PORT_QLIMIT_MAX)
1873                        return KERN_INVALID_VALUE;
1874
1875		if (!MACH_PORT_VALID(name))
1876			return KERN_INVALID_RIGHT;
1877
1878                kr = ipc_port_translate_receive(space, name, &port);
1879                if (kr != KERN_SUCCESS)
1880                        return kr;
1881                /* port is locked and active */
1882
1883                ipc_mqueue_set_qlimit(&port->ip_messages, mplp->mpl_qlimit);
1884                ip_unlock(port);
1885                break;
1886        }
1887	case MACH_PORT_DNREQUESTS_SIZE: {
1888                if (count < MACH_PORT_DNREQUESTS_SIZE_COUNT)
1889                        return KERN_FAILURE;
1890
1891		if (!MACH_PORT_VALID(name))
1892			return KERN_INVALID_RIGHT;
1893
1894                kr = ipc_port_translate_receive(space, name, &port);
1895                if (kr != KERN_SUCCESS)
1896                        return kr;
1897                /* port is locked and active */
1898
1899		kr = ipc_port_request_grow(port, *(int *)info);
1900		if (kr != KERN_SUCCESS)
1901			return kr;
1902		break;
1903	}
1904	case MACH_PORT_TEMPOWNER:
1905		if (!MACH_PORT_VALID(name))
1906			return KERN_INVALID_RIGHT;
1907
1908		ipc_importance_task_t release_imp_task = IIT_NULL;
1909		natural_t assertcnt = 0;
1910
1911		kr = ipc_port_translate_receive(space, name, &port);
1912		if (kr != KERN_SUCCESS)
1913			return kr;
1914		/* port is locked and active */
1915
1916		/*
1917		 * don't allow temp-owner importance donation if user
1918		 * associated it with a kobject already (timer, host_notify target).
1919		 */
1920		if (is_ipc_kobject(ip_kotype(port))) {
1921			ip_unlock(port);
1922			return KERN_INVALID_ARGUMENT;
1923		}
1924
1925		if (port->ip_tempowner != 0) {
1926			if (IIT_NULL != port->ip_imp_task) {
1927				release_imp_task = port->ip_imp_task;
1928				port->ip_imp_task = IIT_NULL;
1929				assertcnt = port->ip_impcount;
1930			}
1931		} else {
1932			assertcnt = port->ip_impcount;
1933		}
1934
1935		port->ip_impdonation = 1;
1936		port->ip_tempowner = 1;
1937		ip_unlock(port);
1938
1939#if IMPORTANCE_INHERITANCE
1940		/* drop assertions from previous destination task */
1941		if (release_imp_task != IIT_NULL) {
1942			assert(ipc_importance_task_is_any_receiver_type(release_imp_task));
1943			if (assertcnt > 0)
1944				ipc_importance_task_drop_internal_assertion(release_imp_task, assertcnt);
1945			ipc_importance_task_release(release_imp_task);
1946		} else if (assertcnt > 0) {
1947			release_imp_task = current_task()->task_imp_base;
1948			if (release_imp_task != IIT_NULL &&
1949			    ipc_importance_task_is_any_receiver_type(release_imp_task)) {
1950				ipc_importance_task_drop_internal_assertion(release_imp_task, assertcnt);
1951			}
1952		}
1953#else
1954		if (release_imp_task != IIT_NULL)
1955			ipc_importance_task_release(release_imp_task);
1956#endif /* IMPORTANCE_INHERITANCE */
1957
1958		break;
1959
1960#if IMPORTANCE_INHERITANCE
1961	case MACH_PORT_DENAP_RECEIVER:
1962	case MACH_PORT_IMPORTANCE_RECEIVER:
1963		if (!MACH_PORT_VALID(name))
1964			return KERN_INVALID_RIGHT;
1965
1966		kr = ipc_port_translate_receive(space, name, &port);
1967		if (kr != KERN_SUCCESS)
1968			return kr;
1969
1970		/*
1971		 * don't allow importance donation if user associated
1972		 * it with a kobject already (timer, host_notify target).
1973		 */
1974		if (is_ipc_kobject(ip_kotype(port))) {
1975			ip_unlock(port);
1976			return KERN_INVALID_ARGUMENT;
1977		}
1978
1979		/* port is locked and active */
1980		port->ip_impdonation = 1;
1981		ip_unlock(port);
1982
1983		break;
1984#endif /* IMPORTANCE_INHERITANCE */
1985
1986        default:
1987		return KERN_INVALID_ARGUMENT;
1988                /*NOTREACHED*/
1989        }
1990	return KERN_SUCCESS;
1991}
1992
1993/*
1994 *	Routine:	mach_port_insert_member [kernel call]
1995 *	Purpose:
1996 *		Add the receive right, specified by name, to
1997 *		a portset.
1998 *		The port cannot already be a member of the set.
1999 *	Conditions:
2000 *		Nothing locked.
2001 *	Returns:
2002 *		KERN_SUCCESS		Moved the port.
2003 *		KERN_INVALID_TASK	The space is null.
2004 *		KERN_INVALID_TASK	The space is dead.
2005 *		KERN_INVALID_NAME	name didn't denote a right.
2006 *		KERN_INVALID_RIGHT	name didn't denote a receive right.
2007 *		KERN_INVALID_NAME	pset_name didn't denote a right.
2008 *		KERN_INVALID_RIGHT	pset_name didn't denote a portset right.
2009 *		KERN_ALREADY_IN_SET	name was already a member of pset.
2010 */
2011
2012kern_return_t
2013mach_port_insert_member(
2014	ipc_space_t		space,
2015	mach_port_name_t	name,
2016	mach_port_name_t	psname)
2017{
2018	ipc_object_t obj;
2019	ipc_object_t psobj;
2020	kern_return_t kr;
2021	wait_queue_link_t wql;
2022
2023	if (space == IS_NULL)
2024		return KERN_INVALID_TASK;
2025
2026	if (!MACH_PORT_VALID(name) || !MACH_PORT_VALID(psname))
2027		return KERN_INVALID_RIGHT;
2028
2029	wql = wait_queue_link_allocate();
2030
2031	kr = ipc_object_translate_two(space,
2032				      name, MACH_PORT_RIGHT_RECEIVE, &obj,
2033				      psname, MACH_PORT_RIGHT_PORT_SET, &psobj);
2034	if (kr != KERN_SUCCESS)
2035		goto done;
2036
2037	/* obj and psobj are locked (and were locked in that order) */
2038	assert(psobj != IO_NULL);
2039	assert(obj != IO_NULL);
2040
2041	kr = ipc_pset_add((ipc_pset_t)psobj, (ipc_port_t)obj, wql);
2042	io_unlock(psobj);
2043	io_unlock(obj);
2044
2045 done:
2046	if (kr != KERN_SUCCESS)
2047		wait_queue_link_free(wql);
2048
2049	return kr;
2050}
2051
2052/*
2053 *	Routine:	mach_port_extract_member [kernel call]
2054 *	Purpose:
2055 *		Remove a port from one portset that it is a member of.
2056 *	Conditions:
2057 *		Nothing locked.
2058 *	Returns:
2059 *		KERN_SUCCESS		Moved the port.
2060 *		KERN_INVALID_TASK	The space is null.
2061 *		KERN_INVALID_TASK	The space is dead.
2062 *		KERN_INVALID_NAME	Member didn't denote a right.
2063 *		KERN_INVALID_RIGHT	Member didn't denote a receive right.
2064 *		KERN_INVALID_NAME	After didn't denote a right.
2065 *		KERN_INVALID_RIGHT	After didn't denote a port set right.
2066 *		KERN_NOT_IN_SET
2067 *			After is MACH_PORT_NULL and Member isn't in a port set.
2068 */
2069
2070kern_return_t
2071mach_port_extract_member(
2072	ipc_space_t		space,
2073	mach_port_name_t	name,
2074	mach_port_name_t	psname)
2075{
2076	ipc_object_t psobj;
2077	ipc_object_t obj;
2078	kern_return_t kr;
2079	wait_queue_link_t wql = WAIT_QUEUE_LINK_NULL;
2080
2081	if (space == IS_NULL)
2082		return KERN_INVALID_TASK;
2083
2084	if (!MACH_PORT_VALID(name) || !MACH_PORT_VALID(psname))
2085		return KERN_INVALID_RIGHT;
2086
2087	kr = ipc_object_translate_two(space,
2088				      name, MACH_PORT_RIGHT_RECEIVE, &obj,
2089				      psname, MACH_PORT_RIGHT_PORT_SET, &psobj);
2090	if (kr != KERN_SUCCESS)
2091		return kr;
2092
2093	/* obj and psobj are both locked (and were locked in that order) */
2094	assert(psobj != IO_NULL);
2095	assert(obj != IO_NULL);
2096
2097	kr = ipc_pset_remove((ipc_pset_t)psobj, (ipc_port_t)obj, &wql);
2098	io_unlock(psobj);
2099	io_unlock(obj);
2100
2101	if (wql != WAIT_QUEUE_LINK_NULL)
2102		wait_queue_link_free(wql);
2103
2104	return kr;
2105}
2106
2107/*
2108 *	task_set_port_space:
2109 *
2110 *	Set port name space of task to specified size.
2111 */
2112kern_return_t
2113task_set_port_space(
2114 	ipc_space_t	space,
2115 	int		table_entries)
2116{
2117	kern_return_t kr;
2118
2119	is_write_lock(space);
2120
2121	if (!is_active(space)) {
2122		is_write_unlock(space);
2123		return KERN_INVALID_TASK;
2124	}
2125
2126	kr = ipc_entry_grow_table(space, table_entries);
2127	if (kr == KERN_SUCCESS)
2128		is_write_unlock(space);
2129	return kr;
2130}
2131
2132/*
2133 *	Routine:	mach_port_guard_locked [helper routine]
2134 *	Purpose:
2135 *		Sets a new guard for a locked port.
2136 *	Conditions:
2137 *		Port Locked.
2138 *	Returns:
2139 *		KERN_SUCCESS		Port Guarded.
2140 *		KERN_INVALID_ARGUMENT	Port already contains a context/guard.
2141 */
2142static kern_return_t
2143mach_port_guard_locked(
2144	ipc_port_t		port,
2145	uint64_t		guard,
2146	boolean_t		strict)
2147{
2148	if (port->ip_context)
2149		return KERN_INVALID_ARGUMENT;
2150
2151	port->ip_context = guard;
2152	port->ip_guarded = 1;
2153	port->ip_strict_guard = (strict)?1:0;
2154	return KERN_SUCCESS;
2155}
2156
2157/*
2158 *	Routine:	mach_port_unguard_locked [helper routine]
2159 *	Purpose:
2160 *		Removes guard for a locked port.
2161 *	Conditions:
2162 *		Port Locked.
2163 *	Returns:
2164 *		KERN_SUCCESS		Port Unguarded.
2165 *		KERN_INVALID_ARGUMENT	Port is either unguarded already or guard mismatch.
2166 *					This also raises a EXC_GUARD exception.
2167 */
2168static kern_return_t
2169mach_port_unguard_locked(
2170	ipc_port_t		port,
2171	mach_port_name_t	name,
2172	uint64_t		guard)
2173{
2174	/* Port locked and active */
2175	if (!port->ip_guarded) {
2176		/* Port already unguarded; Raise exception */
2177		mach_port_guard_exception(name, guard, 0, kGUARD_EXC_UNGUARDED);
2178		return KERN_INVALID_ARGUMENT;
2179	}
2180
2181	if (port->ip_context != guard) {
2182		/* Incorrect guard; Raise exception */
2183		mach_port_guard_exception(name, guard, port->ip_context, kGUARD_EXC_INCORRECT_GUARD);
2184		return KERN_INVALID_ARGUMENT;
2185	}
2186
2187	port->ip_context = 0;
2188	port->ip_guarded = port->ip_strict_guard = 0;
2189	return KERN_SUCCESS;
2190}
2191
2192
2193/*
2194 *	Routine:	mach_port_guard_exception [helper routine]
2195 *	Purpose:
2196 *		Marks the thread with AST_GUARD for mach port guard violation.
2197 *		Also saves exception info in thread structure.
2198 *	Conditions:
2199 *		None.
2200 *	Returns:
2201 *		KERN_FAILURE		Thread marked with AST_GUARD.
2202 */
2203kern_return_t
2204mach_port_guard_exception(
2205	mach_port_name_t	name,
2206	uint64_t		inguard,
2207	uint64_t		portguard,
2208	unsigned		reason)
2209{
2210	thread_t t = current_thread();
2211	uint64_t code, subcode;
2212
2213	/* Log exception info to syslog */
2214	printf( "Mach Port Guard Exception - "
2215	        "Thread: 0x%x, "
2216		"Port Name: 0x%x, "
2217		"Expected Guard: 0x%x, "
2218		"Received Guard: 0x%x\n",
2219		(unsigned)t,
2220		(unsigned)name,
2221		(unsigned)portguard,
2222		(unsigned)inguard);
2223
2224	/*
2225	 * EXC_GUARD namespace for mach ports
2226	 *
2227	 *
2228	 * Mach Port guards use the exception codes like
2229	 *
2230	 * code:
2231	 * +----------------------------------------------------------------+
2232	 * |[63:61] GUARD_TYPE_MACH_PORT | [60:32] flavor | [31:0] port name|
2233	 * +----------------------------------------------------------------+
2234	 *
2235	 * subcode:
2236	 * +----------------------------------------------------------------+
2237	 * |       [63:0] guard value                                       |
2238	 * +----------------------------------------------------------------+
2239	 */
2240
2241	code =  (((uint64_t)GUARD_TYPE_MACH_PORT) << 61) |
2242		(((uint64_t)reason) << 32) |
2243		((uint64_t)name);
2244	subcode = (uint64_t)(portguard);
2245
2246	t->guard_exc_info.code = code;
2247	t->guard_exc_info.subcode = subcode;
2248
2249	/* Mark thread with AST_GUARD */
2250	thread_guard_violation(t, GUARD_TYPE_MACH_PORT);
2251	return KERN_FAILURE;
2252}
2253
2254
2255/*
2256 *	Routine:	mach_port_guard_ast
2257 *	Purpose:
2258 *		Raises an exception for mach port guard violation.
2259 *	Conditions:
2260 *		None.
2261 *	Returns:
2262 *		None.
2263 */
2264
2265void
2266mach_port_guard_ast(thread_t t)
2267{
2268	mach_exception_data_type_t	code[EXCEPTION_CODE_MAX];
2269
2270	code[0] = t->guard_exc_info.code;
2271	code[1] = t->guard_exc_info.subcode;
2272
2273	/* Raise an EXC_GUARD exception */
2274	exception_triage(EXC_GUARD, code, EXCEPTION_CODE_MAX);
2275
2276	/* Terminate task which caused the exception */
2277	(void) task_terminate_internal(current_task());
2278	return;
2279}
2280
2281/*
2282 *	Routine:	mach_port_construct [kernel call]
2283 *	Purpose:
2284 *		Constructs a mach port with the provided set of options.
2285 *	Conditions:
2286 *		None.
2287 *	Returns:
2288 *		KERN_SUCCESS		The right is allocated.
2289 *		KERN_INVALID_TASK	The space is null.
2290 *		KERN_INVALID_TASK	The space is dead.
2291 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
2292 *		KERN_NO_SPACE		No room in space for another right.
2293 *		KERN_FAILURE		Illegal option values requested.
2294 */
2295
2296kern_return_t
2297mach_port_construct(
2298	ipc_space_t		space,
2299	mach_port_options_t	*options,
2300	uint64_t		context,
2301	mach_port_name_t	*name)
2302{
2303	kern_return_t		kr;
2304	ipc_port_t		port;
2305
2306	if (space == IS_NULL)
2307		return (KERN_INVALID_TASK);
2308
2309	/* Allocate a new port in the IPC space */
2310	kr = ipc_port_alloc(space, name, &port);
2311	if (kr != KERN_SUCCESS)
2312		return kr;
2313
2314	/* Port locked and active */
2315	if (options->flags & MPO_CONTEXT_AS_GUARD) {
2316		kr = mach_port_guard_locked(port, (uint64_t) context, (options->flags & MPO_STRICT));
2317		/* A newly allocated and locked port should always be guarded successfully */
2318		assert(kr == KERN_SUCCESS);
2319	} else {
2320		port->ip_context = context;
2321	}
2322
2323	/* Unlock port */
2324	ip_unlock(port);
2325
2326	/* Set port attributes as requested */
2327
2328	if (options->flags & MPO_QLIMIT) {
2329		kr = mach_port_set_attributes(space, *name, MACH_PORT_LIMITS_INFO,
2330					      (mach_port_info_t)&options->mpl, sizeof(options->mpl)/sizeof(int));
2331		if (kr != KERN_SUCCESS)
2332			goto cleanup;
2333	}
2334
2335	if (options->flags & MPO_TEMPOWNER) {
2336		kr = mach_port_set_attributes(space, *name, MACH_PORT_TEMPOWNER, NULL, 0);
2337		if (kr != KERN_SUCCESS)
2338			goto cleanup;
2339	}
2340
2341	if (options->flags & MPO_IMPORTANCE_RECEIVER) {
2342		kr = mach_port_set_attributes(space, *name, MACH_PORT_IMPORTANCE_RECEIVER, NULL, 0);
2343		if (kr != KERN_SUCCESS)
2344			goto cleanup;
2345	}
2346
2347	if (options->flags & MPO_DENAP_RECEIVER) {
2348		kr = mach_port_set_attributes(space, *name, MACH_PORT_DENAP_RECEIVER, NULL, 0);
2349		if (kr != KERN_SUCCESS)
2350			goto cleanup;
2351	}
2352
2353	if (options->flags & MPO_INSERT_SEND_RIGHT) {
2354		kr = ipc_object_copyin(space, *name, MACH_MSG_TYPE_MAKE_SEND, (ipc_object_t *)&port);
2355		if (kr != KERN_SUCCESS)
2356			goto cleanup;
2357
2358		kr = mach_port_insert_right(space, *name, port, MACH_MSG_TYPE_PORT_SEND);
2359		if (kr != KERN_SUCCESS)
2360			goto cleanup;
2361	}
2362
2363	return KERN_SUCCESS;
2364
2365cleanup:
2366	/* Attempt to destroy port. If its already destroyed by some other thread, we're done */
2367	(void) mach_port_destruct(space, *name, 0, context);
2368	return kr;
2369}
2370
2371/*
2372 *	Routine:	mach_port_destruct [kernel call]
2373 *	Purpose:
2374 *		Destroys a mach port with appropriate guard
2375 *	Conditions:
2376 *		None.
2377 *	Returns:
2378 *		KERN_SUCCESS		The name is destroyed.
2379 *		KERN_INVALID_TASK	The space is null.
2380 *		KERN_INVALID_TASK	The space is dead.
2381 *		KERN_INVALID_NAME	The name doesn't denote a right.
2382 *		KERN_INVALID_RIGHT	The right isn't correct.
2383 *		KERN_INVALID_VALUE	The delta for send right is incorrect.
2384 *		KERN_INVALID_ARGUMENT	Port is either unguarded already or guard mismatch.
2385 *					This also raises a EXC_GUARD exception.
2386 */
2387
2388kern_return_t
2389mach_port_destruct(
2390	ipc_space_t		space,
2391	mach_port_name_t	name,
2392	mach_port_delta_t	srdelta,
2393	uint64_t		guard)
2394{
2395	kern_return_t		kr;
2396	ipc_entry_t		entry;
2397
2398	if (space == IS_NULL)
2399		return KERN_INVALID_TASK;
2400
2401	if (!MACH_PORT_VALID(name))
2402		return KERN_INVALID_NAME;
2403
2404	/* Remove reference for receive right */
2405	kr = ipc_right_lookup_write(space, name, &entry);
2406	if (kr != KERN_SUCCESS)
2407		return kr;
2408	/* space is write-locked and active */
2409	kr = ipc_right_destruct(space, name, entry, srdelta, guard);	/* unlocks */
2410
2411	return kr;
2412}
2413
2414/*
2415 *	Routine:	mach_port_guard [kernel call]
2416 *	Purpose:
2417 *		Guard a mach port with specified guard value.
2418 *		The context field of the port is used as the guard.
2419 *	Conditions:
2420 *		None.
2421 *	Returns:
2422 *		KERN_SUCCESS		The name is destroyed.
2423 *		KERN_INVALID_TASK	The space is null.
2424 *		KERN_INVALID_TASK	The space is dead.
2425 *		KERN_INVALID_NAME	The name doesn't denote a right.
2426 *		KERN_INVALID_RIGHT	The right isn't correct.
2427 *		KERN_INVALID_ARGUMENT	Port already contains a context/guard.
2428 */
2429kern_return_t
2430mach_port_guard(
2431	ipc_space_t		space,
2432	mach_port_name_t	name,
2433	uint64_t		guard,
2434	boolean_t		strict)
2435{
2436	kern_return_t		kr;
2437	ipc_port_t		port;
2438
2439	if (space == IS_NULL)
2440		return KERN_INVALID_TASK;
2441
2442	if (!MACH_PORT_VALID(name))
2443		return KERN_INVALID_NAME;
2444
2445	/* Guard can be applied only to receive rights */
2446	kr = ipc_port_translate_receive(space, name, &port);
2447	if (kr != KERN_SUCCESS)
2448		return kr;
2449
2450	/* Port locked and active */
2451	kr = mach_port_guard_locked(port, guard, strict);
2452	ip_unlock(port);
2453
2454	return kr;
2455
2456}
2457
2458/*
2459 *	Routine:	mach_port_unguard [kernel call]
2460 *	Purpose:
2461 *		Unguard a mach port with specified guard value.
2462 *	Conditions:
2463 *		None.
2464 *	Returns:
2465 *		KERN_SUCCESS		The name is destroyed.
2466 *		KERN_INVALID_TASK	The space is null.
2467 *		KERN_INVALID_TASK	The space is dead.
2468 *		KERN_INVALID_NAME	The name doesn't denote a right.
2469 *		KERN_INVALID_RIGHT	The right isn't correct.
2470 *		KERN_INVALID_ARGUMENT	Port is either unguarded already or guard mismatch.
2471 *					This also raises a EXC_GUARD exception.
2472 */
2473kern_return_t
2474mach_port_unguard(
2475	ipc_space_t		space,
2476	mach_port_name_t	name,
2477	uint64_t		guard)
2478{
2479
2480	kern_return_t		kr;
2481	ipc_port_t		port;
2482
2483	if (space == IS_NULL)
2484		return KERN_INVALID_TASK;
2485
2486	if (!MACH_PORT_VALID(name))
2487		return KERN_INVALID_NAME;
2488
2489	kr = ipc_port_translate_receive(space, name, &port);
2490	if (kr != KERN_SUCCESS)
2491		return kr;
2492
2493	/* Port locked and active */
2494	kr = mach_port_unguard_locked(port, name, guard);
2495	ip_unlock(port);
2496	return kr;
2497}
2498
2499