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_port_t		port,
118	ipc_entry_num_t		maxnames,
119	mach_port_name_t	*names,
120	ipc_entry_num_t		*actualp);
121
122
123/* Zeroed template of qos flags */
124
125static mach_port_qos_t	qos_template;
126
127/*
128 *	Routine:	mach_port_names_helper
129 *	Purpose:
130 *		A helper function for mach_port_names.
131 */
132
133void
134mach_port_names_helper(
135	ipc_port_timestamp_t	timestamp,
136	ipc_entry_t		entry,
137	mach_port_name_t	name,
138	mach_port_name_t	*names,
139	mach_port_type_t	*types,
140	ipc_entry_num_t		*actualp)
141{
142	ipc_entry_bits_t bits;
143	ipc_port_request_index_t request;
144	mach_port_type_t type;
145	ipc_entry_num_t actual;
146
147	bits = entry->ie_bits;
148	request = entry->ie_request;
149	if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
150		ipc_port_t port;
151		boolean_t died;
152
153		port = (ipc_port_t) entry->ie_object;
154		assert(port != IP_NULL);
155
156		/*
157		 *	The timestamp serializes mach_port_names
158		 *	with ipc_port_destroy.  If the port died,
159		 *	but after mach_port_names started, pretend
160		 *	that it isn't dead.
161		 */
162
163		ip_lock(port);
164		died = (!ip_active(port) &&
165			IP_TIMESTAMP_ORDER(port->ip_timestamp, timestamp));
166		ip_unlock(port);
167
168		if (died) {
169			/* pretend this is a dead-name entry */
170
171			bits &= ~(IE_BITS_TYPE_MASK);
172			bits |= MACH_PORT_TYPE_DEAD_NAME;
173			if (request != 0)
174				bits++;
175			request = 0;
176		}
177	}
178
179	type = IE_BITS_TYPE(bits);
180	if (request != 0)
181		type |= MACH_PORT_TYPE_DNREQUEST;
182
183	actual = *actualp;
184	names[actual] = name;
185	types[actual] = type;
186	*actualp = actual+1;
187}
188
189/*
190 *	Routine:	mach_port_names [kernel call]
191 *	Purpose:
192 *		Retrieves a list of the rights present in the space,
193 *		along with type information.  (Same as returned
194 *		by mach_port_type.)  The names are returned in
195 *		no particular order, but they (and the type info)
196 *		are an accurate snapshot of the space.
197 *	Conditions:
198 *		Nothing locked.
199 *	Returns:
200 *		KERN_SUCCESS		Arrays of names and types returned.
201 *		KERN_INVALID_TASK	The space is null.
202 *		KERN_INVALID_TASK	The space is dead.
203 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
204 */
205
206kern_return_t
207mach_port_names(
208	ipc_space_t		space,
209	mach_port_name_t	**namesp,
210	mach_msg_type_number_t	*namesCnt,
211	mach_port_type_t	**typesp,
212	mach_msg_type_number_t	*typesCnt)
213{
214	ipc_tree_entry_t tentry;
215	ipc_entry_t table;
216	ipc_entry_num_t tsize;
217	mach_port_index_t index;
218	ipc_entry_num_t actual;	/* this many names */
219	ipc_port_timestamp_t timestamp;	/* logical time of this operation */
220	mach_port_name_t *names;
221	mach_port_type_t *types;
222	kern_return_t kr;
223
224	vm_size_t size;		/* size of allocated memory */
225	vm_offset_t addr1;	/* allocated memory, for names */
226	vm_offset_t addr2;	/* allocated memory, for types */
227	vm_map_copy_t memory1;	/* copied-in memory, for names */
228	vm_map_copy_t memory2;	/* copied-in memory, for types */
229
230	/* safe simplifying assumption */
231	assert_static(sizeof(mach_port_name_t) == sizeof(mach_port_type_t));
232
233	if (space == IS_NULL)
234		return KERN_INVALID_TASK;
235
236	size = 0;
237
238	for (;;) {
239		ipc_entry_num_t bound;
240		vm_size_t size_needed;
241
242		is_read_lock(space);
243		if (!space->is_active) {
244			is_read_unlock(space);
245			if (size != 0) {
246				kmem_free(ipc_kernel_map, addr1, size);
247				kmem_free(ipc_kernel_map, addr2, size);
248			}
249			return KERN_INVALID_TASK;
250		}
251
252		/* upper bound on number of names in the space */
253
254		bound = space->is_table_size + space->is_tree_total;
255		size_needed = round_page(bound * sizeof(mach_port_name_t));
256
257		if (size_needed <= size)
258			break;
259
260		is_read_unlock(space);
261
262		if (size != 0) {
263			kmem_free(ipc_kernel_map, addr1, size);
264			kmem_free(ipc_kernel_map, addr2, size);
265		}
266		size = size_needed;
267
268		kr = vm_allocate(ipc_kernel_map, &addr1, size, VM_FLAGS_ANYWHERE);
269		if (kr != KERN_SUCCESS)
270			return KERN_RESOURCE_SHORTAGE;
271
272		kr = vm_allocate(ipc_kernel_map, &addr2, size, VM_FLAGS_ANYWHERE);
273		if (kr != KERN_SUCCESS) {
274			kmem_free(ipc_kernel_map, addr1, size);
275			return KERN_RESOURCE_SHORTAGE;
276		}
277
278		/* can't fault while we hold locks */
279
280		kr = vm_map_wire(ipc_kernel_map, vm_map_trunc_page(addr1),
281				 vm_map_round_page(addr1 + size),
282				 VM_PROT_READ|VM_PROT_WRITE, FALSE);
283		if (kr != KERN_SUCCESS) {
284			kmem_free(ipc_kernel_map, addr1, size);
285			kmem_free(ipc_kernel_map, addr2, size);
286			return KERN_RESOURCE_SHORTAGE;
287		}
288
289		kr = vm_map_wire(ipc_kernel_map, vm_map_trunc_page(addr2),
290				 vm_map_round_page(addr2 + size),
291				 VM_PROT_READ|VM_PROT_WRITE, FALSE);
292		if (kr != KERN_SUCCESS) {
293			kmem_free(ipc_kernel_map, addr1, size);
294			kmem_free(ipc_kernel_map, addr2, size);
295			return KERN_RESOURCE_SHORTAGE;
296		}
297
298	}
299	/* space is read-locked and active */
300
301	names = (mach_port_name_t *) addr1;
302	types = (mach_port_type_t *) addr2;
303	actual = 0;
304
305	timestamp = ipc_port_timestamp();
306
307	table = space->is_table;
308	tsize = space->is_table_size;
309
310	for (index = 0; index < tsize; index++) {
311		ipc_entry_t entry = &table[index];
312		ipc_entry_bits_t bits = entry->ie_bits;
313
314		if (IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE) {
315			mach_port_name_t name;
316
317			name = MACH_PORT_MAKE(index, IE_BITS_GEN(bits));
318			mach_port_names_helper(timestamp, entry, name, names,
319					       types, &actual);
320		}
321	}
322
323	for (tentry = ipc_splay_traverse_start(&space->is_tree);
324	    tentry != ITE_NULL;
325	    tentry = ipc_splay_traverse_next(&space->is_tree, FALSE)) {
326		ipc_entry_t entry = &tentry->ite_entry;
327		mach_port_name_t name = tentry->ite_name;
328
329		assert(IE_BITS_TYPE(tentry->ite_bits) != MACH_PORT_TYPE_NONE);
330		mach_port_names_helper(timestamp, entry, name, names,
331				       types, &actual);
332	}
333	ipc_splay_traverse_finish(&space->is_tree);
334	is_read_unlock(space);
335
336	if (actual == 0) {
337		memory1 = VM_MAP_COPY_NULL;
338		memory2 = VM_MAP_COPY_NULL;
339
340		if (size != 0) {
341			kmem_free(ipc_kernel_map, addr1, size);
342			kmem_free(ipc_kernel_map, addr2, size);
343		}
344	} else {
345		vm_size_t size_used;
346		vm_size_t vm_size_used;
347
348		size_used = actual * sizeof(mach_port_name_t);
349		vm_size_used = round_page(size_used);
350
351		/*
352		 *	Make used memory pageable and get it into
353		 *	copied-in form.  Free any unused memory.
354		 */
355
356		kr = vm_map_unwire(ipc_kernel_map, vm_map_trunc_page(addr1),
357				   vm_map_round_page(addr1 + vm_size_used), FALSE);
358		assert(kr == KERN_SUCCESS);
359
360		kr = vm_map_unwire(ipc_kernel_map, vm_map_trunc_page(addr2),
361				   vm_map_round_page(addr2 + vm_size_used), FALSE);
362		assert(kr == KERN_SUCCESS);
363
364		kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr1,
365				   (vm_map_size_t)size_used, TRUE, &memory1);
366		assert(kr == KERN_SUCCESS);
367
368		kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr2,
369				   (vm_map_size_t)size_used, TRUE, &memory2);
370		assert(kr == KERN_SUCCESS);
371
372		if (vm_size_used != size) {
373			kmem_free(ipc_kernel_map,
374				  addr1 + vm_size_used, size - vm_size_used);
375			kmem_free(ipc_kernel_map,
376				  addr2 + vm_size_used, size - vm_size_used);
377		}
378	}
379
380	*namesp = (mach_port_name_t *) memory1;
381	*namesCnt = actual;
382	*typesp = (mach_port_type_t *) memory2;
383	*typesCnt = actual;
384	return KERN_SUCCESS;
385}
386
387/*
388 *	Routine:	mach_port_type [kernel call]
389 *	Purpose:
390 *		Retrieves the type of a right in the space.
391 *		The type is a bitwise combination of one or more
392 *		of the following type bits:
393 *			MACH_PORT_TYPE_SEND
394 *			MACH_PORT_TYPE_RECEIVE
395 *			MACH_PORT_TYPE_SEND_ONCE
396 *			MACH_PORT_TYPE_PORT_SET
397 *			MACH_PORT_TYPE_DEAD_NAME
398 *		In addition, the following pseudo-type bits may be present:
399 *			MACH_PORT_TYPE_DNREQUEST
400 *				A dead-name notification is requested.
401 *	Conditions:
402 *		Nothing locked.
403 *	Returns:
404 *		KERN_SUCCESS		Type is returned.
405 *		KERN_INVALID_TASK	The space is null.
406 *		KERN_INVALID_TASK	The space is dead.
407 *		KERN_INVALID_NAME	The name doesn't denote a right.
408 */
409
410kern_return_t
411mach_port_type(
412	ipc_space_t		space,
413	mach_port_name_t	name,
414	mach_port_type_t	*typep)
415{
416	mach_port_urefs_t urefs;
417	ipc_entry_t entry;
418	kern_return_t kr;
419
420	if (space == IS_NULL)
421		return KERN_INVALID_TASK;
422
423	if (name == MACH_PORT_NULL)
424		return KERN_INVALID_NAME;
425
426	if (name == MACH_PORT_DEAD) {
427		*typep = MACH_PORT_TYPE_DEAD_NAME;
428		return KERN_SUCCESS;
429	}
430
431	kr = ipc_right_lookup_write(space, name, &entry);
432	if (kr != KERN_SUCCESS)
433		return kr;
434	/* space is write-locked and active */
435
436	kr = ipc_right_info(space, name, entry, typep, &urefs);
437	if (kr == KERN_SUCCESS)
438		is_write_unlock(space);
439	/* space is unlocked */
440	return kr;
441}
442
443/*
444 *	Routine:	mach_port_rename [kernel call]
445 *	Purpose:
446 *		Changes the name denoting a right,
447 *		from oname to nname.
448 *	Conditions:
449 *		Nothing locked.
450 *	Returns:
451 *		KERN_SUCCESS		The right is renamed.
452 *		KERN_INVALID_TASK	The space is null.
453 *		KERN_INVALID_TASK	The space is dead.
454 *		KERN_INVALID_NAME	The oname doesn't denote a right.
455 *		KERN_INVALID_VALUE	The nname isn't a legal name.
456 *		KERN_NAME_EXISTS	The nname already denotes a right.
457 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
458 */
459
460kern_return_t
461mach_port_rename(
462	ipc_space_t		space,
463	mach_port_name_t	oname,
464	mach_port_name_t	nname)
465{
466	if (space == IS_NULL)
467		return KERN_INVALID_TASK;
468
469	if (!MACH_PORT_VALID(oname))
470		return KERN_INVALID_NAME;
471
472	if (!MACH_PORT_VALID(nname))
473		return KERN_INVALID_VALUE;
474
475	return ipc_object_rename(space, oname, nname);
476}
477
478/*
479 *	Routine:	mach_port_allocate_name [kernel call]
480 *	Purpose:
481 *		Allocates a right in a space, using a specific name
482 *		for the new right.  Possible rights:
483 *			MACH_PORT_RIGHT_RECEIVE
484 *			MACH_PORT_RIGHT_PORT_SET
485 *			MACH_PORT_RIGHT_DEAD_NAME
486 *
487 *		A new port (allocated with MACH_PORT_RIGHT_RECEIVE)
488 *		has no extant send or send-once rights and no queued
489 *		messages.  Its queue limit is MACH_PORT_QLIMIT_DEFAULT
490 *		and its make-send count is 0.  It is not a member of
491 *		a port set.  It has no registered no-senders or
492 *		port-destroyed notification requests.
493 *
494 *		A new port set has no members.
495 *
496 *		A new dead name has one user reference.
497 *	Conditions:
498 *		Nothing locked.
499 *	Returns:
500 *		KERN_SUCCESS		The right is allocated.
501 *		KERN_INVALID_TASK	The space is null.
502 *		KERN_INVALID_TASK	The space is dead.
503 *		KERN_INVALID_VALUE	The name isn't a legal name.
504 *		KERN_INVALID_VALUE	"right" isn't a legal kind of right.
505 *		KERN_NAME_EXISTS	The name already denotes a right.
506 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
507 *
508 *	Restrictions on name allocation:  NT bits are reserved by kernel,
509 *	must be set on any chosen name.  Can't do this at all in kernel
510 *	loaded server.
511 */
512
513kern_return_t
514mach_port_allocate_name(
515	ipc_space_t		space,
516	mach_port_right_t	right,
517	mach_port_name_t	name)
518{
519	kern_return_t		kr;
520	mach_port_qos_t		qos = qos_template;
521
522	qos.name = TRUE;
523
524	if (!MACH_PORT_VALID(name))
525		return KERN_INVALID_VALUE;
526
527	kr = mach_port_allocate_full (space, right, MACH_PORT_NULL,
528					&qos, &name);
529	return (kr);
530}
531
532/*
533 *	Routine:	mach_port_allocate [kernel call]
534 *	Purpose:
535 *		Allocates a right in a space.  Like mach_port_allocate_name,
536 *		except that the implementation picks a name for the right.
537 *		The name may be any legal name in the space that doesn't
538 *		currently denote a right.
539 *	Conditions:
540 *		Nothing locked.
541 *	Returns:
542 *		KERN_SUCCESS		The right is allocated.
543 *		KERN_INVALID_TASK	The space is null.
544 *		KERN_INVALID_TASK	The space is dead.
545 *		KERN_INVALID_VALUE	"right" isn't a legal kind of right.
546 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
547 *		KERN_NO_SPACE		No room in space for another right.
548 */
549
550kern_return_t
551mach_port_allocate(
552	ipc_space_t		space,
553	mach_port_right_t	right,
554	mach_port_name_t	*namep)
555{
556	kern_return_t		kr;
557	mach_port_qos_t		qos = qos_template;
558
559	kr = mach_port_allocate_full (space, right, MACH_PORT_NULL,
560					&qos, namep);
561	return (kr);
562}
563
564/*
565 *	Routine:	mach_port_allocate_qos [kernel call]
566 *	Purpose:
567 *		Allocates a right, with qos options, in a space.  Like
568 *		mach_port_allocate_name, except that the implementation
569 *		picks a name for the right. The name may be any legal name
570 *		in the space that doesn't 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_INVALID_ARGUMENT   The qos request was invalid.
579 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
580 *		KERN_NO_SPACE		No room in space for another right.
581 */
582
583kern_return_t
584mach_port_allocate_qos(
585	ipc_space_t		space,
586	mach_port_right_t	right,
587	mach_port_qos_t		*qosp,
588	mach_port_name_t	*namep)
589{
590	kern_return_t		kr;
591
592	if (qosp->name)
593		return KERN_INVALID_ARGUMENT;
594	kr = mach_port_allocate_full (space, right, MACH_PORT_NULL,
595					qosp, namep);
596	return (kr);
597}
598
599/*
600 *	Routine:	mach_port_allocate_full [kernel call]
601 *	Purpose:
602 *		Allocates a right in a space.  Supports all of the
603 *		special cases, such as specifying a subsystem,
604 *		a specific name, a real-time port, etc.
605 *		The name may be any legal name in the space that doesn't
606 *		currently denote a right.
607 *	Conditions:
608 *		Nothing locked.
609 *	Returns:
610 *		KERN_SUCCESS		The right is allocated.
611 *		KERN_INVALID_TASK	The space is null.
612 *		KERN_INVALID_TASK	The space is dead.
613 *		KERN_INVALID_VALUE	"right" isn't a legal kind of right.
614 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
615 *		KERN_NO_SPACE		No room in space for another right.
616 */
617
618kern_return_t
619mach_port_allocate_full(
620	ipc_space_t		space,
621	mach_port_right_t	right,
622	mach_port_t		proto,
623	mach_port_qos_t		*qosp,
624	mach_port_name_t	*namep)
625{
626	ipc_kmsg_t		kmsg = IKM_NULL;
627	kern_return_t		kr;
628
629	if (space == IS_NULL)
630		return (KERN_INVALID_TASK);
631
632	if (proto != MACH_PORT_NULL)
633		return (KERN_INVALID_VALUE);
634
635	if (qosp->name) {
636		if (!MACH_PORT_VALID (*namep))
637			return (KERN_INVALID_VALUE);
638		if (is_fast_space (space))
639			return (KERN_FAILURE);
640	}
641
642	if (qosp->prealloc) {
643		if (qosp->len > MACH_MSG_SIZE_MAX - MAX_TRAILER_SIZE) {
644			return KERN_RESOURCE_SHORTAGE;
645		} else {
646			mach_msg_size_t size = qosp->len + MAX_TRAILER_SIZE;
647			if (right != MACH_PORT_RIGHT_RECEIVE)
648				return (KERN_INVALID_VALUE);
649			kmsg = (ipc_kmsg_t)ipc_kmsg_alloc(size);
650			if (kmsg == IKM_NULL)
651				return (KERN_RESOURCE_SHORTAGE);
652		}
653	}
654
655	switch (right) {
656	    case MACH_PORT_RIGHT_RECEIVE:
657	    {
658		ipc_port_t	port;
659
660		if (qosp->name)
661			kr = ipc_port_alloc_name(space, *namep, &port);
662		else
663			kr = ipc_port_alloc(space, namep, &port);
664		if (kr == KERN_SUCCESS) {
665			if (kmsg != IKM_NULL)
666				ipc_kmsg_set_prealloc(kmsg, port);
667
668			ip_unlock(port);
669
670		} else if (kmsg != IKM_NULL)
671			ipc_kmsg_free(kmsg);
672		break;
673	    }
674
675	    case MACH_PORT_RIGHT_PORT_SET:
676	    {
677		ipc_pset_t	pset;
678
679		if (qosp->name)
680			kr = ipc_pset_alloc_name(space, *namep, &pset);
681		else
682			kr = ipc_pset_alloc(space, namep, &pset);
683		if (kr == KERN_SUCCESS)
684			ips_unlock(pset);
685		break;
686	    }
687
688	    case MACH_PORT_RIGHT_DEAD_NAME:
689		kr = ipc_object_alloc_dead(space, namep);
690		break;
691
692	    default:
693		kr = KERN_INVALID_VALUE;
694		break;
695	}
696
697	return (kr);
698}
699
700/*
701 *	Routine:	mach_port_destroy [kernel call]
702 *	Purpose:
703 *		Cleans up and destroys all rights denoted by a name
704 *		in a space.  The destruction of a receive right
705 *		destroys the port, unless a port-destroyed request
706 *		has been made for it; the destruction of a port-set right
707 *		destroys the port set.
708 *	Conditions:
709 *		Nothing locked.
710 *	Returns:
711 *		KERN_SUCCESS		The name is destroyed.
712 *		KERN_INVALID_TASK	The space is null.
713 *		KERN_INVALID_TASK	The space is dead.
714 *		KERN_INVALID_NAME	The name doesn't denote a right.
715 */
716
717kern_return_t
718mach_port_destroy(
719	ipc_space_t		space,
720	mach_port_name_t	name)
721{
722	ipc_entry_t entry;
723	kern_return_t kr;
724
725	if (space == IS_NULL)
726		return KERN_INVALID_TASK;
727
728	if (!MACH_PORT_VALID(name))
729		return KERN_SUCCESS;
730
731	kr = ipc_right_lookup_write(space, name, &entry);
732	if (kr != KERN_SUCCESS)
733		return kr;
734	/* space is write-locked and active */
735
736	kr = ipc_right_destroy(space, name, entry);
737	is_write_unlock(space);
738	return kr;
739}
740
741/*
742 *	Routine:	mach_port_deallocate [kernel call]
743 *	Purpose:
744 *		Deallocates a user reference from a send right,
745 *		send-once right, or a dead-name right.  May
746 *		deallocate the right, if this is the last uref,
747 *		and destroy the name, if it doesn't denote
748 *		other rights.
749 *	Conditions:
750 *		Nothing locked.
751 *	Returns:
752 *		KERN_SUCCESS		The uref is deallocated.
753 *		KERN_INVALID_TASK	The space is null.
754 *		KERN_INVALID_TASK	The space is dead.
755 *		KERN_INVALID_NAME	The name doesn't denote a right.
756 *		KERN_INVALID_RIGHT	The right isn't correct.
757 */
758
759kern_return_t
760mach_port_deallocate(
761	ipc_space_t		space,
762	mach_port_name_t	name)
763{
764	ipc_entry_t entry;
765	kern_return_t kr;
766
767	if (space == IS_NULL)
768		return KERN_INVALID_TASK;
769
770	if (!MACH_PORT_VALID(name))
771		return KERN_SUCCESS;
772
773	kr = ipc_right_lookup_write(space, name, &entry);
774	if (kr != KERN_SUCCESS)
775		return kr;
776	/* space is write-locked */
777
778	kr = ipc_right_dealloc(space, name, entry); /* unlocks space */
779	return kr;
780}
781
782/*
783 *	Routine:	mach_port_get_refs [kernel call]
784 *	Purpose:
785 *		Retrieves the number of user references held by a right.
786 *		Receive rights, port-set rights, and send-once rights
787 *		always have one user reference.  Returns zero if the
788 *		name denotes a right, but not the queried right.
789 *	Conditions:
790 *		Nothing locked.
791 *	Returns:
792 *		KERN_SUCCESS		Number of urefs returned.
793 *		KERN_INVALID_TASK	The space is null.
794 *		KERN_INVALID_TASK	The space is dead.
795 *		KERN_INVALID_VALUE	"right" isn't a legal value.
796 *		KERN_INVALID_NAME	The name doesn't denote a right.
797 */
798
799kern_return_t
800mach_port_get_refs(
801	ipc_space_t		space,
802	mach_port_name_t	name,
803	mach_port_right_t	right,
804	mach_port_urefs_t	*urefsp)
805{
806	mach_port_type_t type;
807	mach_port_urefs_t urefs;
808	ipc_entry_t entry;
809	kern_return_t kr;
810
811	if (space == IS_NULL)
812		return KERN_INVALID_TASK;
813
814	if (right >= MACH_PORT_RIGHT_NUMBER)
815		return KERN_INVALID_VALUE;
816
817	if (!MACH_PORT_VALID(name)) {
818	  	if (right == MACH_PORT_RIGHT_SEND ||
819		    right == MACH_PORT_RIGHT_SEND_ONCE) {
820			*urefsp = 1;
821			return KERN_SUCCESS;
822		}
823		return KERN_INVALID_NAME;
824	}
825
826	kr = ipc_right_lookup_write(space, name, &entry);
827	if (kr != KERN_SUCCESS)
828		return kr;
829	/* space is write-locked and active */
830
831	kr = ipc_right_info(space, name, entry, &type, &urefs);	/* unlocks */
832	if (kr != KERN_SUCCESS)
833		return kr;	/* space is unlocked */
834	is_write_unlock(space);
835
836	if (type & MACH_PORT_TYPE(right))
837		switch (right) {
838		    case MACH_PORT_RIGHT_SEND_ONCE:
839			assert(urefs == 1);
840			/* fall-through */
841
842		    case MACH_PORT_RIGHT_PORT_SET:
843		    case MACH_PORT_RIGHT_RECEIVE:
844			*urefsp = 1;
845			break;
846
847		    case MACH_PORT_RIGHT_DEAD_NAME:
848		    case MACH_PORT_RIGHT_SEND:
849			assert(urefs > 0);
850			*urefsp = urefs;
851			break;
852
853		    default:
854			panic("mach_port_get_refs: strange rights");
855		}
856	else
857		*urefsp = 0;
858
859	return kr;
860}
861
862/*
863 *	Routine:	mach_port_mod_refs
864 *	Purpose:
865 *		Modifies the number of user references held by a right.
866 *		The resulting number of user references must be non-negative.
867 *		If it is zero, the right is deallocated.  If the name
868 *		doesn't denote other rights, it is destroyed.
869 *	Conditions:
870 *		Nothing locked.
871 *	Returns:
872 *		KERN_SUCCESS		Modified number of urefs.
873 *		KERN_INVALID_TASK	The space is null.
874 *		KERN_INVALID_TASK	The space is dead.
875 *		KERN_INVALID_VALUE	"right" isn't a legal value.
876 *		KERN_INVALID_NAME	The name doesn't denote a right.
877 *		KERN_INVALID_RIGHT	Name doesn't denote specified right.
878 *		KERN_INVALID_VALUE	Impossible modification to urefs.
879 *		KERN_UREFS_OVERFLOW	Urefs would overflow.
880 */
881
882kern_return_t
883mach_port_mod_refs(
884	ipc_space_t		space,
885	mach_port_name_t	name,
886	mach_port_right_t	right,
887	mach_port_delta_t	delta)
888{
889	ipc_entry_t entry;
890	kern_return_t kr;
891
892	if (space == IS_NULL)
893		return KERN_INVALID_TASK;
894
895	if (right >= MACH_PORT_RIGHT_NUMBER)
896		return KERN_INVALID_VALUE;
897
898	if (!MACH_PORT_VALID(name)) {
899		if (right == MACH_PORT_RIGHT_SEND ||
900		    right == MACH_PORT_RIGHT_SEND_ONCE)
901			return KERN_SUCCESS;
902		return KERN_INVALID_NAME;
903	}
904
905	kr = ipc_right_lookup_write(space, name, &entry);
906	if (kr != KERN_SUCCESS)
907		return kr;
908	/* space is write-locked and active */
909
910	kr = ipc_right_delta(space, name, entry, right, delta);	/* unlocks */
911	return kr;
912}
913
914
915/*
916 *	Routine:	mach_port_set_mscount [kernel call]
917 *	Purpose:
918 *		Changes a receive right's make-send count.
919 *	Conditions:
920 *		Nothing locked.
921 *	Returns:
922 *		KERN_SUCCESS		Set make-send count.
923 *		KERN_INVALID_TASK	The space is null.
924 *		KERN_INVALID_TASK	The space is dead.
925 *		KERN_INVALID_NAME	The name doesn't denote a right.
926 *		KERN_INVALID_RIGHT	Name doesn't denote receive rights.
927 */
928
929kern_return_t
930mach_port_set_mscount(
931	ipc_space_t		space,
932	mach_port_name_t	name,
933	mach_port_mscount_t	mscount)
934{
935	ipc_port_t port;
936	kern_return_t kr;
937
938	if (space == IS_NULL)
939		return KERN_INVALID_TASK;
940
941	if (!MACH_PORT_VALID(name))
942		return KERN_INVALID_RIGHT;
943
944	kr = ipc_port_translate_receive(space, name, &port);
945	if (kr != KERN_SUCCESS)
946		return kr;
947	/* port is locked and active */
948
949	ipc_port_set_mscount(port, mscount);
950
951	ip_unlock(port);
952	return KERN_SUCCESS;
953}
954
955/*
956 *	Routine:	mach_port_set_seqno [kernel call]
957 *	Purpose:
958 *		Changes a receive right's sequence number.
959 *	Conditions:
960 *		Nothing locked.
961 *	Returns:
962 *		KERN_SUCCESS		Set sequence number.
963 *		KERN_INVALID_TASK	The space is null.
964 *		KERN_INVALID_TASK	The space is dead.
965 *		KERN_INVALID_NAME	The name doesn't denote a right.
966 *		KERN_INVALID_RIGHT	Name doesn't denote receive rights.
967 */
968
969kern_return_t
970mach_port_set_seqno(
971	ipc_space_t		space,
972	mach_port_name_t	name,
973	mach_port_seqno_t	seqno)
974{
975	ipc_port_t port;
976	kern_return_t kr;
977
978	if (space == IS_NULL)
979		return KERN_INVALID_TASK;
980
981	if (!MACH_PORT_VALID(name))
982		return KERN_INVALID_RIGHT;
983
984	kr = ipc_port_translate_receive(space, name, &port);
985	if (kr != KERN_SUCCESS)
986		return kr;
987	/* port is locked and active */
988
989	ipc_mqueue_set_seqno(&port->ip_messages, seqno);
990
991	ip_unlock(port);
992	return KERN_SUCCESS;
993}
994
995/*
996 *	Routine:	mach_port_gst_helper
997 *	Purpose:
998 *		A helper function for mach_port_get_set_status.
999 */
1000
1001void
1002mach_port_gst_helper(
1003	ipc_pset_t		pset,
1004	ipc_port_t		port,
1005	ipc_entry_num_t		maxnames,
1006	mach_port_name_t	*names,
1007	ipc_entry_num_t		*actualp)
1008{
1009	mach_port_name_t name;
1010
1011	assert(port != IP_NULL);
1012
1013	ip_lock(port);
1014	assert(ip_active(port));
1015
1016	name = port->ip_receiver_name;
1017	assert(name != MACH_PORT_NULL);
1018
1019	ip_unlock(port);
1020
1021	if (ipc_pset_member(pset, port)) {
1022		ipc_entry_num_t actual = *actualp;
1023
1024		if (actual < maxnames)
1025			names[actual] = name;
1026
1027		*actualp = actual+1;
1028	}
1029}
1030
1031/*
1032 *	Routine:	mach_port_get_set_status [kernel call]
1033 *	Purpose:
1034 *		Retrieves a list of members in a port set.
1035 *		Returns the space's name for each receive right member.
1036 *	Conditions:
1037 *		Nothing locked.
1038 *	Returns:
1039 *		KERN_SUCCESS		Retrieved list of members.
1040 *		KERN_INVALID_TASK	The space is null.
1041 *		KERN_INVALID_TASK	The space is dead.
1042 *		KERN_INVALID_NAME	The name doesn't denote a right.
1043 *		KERN_INVALID_RIGHT	Name doesn't denote a port set.
1044 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
1045 */
1046
1047kern_return_t
1048mach_port_get_set_status(
1049	ipc_space_t			space,
1050	mach_port_name_t		name,
1051	mach_port_name_t		**members,
1052	mach_msg_type_number_t		*membersCnt)
1053{
1054	ipc_entry_num_t actual;		/* this many members */
1055	ipc_entry_num_t maxnames;	/* space for this many members */
1056	kern_return_t kr;
1057
1058	vm_size_t size;		/* size of allocated memory */
1059	vm_offset_t addr;	/* allocated memory */
1060	vm_map_copy_t memory;	/* copied-in memory */
1061
1062	if (space == IS_NULL)
1063		return KERN_INVALID_TASK;
1064
1065	if (!MACH_PORT_VALID(name))
1066		return KERN_INVALID_RIGHT;
1067
1068	size = PAGE_SIZE;	/* initial guess */
1069
1070	for (;;) {
1071		ipc_tree_entry_t tentry;
1072		ipc_entry_t entry, table;
1073		ipc_entry_num_t tsize;
1074		mach_port_index_t index;
1075		mach_port_name_t *names;
1076		ipc_pset_t pset;
1077
1078		kr = vm_allocate(ipc_kernel_map, &addr, size, VM_FLAGS_ANYWHERE);
1079		if (kr != KERN_SUCCESS)
1080			return KERN_RESOURCE_SHORTAGE;
1081
1082		/* can't fault while we hold locks */
1083
1084		kr = vm_map_wire(ipc_kernel_map, addr, addr + size,
1085				     VM_PROT_READ|VM_PROT_WRITE, FALSE);
1086		assert(kr == KERN_SUCCESS);
1087
1088		kr = ipc_right_lookup_read(space, name, &entry);
1089		if (kr != KERN_SUCCESS) {
1090			kmem_free(ipc_kernel_map, addr, size);
1091			return kr;
1092		}
1093		/* space is read-locked and active */
1094
1095		if (IE_BITS_TYPE(entry->ie_bits) != MACH_PORT_TYPE_PORT_SET) {
1096			is_read_unlock(space);
1097			kmem_free(ipc_kernel_map, addr, size);
1098			return KERN_INVALID_RIGHT;
1099		}
1100
1101		pset = (ipc_pset_t) entry->ie_object;
1102		assert(pset != IPS_NULL);
1103		/* the port set must be active */
1104
1105		names = (mach_port_name_t *) addr;
1106		maxnames = size / sizeof(mach_port_name_t);
1107		actual = 0;
1108
1109		table = space->is_table;
1110		tsize = space->is_table_size;
1111
1112		for (index = 0; index < tsize; index++) {
1113			ipc_entry_t ientry = &table[index];
1114
1115			if (ientry->ie_bits & MACH_PORT_TYPE_RECEIVE) {
1116				ipc_port_t port =
1117					(ipc_port_t) ientry->ie_object;
1118
1119				mach_port_gst_helper(pset, port,
1120						     maxnames, names, &actual);
1121			}
1122		}
1123
1124		for (tentry = ipc_splay_traverse_start(&space->is_tree);
1125		    tentry != ITE_NULL;
1126		    tentry = ipc_splay_traverse_next(&space->is_tree,FALSE)) {
1127			ipc_entry_bits_t bits = tentry->ite_bits;
1128
1129			assert(IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE);
1130
1131			if (bits & MACH_PORT_TYPE_RECEIVE) {
1132			    ipc_port_t port = (ipc_port_t) tentry->ite_object;
1133
1134			    mach_port_gst_helper(pset, port, maxnames,
1135						 names, &actual);
1136			}
1137		}
1138		ipc_splay_traverse_finish(&space->is_tree);
1139		is_read_unlock(space);
1140
1141		if (actual <= maxnames)
1142			break;
1143
1144		/* didn't have enough memory; allocate more */
1145
1146		kmem_free(ipc_kernel_map, addr, size);
1147		size = round_page(actual * sizeof(mach_port_name_t)) + PAGE_SIZE;
1148	}
1149
1150	if (actual == 0) {
1151		memory = VM_MAP_COPY_NULL;
1152
1153		kmem_free(ipc_kernel_map, addr, size);
1154	} else {
1155		vm_size_t size_used;
1156		vm_size_t vm_size_used;
1157
1158		size_used = actual * sizeof(mach_port_name_t);
1159		vm_size_used = round_page(size_used);
1160
1161		/*
1162		 *	Make used memory pageable and get it into
1163		 *	copied-in form.  Free any unused memory.
1164		 */
1165
1166		kr = vm_map_unwire(ipc_kernel_map, vm_map_trunc_page(addr),
1167				   vm_map_round_page(addr + vm_size_used), FALSE);
1168		assert(kr == KERN_SUCCESS);
1169
1170		kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr,
1171				   (vm_map_size_t)size_used, TRUE, &memory);
1172		assert(kr == KERN_SUCCESS);
1173
1174		if (vm_size_used != size)
1175			kmem_free(ipc_kernel_map,
1176				  addr + vm_size_used, size - vm_size_used);
1177	}
1178
1179	*members = (mach_port_name_t *) memory;
1180	*membersCnt = actual;
1181	return KERN_SUCCESS;
1182}
1183
1184/*
1185 *	Routine:	mach_port_move_member [kernel call]
1186 *	Purpose:
1187 *		If after is MACH_PORT_NULL, removes member
1188 *		from the port set it is in.  Otherwise, adds
1189 *		member to after, removing it from any set
1190 *		it might already be in.
1191 *	Conditions:
1192 *		Nothing locked.
1193 *	Returns:
1194 *		KERN_SUCCESS		Moved the port.
1195 *		KERN_INVALID_TASK	The space is null.
1196 *		KERN_INVALID_TASK	The space is dead.
1197 *		KERN_INVALID_NAME	Member didn't denote a right.
1198 *		KERN_INVALID_RIGHT	Member didn't denote a receive right.
1199 *		KERN_INVALID_NAME	After didn't denote a right.
1200 *		KERN_INVALID_RIGHT	After didn't denote a port set right.
1201 *		KERN_NOT_IN_SET
1202 *			After is MACH_PORT_NULL and Member isn't in a port set.
1203 */
1204
1205kern_return_t
1206mach_port_move_member(
1207	ipc_space_t		space,
1208	mach_port_name_t	member,
1209	mach_port_name_t	after)
1210{
1211	ipc_entry_t entry;
1212	ipc_port_t port;
1213	ipc_pset_t nset;
1214	kern_return_t kr;
1215
1216	if (space == IS_NULL)
1217		return KERN_INVALID_TASK;
1218
1219	if (!MACH_PORT_VALID(member))
1220		return KERN_INVALID_RIGHT;
1221
1222	if (after == MACH_PORT_DEAD)
1223		return KERN_INVALID_RIGHT;
1224
1225	kr = ipc_right_lookup_read(space, member, &entry);
1226	if (kr != KERN_SUCCESS)
1227		return kr;
1228	/* space is read-locked and active */
1229
1230	if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0) {
1231		is_read_unlock(space);
1232		return KERN_INVALID_RIGHT;
1233	}
1234
1235	port = (ipc_port_t) entry->ie_object;
1236	assert(port != IP_NULL);
1237
1238	if (after == MACH_PORT_NULL)
1239		nset = IPS_NULL;
1240	else {
1241		entry = ipc_entry_lookup(space, after);
1242		if (entry == IE_NULL) {
1243			is_read_unlock(space);
1244			return KERN_INVALID_NAME;
1245		}
1246
1247		if ((entry->ie_bits & MACH_PORT_TYPE_PORT_SET) == 0) {
1248			is_read_unlock(space);
1249			return KERN_INVALID_RIGHT;
1250		}
1251
1252		nset = (ipc_pset_t) entry->ie_object;
1253		assert(nset != IPS_NULL);
1254	}
1255	ip_lock(port);
1256	ipc_pset_remove_from_all(port);
1257
1258	if (nset != IPS_NULL) {
1259		ips_lock(nset);
1260		kr = ipc_pset_add(nset, port);
1261		ips_unlock(nset);
1262	}
1263	ip_unlock(port);
1264	is_read_unlock(space);
1265	return kr;
1266}
1267
1268/*
1269 *	Routine:	mach_port_request_notification [kernel call]
1270 *	Purpose:
1271 *		Requests a notification.  The caller supplies
1272 *		a send-once right for the notification to use,
1273 *		and the call returns the previously registered
1274 *		send-once right, if any.  Possible types:
1275 *
1276 *		MACH_NOTIFY_PORT_DESTROYED
1277 *			Requests a port-destroyed notification
1278 *			for a receive right.  Sync should be zero.
1279 *		MACH_NOTIFY_NO_SENDERS
1280 *			Requests a no-senders notification for a
1281 *			receive right.  If there are currently no
1282 *			senders, sync is less than or equal to the
1283 *			current make-send count, and a send-once right
1284 *			is supplied, then an immediate no-senders
1285 *			notification is generated.
1286 *		MACH_NOTIFY_DEAD_NAME
1287 *			Requests a dead-name notification for a send
1288 *			or receive right.  If the name is already a
1289 *			dead name, sync is non-zero, and a send-once
1290 *			right is supplied, then an immediate dead-name
1291 *			notification is generated.
1292 *	Conditions:
1293 *		Nothing locked.
1294 *	Returns:
1295 *		KERN_SUCCESS		Requested a notification.
1296 *		KERN_INVALID_TASK	The space is null.
1297 *		KERN_INVALID_TASK	The space is dead.
1298 *		KERN_INVALID_VALUE	Bad id value.
1299 *		KERN_INVALID_NAME	Name doesn't denote a right.
1300 *		KERN_INVALID_RIGHT	Name doesn't denote appropriate right.
1301 *		KERN_INVALID_CAPABILITY	The notify port is dead.
1302 *	MACH_NOTIFY_PORT_DESTROYED:
1303 *		KERN_INVALID_VALUE	Sync isn't zero.
1304 *	MACH_NOTIFY_DEAD_NAME:
1305 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
1306 *		KERN_INVALID_ARGUMENT	Name denotes dead name, but
1307 *			sync is zero or notify is IP_NULL.
1308 *		KERN_UREFS_OVERFLOW	Name denotes dead name, but
1309 *			generating immediate notif. would overflow urefs.
1310 */
1311
1312kern_return_t
1313mach_port_request_notification(
1314	ipc_space_t		space,
1315	mach_port_name_t	name,
1316	mach_msg_id_t		id,
1317	mach_port_mscount_t	sync,
1318	ipc_port_t		notify,
1319	ipc_port_t		*previousp)
1320{
1321	kern_return_t kr;
1322
1323	if (space == IS_NULL)
1324		return KERN_INVALID_TASK;
1325
1326	if (notify == IP_DEAD)
1327		return KERN_INVALID_CAPABILITY;
1328
1329#if	NOTYET
1330	/*
1331	 *	Requesting notifications on RPC ports is an error.
1332	 */
1333	{
1334		ipc_port_t port;
1335		ipc_entry_t entry;
1336
1337		kr = ipc_right_lookup_write(space, name, &entry);
1338		if (kr != KERN_SUCCESS)
1339			return kr;
1340
1341		port = (ipc_port_t) entry->ie_object;
1342
1343		if (port->ip_subsystem != NULL) {
1344			is_write_unlock(space);
1345			panic("mach_port_request_notification: on RPC port!!");
1346			return KERN_INVALID_CAPABILITY;
1347		}
1348		is_write_unlock(space);
1349	}
1350#endif 	/* NOTYET */
1351
1352
1353	switch (id) {
1354	    case MACH_NOTIFY_PORT_DESTROYED: {
1355		ipc_port_t port, previous;
1356
1357		if (sync != 0)
1358			return KERN_INVALID_VALUE;
1359
1360		if (!MACH_PORT_VALID(name))
1361			return KERN_INVALID_RIGHT;
1362
1363		kr = ipc_port_translate_receive(space, name, &port);
1364		if (kr != KERN_SUCCESS)
1365			return kr;
1366		/* port is locked and active */
1367
1368		ipc_port_pdrequest(port, notify, &previous);
1369		/* port is unlocked */
1370
1371		*previousp = previous;
1372		break;
1373	    }
1374
1375	    case MACH_NOTIFY_NO_SENDERS: {
1376		ipc_port_t port;
1377
1378		if (!MACH_PORT_VALID(name))
1379			return KERN_INVALID_RIGHT;
1380
1381		kr = ipc_port_translate_receive(space, name, &port);
1382		if (kr != KERN_SUCCESS)
1383			return kr;
1384		/* port is locked and active */
1385
1386		ipc_port_nsrequest(port, sync, notify, previousp);
1387		/* port is unlocked */
1388		break;
1389	    }
1390
1391	    case MACH_NOTIFY_DEAD_NAME:
1392
1393	    	if (!MACH_PORT_VALID(name)) {
1394			/*
1395			 * Already dead.
1396			 * Should do immediate delivery check -
1397			 * will do that in the near future.
1398			 */
1399	      		return KERN_INVALID_ARGUMENT;
1400		}
1401
1402		kr = ipc_right_dnrequest(space, name, sync != 0,
1403					 notify, previousp);
1404		if (kr != KERN_SUCCESS)
1405			return kr;
1406		break;
1407
1408	    default:
1409		return KERN_INVALID_VALUE;
1410	}
1411
1412	return KERN_SUCCESS;
1413}
1414
1415/*
1416 *	Routine:	mach_port_insert_right [kernel call]
1417 *	Purpose:
1418 *		Inserts a right into a space, as if the space
1419 *		voluntarily received the right in a message,
1420 *		except that the right gets the specified name.
1421 *	Conditions:
1422 *		Nothing locked.
1423 *	Returns:
1424 *		KERN_SUCCESS		Inserted the right.
1425 *		KERN_INVALID_TASK	The space is null.
1426 *		KERN_INVALID_TASK	The space is dead.
1427 *		KERN_INVALID_VALUE	The name isn't a legal name.
1428 *		KERN_NAME_EXISTS	The name already denotes a right.
1429 *		KERN_INVALID_VALUE	Message doesn't carry a port right.
1430 *		KERN_INVALID_CAPABILITY	Port is null or dead.
1431 *		KERN_UREFS_OVERFLOW	Urefs limit would be exceeded.
1432 *		KERN_RIGHT_EXISTS	Space has rights under another name.
1433 *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
1434 */
1435
1436kern_return_t
1437mach_port_insert_right(
1438	ipc_space_t			space,
1439	mach_port_name_t		name,
1440	ipc_port_t			poly,
1441	mach_msg_type_name_t		polyPoly)
1442{
1443	if (space == IS_NULL)
1444		return KERN_INVALID_TASK;
1445
1446	if (!MACH_PORT_VALID(name) ||
1447	    !MACH_MSG_TYPE_PORT_ANY_RIGHT(polyPoly))
1448		return KERN_INVALID_VALUE;
1449
1450	if (!IO_VALID((ipc_object_t) poly))
1451		return KERN_INVALID_CAPABILITY;
1452
1453	return ipc_object_copyout_name(space, (ipc_object_t) poly,
1454				       polyPoly, FALSE, name);
1455}
1456
1457/*
1458 *	Routine:	mach_port_extract_right [kernel call]
1459 *	Purpose:
1460 *		Extracts a right from a space, as if the space
1461 *		voluntarily sent the right to the caller.
1462 *	Conditions:
1463 *		Nothing locked.
1464 *	Returns:
1465 *		KERN_SUCCESS		Extracted the right.
1466 *		KERN_INVALID_TASK	The space is null.
1467 *		KERN_INVALID_TASK	The space is dead.
1468 *		KERN_INVALID_VALUE	Requested type isn't a port right.
1469 *		KERN_INVALID_NAME	Name doesn't denote a right.
1470 *		KERN_INVALID_RIGHT	Name doesn't denote appropriate right.
1471 */
1472
1473kern_return_t
1474mach_port_extract_right(
1475	ipc_space_t		space,
1476	mach_port_name_t	name,
1477	mach_msg_type_name_t	msgt_name,
1478	ipc_port_t		*poly,
1479	mach_msg_type_name_t	*polyPoly)
1480{
1481	kern_return_t kr;
1482
1483	if (space == IS_NULL)
1484		return KERN_INVALID_TASK;
1485
1486	if (!MACH_MSG_TYPE_PORT_ANY(msgt_name))
1487		return KERN_INVALID_VALUE;
1488
1489	if (!MACH_PORT_VALID(name)) {
1490		/*
1491		 * really should copy out a dead name, if it is a send or
1492		 * send-once right being copied, but instead return an
1493		 * error for now.
1494		 */
1495		return KERN_INVALID_RIGHT;
1496	}
1497
1498	kr = ipc_object_copyin(space, name, msgt_name, (ipc_object_t *) poly);
1499
1500	if (kr == KERN_SUCCESS)
1501		*polyPoly = ipc_object_copyin_type(msgt_name);
1502	return kr;
1503}
1504
1505
1506kern_return_t
1507mach_port_get_attributes(
1508	ipc_space_t		space,
1509	mach_port_name_t	name,
1510	int			flavor,
1511        mach_port_info_t	info,
1512        mach_msg_type_number_t	*count)
1513{
1514	ipc_port_t port;
1515	kern_return_t kr;
1516
1517	if (space == IS_NULL)
1518		return KERN_INVALID_TASK;
1519
1520        switch (flavor) {
1521        case MACH_PORT_LIMITS_INFO: {
1522                mach_port_limits_t *lp = (mach_port_limits_t *)info;
1523
1524                if (*count < MACH_PORT_LIMITS_INFO_COUNT)
1525                        return KERN_FAILURE;
1526
1527                if (!MACH_PORT_VALID(name)) {
1528			*count = 0;
1529			break;
1530		}
1531
1532                kr = ipc_port_translate_receive(space, name, &port);
1533                if (kr != KERN_SUCCESS)
1534                        return kr;
1535                /* port is locked and active */
1536
1537                lp->mpl_qlimit = port->ip_messages.imq_qlimit;
1538                *count = MACH_PORT_LIMITS_INFO_COUNT;
1539                ip_unlock(port);
1540                break;
1541        }
1542
1543        case MACH_PORT_RECEIVE_STATUS: {
1544                mach_port_status_t *statusp = (mach_port_status_t *)info;
1545		spl_t s;
1546
1547                if (*count < MACH_PORT_RECEIVE_STATUS_COUNT)
1548                        return KERN_FAILURE;
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		statusp->mps_pset = port->ip_pset_count;
1559
1560		s = splsched();
1561		imq_lock(&port->ip_messages);
1562		statusp->mps_seqno = port->ip_messages.imq_seqno;
1563                statusp->mps_qlimit = port->ip_messages.imq_qlimit;
1564                statusp->mps_msgcount = port->ip_messages.imq_msgcount;
1565		imq_unlock(&port->ip_messages);
1566		splx(s);
1567
1568                statusp->mps_mscount = port->ip_mscount;
1569                statusp->mps_sorights = port->ip_sorights;
1570                statusp->mps_srights = port->ip_srights > 0;
1571                statusp->mps_pdrequest = port->ip_pdrequest != IP_NULL;
1572                statusp->mps_nsrequest = port->ip_nsrequest != IP_NULL;
1573		statusp->mps_flags = 0;
1574
1575                *count = MACH_PORT_RECEIVE_STATUS_COUNT;
1576                ip_unlock(port);
1577                break;
1578        }
1579
1580	case MACH_PORT_DNREQUESTS_SIZE: {
1581		ipc_port_request_t	table;
1582
1583                if (*count < MACH_PORT_DNREQUESTS_SIZE_COUNT)
1584                        return KERN_FAILURE;
1585
1586		if (!MACH_PORT_VALID(name)) {
1587			*(int *)info = 0;
1588			break;
1589		}
1590
1591                kr = ipc_port_translate_receive(space, name, &port);
1592                if (kr != KERN_SUCCESS)
1593                        return kr;
1594                /* port is locked and active */
1595
1596		table = port->ip_dnrequests;
1597		if (table == IPR_NULL)
1598			*(int *)info = 0;
1599		else
1600			*(int *)info = table->ipr_size->its_size;
1601                *count = MACH_PORT_DNREQUESTS_SIZE_COUNT;
1602                ip_unlock(port);
1603		break;
1604	}
1605
1606        default:
1607		return KERN_INVALID_ARGUMENT;
1608                /*NOTREACHED*/
1609        }
1610
1611	return KERN_SUCCESS;
1612}
1613
1614kern_return_t
1615mach_port_set_attributes(
1616	ipc_space_t		space,
1617	mach_port_name_t	name,
1618	int			flavor,
1619        mach_port_info_t	info,
1620        mach_msg_type_number_t	count)
1621{
1622	ipc_port_t port;
1623	kern_return_t kr;
1624
1625	if (space == IS_NULL)
1626		return KERN_INVALID_TASK;
1627
1628        switch (flavor) {
1629
1630        case MACH_PORT_LIMITS_INFO: {
1631                mach_port_limits_t *mplp = (mach_port_limits_t *)info;
1632
1633                if (count < MACH_PORT_LIMITS_INFO_COUNT)
1634                        return KERN_FAILURE;
1635
1636                if (mplp->mpl_qlimit > MACH_PORT_QLIMIT_MAX)
1637                        return KERN_INVALID_VALUE;
1638
1639		if (!MACH_PORT_VALID(name))
1640			return KERN_INVALID_RIGHT;
1641
1642                kr = ipc_port_translate_receive(space, name, &port);
1643                if (kr != KERN_SUCCESS)
1644                        return kr;
1645                /* port is locked and active */
1646
1647                ipc_mqueue_set_qlimit(&port->ip_messages, mplp->mpl_qlimit);
1648                ip_unlock(port);
1649                break;
1650        }
1651	case MACH_PORT_DNREQUESTS_SIZE: {
1652                if (count < MACH_PORT_DNREQUESTS_SIZE_COUNT)
1653                        return KERN_FAILURE;
1654
1655		if (!MACH_PORT_VALID(name))
1656			return KERN_INVALID_RIGHT;
1657
1658                kr = ipc_port_translate_receive(space, name, &port);
1659                if (kr != KERN_SUCCESS)
1660                        return kr;
1661                /* port is locked and active */
1662
1663		kr = ipc_port_dngrow(port, *(int *)info);
1664		if (kr != KERN_SUCCESS)
1665			return kr;
1666		break;
1667	}
1668        default:
1669		return KERN_INVALID_ARGUMENT;
1670                /*NOTREACHED*/
1671        }
1672	return KERN_SUCCESS;
1673}
1674
1675/*
1676 *	Routine:	mach_port_insert_member [kernel call]
1677 *	Purpose:
1678 *		Add the receive right, specified by name, to
1679 *		a portset.
1680 *		The port cannot already be a member of the set.
1681 *	Conditions:
1682 *		Nothing locked.
1683 *	Returns:
1684 *		KERN_SUCCESS		Moved the port.
1685 *		KERN_INVALID_TASK	The space is null.
1686 *		KERN_INVALID_TASK	The space is dead.
1687 *		KERN_INVALID_NAME	name didn't denote a right.
1688 *		KERN_INVALID_RIGHT	name didn't denote a receive right.
1689 *		KERN_INVALID_NAME	pset_name didn't denote a right.
1690 *		KERN_INVALID_RIGHT	pset_name didn't denote a portset right.
1691 *		KERN_ALREADY_IN_SET	name was already a member of pset.
1692 */
1693
1694kern_return_t
1695mach_port_insert_member(
1696	ipc_space_t		space,
1697	mach_port_name_t	name,
1698	mach_port_name_t	psname)
1699{
1700	ipc_object_t obj;
1701	ipc_object_t psobj;
1702	kern_return_t kr;
1703
1704	if (space == IS_NULL)
1705		return KERN_INVALID_TASK;
1706
1707	if (!MACH_PORT_VALID(name) || !MACH_PORT_VALID(psname))
1708		return KERN_INVALID_RIGHT;
1709
1710	kr = ipc_object_translate_two(space,
1711				      name, MACH_PORT_RIGHT_RECEIVE, &obj,
1712				      psname, MACH_PORT_RIGHT_PORT_SET, &psobj);
1713	if (kr != KERN_SUCCESS)
1714		return kr;
1715
1716	/* obj and psobj are locked (and were locked in that order) */
1717	assert(psobj != IO_NULL);
1718	assert(obj != IO_NULL);
1719
1720	kr = ipc_pset_add((ipc_pset_t)psobj, (ipc_port_t)obj);
1721	io_unlock(psobj);
1722	io_unlock(obj);
1723	return kr;
1724}
1725
1726/*
1727 *	Routine:	mach_port_extract_member [kernel call]
1728 *	Purpose:
1729 *		Remove a port from one portset that it is a member of.
1730 *	Conditions:
1731 *		Nothing locked.
1732 *	Returns:
1733 *		KERN_SUCCESS		Moved the port.
1734 *		KERN_INVALID_TASK	The space is null.
1735 *		KERN_INVALID_TASK	The space is dead.
1736 *		KERN_INVALID_NAME	Member didn't denote a right.
1737 *		KERN_INVALID_RIGHT	Member didn't denote a receive right.
1738 *		KERN_INVALID_NAME	After didn't denote a right.
1739 *		KERN_INVALID_RIGHT	After didn't denote a port set right.
1740 *		KERN_NOT_IN_SET
1741 *			After is MACH_PORT_NULL and Member isn't in a port set.
1742 */
1743
1744kern_return_t
1745mach_port_extract_member(
1746	ipc_space_t		space,
1747	mach_port_name_t	name,
1748	mach_port_name_t	psname)
1749{
1750	ipc_object_t psobj;
1751	ipc_object_t obj;
1752	kern_return_t kr;
1753
1754	if (space == IS_NULL)
1755		return KERN_INVALID_TASK;
1756
1757	if (!MACH_PORT_VALID(name) || !MACH_PORT_VALID(psname))
1758		return KERN_INVALID_RIGHT;
1759
1760	kr = ipc_object_translate_two(space,
1761				      name, MACH_PORT_RIGHT_RECEIVE, &obj,
1762				      psname, MACH_PORT_RIGHT_PORT_SET, &psobj);
1763	if (kr != KERN_SUCCESS)
1764		return kr;
1765
1766	/* obj and psobj are both locked (and were locked in that order) */
1767	assert(psobj != IO_NULL);
1768	assert(obj != IO_NULL);
1769
1770	kr = ipc_pset_remove((ipc_pset_t)psobj, (ipc_port_t)obj);
1771	io_unlock(psobj);
1772	io_unlock(obj);
1773	return kr;
1774}
1775
1776/*
1777 *	task_set_port_space:
1778 *
1779 *	Set port name space of task to specified size.
1780 */
1781kern_return_t
1782task_set_port_space(
1783 	ipc_space_t	space,
1784 	int		table_entries)
1785{
1786	kern_return_t kr;
1787
1788	is_write_lock(space);
1789	kr = ipc_entry_grow_table(space, table_entries);
1790	if (kr == KERN_SUCCESS)
1791		is_write_unlock(space);
1792	return kr;
1793}
1794
1795/*
1796 * Get a (new) label handle representing the given port's port label.
1797 */
1798#if CONFIG_MACF_MACH
1799kern_return_t
1800mach_get_label(
1801	ipc_space_t		space,
1802	mach_port_name_t	name,
1803	mach_port_name_t	*outlabel)
1804{
1805	ipc_entry_t entry;
1806	ipc_port_t port;
1807	struct label outl;
1808	kern_return_t kr;
1809	int dead;
1810
1811	if (!MACH_PORT_VALID(name))
1812		return KERN_INVALID_NAME;
1813
1814	/* Lookup the port name in the task's space. */
1815	kr = ipc_right_lookup_write(space, name, &entry);
1816	if (kr != KERN_SUCCESS)
1817		return kr;
1818
1819	port = (ipc_port_t) entry->ie_object;
1820	dead = ipc_right_check(space, port, name, entry);
1821	if (dead) {
1822		is_write_unlock(space);
1823		return KERN_INVALID_RIGHT;
1824	}
1825	/* port is now locked */
1826
1827	is_write_unlock(space);
1828	/* Make sure we are not dealing with a label handle. */
1829	if (ip_kotype(port) == IKOT_LABELH) {
1830		/* already is a label handle! */
1831		ip_unlock(port);
1832		return KERN_INVALID_ARGUMENT;
1833	}
1834
1835	/* Copy the port label and stash it in a new label handle. */
1836	mac_port_label_init(&outl);
1837	mac_port_label_copy(&port->ip_label, &outl);
1838	kr = labelh_new_user(space, &outl, outlabel);
1839	ip_unlock(port);
1840
1841	return KERN_SUCCESS;
1842}
1843#else
1844kern_return_t
1845mach_get_label(
1846	 __unused ipc_space_t		space,
1847	 __unused mach_port_name_t	name,
1848	 __unused mach_port_name_t	*outlabel)
1849{
1850	return KERN_INVALID_ARGUMENT;
1851}
1852#endif
1853
1854/*
1855 * also works on label handles
1856 */
1857#if CONFIG_MACF_MACH
1858kern_return_t
1859mach_get_label_text(
1860	ipc_space_t		space,
1861	mach_port_name_t	name,
1862	labelstr_t		policies,
1863	labelstr_t		outlabel)
1864{
1865	ipc_entry_t entry;
1866	kern_return_t kr;
1867	struct label *l;
1868	int dead;
1869
1870	if (space == IS_NULL || space->is_task == NULL)
1871		return KERN_INVALID_TASK;
1872
1873	if (!MACH_PORT_VALID(name))
1874		return KERN_INVALID_NAME;
1875
1876	kr = ipc_right_lookup_write(space, name, &entry);
1877	if (kr != KERN_SUCCESS)
1878		return kr;
1879
1880	dead = ipc_right_check(space, (ipc_port_t) entry->ie_object, name,
1881	    entry);
1882	if (dead) {
1883		is_write_unlock(space);
1884		return KERN_INVALID_RIGHT;
1885	}
1886	/* object (port) is now locked */
1887
1888	is_write_unlock (space);
1889	l = io_getlabel(entry->ie_object);
1890
1891	mac_port_label_externalize(l, policies, outlabel, 512, 0);
1892
1893	io_unlocklabel(entry->ie_object);
1894	io_unlock(entry->ie_object);
1895	return KERN_SUCCESS;
1896}
1897#else
1898kern_return_t
1899mach_get_label_text(
1900	__unused ipc_space_t		space,
1901	__unused mach_port_name_t	name,
1902	__unused labelstr_t		policies,
1903	__unused labelstr_t		outlabel)
1904{
1905	return KERN_INVALID_ARGUMENT;
1906}
1907#endif
1908
1909
1910#if CONFIG_MACF_MACH
1911kern_return_t
1912mach_set_port_label(
1913	ipc_space_t		space,
1914	mach_port_name_t	name,
1915	labelstr_t		labelstr)
1916{
1917	ipc_entry_t entry;
1918	kern_return_t kr;
1919	struct label inl;
1920	ipc_port_t port;
1921	int rc;
1922
1923	if (space == IS_NULL || space->is_task == NULL)
1924		return KERN_INVALID_TASK;
1925
1926	if (!MACH_PORT_VALID(name))
1927		return KERN_INVALID_NAME;
1928
1929	mac_port_label_init(&inl);
1930	rc = mac_port_label_internalize(&inl, labelstr);
1931	if (rc)
1932		return KERN_INVALID_ARGUMENT;
1933
1934	kr = ipc_right_lookup_write(space, name, &entry);
1935	if (kr != KERN_SUCCESS)
1936		return kr;
1937
1938	if (io_otype(entMACry->ie_object) != IOT_PORT) {
1939		is_write_unlock(space);
1940		return KERN_INVALID_RIGHT;
1941	}
1942
1943	port = (ipc_port_t) entry->ie_object;
1944	ip_lock(port);
1945
1946	tasklabel_lock(space->is_task);
1947	rc = mac_port_check_label_update(&space->is_task->maclabel,
1948				    &port->ip_label, &inl);
1949	tasklabel_unlock(space->is_task);
1950	if (rc)
1951		kr = KERN_NO_ACCESS;
1952	else
1953		mac_port_label_copy(&inl, &port->ip_label);
1954
1955	ip_unlock(port);
1956	is_write_unlock(space);
1957	return kr;
1958}
1959#else
1960kern_return_t
1961mach_set_port_label(
1962	ipc_space_t		space __unused,
1963	mach_port_name_t	name __unused,
1964	labelstr_t		labelstr __unused)
1965{
1966	return KERN_INVALID_ARGUMENT;
1967}
1968#endif
1969