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