xref: /xnu-8020.121.3/osfmk/ipc/mach_port.c (revision fdd8201d7b966f0c3ea610489d29bd841d358941)
1 /*
2  * Copyright (c) 2000-2020 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  [email protected]
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 
75 #include <mach/port.h>
76 #include <mach/kern_return.h>
77 #include <mach/notify.h>
78 #include <mach/mach_param.h>
79 #include <mach/vm_param.h>
80 #include <mach/vm_prot.h>
81 #include <mach/vm_map.h>
82 #include <kern/task.h>
83 #include <kern/thread.h>
84 #include <kern/exc_guard.h>
85 #include <mach/mach_port_server.h>
86 #include <vm/vm_map.h>
87 #include <vm/vm_kern.h>
88 #include <ipc/port.h>
89 #include <ipc/ipc_entry.h>
90 #include <ipc/ipc_space.h>
91 #include <ipc/ipc_object.h>
92 #include <ipc/ipc_notify.h>
93 #include <ipc/ipc_port.h>
94 #include <ipc/ipc_pset.h>
95 #include <ipc/ipc_right.h>
96 #include <ipc/ipc_kmsg.h>
97 #include <ipc/ipc_service_port.h>
98 #include <kern/misc_protos.h>
99 #include <security/mac_mach_internal.h>
100 #include <kern/work_interval.h>
101 #include <kern/policy_internal.h>
102 #include <kern/coalition.h>
103 #include <ipc/ipc_service_port.h>
104 #include <kern/mach_filter.h>
105 
106 #if IMPORTANCE_INHERITANCE
107 #include <ipc/ipc_importance.h>
108 #endif
109 
110 extern void qsort(void *a, size_t n, size_t es, int (*cmp)(const void *, const void *));
111 extern int proc_isinitproc(struct proc *p);
112 
113 static int
mach_port_name_cmp(const void * _n1,const void * _n2)114 mach_port_name_cmp(const void *_n1, const void *_n2)
115 {
116 	mach_port_name_t n1 = *(const mach_port_name_t *)_n1;
117 	mach_port_name_t n2 = *(const mach_port_name_t *)_n2;
118 
119 	if (n1 == n2) {
120 		return 0;
121 	}
122 
123 	return n1 < n2 ? -1 : 1;
124 }
125 
126 kern_return_t mach_port_get_attributes(ipc_space_t space, mach_port_name_t name,
127     int flavor, mach_port_info_t info, mach_msg_type_number_t  *count);
128 kern_return_t mach_port_get_context(ipc_space_t space, mach_port_name_t name,
129     mach_vm_address_t *context);
130 kern_return_t mach_port_get_set_status(ipc_space_t space, mach_port_name_t name,
131     mach_port_name_t **members, mach_msg_type_number_t *membersCnt);
132 extern int exit_with_guard_exception(void *p, mach_exception_data_type_t code,
133     mach_exception_data_type_t subcode);
134 
135 /*
136  *	Routine:	mach_port_names_helper
137  *	Purpose:
138  *		A helper function for mach_port_names.
139  *
140  *	Conditions:
141  *		Space containing entry is [at least] read-locked.
142  */
143 static void
mach_port_names_helper(ipc_port_timestamp_t timestamp,ipc_entry_t entry,mach_port_name_t name,mach_port_name_t * names,mach_port_type_t * types,ipc_entry_num_t * actualp)144 mach_port_names_helper(
145 	ipc_port_timestamp_t    timestamp,
146 	ipc_entry_t             entry,
147 	mach_port_name_t        name,
148 	mach_port_name_t        *names,
149 	mach_port_type_t        *types,
150 	ipc_entry_num_t         *actualp)
151 {
152 	ipc_entry_bits_t bits;
153 	ipc_port_request_index_t request;
154 	mach_port_type_t type = 0;
155 	ipc_entry_num_t actual;
156 	ipc_port_t port;
157 
158 	bits = entry->ie_bits;
159 	request = entry->ie_request;
160 	port = ip_object_to_port(entry->ie_object);
161 
162 	if (bits & MACH_PORT_TYPE_RECEIVE) {
163 		assert(IP_VALID(port));
164 
165 		if (request != IE_REQ_NONE) {
166 			ip_mq_lock(port);
167 			require_ip_active(port);
168 			type |= ipc_port_request_type(port, name, request);
169 			ip_mq_unlock(port);
170 		}
171 	} else if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
172 		mach_port_type_t reqtype;
173 
174 		assert(IP_VALID(port));
175 		ip_mq_lock(port);
176 
177 		reqtype = (request != IE_REQ_NONE) ?
178 		    ipc_port_request_type(port, name, request) : 0;
179 
180 		/*
181 		 * If the port is alive, or was alive when the mach_port_names
182 		 * started, then return that fact.  Otherwise, pretend we found
183 		 * a dead name entry.
184 		 */
185 		if (ip_active(port) || IP_TIMESTAMP_ORDER(timestamp, ip_get_death_time(port))) {
186 			type |= reqtype;
187 		} else {
188 			bits &= ~(IE_BITS_TYPE_MASK);
189 			bits |= MACH_PORT_TYPE_DEAD_NAME;
190 			/* account for additional reference for dead-name notification */
191 			if (reqtype != 0) {
192 				bits++;
193 			}
194 		}
195 		ip_mq_unlock(port);
196 	}
197 
198 	type |= IE_BITS_TYPE(bits);
199 
200 	actual = *actualp;
201 	names[actual] = name;
202 	types[actual] = type;
203 	*actualp = actual + 1;
204 }
205 
206 /*
207  *	Routine:	mach_port_names [kernel call]
208  *	Purpose:
209  *		Retrieves a list of the rights present in the space,
210  *		along with type information.  (Same as returned
211  *		by mach_port_type.)  The names are returned in
212  *		no particular order, but they (and the type info)
213  *		are an accurate snapshot of the space.
214  *	Conditions:
215  *		Nothing locked.
216  *	Returns:
217  *		KERN_SUCCESS		Arrays of names and types returned.
218  *		KERN_INVALID_TASK	The space is null.
219  *		KERN_INVALID_TASK	The space is dead.
220  *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
221  */
222 
223 kern_return_t
mach_port_names(ipc_space_t space,mach_port_name_t ** namesp,mach_msg_type_number_t * namesCnt,mach_port_type_t ** typesp,mach_msg_type_number_t * typesCnt)224 mach_port_names(
225 	ipc_space_t             space,
226 	mach_port_name_t        **namesp,
227 	mach_msg_type_number_t  *namesCnt,
228 	mach_port_type_t        **typesp,
229 	mach_msg_type_number_t  *typesCnt)
230 {
231 	ipc_entry_t table;
232 	ipc_entry_num_t tsize;
233 	mach_port_index_t index;
234 	ipc_entry_num_t actual; /* this many names */
235 	ipc_port_timestamp_t timestamp; /* logical time of this operation */
236 	mach_port_name_t *names;
237 	mach_port_type_t *types;
238 	kern_return_t kr;
239 
240 	vm_size_t size;         /* size of allocated memory */
241 	vm_offset_t addr1 = 0;      /* allocated memory, for names */
242 	vm_offset_t addr2 = 0;      /* allocated memory, for types */
243 	vm_map_copy_t memory1;  /* copied-in memory, for names */
244 	vm_map_copy_t memory2;  /* copied-in memory, for types */
245 
246 	/* safe simplifying assumption */
247 	static_assert(sizeof(mach_port_name_t) == sizeof(mach_port_type_t));
248 
249 	if (space == IS_NULL) {
250 		return KERN_INVALID_TASK;
251 	}
252 
253 	size = 0;
254 
255 	for (;;) {
256 		ipc_entry_num_t bound;
257 		vm_size_t size_needed;
258 
259 		is_read_lock(space);
260 		if (!is_active(space)) {
261 			is_read_unlock(space);
262 			if (size != 0) {
263 				kmem_free(ipc_kernel_map, addr1, size);
264 				kmem_free(ipc_kernel_map, addr2, size);
265 			}
266 			return KERN_INVALID_TASK;
267 		}
268 
269 		/* upper bound on number of names in the space */
270 		bound = is_active_table(space)->ie_size;
271 		size_needed = vm_map_round_page(
272 			(bound * sizeof(mach_port_name_t)),
273 			VM_MAP_PAGE_MASK(ipc_kernel_map));
274 
275 		if (size_needed <= size) {
276 			break;
277 		}
278 
279 		is_read_unlock(space);
280 
281 		if (size != 0) {
282 			kmem_free(ipc_kernel_map, addr1, size);
283 			kmem_free(ipc_kernel_map, addr2, size);
284 		}
285 		size = size_needed;
286 
287 		kr = kmem_alloc(ipc_kernel_map, &addr1, size,
288 		    KMA_DATA, VM_KERN_MEMORY_IPC);
289 		if (kr != KERN_SUCCESS) {
290 			return KERN_RESOURCE_SHORTAGE;
291 		}
292 
293 		kr = kmem_alloc(ipc_kernel_map, &addr2, size,
294 		    KMA_DATA, VM_KERN_MEMORY_IPC);
295 		if (kr != KERN_SUCCESS) {
296 			kmem_free(ipc_kernel_map, addr1, size);
297 			return KERN_RESOURCE_SHORTAGE;
298 		}
299 	}
300 	/* space is read-locked and active */
301 
302 	names = (mach_port_name_t *) addr1;
303 	types = (mach_port_type_t *) addr2;
304 	actual = 0;
305 
306 	timestamp = ipc_port_timestamp();
307 
308 	table = is_active_table(space);
309 	tsize = table->ie_size;
310 
311 	for (index = 1; index < tsize; index++) {
312 		ipc_entry_t entry = &table[index];
313 		ipc_entry_bits_t bits = entry->ie_bits;
314 
315 		if (IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE) {
316 			mach_port_name_t name;
317 
318 			name = MACH_PORT_MAKE(index, IE_BITS_GEN(bits));
319 			mach_port_names_helper(timestamp, entry, name, names,
320 			    types, &actual);
321 		}
322 	}
323 
324 	is_read_unlock(space);
325 
326 	if (actual == 0) {
327 		memory1 = VM_MAP_COPY_NULL;
328 		memory2 = VM_MAP_COPY_NULL;
329 
330 		if (size != 0) {
331 			kmem_free(ipc_kernel_map, addr1, size);
332 			kmem_free(ipc_kernel_map, addr2, size);
333 		}
334 	} else {
335 		vm_size_t size_used;
336 		vm_size_t vm_size_used;
337 
338 		size_used = actual * sizeof(mach_port_name_t);
339 		vm_size_used =
340 		    vm_map_round_page(size_used,
341 		    VM_MAP_PAGE_MASK(ipc_kernel_map));
342 
343 		/*
344 		 *	Make used memory pageable and get it into
345 		 *	copied-in form.  Free any unused memory.
346 		 */
347 
348 		if (size_used < vm_size_used) {
349 			bzero((char *)addr1 + size_used, vm_size_used - size_used);
350 			bzero((char *)addr2 + size_used, vm_size_used - size_used);
351 		}
352 
353 		kr = vm_map_unwire(ipc_kernel_map, addr1, addr1 + vm_size_used, FALSE);
354 		assert(kr == KERN_SUCCESS);
355 
356 		kr = vm_map_unwire(ipc_kernel_map, addr2, addr2 + vm_size_used, FALSE);
357 		assert(kr == KERN_SUCCESS);
358 
359 		kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr1,
360 		    (vm_map_size_t)size_used, TRUE, &memory1);
361 		assert(kr == KERN_SUCCESS);
362 
363 		kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr2,
364 		    (vm_map_size_t)size_used, TRUE, &memory2);
365 		assert(kr == KERN_SUCCESS);
366 
367 		if (vm_size_used != size) {
368 			kmem_free(ipc_kernel_map,
369 			    addr1 + vm_size_used, size - vm_size_used);
370 			kmem_free(ipc_kernel_map,
371 			    addr2 + vm_size_used, size - vm_size_used);
372 		}
373 	}
374 
375 	*namesp = (mach_port_name_t *) memory1;
376 	*namesCnt = actual;
377 	*typesp = (mach_port_type_t *) memory2;
378 	*typesCnt = actual;
379 	return KERN_SUCCESS;
380 }
381 
382 /*
383  *	Routine:	mach_port_type [kernel call]
384  *	Purpose:
385  *		Retrieves the type of a right in the space.
386  *		The type is a bitwise combination of one or more
387  *		of the following type bits:
388  *			MACH_PORT_TYPE_SEND
389  *			MACH_PORT_TYPE_RECEIVE
390  *			MACH_PORT_TYPE_SEND_ONCE
391  *			MACH_PORT_TYPE_PORT_SET
392  *			MACH_PORT_TYPE_DEAD_NAME
393  *		In addition, the following pseudo-type bits may be present:
394  *			MACH_PORT_TYPE_DNREQUEST
395  *				A dead-name notification is requested.
396  *	Conditions:
397  *		Nothing locked.
398  *	Returns:
399  *		KERN_SUCCESS		Type is returned.
400  *		KERN_INVALID_TASK	The space is null.
401  *		KERN_INVALID_TASK	The space is dead.
402  *		KERN_INVALID_NAME	The name doesn't denote a right.
403  */
404 
405 kern_return_t
mach_port_type(ipc_space_t space,mach_port_name_t name,mach_port_type_t * typep)406 mach_port_type(
407 	ipc_space_t             space,
408 	mach_port_name_t        name,
409 	mach_port_type_t        *typep)
410 {
411 	mach_port_urefs_t urefs;
412 	ipc_entry_t entry;
413 	kern_return_t kr;
414 
415 	if (space == IS_NULL) {
416 		return KERN_INVALID_TASK;
417 	}
418 
419 	if (name == MACH_PORT_NULL) {
420 		return KERN_INVALID_NAME;
421 	}
422 
423 	if (name == MACH_PORT_DEAD) {
424 		*typep = MACH_PORT_TYPE_DEAD_NAME;
425 		return KERN_SUCCESS;
426 	}
427 
428 	kr = ipc_right_lookup_write(space, name, &entry);
429 	if (kr != KERN_SUCCESS) {
430 		return kr;
431 	}
432 
433 	/* space is write-locked and active */
434 	kr = ipc_right_info(space, name, entry, typep, &urefs);
435 	/* space is unlocked */
436 
437 #if 1
438 	/* JMM - workaround rdar://problem/9121297 (CF being too picky on these bits). */
439 	*typep &= ~(MACH_PORT_TYPE_SPREQUEST | MACH_PORT_TYPE_SPREQUEST_DELAYED);
440 #endif
441 
442 	return kr;
443 }
444 
445 /*
446  *	Routine:	mach_port_rename [kernel call]
447  *	Purpose:
448  *		Changes the name denoting a right,
449  *		from oname to nname.
450  *	Conditions:
451  *		Nothing locked.
452  *	Returns:
453  *		KERN_SUCCESS		The right is renamed.
454  *		KERN_INVALID_TASK	The space is null.
455  *		KERN_INVALID_TASK	The space is dead.
456  *		KERN_INVALID_NAME	The oname doesn't denote a right.
457  *		KERN_INVALID_VALUE	The nname isn't a legal name.
458  *		KERN_NAME_EXISTS	The nname already denotes a right.
459  *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
460  *
461  *      This interface is obsolete and always returns
462  *      KERN_NOT_SUPPORTED.
463  */
464 
465 kern_return_t
mach_port_rename(__unused ipc_space_t space,__unused mach_port_name_t oname,__unused mach_port_name_t nname)466 mach_port_rename(
467 	__unused ipc_space_t            space,
468 	__unused mach_port_name_t       oname,
469 	__unused mach_port_name_t       nname)
470 {
471 	return KERN_NOT_SUPPORTED;
472 }
473 
474 
475 /*
476  *	Routine:	mach_port_allocate_name [kernel call]
477  *	Purpose:
478  *		Allocates a right in a space, using a specific name
479  *		for the new right.  Possible rights:
480  *			MACH_PORT_RIGHT_RECEIVE
481  *			MACH_PORT_RIGHT_PORT_SET
482  *			MACH_PORT_RIGHT_DEAD_NAME
483  *
484  *		A new port (allocated with MACH_PORT_RIGHT_RECEIVE)
485  *		has no extant send or send-once rights and no queued
486  *		messages.  Its queue limit is MACH_PORT_QLIMIT_DEFAULT
487  *		and its make-send count is 0.  It is not a member of
488  *		a port set.  It has no registered no-senders or
489  *		port-destroyed notification requests.
490  *
491  *		A new port set has no members.
492  *
493  *		A new dead name has one user reference.
494  *	Conditions:
495  *		Nothing locked.
496  *	Returns:
497  *		KERN_SUCCESS		The right is allocated.
498  *		KERN_INVALID_TASK	The space is null.
499  *		KERN_INVALID_TASK	The space is dead.
500  *		KERN_INVALID_VALUE	The name isn't a legal name.
501  *		KERN_INVALID_VALUE	"right" isn't a legal kind of right.
502  *		KERN_NAME_EXISTS	The name already denotes a right.
503  *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
504  *
505  *	Restrictions on name allocation:  NT bits are reserved by kernel,
506  *	must be set on any chosen name.  Can't do this at all in kernel
507  *	loaded server.
508  */
509 
510 kern_return_t
mach_port_allocate_name(ipc_space_t space,mach_port_right_t right,mach_port_name_t name)511 mach_port_allocate_name(
512 	ipc_space_t             space,
513 	mach_port_right_t       right,
514 	mach_port_name_t        name)
515 {
516 	kern_return_t           kr;
517 	mach_port_qos_t         qos = { .name = TRUE };
518 
519 	if (!MACH_PORT_VALID(name)) {
520 		return KERN_INVALID_VALUE;
521 	}
522 
523 	kr = mach_port_allocate_full(space, right, MACH_PORT_NULL,
524 	    &qos, &name);
525 	return kr;
526 }
527 
528 /*
529  *	Routine:	mach_port_allocate [kernel call]
530  *	Purpose:
531  *		Allocates a right in a space.  Like mach_port_allocate_name,
532  *		except that the implementation picks a name for the right.
533  *		The name may be any legal name in the space that doesn't
534  *		currently denote a right.
535  *	Conditions:
536  *		Nothing locked.
537  *	Returns:
538  *		KERN_SUCCESS		The right is allocated.
539  *		KERN_INVALID_TASK	The space is null.
540  *		KERN_INVALID_TASK	The space is dead.
541  *		KERN_INVALID_VALUE	"right" isn't a legal kind of right.
542  *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
543  *		KERN_NO_SPACE		No room in space for another right.
544  */
545 
546 kern_return_t
mach_port_allocate(ipc_space_t space,mach_port_right_t right,mach_port_name_t * namep)547 mach_port_allocate(
548 	ipc_space_t             space,
549 	mach_port_right_t       right,
550 	mach_port_name_t        *namep)
551 {
552 	kern_return_t           kr;
553 	mach_port_qos_t         qos = { };
554 
555 	kr = mach_port_allocate_full(space, right, MACH_PORT_NULL,
556 	    &qos, namep);
557 	return kr;
558 }
559 
560 /*
561  *	Routine:	mach_port_allocate_qos [kernel call]
562  *	Purpose:
563  *		Allocates a right, with qos options, in a space.  Like
564  *		mach_port_allocate_name, except that the implementation
565  *		picks a name for the right. The name may be any legal name
566  *		in the space that doesn't currently denote a right.
567  *	Conditions:
568  *		Nothing locked.
569  *	Returns:
570  *		KERN_SUCCESS		The right is allocated.
571  *		KERN_INVALID_TASK	The space is null.
572  *		KERN_INVALID_TASK	The space is dead.
573  *		KERN_INVALID_VALUE	"right" isn't a legal kind of right.
574  *		KERN_INVALID_ARGUMENT   The qos request was invalid.
575  *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
576  *		KERN_NO_SPACE		No room in space for another right.
577  */
578 
579 kern_return_t
mach_port_allocate_qos(ipc_space_t space,mach_port_right_t right,mach_port_qos_t * qosp,mach_port_name_t * namep)580 mach_port_allocate_qos(
581 	ipc_space_t             space,
582 	mach_port_right_t       right,
583 	mach_port_qos_t         *qosp,
584 	mach_port_name_t        *namep)
585 {
586 	kern_return_t           kr;
587 
588 	if (qosp->name) {
589 		return KERN_INVALID_ARGUMENT;
590 	}
591 	kr = mach_port_allocate_full(space, right, MACH_PORT_NULL,
592 	    qosp, namep);
593 	return kr;
594 }
595 
596 /*
597  *	Routine:	mach_port_allocate_full [kernel call]
598  *	Purpose:
599  *		Allocates a right in a space.  Supports the
600  *		special case of specifying a name. The name may
601  *      be any legal name in the space that doesn't
602  *		currently denote a right.
603  *
604  *      While we no longer support users requesting
605  *      preallocated message for the port, we still
606  *      check for errors in such requests and then
607  *      just clear the request.
608  *	Conditions:
609  *		Nothing locked.
610  *	Returns:
611  *		KERN_SUCCESS		The right is allocated.
612  *		KERN_INVALID_TASK	The space is null.
613  *		KERN_INVALID_TASK	The space is dead.
614  *		KERN_INVALID_VALUE	"right" isn't a legal kind of right, or supplied port
615  *                          name is invalid.
616  *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
617  *		KERN_NO_SPACE		No room in space for another right.
618  */
619 
620 kern_return_t
mach_port_allocate_full(ipc_space_t space,mach_port_right_t right,mach_port_t proto,mach_port_qos_t * qosp,mach_port_name_t * namep)621 mach_port_allocate_full(
622 	ipc_space_t             space,
623 	mach_port_right_t       right,
624 	mach_port_t             proto,
625 	mach_port_qos_t         *qosp,
626 	mach_port_name_t        *namep)
627 {
628 	kern_return_t           kr;
629 
630 	if (space == IS_NULL) {
631 		return KERN_INVALID_TASK;
632 	}
633 
634 	if (proto != MACH_PORT_NULL) {
635 		return KERN_INVALID_VALUE;
636 	}
637 
638 	if (qosp->name) {
639 		if (!MACH_PORT_VALID(*namep)) {
640 			return KERN_INVALID_VALUE;
641 		}
642 	}
643 
644 	/*
645 	 * Don't actually honor prealloc requests anymore,
646 	 * (only mk_timer still uses IP_PREALLOC messages, by hand).
647 	 *
648 	 * (for security reasons, and because it isn't guaranteed anyway).
649 	 * Keep old errors for legacy reasons.
650 	 */
651 	if (qosp->prealloc) {
652 		if (qosp->len > MACH_MSG_SIZE_MAX - MAX_TRAILER_SIZE) {
653 			return KERN_RESOURCE_SHORTAGE;
654 		}
655 		if (right != MACH_PORT_RIGHT_RECEIVE) {
656 			return KERN_INVALID_VALUE;
657 		}
658 		qosp->prealloc = 0;
659 	}
660 
661 	switch (right) {
662 	case MACH_PORT_RIGHT_RECEIVE:
663 	{
664 		ipc_port_t      port;
665 
666 		if (qosp->name) {
667 			kr = ipc_port_alloc_name(space, IPC_PORT_INIT_MESSAGE_QUEUE,
668 			    *namep, &port);
669 		} else {
670 			kr = ipc_port_alloc(space, IPC_PORT_INIT_MESSAGE_QUEUE,
671 			    namep, &port);
672 		}
673 		if (kr == KERN_SUCCESS) {
674 			ip_mq_unlock(port);
675 		}
676 		break;
677 	}
678 
679 	case MACH_PORT_RIGHT_PORT_SET:
680 	{
681 		ipc_pset_t      pset;
682 
683 		if (qosp->name) {
684 			kr = ipc_pset_alloc_name(space, *namep, &pset);
685 		} else {
686 			kr = ipc_pset_alloc(space, namep, &pset);
687 		}
688 		if (kr == KERN_SUCCESS) {
689 			ips_mq_unlock(pset);
690 		}
691 		break;
692 	}
693 
694 	case MACH_PORT_RIGHT_DEAD_NAME:
695 		kr = ipc_object_alloc_dead(space, namep);
696 		break;
697 
698 	default:
699 		kr = KERN_INVALID_VALUE;
700 		break;
701 	}
702 
703 	return kr;
704 }
705 
706 /*
707  *	Routine:	mach_port_destroy [kernel call]
708  *	Purpose:
709  *		Cleans up and destroys all rights denoted by a name
710  *		in a space.  The destruction of a receive right
711  *		destroys the port, unless a port-destroyed request
712  *		has been made for it; the destruction of a port-set right
713  *		destroys the port set.
714  *	Conditions:
715  *		Nothing locked.
716  *	Returns:
717  *		KERN_SUCCESS		The name is destroyed.
718  *		KERN_INVALID_TASK	The space is null.
719  *		KERN_INVALID_TASK	The space is dead.
720  *		KERN_INVALID_NAME	The name doesn't denote a right.
721  */
722 
723 kern_return_t
mach_port_destroy(ipc_space_t space,mach_port_name_t name)724 mach_port_destroy(
725 	ipc_space_t             space,
726 	mach_port_name_t        name)
727 {
728 	ipc_entry_t entry;
729 	kern_return_t kr;
730 
731 	if (space == IS_NULL) {
732 		return KERN_INVALID_TASK;
733 	}
734 
735 	if (!MACH_PORT_VALID(name)) {
736 		return KERN_SUCCESS;
737 	}
738 
739 	kr = ipc_right_lookup_write(space, name, &entry);
740 	if (kr != KERN_SUCCESS) {
741 		mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_NAME);
742 		return kr;
743 	}
744 	/* space is write-locked and active */
745 
746 	kr = ipc_right_destroy(space, name, entry, TRUE, 0); /* unlocks space */
747 	return kr;
748 }
749 
750 /*
751  *	Routine:	mach_port_deallocate [kernel call]
752  *	Purpose:
753  *		Deallocates a user reference from a send right,
754  *		send-once right, dead-name right or a port_set right.
755  *		May deallocate the right, if this is the last uref,
756  *		and destroy the name, if it doesn't denote
757  *		other rights.
758  *	Conditions:
759  *		Nothing locked.
760  *	Returns:
761  *		KERN_SUCCESS		The uref is deallocated.
762  *		KERN_INVALID_TASK	The space is null.
763  *		KERN_INVALID_TASK	The space is dead.
764  *		KERN_INVALID_NAME	The name doesn't denote a right.
765  *		KERN_INVALID_RIGHT	The right isn't correct.
766  */
767 
768 kern_return_t
mach_port_deallocate(ipc_space_t space,mach_port_name_t name)769 mach_port_deallocate(
770 	ipc_space_t             space,
771 	mach_port_name_t        name)
772 {
773 	ipc_entry_t entry;
774 	kern_return_t kr;
775 
776 	if (space == IS_NULL) {
777 		return KERN_INVALID_TASK;
778 	}
779 
780 	if (!MACH_PORT_VALID(name)) {
781 		return KERN_SUCCESS;
782 	}
783 
784 	kr = ipc_right_lookup_write(space, name, &entry);
785 	if (kr != KERN_SUCCESS) {
786 		mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_NAME);
787 		return kr;
788 	}
789 	/* space is write-locked */
790 
791 	kr = ipc_right_dealloc(space, name, entry); /* unlocks space */
792 	return kr;
793 }
794 
795 /*
796  *	Routine:	mach_port_get_refs [kernel call]
797  *	Purpose:
798  *		Retrieves the number of user references held by a right.
799  *		Receive rights, port-set rights, and send-once rights
800  *		always have one user reference.  Returns zero if the
801  *		name denotes a right, but not the queried right.
802  *	Conditions:
803  *		Nothing locked.
804  *	Returns:
805  *		KERN_SUCCESS		Number of urefs returned.
806  *		KERN_INVALID_TASK	The space is null.
807  *		KERN_INVALID_TASK	The space is dead.
808  *		KERN_INVALID_VALUE	"right" isn't a legal value.
809  *		KERN_INVALID_NAME	The name doesn't denote a right.
810  */
811 
812 kern_return_t
mach_port_get_refs(ipc_space_t space,mach_port_name_t name,mach_port_right_t right,mach_port_urefs_t * urefsp)813 mach_port_get_refs(
814 	ipc_space_t             space,
815 	mach_port_name_t        name,
816 	mach_port_right_t       right,
817 	mach_port_urefs_t       *urefsp)
818 {
819 	mach_port_type_t type;
820 	mach_port_urefs_t urefs;
821 	ipc_entry_t entry;
822 	kern_return_t kr;
823 
824 	if (space == IS_NULL) {
825 		return KERN_INVALID_TASK;
826 	}
827 
828 	if (right >= MACH_PORT_RIGHT_NUMBER) {
829 		return KERN_INVALID_VALUE;
830 	}
831 
832 	if (!MACH_PORT_VALID(name)) {
833 		if (right == MACH_PORT_RIGHT_SEND ||
834 		    right == MACH_PORT_RIGHT_SEND_ONCE) {
835 			*urefsp = 1;
836 			return KERN_SUCCESS;
837 		}
838 		return KERN_INVALID_NAME;
839 	}
840 
841 	kr = ipc_right_lookup_write(space, name, &entry);
842 	if (kr != KERN_SUCCESS) {
843 		return kr;
844 	}
845 
846 	/* space is write-locked and active */
847 	kr = ipc_right_info(space, name, entry, &type, &urefs);
848 	/* space is unlocked */
849 
850 	if (kr != KERN_SUCCESS) {
851 		return kr;
852 	}
853 
854 	if (type & MACH_PORT_TYPE(right)) {
855 		switch (right) {
856 		case MACH_PORT_RIGHT_SEND_ONCE:
857 			assert(urefs == 1);
858 			OS_FALLTHROUGH;
859 
860 		case MACH_PORT_RIGHT_PORT_SET:
861 		case MACH_PORT_RIGHT_RECEIVE:
862 			*urefsp = 1;
863 			break;
864 
865 		case MACH_PORT_RIGHT_DEAD_NAME:
866 		case MACH_PORT_RIGHT_SEND:
867 			assert(urefs > 0);
868 			*urefsp = urefs;
869 			break;
870 
871 		default:
872 			panic("mach_port_get_refs: strange rights");
873 		}
874 	} else {
875 		*urefsp = 0;
876 	}
877 
878 	return kr;
879 }
880 
881 /*
882  *	Routine:	mach_port_mod_refs
883  *	Purpose:
884  *		Modifies the number of user references held by a right.
885  *		The resulting number of user references must be non-negative.
886  *		If it is zero, the right is deallocated.  If the name
887  *		doesn't denote other rights, it is destroyed.
888  *	Conditions:
889  *		Nothing locked.
890  *	Returns:
891  *		KERN_SUCCESS		Modified number of urefs.
892  *		KERN_INVALID_TASK	The space is null.
893  *		KERN_INVALID_TASK	The space is dead.
894  *		KERN_INVALID_VALUE	"right" isn't a legal value.
895  *		KERN_INVALID_NAME	The name doesn't denote a right.
896  *		KERN_INVALID_RIGHT	Name doesn't denote specified right.
897  *		KERN_INVALID_VALUE	Impossible modification to urefs.
898  *		KERN_UREFS_OVERFLOW	Urefs would overflow.
899  */
900 
901 kern_return_t
mach_port_mod_refs(ipc_space_t space,mach_port_name_t name,mach_port_right_t right,mach_port_delta_t delta)902 mach_port_mod_refs(
903 	ipc_space_t             space,
904 	mach_port_name_t        name,
905 	mach_port_right_t       right,
906 	mach_port_delta_t       delta)
907 {
908 	ipc_entry_t entry;
909 	kern_return_t kr;
910 
911 	if (space == IS_NULL) {
912 		return KERN_INVALID_TASK;
913 	}
914 
915 	if (right >= MACH_PORT_RIGHT_NUMBER) {
916 		return KERN_INVALID_VALUE;
917 	}
918 
919 	if (!MACH_PORT_VALID(name)) {
920 		if (right == MACH_PORT_RIGHT_SEND ||
921 		    right == MACH_PORT_RIGHT_SEND_ONCE) {
922 			return KERN_SUCCESS;
923 		}
924 		return KERN_INVALID_NAME;
925 	}
926 
927 	kr = ipc_right_lookup_write(space, name, &entry);
928 	if (kr != KERN_SUCCESS) {
929 		mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_NAME);
930 		return kr;
931 	}
932 
933 	/* space is write-locked and active */
934 
935 	kr = ipc_right_delta(space, name, entry, right, delta); /* unlocks */
936 	return kr;
937 }
938 
939 
940 /*
941  *	Routine:	mach_port_peek [kernel call]
942  *	Purpose:
943  *		Peek at the message queue for the specified receive
944  *		right and return info about a message in the queue.
945  *
946  *		On input, seqnop points to a sequence number value
947  *		to match the message being peeked. If zero is specified
948  *		as the seqno, the first message in the queue will be
949  *		peeked.
950  *
951  *		Only the following trailer types are currently supported:
952  *			MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)
953  *
954  *				or'ed with one of these element types:
955  *			MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_NULL)
956  *			MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SEQNO)
957  *			MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER)
958  *			MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT)
959  *
960  *		On input, the value pointed to by trailer_sizep must be
961  *		large enough to hold the requested trailer size.
962  *
963  *		The message sequence number, id, size, requested trailer info
964  *		and requested trailer size are returned in their respective
965  *		output parameters upon success.
966  *
967  *	Conditions:
968  *		Nothing locked.
969  *	Returns:
970  *		KERN_SUCCESS		Matching message found, out parameters set.
971  *		KERN_INVALID_TASK	The space is null or dead.
972  *		KERN_INVALID_NAME	The name doesn't denote a right.
973  *		KERN_INVALID_RIGHT	Name doesn't denote receive rights.
974  *		KERN_INVALID_VALUE	The input parameter values are out of bounds.
975  *		KERN_FAILURE		The requested message was not found.
976  */
977 
978 kern_return_t
mach_port_peek(ipc_space_t space,mach_port_name_t name,mach_msg_trailer_type_t trailer_type,mach_port_seqno_t * seqnop,mach_msg_size_t * msg_sizep,mach_msg_id_t * msg_idp,mach_msg_trailer_info_t trailer_infop,mach_msg_type_number_t * trailer_sizep)979 mach_port_peek(
980 	ipc_space_t                     space,
981 	mach_port_name_t                name,
982 	mach_msg_trailer_type_t         trailer_type,
983 	mach_port_seqno_t               *seqnop,
984 	mach_msg_size_t                 *msg_sizep,
985 	mach_msg_id_t                   *msg_idp,
986 	mach_msg_trailer_info_t         trailer_infop,
987 	mach_msg_type_number_t          *trailer_sizep)
988 {
989 	ipc_port_t port;
990 	kern_return_t kr;
991 	boolean_t found;
992 	mach_msg_max_trailer_t max_trailer;
993 
994 	if (space == IS_NULL) {
995 		return KERN_INVALID_TASK;
996 	}
997 
998 	if (!MACH_PORT_VALID(name)) {
999 		return KERN_INVALID_RIGHT;
1000 	}
1001 
1002 	/*
1003 	 * We don't allow anything greater than the audit trailer - to avoid
1004 	 * leaking the context pointer and to avoid variable-sized context issues.
1005 	 */
1006 	if (GET_RCV_ELEMENTS(trailer_type) > MACH_RCV_TRAILER_AUDIT ||
1007 	    REQUESTED_TRAILER_SIZE(TRUE, trailer_type) > *trailer_sizep) {
1008 		mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_VALUE);
1009 		return KERN_INVALID_VALUE;
1010 	}
1011 
1012 	*trailer_sizep = REQUESTED_TRAILER_SIZE(TRUE, trailer_type);
1013 
1014 	kr = ipc_port_translate_receive(space, name, &port);
1015 	if (kr != KERN_SUCCESS) {
1016 		mach_port_guard_exception(name, 0, 0,
1017 		    ((KERN_INVALID_NAME == kr) ?
1018 		    kGUARD_EXC_INVALID_NAME :
1019 		    kGUARD_EXC_INVALID_RIGHT));
1020 		return kr;
1021 	}
1022 
1023 	/* Port locked and active */
1024 	found = ipc_mqueue_peek_locked(&port->ip_messages, seqnop,
1025 	    msg_sizep, msg_idp, &max_trailer, NULL);
1026 	ip_mq_unlock(port);
1027 
1028 	if (found != TRUE) {
1029 		return KERN_FAILURE;
1030 	}
1031 
1032 	max_trailer.msgh_seqno = *seqnop;
1033 	memcpy(trailer_infop, &max_trailer, *trailer_sizep);
1034 
1035 	return KERN_SUCCESS;
1036 }
1037 
1038 /*
1039  *	Routine:	mach_port_set_mscount [kernel call]
1040  *	Purpose:
1041  *		Changes a receive right's make-send count.
1042  *	Conditions:
1043  *		Nothing locked.
1044  *	Returns:
1045  *		KERN_SUCCESS		Set make-send count.
1046  *		KERN_INVALID_TASK	The space is null.
1047  *		KERN_INVALID_TASK	The space is dead.
1048  *		KERN_INVALID_NAME	The name doesn't denote a right.
1049  *		KERN_INVALID_RIGHT	Name doesn't denote receive rights.
1050  */
1051 
1052 kern_return_t
mach_port_set_mscount(ipc_space_t space,mach_port_name_t name,mach_port_mscount_t mscount)1053 mach_port_set_mscount(
1054 	ipc_space_t             space,
1055 	mach_port_name_t        name,
1056 	mach_port_mscount_t     mscount)
1057 {
1058 	ipc_port_t port;
1059 	kern_return_t kr;
1060 
1061 	if (space == IS_NULL) {
1062 		return KERN_INVALID_TASK;
1063 	}
1064 
1065 	if (!MACH_PORT_VALID(name)) {
1066 		return KERN_INVALID_RIGHT;
1067 	}
1068 
1069 	kr = ipc_port_translate_receive(space, name, &port);
1070 	if (kr != KERN_SUCCESS) {
1071 		return kr;
1072 	}
1073 	/* port is locked and active */
1074 
1075 	port->ip_mscount = mscount;
1076 	ip_mq_unlock(port);
1077 	return KERN_SUCCESS;
1078 }
1079 
1080 /*
1081  *	Routine:	mach_port_set_seqno [kernel call]
1082  *	Purpose:
1083  *		Changes a receive right's sequence number.
1084  *	Conditions:
1085  *		Nothing locked.
1086  *	Returns:
1087  *		KERN_SUCCESS		Set sequence number.
1088  *		KERN_INVALID_TASK	The space is null.
1089  *		KERN_INVALID_TASK	The space is dead.
1090  *		KERN_INVALID_NAME	The name doesn't denote a right.
1091  *		KERN_INVALID_RIGHT	Name doesn't denote receive rights.
1092  */
1093 
1094 kern_return_t
mach_port_set_seqno(ipc_space_t space,mach_port_name_t name,mach_port_seqno_t seqno)1095 mach_port_set_seqno(
1096 	ipc_space_t             space,
1097 	mach_port_name_t        name,
1098 	mach_port_seqno_t       seqno)
1099 {
1100 	ipc_port_t port;
1101 	kern_return_t kr;
1102 
1103 	if (space == IS_NULL) {
1104 		return KERN_INVALID_TASK;
1105 	}
1106 
1107 	if (!MACH_PORT_VALID(name)) {
1108 		return KERN_INVALID_RIGHT;
1109 	}
1110 
1111 	kr = ipc_port_translate_receive(space, name, &port);
1112 	if (kr != KERN_SUCCESS) {
1113 		return kr;
1114 	}
1115 	/* port is locked and active */
1116 
1117 	ipc_mqueue_set_seqno_locked(&port->ip_messages, seqno);
1118 
1119 	ip_mq_unlock(port);
1120 	return KERN_SUCCESS;
1121 }
1122 
1123 /*
1124  *	Routine:	mach_port_get_context [kernel call]
1125  *	Purpose:
1126  *		Returns a receive right's context pointer.
1127  *	Conditions:
1128  *		Nothing locked.
1129  *	Returns:
1130  *		KERN_SUCCESS		Set context pointer.
1131  *		KERN_INVALID_TASK	The space is null.
1132  *		KERN_INVALID_TASK	The space is dead.
1133  *		KERN_INVALID_NAME	The name doesn't denote a right.
1134  *		KERN_INVALID_RIGHT	Name doesn't denote receive rights.
1135  */
1136 
1137 kern_return_t
mach_port_get_context(ipc_space_t space,mach_port_name_t name,mach_vm_address_t * context)1138 mach_port_get_context(
1139 	ipc_space_t             space,
1140 	mach_port_name_t        name,
1141 	mach_vm_address_t       *context)
1142 {
1143 	ipc_port_t port;
1144 	kern_return_t kr;
1145 
1146 	if (space == IS_NULL) {
1147 		return KERN_INVALID_TASK;
1148 	}
1149 
1150 	if (!MACH_PORT_VALID(name)) {
1151 		return KERN_INVALID_RIGHT;
1152 	}
1153 
1154 	kr = ipc_port_translate_receive(space, name, &port);
1155 	if (kr != KERN_SUCCESS) {
1156 		return kr;
1157 	}
1158 
1159 	/* Port locked and active */
1160 
1161 	/* For strictly guarded ports, return empty context (which acts as guard) */
1162 	if (port->ip_strict_guard) {
1163 		*context = 0;
1164 	} else {
1165 		*context = port->ip_context;
1166 	}
1167 
1168 	ip_mq_unlock(port);
1169 	return KERN_SUCCESS;
1170 }
1171 
1172 kern_return_t
mach_port_get_context_from_user(mach_port_t port,mach_port_name_t name,mach_vm_address_t * context)1173 mach_port_get_context_from_user(
1174 	mach_port_t             port,
1175 	mach_port_name_t        name,
1176 	mach_vm_address_t       *context)
1177 {
1178 	kern_return_t kr;
1179 
1180 	ipc_space_t space = convert_port_to_space_read_no_eval(port);
1181 
1182 	if (space == IPC_SPACE_NULL) {
1183 		return KERN_INVALID_ARGUMENT;
1184 	}
1185 
1186 	kr = mach_port_get_context(space, name, context);
1187 
1188 	ipc_space_release(space);
1189 	return kr;
1190 }
1191 
1192 /*
1193  *	Routine:	mach_port_set_context [kernel call]
1194  *	Purpose:
1195  *		Changes a receive right's context pointer.
1196  *	Conditions:
1197  *		Nothing locked.
1198  *	Returns:
1199  *		KERN_SUCCESS		Set context pointer.
1200  *		KERN_INVALID_TASK	The space is null.
1201  *		KERN_INVALID_TASK	The space is dead.
1202  *		KERN_INVALID_NAME	The name doesn't denote a right.
1203  *		KERN_INVALID_RIGHT	Name doesn't denote receive rights.
1204  */
1205 
1206 kern_return_t
mach_port_set_context(ipc_space_t space,mach_port_name_t name,mach_vm_address_t context)1207 mach_port_set_context(
1208 	ipc_space_t             space,
1209 	mach_port_name_t        name,
1210 	mach_vm_address_t       context)
1211 {
1212 	ipc_port_t port;
1213 	kern_return_t kr;
1214 
1215 	if (space == IS_NULL) {
1216 		return KERN_INVALID_TASK;
1217 	}
1218 
1219 	if (!MACH_PORT_VALID(name)) {
1220 		return KERN_INVALID_RIGHT;
1221 	}
1222 
1223 	kr = ipc_port_translate_receive(space, name, &port);
1224 	if (kr != KERN_SUCCESS) {
1225 		return kr;
1226 	}
1227 
1228 	/* port is locked and active */
1229 	if (port->ip_strict_guard) {
1230 		uint64_t portguard = port->ip_context;
1231 		ip_mq_unlock(port);
1232 		/* For strictly guarded ports, disallow overwriting context; Raise Exception */
1233 		mach_port_guard_exception(name, context, portguard, kGUARD_EXC_SET_CONTEXT);
1234 		return KERN_INVALID_ARGUMENT;
1235 	}
1236 
1237 	port->ip_context = context;
1238 
1239 	ip_mq_unlock(port);
1240 	return KERN_SUCCESS;
1241 }
1242 
1243 
1244 /*
1245  *	Routine:	mach_port_get_set_status [kernel call]
1246  *	Purpose:
1247  *		Retrieves a list of members in a port set.
1248  *		Returns the space's name for each receive right member.
1249  *	Conditions:
1250  *		Nothing locked.
1251  *	Returns:
1252  *		KERN_SUCCESS		Retrieved list of members.
1253  *		KERN_INVALID_TASK	The space is null.
1254  *		KERN_INVALID_TASK	The space is dead.
1255  *		KERN_INVALID_NAME	The name doesn't denote a right.
1256  *		KERN_INVALID_RIGHT	Name doesn't denote a port set.
1257  *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
1258  */
1259 
1260 kern_return_t
mach_port_get_set_status(ipc_space_t space,mach_port_name_t name,mach_port_name_t ** members,mach_msg_type_number_t * membersCnt)1261 mach_port_get_set_status(
1262 	ipc_space_t                     space,
1263 	mach_port_name_t                name,
1264 	mach_port_name_t                **members,
1265 	mach_msg_type_number_t          *membersCnt)
1266 {
1267 	__block ipc_entry_num_t actual;         /* this many members */
1268 	ipc_entry_num_t maxnames;       /* space for this many members */
1269 	kern_return_t kr;
1270 
1271 	vm_size_t size;         /* size of allocated memory */
1272 	vm_offset_t addr;       /* allocated memory */
1273 	vm_map_copy_t memory;   /* copied-in memory */
1274 
1275 	if (space == IS_NULL) {
1276 		return KERN_INVALID_TASK;
1277 	}
1278 
1279 	if (!MACH_PORT_VALID(name)) {
1280 		return KERN_INVALID_RIGHT;
1281 	}
1282 
1283 	size = VM_MAP_PAGE_SIZE(ipc_kernel_map);        /* initial guess */
1284 
1285 	for (;;) {
1286 		mach_port_name_t *names;
1287 		ipc_object_t psobj;
1288 		ipc_pset_t pset;
1289 
1290 		kr = kmem_alloc(ipc_kernel_map, &addr, size,
1291 		    KMA_DATA, VM_KERN_MEMORY_IPC);
1292 		if (kr != KERN_SUCCESS) {
1293 			return KERN_RESOURCE_SHORTAGE;
1294 		}
1295 
1296 		kr = ipc_object_translate(space, name, MACH_PORT_RIGHT_PORT_SET, &psobj);
1297 		if (kr != KERN_SUCCESS) {
1298 			kmem_free(ipc_kernel_map, addr, size);
1299 			return kr;
1300 		}
1301 
1302 		/* just use a portset reference from here on out */
1303 		pset = ips_object_to_pset(psobj);
1304 		names = (mach_port_name_t *)addr;
1305 		maxnames = (ipc_entry_num_t)(size / sizeof(mach_port_name_t));
1306 
1307 		waitq_set_foreach_member_locked(&pset->ips_wqset, ^(struct waitq *wq){
1308 			if (actual < maxnames) {
1309 			        names[actual] = ip_get_receiver_name(ip_from_waitq(wq));
1310 			}
1311 			actual++;
1312 		});
1313 
1314 		/* release the portset reference */
1315 		ips_mq_unlock(pset);
1316 
1317 		if (actual <= maxnames) {
1318 			break;
1319 		}
1320 
1321 		/* didn't have enough memory; allocate more */
1322 		kmem_free(ipc_kernel_map, addr, size);
1323 		size = vm_map_round_page(actual * sizeof(mach_port_name_t),
1324 		    VM_MAP_PAGE_MASK(ipc_kernel_map)) +
1325 		    VM_MAP_PAGE_SIZE(ipc_kernel_map);
1326 	}
1327 
1328 	if (actual == 0) {
1329 		memory = VM_MAP_COPY_NULL;
1330 
1331 		kmem_free(ipc_kernel_map, addr, size);
1332 	} else {
1333 		vm_size_t size_used;
1334 		vm_size_t vm_size_used;
1335 
1336 		qsort((void *)addr, actual, sizeof(mach_port_name_t),
1337 		    mach_port_name_cmp);
1338 
1339 		size_used = actual * sizeof(mach_port_name_t);
1340 		vm_size_used = vm_map_round_page(size_used,
1341 		    VM_MAP_PAGE_MASK(ipc_kernel_map));
1342 
1343 		if (size_used < vm_size_used) {
1344 			bzero((char *)addr + size_used, vm_size_used - size_used);
1345 		}
1346 
1347 		/*
1348 		 *	Make used memory pageable and get it into
1349 		 *	copied-in form.  Free any unused memory.
1350 		 */
1351 
1352 		kr = vm_map_unwire(ipc_kernel_map, addr, addr + vm_size_used, FALSE);
1353 		assert(kr == KERN_SUCCESS);
1354 
1355 		kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr,
1356 		    (vm_map_size_t)size_used, TRUE, &memory);
1357 		assert(kr == KERN_SUCCESS);
1358 
1359 		if (vm_size_used != size) {
1360 			kmem_free(ipc_kernel_map,
1361 			    addr + vm_size_used, size - vm_size_used);
1362 		}
1363 	}
1364 
1365 	*members = (mach_port_name_t *) memory;
1366 	*membersCnt = actual;
1367 	return KERN_SUCCESS;
1368 }
1369 
1370 kern_return_t
mach_port_get_set_status_from_user(mach_port_t port,mach_port_name_t name,mach_port_name_t ** members,mach_msg_type_number_t * membersCnt)1371 mach_port_get_set_status_from_user(
1372 	mach_port_t                     port,
1373 	mach_port_name_t                name,
1374 	mach_port_name_t                **members,
1375 	mach_msg_type_number_t          *membersCnt)
1376 {
1377 	kern_return_t kr;
1378 
1379 	ipc_space_t space = convert_port_to_space_read_no_eval(port);
1380 
1381 	if (space == IPC_SPACE_NULL) {
1382 		return KERN_INVALID_ARGUMENT;
1383 	}
1384 
1385 	kr = mach_port_get_set_status(space, name, members, membersCnt);
1386 
1387 	ipc_space_release(space);
1388 	return kr;
1389 }
1390 
1391 /*
1392  *	Routine:	mach_port_move_member [kernel call]
1393  *	Purpose:
1394  *		If after is MACH_PORT_NULL, removes member
1395  *		from the port set it is in.  Otherwise, adds
1396  *		member to after, removing it from any set
1397  *		it might already be in.
1398  *	Conditions:
1399  *		Nothing locked.
1400  *	Returns:
1401  *		KERN_SUCCESS		Moved the port.
1402  *		KERN_INVALID_TASK	The space is null.
1403  *		KERN_INVALID_TASK	The space is dead.
1404  *		KERN_INVALID_NAME	Member didn't denote a right.
1405  *		KERN_INVALID_RIGHT	Member didn't denote a receive right.
1406  *		KERN_INVALID_NAME	After didn't denote a right.
1407  *		KERN_INVALID_RIGHT	After didn't denote a port set right.
1408  *		KERN_NOT_IN_SET
1409  *			After is MACH_PORT_NULL and Member isn't in a port set.
1410  */
1411 
1412 kern_return_t
mach_port_move_member(ipc_space_t space,mach_port_name_t member,mach_port_name_t after)1413 mach_port_move_member(
1414 	ipc_space_t             space,
1415 	mach_port_name_t        member,
1416 	mach_port_name_t        after)
1417 {
1418 	ipc_object_t port_obj, ps_obj;
1419 	ipc_port_t port = IP_NULL;
1420 	kern_return_t kr;
1421 	waitq_link_list_t free_l = { };
1422 	waitq_link_t link = WQL_NULL;
1423 	struct waitq_set *keep_waitq_set = NULL;
1424 
1425 	if (space == IS_NULL) {
1426 		return KERN_INVALID_TASK;
1427 	}
1428 
1429 	if (!MACH_PORT_VALID(member)) {
1430 		return KERN_INVALID_RIGHT;
1431 	}
1432 
1433 	if (after == MACH_PORT_DEAD) {
1434 		return KERN_INVALID_RIGHT;
1435 	}
1436 
1437 	if (after != MACH_PORT_NULL) {
1438 		link = waitq_link_alloc(WQT_PORT_SET);
1439 		kr = ipc_object_translate_two(space,
1440 		    member, MACH_PORT_RIGHT_RECEIVE, &port_obj,
1441 		    after, MACH_PORT_RIGHT_PORT_SET, &ps_obj);
1442 	} else {
1443 		kr = ipc_object_translate(space,
1444 		    member, MACH_PORT_RIGHT_RECEIVE, &port_obj);
1445 	}
1446 	if (kr != KERN_SUCCESS) {
1447 		goto done;
1448 	}
1449 
1450 	port = ip_object_to_port(port_obj);
1451 
1452 	if (after != MACH_PORT_NULL) {
1453 		ipc_pset_t nset = ips_object_to_pset(ps_obj);
1454 
1455 		ipc_mqueue_add_locked(&port->ip_messages, nset, &link);
1456 		ips_mq_unlock(nset);
1457 
1458 		keep_waitq_set = &nset->ips_wqset;
1459 	} else if (!ip_in_pset(port)) {
1460 		kr = KERN_NOT_IN_SET;
1461 	}
1462 
1463 	/*
1464 	 * waitq_unlink_all_locked() doesn't dereference `keep_waitq_set,
1465 	 * but we wouldn't want an ABA issue. Fortunately, while `port`
1466 	 * is locked and linked to `nset`, then `nset` can't be reused/freed.
1467 	 */
1468 	waitq_unlink_all_locked(&port->ip_waitq, keep_waitq_set, &free_l);
1469 
1470 	ip_mq_unlock(port);
1471 
1472 	waitq_link_free_list(WQT_PORT_SET, &free_l);
1473 done:
1474 	if (link.wqlh) {
1475 		waitq_link_free(WQT_PORT_SET, link);
1476 	}
1477 
1478 	return kr;
1479 }
1480 
1481 /*
1482  *	Routine:	mach_port_request_notification [kernel call]
1483  *	Purpose:
1484  *		Requests a notification.  The caller supplies
1485  *		a send-once right for the notification to use,
1486  *		and the call returns the previously registered
1487  *		send-once right, if any.  Possible types:
1488  *
1489  *		MACH_NOTIFY_PORT_DESTROYED
1490  *			Requests a port-destroyed notification
1491  *			for a receive right.  Sync should be zero.
1492  *		MACH_NOTIFY_SERVICE_PORT_DESTROYED
1493  *			Special port destroyed notifications to be
1494  *			used by launchd for service ports only.
1495  *		MACH_NOTIFY_NO_SENDERS
1496  *			Requests a no-senders notification for a
1497  *			receive right.  If there are currently no
1498  *			senders, sync is less than or equal to the
1499  *			current make-send count, and a send-once right
1500  *			is supplied, then an immediate no-senders
1501  *			notification is generated.
1502  *		MACH_NOTIFY_DEAD_NAME
1503  *			Requests a dead-name notification for a send
1504  *			or receive right.  If the name is already a
1505  *			dead name, sync is non-zero, and a send-once
1506  *			right is supplied, then an immediate dead-name
1507  *			notification is generated.
1508  *	Conditions:
1509  *		Nothing locked.
1510  *	Returns:
1511  *		KERN_SUCCESS		Requested a notification.
1512  *		KERN_INVALID_TASK	The space is null.
1513  *		KERN_INVALID_TASK	The space is dead.
1514  *		KERN_INVALID_VALUE	Bad id value.
1515  *		KERN_INVALID_NAME	Name doesn't denote a right.
1516  *		KERN_INVALID_RIGHT	Name doesn't denote appropriate right.
1517  *		KERN_INVALID_CAPABILITY	The notify port is dead.
1518  *	MACH_NOTIFY_PORT_DESTROYED:
1519  *		KERN_INVALID_VALUE	Sync isn't zero.
1520  *		KERN_FAILURE		Re-registering for this notification
1521  *	MACH_NOTIFY_SERVICE_PORT_DESTROYED
1522  *		KERN_INVALID_CAPABILITY	Name is not a service port
1523  *		KERN_DENIED		Only launchd can set this notification or
1524  *					Launchd tried to register the old port
1525  *					destroyed notification
1526  *	MACH_NOTIFY_DEAD_NAME:
1527  *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
1528  *		KERN_INVALID_ARGUMENT	Name denotes dead name, but
1529  *			sync is zero or notify is IP_NULL.
1530  *		KERN_UREFS_OVERFLOW	Name denotes dead name, but
1531  *			generating immediate notif. would overflow urefs.
1532  */
1533 
1534 kern_return_t
mach_port_request_notification(ipc_space_t space,mach_port_name_t name,mach_msg_id_t id,mach_port_mscount_t sync,ipc_port_t notify,ipc_port_t * previousp)1535 mach_port_request_notification(
1536 	ipc_space_t             space,
1537 	mach_port_name_t        name,
1538 	mach_msg_id_t           id,
1539 	mach_port_mscount_t     sync,
1540 	ipc_port_t              notify,
1541 	ipc_port_t              *previousp)
1542 {
1543 	kern_return_t kr;
1544 
1545 	if (space == IS_NULL) {
1546 		return KERN_INVALID_TASK;
1547 	}
1548 
1549 	if (notify == IP_DEAD) {
1550 		return KERN_INVALID_CAPABILITY;
1551 	}
1552 
1553 	switch (id) {
1554 	case MACH_NOTIFY_PORT_DESTROYED: {
1555 		ipc_port_t port;
1556 
1557 		if (sync != 0) {
1558 			return KERN_INVALID_VALUE;
1559 		}
1560 
1561 		if (!MACH_PORT_VALID(name)) {
1562 			return KERN_INVALID_RIGHT;
1563 		}
1564 
1565 		kr = ipc_port_translate_receive(space, name, &port);
1566 		if (kr != KERN_SUCCESS) {
1567 			return kr;
1568 		}
1569 		/* port is locked and active */
1570 
1571 		/*
1572 		 * you cannot register for port death notifications on a kobject,
1573 		 * kolabel or special reply port
1574 		 */
1575 		if (ip_is_kobject(port) || ip_is_kolabeled(port) ||
1576 		    port->ip_specialreply) {
1577 			ip_mq_unlock(port);
1578 			mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_RIGHT);
1579 			return KERN_INVALID_RIGHT;
1580 		}
1581 
1582 		/* Allow only one registeration of this notification */
1583 		if (ipc_port_has_prdrequest(port)) {
1584 			ip_mq_unlock(port);
1585 			mach_port_guard_exception(name, 0, 0, kGUARD_EXC_KERN_FAILURE);
1586 			return KERN_FAILURE;
1587 		}
1588 
1589 		if (port->ip_has_watchport) {
1590 			port->ip_twe->twe_pdrequest = notify;
1591 		} else {
1592 			port->ip_pdrequest = notify;
1593 		}
1594 		ip_mq_unlock(port);
1595 		*previousp = IP_NULL;
1596 		break;
1597 	}
1598 
1599 	case MACH_NOTIFY_NO_SENDERS: {
1600 		ipc_port_t port;
1601 
1602 		if (!MACH_PORT_VALID(name)) {
1603 			return KERN_INVALID_RIGHT;
1604 		}
1605 
1606 		kr = ipc_port_translate_receive(space, name, &port);
1607 		if (kr != KERN_SUCCESS) {
1608 			return kr;
1609 		}
1610 		/* port is locked and active */
1611 
1612 		ipc_port_nsrequest(port, sync, notify, previousp);
1613 		/* port is unlocked */
1614 		break;
1615 	}
1616 
1617 	case MACH_NOTIFY_SEND_POSSIBLE:
1618 
1619 		if (!MACH_PORT_VALID(name)) {
1620 			return KERN_INVALID_ARGUMENT;
1621 		}
1622 
1623 		kr = ipc_right_request_alloc(space, name, sync != 0,
1624 		    TRUE, notify, previousp);
1625 		if (kr != KERN_SUCCESS) {
1626 			return kr;
1627 		}
1628 		break;
1629 
1630 	case MACH_NOTIFY_DEAD_NAME:
1631 
1632 		if (!MACH_PORT_VALID(name)) {
1633 			/*
1634 			 * Already dead.
1635 			 * Should do immediate delivery check -
1636 			 * will do that in the near future.
1637 			 */
1638 			return KERN_INVALID_ARGUMENT;
1639 		}
1640 
1641 		kr = ipc_right_request_alloc(space, name, sync != 0,
1642 		    FALSE, notify, previousp);
1643 		if (kr != KERN_SUCCESS) {
1644 			return kr;
1645 		}
1646 		break;
1647 
1648 	default:
1649 		return KERN_INVALID_VALUE;
1650 	}
1651 
1652 	return KERN_SUCCESS;
1653 }
1654 
1655 /*
1656  *	Routine:	mach_port_insert_right [kernel call]
1657  *	Purpose:
1658  *		Inserts a right into a space, as if the space
1659  *		voluntarily received the right in a message,
1660  *		except that the right gets the specified name.
1661  *	Conditions:
1662  *		Nothing locked.
1663  *	Returns:
1664  *		KERN_SUCCESS		Inserted the right.
1665  *		KERN_INVALID_TASK	The space is null.
1666  *		KERN_INVALID_TASK	The space is dead.
1667  *		KERN_INVALID_VALUE	The name isn't a legal name.
1668  *		KERN_NAME_EXISTS	The name already denotes a right.
1669  *		KERN_INVALID_VALUE	Message doesn't carry a port right.
1670  *		KERN_INVALID_CAPABILITY	Port is null or dead.
1671  *		KERN_UREFS_OVERFLOW	Urefs limit would be exceeded.
1672  *		KERN_RIGHT_EXISTS	Space has rights under another name.
1673  *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
1674  */
1675 
1676 kern_return_t
mach_port_insert_right(ipc_space_t space,mach_port_name_t name,ipc_port_t poly,mach_msg_type_name_t polyPoly)1677 mach_port_insert_right(
1678 	ipc_space_t                     space,
1679 	mach_port_name_t                name,
1680 	ipc_port_t                      poly,
1681 	mach_msg_type_name_t            polyPoly)
1682 {
1683 	if (space == IS_NULL) {
1684 		return KERN_INVALID_TASK;
1685 	}
1686 
1687 	if (!MACH_PORT_VALID(name) ||
1688 	    !MACH_MSG_TYPE_PORT_ANY_RIGHT(polyPoly)) {
1689 		return KERN_INVALID_VALUE;
1690 	}
1691 
1692 	if (!IP_VALID(poly)) {
1693 		return KERN_INVALID_CAPABILITY;
1694 	}
1695 
1696 	return ipc_object_copyout_name(space, ip_to_object(poly),
1697 	           polyPoly, name);
1698 }
1699 
1700 /*
1701  *	Routine:	mach_port_extract_right [kernel call]
1702  *	Purpose:
1703  *		Extracts a right from a space, as if the space
1704  *		voluntarily sent the right to the caller.
1705  *	Conditions:
1706  *		Nothing locked.
1707  *	Returns:
1708  *		KERN_SUCCESS		Extracted the right.
1709  *		KERN_INVALID_TASK	The space is null.
1710  *		KERN_INVALID_TASK	The space is dead.
1711  *		KERN_INVALID_VALUE	Requested type isn't a port right.
1712  *		KERN_INVALID_NAME	Name doesn't denote a right.
1713  *		KERN_INVALID_RIGHT	Name doesn't denote appropriate right.
1714  */
1715 
1716 kern_return_t
mach_port_extract_right(ipc_space_t space,mach_port_name_t name,mach_msg_type_name_t msgt_name,ipc_port_t * poly,mach_msg_type_name_t * polyPoly)1717 mach_port_extract_right(
1718 	ipc_space_t             space,
1719 	mach_port_name_t        name,
1720 	mach_msg_type_name_t    msgt_name,
1721 	ipc_port_t              *poly,
1722 	mach_msg_type_name_t    *polyPoly)
1723 {
1724 	kern_return_t kr;
1725 
1726 	if (space == IS_NULL) {
1727 		return KERN_INVALID_TASK;
1728 	}
1729 
1730 	if (!MACH_MSG_TYPE_PORT_ANY(msgt_name)) {
1731 		return KERN_INVALID_VALUE;
1732 	}
1733 
1734 	if (!MACH_PORT_VALID(name)) {
1735 		/*
1736 		 * really should copy out a dead name, if it is a send or
1737 		 * send-once right being copied, but instead return an
1738 		 * error for now.
1739 		 */
1740 		return KERN_INVALID_RIGHT;
1741 	}
1742 
1743 	kr = ipc_object_copyin(space, name, msgt_name, (ipc_object_t *) poly, 0, NULL,
1744 	    (space == current_space() && msgt_name == MACH_MSG_TYPE_COPY_SEND) ?
1745 	    IPC_OBJECT_COPYIN_FLAGS_ALLOW_IMMOVABLE_SEND : IPC_OBJECT_COPYIN_FLAGS_NONE);
1746 
1747 	if (kr == KERN_SUCCESS) {
1748 		*polyPoly = ipc_object_copyin_type(msgt_name);
1749 	}
1750 	return kr;
1751 }
1752 
1753 /*
1754  *	Routine:	mach_port_get_status_helper [helper]
1755  *	Purpose:
1756  *		Populates a mach_port_status_t structure with
1757  *		port information.
1758  *	Conditions:
1759  *		Port needs to be locked
1760  *	Returns:
1761  *		None.
1762  */
1763 static void
mach_port_get_status_helper(ipc_port_t port,mach_port_status_t * statusp)1764 mach_port_get_status_helper(
1765 	ipc_port_t              port,
1766 	mach_port_status_t      *statusp)
1767 {
1768 	/* don't leak set IDs, just indicate that the port is in one or not */
1769 	statusp->mps_pset = ip_in_pset(port);
1770 	statusp->mps_seqno = port->ip_messages.imq_seqno;
1771 	statusp->mps_qlimit = port->ip_messages.imq_qlimit;
1772 	statusp->mps_msgcount = port->ip_messages.imq_msgcount;
1773 
1774 	statusp->mps_mscount = port->ip_mscount;
1775 	statusp->mps_sorights = port->ip_sorights;
1776 	statusp->mps_srights = port->ip_srights > 0;
1777 	statusp->mps_pdrequest = ipc_port_has_prdrequest(port);
1778 	statusp->mps_nsrequest = port->ip_nsrequest != IP_NULL;
1779 	statusp->mps_flags = 0;
1780 	if (port->ip_impdonation) {
1781 		statusp->mps_flags |= MACH_PORT_STATUS_FLAG_IMP_DONATION;
1782 		if (port->ip_tempowner) {
1783 			statusp->mps_flags |= MACH_PORT_STATUS_FLAG_TEMPOWNER;
1784 			if (IIT_NULL != ip_get_imp_task(port)) {
1785 				statusp->mps_flags |= MACH_PORT_STATUS_FLAG_TASKPTR;
1786 			}
1787 		}
1788 	}
1789 	if (port->ip_guarded) {
1790 		statusp->mps_flags |= MACH_PORT_STATUS_FLAG_GUARDED;
1791 		if (port->ip_strict_guard) {
1792 			statusp->mps_flags |= MACH_PORT_STATUS_FLAG_STRICT_GUARD;
1793 		}
1794 		if (port->ip_immovable_receive) {
1795 			statusp->mps_flags |= MACH_PORT_STATUS_FLAG_GUARD_IMMOVABLE_RECEIVE;
1796 		}
1797 	}
1798 	if (port->ip_no_grant) {
1799 		statusp->mps_flags |= MACH_PORT_STATUS_FLAG_NO_GRANT;
1800 	}
1801 	return;
1802 }
1803 
1804 kern_return_t
mach_port_get_attributes(ipc_space_t space,mach_port_name_t name,int flavor,mach_port_info_t info,mach_msg_type_number_t * count)1805 mach_port_get_attributes(
1806 	ipc_space_t             space,
1807 	mach_port_name_t        name,
1808 	int                     flavor,
1809 	mach_port_info_t        info,
1810 	mach_msg_type_number_t  *count)
1811 {
1812 	ipc_port_t port;
1813 	kern_return_t kr;
1814 
1815 	if (space == IS_NULL) {
1816 		return KERN_INVALID_TASK;
1817 	}
1818 
1819 	switch (flavor) {
1820 	case MACH_PORT_LIMITS_INFO: {
1821 		mach_port_limits_t *lp = (mach_port_limits_t *)info;
1822 
1823 		if (*count < MACH_PORT_LIMITS_INFO_COUNT) {
1824 			return KERN_FAILURE;
1825 		}
1826 
1827 		if (!MACH_PORT_VALID(name)) {
1828 			*count = 0;
1829 			break;
1830 		}
1831 
1832 		kr = ipc_port_translate_receive(space, name, &port);
1833 		if (kr != KERN_SUCCESS) {
1834 			return kr;
1835 		}
1836 		/* port is locked and active */
1837 
1838 		lp->mpl_qlimit = port->ip_messages.imq_qlimit;
1839 		*count = MACH_PORT_LIMITS_INFO_COUNT;
1840 		ip_mq_unlock(port);
1841 		break;
1842 	}
1843 
1844 	case MACH_PORT_RECEIVE_STATUS: {
1845 		mach_port_status_t *statusp = (mach_port_status_t *)info;
1846 
1847 		if (*count < MACH_PORT_RECEIVE_STATUS_COUNT) {
1848 			return KERN_FAILURE;
1849 		}
1850 
1851 		if (!MACH_PORT_VALID(name)) {
1852 			return KERN_INVALID_RIGHT;
1853 		}
1854 
1855 		kr = ipc_port_translate_receive(space, name, &port);
1856 		if (kr != KERN_SUCCESS) {
1857 			return kr;
1858 		}
1859 		/* port is locked and active */
1860 		mach_port_get_status_helper(port, statusp);
1861 		*count = MACH_PORT_RECEIVE_STATUS_COUNT;
1862 		ip_mq_unlock(port);
1863 		break;
1864 	}
1865 
1866 	case MACH_PORT_DNREQUESTS_SIZE: {
1867 		ipc_port_request_t      table;
1868 
1869 		if (*count < MACH_PORT_DNREQUESTS_SIZE_COUNT) {
1870 			return KERN_FAILURE;
1871 		}
1872 
1873 		if (!MACH_PORT_VALID(name)) {
1874 			*(int *)info = 0;
1875 			break;
1876 		}
1877 
1878 		kr = ipc_port_translate_receive(space, name, &port);
1879 		if (kr != KERN_SUCCESS) {
1880 			return kr;
1881 		}
1882 		/* port is locked and active */
1883 
1884 		table = port->ip_requests;
1885 		if (table == IPR_NULL) {
1886 			*(int *)info = 0;
1887 		} else {
1888 			*(int *)info = table->ipr_size->its_size;
1889 		}
1890 		*count = MACH_PORT_DNREQUESTS_SIZE_COUNT;
1891 		ip_mq_unlock(port);
1892 		break;
1893 	}
1894 
1895 	case MACH_PORT_INFO_EXT: {
1896 		mach_port_info_ext_t *mp_info = (mach_port_info_ext_t *)info;
1897 		if (*count < MACH_PORT_INFO_EXT_COUNT) {
1898 			return KERN_FAILURE;
1899 		}
1900 
1901 		if (!MACH_PORT_VALID(name)) {
1902 			return KERN_INVALID_RIGHT;
1903 		}
1904 
1905 		kr = ipc_port_translate_receive(space, name, &port);
1906 		if (kr != KERN_SUCCESS) {
1907 			return kr;
1908 		}
1909 		/* port is locked and active */
1910 		mach_port_get_status_helper(port, &mp_info->mpie_status);
1911 		mp_info->mpie_boost_cnt = port->ip_impcount;
1912 		*count = MACH_PORT_INFO_EXT_COUNT;
1913 		ip_mq_unlock(port);
1914 		break;
1915 	}
1916 
1917 	default:
1918 		return KERN_INVALID_ARGUMENT;
1919 		/*NOTREACHED*/
1920 	}
1921 
1922 	return KERN_SUCCESS;
1923 }
1924 
1925 kern_return_t
mach_port_get_attributes_from_user(mach_port_t port,mach_port_name_t name,int flavor,mach_port_info_t info,mach_msg_type_number_t * count)1926 mach_port_get_attributes_from_user(
1927 	mach_port_t             port,
1928 	mach_port_name_t        name,
1929 	int                     flavor,
1930 	mach_port_info_t        info,
1931 	mach_msg_type_number_t  *count)
1932 {
1933 	kern_return_t kr;
1934 
1935 	ipc_space_t space = convert_port_to_space_read_no_eval(port);
1936 
1937 	if (space == IPC_SPACE_NULL) {
1938 		return KERN_INVALID_ARGUMENT;
1939 	}
1940 
1941 	kr = mach_port_get_attributes(space, name, flavor, info, count);
1942 
1943 	ipc_space_release(space);
1944 	return kr;
1945 }
1946 
1947 kern_return_t
mach_port_set_attributes(ipc_space_t space,mach_port_name_t name,int flavor,mach_port_info_t info,mach_msg_type_number_t count)1948 mach_port_set_attributes(
1949 	ipc_space_t             space,
1950 	mach_port_name_t        name,
1951 	int                     flavor,
1952 	mach_port_info_t        info,
1953 	mach_msg_type_number_t  count)
1954 {
1955 	ipc_port_t port;
1956 	kern_return_t kr;
1957 
1958 	if (space == IS_NULL) {
1959 		return KERN_INVALID_TASK;
1960 	}
1961 
1962 	switch (flavor) {
1963 	case MACH_PORT_LIMITS_INFO: {
1964 		mach_port_limits_t *mplp = (mach_port_limits_t *)info;
1965 
1966 		if (count < MACH_PORT_LIMITS_INFO_COUNT) {
1967 			return KERN_FAILURE;
1968 		}
1969 
1970 		if (mplp->mpl_qlimit > MACH_PORT_QLIMIT_MAX) {
1971 			return KERN_INVALID_VALUE;
1972 		}
1973 
1974 		if (!MACH_PORT_VALID(name)) {
1975 			return KERN_INVALID_RIGHT;
1976 		}
1977 
1978 		kr = ipc_port_translate_receive(space, name, &port);
1979 		if (kr != KERN_SUCCESS) {
1980 			return kr;
1981 		}
1982 		/* port is locked and active */
1983 
1984 		ipc_mqueue_set_qlimit_locked(&port->ip_messages, mplp->mpl_qlimit);
1985 		ip_mq_unlock(port);
1986 		break;
1987 	}
1988 	case MACH_PORT_DNREQUESTS_SIZE: {
1989 		if (count < MACH_PORT_DNREQUESTS_SIZE_COUNT) {
1990 			return KERN_FAILURE;
1991 		}
1992 
1993 		if (!MACH_PORT_VALID(name)) {
1994 			return KERN_INVALID_RIGHT;
1995 		}
1996 
1997 		kr = ipc_port_translate_receive(space, name, &port);
1998 		if (kr != KERN_SUCCESS) {
1999 			return kr;
2000 		}
2001 		/* port is locked and active */
2002 
2003 		kr = ipc_port_request_grow(port, *(int *)info);
2004 		if (kr != KERN_SUCCESS) {
2005 			return kr;
2006 		}
2007 		break;
2008 	}
2009 	case MACH_PORT_TEMPOWNER:
2010 		if (!MACH_PORT_VALID(name)) {
2011 			return KERN_INVALID_RIGHT;
2012 		}
2013 
2014 		ipc_importance_task_t release_imp_task = IIT_NULL;
2015 		natural_t assertcnt = 0;
2016 
2017 		kr = ipc_port_translate_receive(space, name, &port);
2018 		if (kr != KERN_SUCCESS) {
2019 			return kr;
2020 		}
2021 		/* port is locked and active */
2022 
2023 		/*
2024 		 * don't allow temp-owner importance donation if user
2025 		 * associated it with a kobject already (timer, host_notify target),
2026 		 * or is a special reply port.
2027 		 */
2028 		if (ip_is_kobject(port) || port->ip_specialreply) {
2029 			ip_mq_unlock(port);
2030 			return KERN_INVALID_ARGUMENT;
2031 		}
2032 
2033 		if (port->ip_tempowner != 0) {
2034 			if (IIT_NULL != ip_get_imp_task(port)) {
2035 				release_imp_task = ip_get_imp_task(port);
2036 				port->ip_imp_task = IIT_NULL;
2037 				assertcnt = port->ip_impcount;
2038 			}
2039 		} else {
2040 			assertcnt = port->ip_impcount;
2041 		}
2042 
2043 		port->ip_impdonation = 1;
2044 		port->ip_tempowner = 1;
2045 		ip_mq_unlock(port);
2046 
2047 #if IMPORTANCE_INHERITANCE
2048 		/* drop assertions from previous destination task */
2049 		if (release_imp_task != IIT_NULL) {
2050 			assert(ipc_importance_task_is_any_receiver_type(release_imp_task));
2051 			if (assertcnt > 0) {
2052 				ipc_importance_task_drop_internal_assertion(release_imp_task, assertcnt);
2053 			}
2054 			ipc_importance_task_release(release_imp_task);
2055 		} else if (assertcnt > 0) {
2056 			release_imp_task = current_task()->task_imp_base;
2057 			if (release_imp_task != IIT_NULL &&
2058 			    ipc_importance_task_is_any_receiver_type(release_imp_task)) {
2059 				ipc_importance_task_drop_internal_assertion(release_imp_task, assertcnt);
2060 			}
2061 		}
2062 #else
2063 		if (release_imp_task != IIT_NULL) {
2064 			ipc_importance_task_release(release_imp_task);
2065 		}
2066 #endif /* IMPORTANCE_INHERITANCE */
2067 
2068 		break;
2069 
2070 #if IMPORTANCE_INHERITANCE
2071 	case MACH_PORT_DENAP_RECEIVER:
2072 	case MACH_PORT_IMPORTANCE_RECEIVER:
2073 		if (!MACH_PORT_VALID(name)) {
2074 			return KERN_INVALID_RIGHT;
2075 		}
2076 
2077 		kr = ipc_port_translate_receive(space, name, &port);
2078 		if (kr != KERN_SUCCESS) {
2079 			return kr;
2080 		}
2081 
2082 		/*
2083 		 * don't allow importance donation if user associated
2084 		 * it with a kobject already (timer, host_notify target),
2085 		 * or is a special reply port.
2086 		 */
2087 		if (ip_is_kobject(port) || port->ip_specialreply) {
2088 			ip_mq_unlock(port);
2089 			return KERN_INVALID_ARGUMENT;
2090 		}
2091 
2092 		/* port is locked and active */
2093 		port->ip_impdonation = 1;
2094 		ip_mq_unlock(port);
2095 
2096 		break;
2097 #endif /* IMPORTANCE_INHERITANCE */
2098 
2099 	default:
2100 		return KERN_INVALID_ARGUMENT;
2101 		/*NOTREACHED*/
2102 	}
2103 	return KERN_SUCCESS;
2104 }
2105 
2106 /*
2107  *	Routine:	mach_port_insert_member [kernel call]
2108  *	Purpose:
2109  *		Add the receive right, specified by name, to
2110  *		a portset.
2111  *		The port cannot already be a member of the set.
2112  *	Conditions:
2113  *		Nothing locked.
2114  *	Returns:
2115  *		KERN_SUCCESS		Moved the port.
2116  *		KERN_INVALID_TASK	The space is null.
2117  *		KERN_INVALID_TASK	The space is dead.
2118  *		KERN_INVALID_NAME	name didn't denote a right.
2119  *		KERN_INVALID_RIGHT	name didn't denote a receive right.
2120  *		KERN_INVALID_NAME	pset_name didn't denote a right.
2121  *		KERN_INVALID_RIGHT	pset_name didn't denote a portset right.
2122  *		KERN_ALREADY_IN_SET	name was already a member of pset.
2123  */
2124 
2125 kern_return_t
mach_port_insert_member(ipc_space_t space,mach_port_name_t name,mach_port_name_t psname)2126 mach_port_insert_member(
2127 	ipc_space_t             space,
2128 	mach_port_name_t        name,
2129 	mach_port_name_t        psname)
2130 {
2131 	ipc_object_t obj;
2132 	ipc_object_t psobj;
2133 	kern_return_t kr;
2134 	ipc_port_t port = IP_NULL;
2135 	ipc_pset_t pset = IPS_NULL;
2136 	waitq_link_t link;
2137 
2138 	if (space == IS_NULL) {
2139 		return KERN_INVALID_TASK;
2140 	}
2141 
2142 	if (!MACH_PORT_VALID(name) || !MACH_PORT_VALID(psname)) {
2143 		return KERN_INVALID_RIGHT;
2144 	}
2145 
2146 	link = waitq_link_alloc(WQT_PORT_SET);
2147 
2148 	kr = ipc_object_translate_two(space,
2149 	    name, MACH_PORT_RIGHT_RECEIVE, &obj,
2150 	    psname, MACH_PORT_RIGHT_PORT_SET, &psobj);
2151 	if (kr != KERN_SUCCESS) {
2152 		goto done;
2153 	}
2154 
2155 	/* obj and psobj are locked (and were locked in that order) */
2156 	assert(psobj != IO_NULL);
2157 	assert(obj != IO_NULL);
2158 
2159 	port = ip_object_to_port(obj);
2160 	pset = ips_object_to_pset(psobj);
2161 
2162 	kr = ipc_mqueue_add_locked(&port->ip_messages, pset, &link);
2163 
2164 	ips_mq_unlock(pset);
2165 	ip_mq_unlock(port);
2166 
2167 done:
2168 	if (link.wqlh) {
2169 		waitq_link_free(WQT_PORT_SET, link);
2170 	}
2171 
2172 	return kr;
2173 }
2174 
2175 /*
2176  *	Routine:	mach_port_extract_member [kernel call]
2177  *	Purpose:
2178  *		Remove a port from one portset that it is a member of.
2179  *	Conditions:
2180  *		Nothing locked.
2181  *	Returns:
2182  *		KERN_SUCCESS		Moved the port.
2183  *		KERN_INVALID_TASK	The space is null.
2184  *		KERN_INVALID_TASK	The space is dead.
2185  *		KERN_INVALID_NAME	Member didn't denote a right.
2186  *		KERN_INVALID_RIGHT	Member didn't denote a receive right.
2187  *		KERN_INVALID_NAME	After didn't denote a right.
2188  *		KERN_INVALID_RIGHT	After didn't denote a port set right.
2189  *		KERN_NOT_IN_SET
2190  *			After is MACH_PORT_NULL and Member isn't in a port set.
2191  */
2192 
2193 kern_return_t
mach_port_extract_member(ipc_space_t space,mach_port_name_t name,mach_port_name_t psname)2194 mach_port_extract_member(
2195 	ipc_space_t             space,
2196 	mach_port_name_t        name,
2197 	mach_port_name_t        psname)
2198 {
2199 	ipc_object_t psobj;
2200 	ipc_object_t obj;
2201 	kern_return_t kr;
2202 	ipc_port_t port = IP_NULL;
2203 	ipc_pset_t pset = IPS_NULL;
2204 	waitq_link_t link;
2205 
2206 	if (space == IS_NULL) {
2207 		return KERN_INVALID_TASK;
2208 	}
2209 
2210 	if (!MACH_PORT_VALID(name) || !MACH_PORT_VALID(psname)) {
2211 		return KERN_INVALID_RIGHT;
2212 	}
2213 
2214 	kr = ipc_object_translate_two(space,
2215 	    name, MACH_PORT_RIGHT_RECEIVE, &obj,
2216 	    psname, MACH_PORT_RIGHT_PORT_SET, &psobj);
2217 	if (kr != KERN_SUCCESS) {
2218 		return kr;
2219 	}
2220 
2221 	/* obj and psobj are both locked (and were locked in that order) */
2222 	assert(psobj != IO_NULL);
2223 	assert(obj != IO_NULL);
2224 
2225 	port = ip_object_to_port(obj);
2226 	pset = ips_object_to_pset(psobj);
2227 
2228 	link = waitq_unlink_locked(&port->ip_waitq, &pset->ips_wqset);
2229 
2230 	ips_mq_unlock(pset);
2231 	ip_mq_unlock(port);
2232 
2233 	if (link.wqlh) {
2234 		waitq_link_free(WQT_PORT_SET, link);
2235 		return KERN_SUCCESS;
2236 	}
2237 
2238 	return KERN_NOT_IN_SET;
2239 }
2240 
2241 /*
2242  *	task_set_port_space:
2243  *
2244  *	Set port name space of task to specified size.
2245  */
2246 kern_return_t
task_set_port_space(ipc_space_t space,int table_entries)2247 task_set_port_space(
2248 	ipc_space_t     space,
2249 	int             table_entries)
2250 {
2251 	kern_return_t kr;
2252 
2253 	if (space == IS_NULL) {
2254 		return KERN_INVALID_TASK;
2255 	}
2256 
2257 	is_write_lock(space);
2258 
2259 	if (!is_active(space)) {
2260 		is_write_unlock(space);
2261 		return KERN_INVALID_TASK;
2262 	}
2263 
2264 	kr = ipc_entry_grow_table(space, table_entries);
2265 	if (kr == KERN_SUCCESS) {
2266 		is_write_unlock(space);
2267 	}
2268 	return kr;
2269 }
2270 
2271 /*
2272  *	Routine:	mach_port_guard_locked [helper routine]
2273  *	Purpose:
2274  *		Sets a new guard for a locked port.
2275  *	Conditions:
2276  *		Port Locked.
2277  *	Returns:
2278  *		KERN_SUCCESS		Port Guarded.
2279  *		KERN_INVALID_ARGUMENT	Port already contains a context/guard.
2280  */
2281 static kern_return_t
mach_port_guard_locked(ipc_port_t port,uint64_t guard,uint64_t flags)2282 mach_port_guard_locked(
2283 	ipc_port_t              port,
2284 	uint64_t                guard,
2285 	uint64_t                flags)
2286 {
2287 	if (port->ip_context) {
2288 		return KERN_INVALID_ARGUMENT;
2289 	}
2290 
2291 	int strict = (flags & MPG_STRICT)? 1 : 0;
2292 	int immovable_receive = (flags & MPG_IMMOVABLE_RECEIVE)? 1 : 0;
2293 
2294 	port->ip_context = guard;
2295 	port->ip_guarded = 1;
2296 	port->ip_strict_guard = strict;
2297 	/* ip_immovable_receive bit is sticky and can't be un-guarded */
2298 	if (!port->ip_immovable_receive) {
2299 		port->ip_immovable_receive = immovable_receive;
2300 	}
2301 
2302 	return KERN_SUCCESS;
2303 }
2304 
2305 /*
2306  *	Routine:	mach_port_unguard_locked [helper routine]
2307  *	Purpose:
2308  *		Removes guard for a locked port.
2309  *	Conditions:
2310  *		Port Locked.
2311  *	Returns:
2312  *		KERN_SUCCESS		Port Unguarded.
2313  *		KERN_INVALID_ARGUMENT	Port is either unguarded already or guard mismatch.
2314  *					This also raises a EXC_GUARD exception.
2315  */
2316 static kern_return_t
mach_port_unguard_locked(ipc_port_t port,mach_port_name_t name,uint64_t guard)2317 mach_port_unguard_locked(
2318 	ipc_port_t              port,
2319 	mach_port_name_t        name,
2320 	uint64_t                guard)
2321 {
2322 	/* Port locked and active */
2323 	if (!port->ip_guarded) {
2324 		/* Port already unguarded; Raise exception */
2325 		mach_port_guard_exception(name, guard, 0, kGUARD_EXC_UNGUARDED);
2326 		return KERN_INVALID_ARGUMENT;
2327 	}
2328 
2329 	if (port->ip_context != guard) {
2330 		/* Incorrect guard; Raise exception */
2331 		mach_port_guard_exception(name, guard, port->ip_context, kGUARD_EXC_INCORRECT_GUARD);
2332 		return KERN_INVALID_ARGUMENT;
2333 	}
2334 
2335 	port->ip_context = 0;
2336 	port->ip_guarded = port->ip_strict_guard = 0;
2337 	/* Don't clear the ip_immovable_receive bit */
2338 
2339 	return KERN_SUCCESS;
2340 }
2341 
2342 
2343 /*
2344  *	Routine:	mach_port_guard_exception [helper routine]
2345  *	Purpose:
2346  *		Marks the thread with AST_GUARD for mach port guard violation.
2347  *		Also saves exception info in thread structure.
2348  *	Conditions:
2349  *		None.
2350  *	Returns:
2351  *		KERN_FAILURE		Thread marked with AST_GUARD.
2352  */
2353 void
mach_port_guard_exception(mach_port_name_t name,__unused uint64_t inguard,uint64_t portguard,unsigned reason)2354 mach_port_guard_exception(
2355 	mach_port_name_t        name,
2356 	__unused uint64_t       inguard,
2357 	uint64_t                        portguard,
2358 	unsigned                        reason)
2359 {
2360 	mach_exception_code_t code = 0;
2361 	EXC_GUARD_ENCODE_TYPE(code, GUARD_TYPE_MACH_PORT);
2362 	EXC_GUARD_ENCODE_FLAVOR(code, reason);
2363 	EXC_GUARD_ENCODE_TARGET(code, name);
2364 	mach_exception_subcode_t subcode = (uint64_t)portguard;
2365 	thread_t t = current_thread();
2366 	boolean_t fatal = FALSE;
2367 
2368 	if (reason <= MAX_OPTIONAL_kGUARD_EXC_CODE &&
2369 	    (get_threadtask(t)->task_exc_guard & TASK_EXC_GUARD_MP_FATAL)) {
2370 		fatal = TRUE;
2371 	} else if (reason <= MAX_FATAL_kGUARD_EXC_CODE) {
2372 		fatal = TRUE;
2373 	}
2374 	thread_guard_violation(t, code, subcode, fatal);
2375 }
2376 
2377 /*
2378  * Deliver a soft or hard immovable guard exception.
2379  *
2380  * Conditions: port is marked as immovable.
2381  */
2382 void
mach_port_guard_exception_immovable(ipc_space_t space,mach_port_name_t name,mach_port_t port,uint64_t portguard)2383 mach_port_guard_exception_immovable(
2384 	ipc_space_t             space,
2385 	mach_port_name_t        name,
2386 	mach_port_t             port,
2387 	uint64_t                portguard)
2388 {
2389 	if (space == current_space()) {
2390 		assert(ip_is_immovable_send(port));
2391 
2392 		boolean_t hard = current_task()->task_control_port_options & TASK_CONTROL_PORT_IMMOVABLE_HARD;
2393 
2394 		if (ip_is_control(port)) {
2395 			assert(task_is_immovable(current_task()));
2396 			mach_port_guard_exception(name, 0, portguard,
2397 			    hard ? kGUARD_EXC_IMMOVABLE : kGUARD_EXC_IMMOVABLE_NON_FATAL);
2398 		} else {
2399 			/* always fatal exception for non-control port violation */
2400 			mach_port_guard_exception(name, 0, portguard, kGUARD_EXC_IMMOVABLE);
2401 		}
2402 	}
2403 }
2404 
2405 /*
2406  * Deliver a soft or hard immovable guard exception.
2407  *
2408  * Conditions: port is marked as immovable and pinned.
2409  */
2410 void
mach_port_guard_exception_pinned(ipc_space_t space,mach_port_name_t name,__assert_only mach_port_t port,uint64_t portguard)2411 mach_port_guard_exception_pinned(
2412 	ipc_space_t             space,
2413 	mach_port_name_t        name,
2414 	__assert_only mach_port_t port,
2415 	uint64_t                portguard)
2416 {
2417 	if (space == current_space()) {
2418 		assert(ip_is_immovable_send(port));
2419 		assert(ip_is_control(port)); /* only task/thread control ports can be pinned */
2420 
2421 		boolean_t hard = current_task()->task_control_port_options & TASK_CONTROL_PORT_PINNED_HARD;
2422 
2423 		assert(task_is_pinned(current_task()));
2424 
2425 		mach_port_guard_exception(name, 0, portguard,
2426 		    hard ? kGUARD_EXC_MOD_REFS : kGUARD_EXC_MOD_REFS_NON_FATAL);
2427 	}
2428 }
2429 
2430 /*
2431  *	Routine:	mach_port_guard_ast
2432  *	Purpose:
2433  *		Raises an exception for mach port guard violation.
2434  *	Conditions:
2435  *		None.
2436  *	Returns:
2437  *		None.
2438  */
2439 
2440 void
mach_port_guard_ast(thread_t t,mach_exception_data_type_t code,mach_exception_data_type_t subcode)2441 mach_port_guard_ast(thread_t t,
2442     mach_exception_data_type_t code, mach_exception_data_type_t subcode)
2443 {
2444 	unsigned int reason = EXC_GUARD_DECODE_GUARD_FLAVOR(code);
2445 	task_t task = get_threadtask(t);
2446 	unsigned int behavior = task->task_exc_guard;
2447 
2448 	assert(task == current_task());
2449 	assert(task != kernel_task);
2450 
2451 	switch (reason) {
2452 	/*
2453 	 * Fatal Mach port guards - always delivered synchronously
2454 	 */
2455 	case kGUARD_EXC_DESTROY:
2456 	case kGUARD_EXC_MOD_REFS:
2457 	case kGUARD_EXC_SET_CONTEXT:
2458 	case kGUARD_EXC_UNGUARDED:
2459 	case kGUARD_EXC_INCORRECT_GUARD:
2460 	case kGUARD_EXC_IMMOVABLE:
2461 	case kGUARD_EXC_STRICT_REPLY:
2462 	case kGUARD_EXC_MSG_FILTERED: {
2463 		/*
2464 		 * Check if anyone has registered for Synchronous EXC_GUARD, if yes then,
2465 		 * deliver it synchronously and then kill the process, else kill the process
2466 		 * and deliver the exception via EXC_CORPSE_NOTIFY.
2467 		 */
2468 		if (task_exception_notify(EXC_GUARD, code, subcode) == KERN_SUCCESS) {
2469 			task_bsdtask_kill(task);
2470 		} else {
2471 			exit_with_guard_exception(task->bsd_info, code, subcode);
2472 		}
2473 		break;
2474 	}
2475 
2476 	default:
2477 		/*
2478 		 * Mach port guards controlled by task settings.
2479 		 */
2480 
2481 		/* Is delivery enabled */
2482 		if ((behavior & TASK_EXC_GUARD_MP_DELIVER) == 0) {
2483 			return;
2484 		}
2485 
2486 		/* If only once, make sure we're that once */
2487 		while (behavior & TASK_EXC_GUARD_MP_ONCE) {
2488 			uint32_t new_behavior = behavior & ~TASK_EXC_GUARD_MP_DELIVER;
2489 
2490 			if (OSCompareAndSwap(behavior, new_behavior, &task->task_exc_guard)) {
2491 				break;
2492 			}
2493 			behavior = task->task_exc_guard;
2494 			if ((behavior & TASK_EXC_GUARD_MP_DELIVER) == 0) {
2495 				return;
2496 			}
2497 		}
2498 
2499 		kern_return_t sync_exception_result;
2500 		sync_exception_result = task_exception_notify(EXC_GUARD, code, subcode);
2501 
2502 		if (task->task_exc_guard & TASK_EXC_GUARD_MP_FATAL) {
2503 			if (reason >= MAX_OPTIONAL_kGUARD_EXC_CODE) {
2504 				/* generate a simulated crash if not handled synchronously */
2505 				if (sync_exception_result != KERN_SUCCESS) {
2506 					task_violated_guard(code, subcode, NULL);
2507 				}
2508 			} else {
2509 				/*
2510 				 * Only generate crash report if synchronous EXC_GUARD wasn't handled,
2511 				 * but it has to die regardless.
2512 				 */
2513 				if (sync_exception_result == KERN_SUCCESS) {
2514 					task_bsdtask_kill(task);
2515 				} else {
2516 					exit_with_guard_exception(task->bsd_info, code, subcode);
2517 				}
2518 			}
2519 		} else if (task->task_exc_guard & TASK_EXC_GUARD_MP_CORPSE) {
2520 			/* Raise exception via corpse fork if not handled synchronously */
2521 			if (sync_exception_result != KERN_SUCCESS) {
2522 				task_violated_guard(code, subcode, NULL);
2523 			}
2524 		}
2525 		break;
2526 	}
2527 }
2528 
2529 /*
2530  *	Routine:	mach_port_construct [kernel call]
2531  *	Purpose:
2532  *		Constructs a mach port with the provided set of options.
2533  *	Conditions:
2534  *		None.
2535  *	Returns:
2536  *		KERN_SUCCESS		The right is allocated.
2537  *		KERN_INVALID_TASK	The space is null.
2538  *		KERN_INVALID_TASK	The space is dead.
2539  *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
2540  *		KERN_NO_SPACE		No room in space for another right.
2541  *		KERN_FAILURE		Illegal option values requested.
2542  */
2543 
2544 kern_return_t
mach_port_construct(ipc_space_t space,mach_port_options_t * options,uint64_t context,mach_port_name_t * name)2545 mach_port_construct(
2546 	ipc_space_t             space,
2547 	mach_port_options_t     *options,
2548 	uint64_t                context,
2549 	mach_port_name_t        *name)
2550 {
2551 	kern_return_t           kr;
2552 	ipc_port_t              port;
2553 	ipc_port_init_flags_t   init_flags = IPC_PORT_INIT_MESSAGE_QUEUE;
2554 	void *port_splabel = NULL;
2555 	bool filter_msgs = FALSE;
2556 	struct mach_service_port_info sp_info = {};
2557 	size_t sp_name_length = 0;
2558 	user_addr_t service_port_info = 0;
2559 
2560 	uint32_t at_most_one_flags = options->flags & (MPO_SERVICE_PORT | MPO_CONNECTION_PORT | MPO_TG_BLOCK_TRACKING);
2561 	if (at_most_one_flags & (at_most_one_flags - 1)) {
2562 		/* at most one of the listed flags can be set */
2563 		return KERN_INVALID_ARGUMENT;
2564 	}
2565 
2566 	if (space == IS_NULL) {
2567 		return KERN_INVALID_TASK;
2568 	}
2569 
2570 	if (options->flags & MPO_INSERT_SEND_RIGHT) {
2571 		init_flags |= IPC_PORT_INIT_MAKE_SEND_RIGHT;
2572 	}
2573 
2574 	if (options->flags & MPO_FILTER_MSG) {
2575 		init_flags |= IPC_PORT_INIT_FILTER_MESSAGE;
2576 	}
2577 
2578 	if (options->flags & MPO_TG_BLOCK_TRACKING) {
2579 		/* Check the task role to allow only TASK_GRAPHICS_SERVER to set this option */
2580 		if (proc_get_effective_task_policy(current_task(),
2581 		    TASK_POLICY_ROLE) != TASK_GRAPHICS_SERVER) {
2582 			return KERN_DENIED;
2583 		}
2584 
2585 		/*
2586 		 * Check the work interval port passed in to make sure it is the render server type.
2587 		 * Since the creation of the render server work interval is privileged, this check
2588 		 * acts as a guard to make sure only the render server is setting the thread group
2589 		 * blocking behavior on the port.
2590 		 */
2591 		mach_port_name_t wi_port_name = options->work_interval_port;
2592 		if (work_interval_port_type_render_server(wi_port_name) == false) {
2593 			return KERN_INVALID_ARGUMENT;
2594 		}
2595 		init_flags |= IPC_PORT_INIT_TG_BLOCK_TRACKING;
2596 	}
2597 
2598 	if (options->flags & MPO_SERVICE_PORT) {
2599 #if !(DEVELOPMENT || DEBUG)
2600 #if CONFIG_COALITIONS
2601 		/*
2602 		 * Allow only launchd to add the service port labels
2603 		 * Not enforcing on development/debug kernels to
2604 		 * support testing
2605 		 */
2606 		if (!task_is_in_privileged_coalition(current_task(), COALITION_TYPE_JETSAM)) {
2607 			return KERN_DENIED;
2608 		}
2609 #else /* CONFIG_COALITIONS */
2610 		/*
2611 		 * This flag is not used by launchd on simulators
2612 		 */
2613 		if (proc_isinitproc(current_task()->bsd_info)) {
2614 			return KERN_DENIED;
2615 		}
2616 #endif /* CONFIG_COALITIONS */
2617 #endif /* !(DEVELOPMENT || DEBUG) */
2618 
2619 		if (task_has_64Bit_addr(current_task())) {
2620 			service_port_info = CAST_USER_ADDR_T(options->service_port_info64);
2621 		} else {
2622 			service_port_info = CAST_USER_ADDR_T(options->service_port_info32);
2623 		}
2624 
2625 		if (!service_port_info) {
2626 			return KERN_INVALID_ARGUMENT;
2627 		}
2628 
2629 		if (copyin(service_port_info, (void *)&sp_info, sizeof(sp_info))) {
2630 			return KERN_MEMORY_ERROR;
2631 		}
2632 
2633 		sp_name_length = strnlen(sp_info.mspi_string_name, MACH_SERVICE_PORT_INFO_STRING_NAME_MAX_BUF_LEN);
2634 		if (sp_name_length >= (MACH_SERVICE_PORT_INFO_STRING_NAME_MAX_BUF_LEN)) {
2635 			return KERN_INVALID_ARGUMENT;
2636 		}
2637 
2638 		kr = ipc_service_port_label_alloc(&sp_info, &port_splabel);
2639 		if (kr != KERN_SUCCESS) {
2640 			return kr;
2641 		}
2642 		/* Always filter messages on service ports */
2643 		init_flags |= IPC_PORT_INIT_FILTER_MESSAGE;
2644 	}
2645 
2646 	if (options->flags & MPO_CONNECTION_PORT) {
2647 		if (!options->service_port_name) {
2648 			return KERN_INVALID_ARGUMENT;
2649 		}
2650 
2651 		kr = ipc_service_port_derive_sblabel(options->service_port_name, &port_splabel, &filter_msgs);
2652 		if (kr != KERN_SUCCESS) {
2653 			return kr;
2654 		}
2655 		if (filter_msgs) {
2656 			init_flags |= IPC_PORT_INIT_FILTER_MESSAGE;
2657 		}
2658 	}
2659 
2660 	/* Allocate a new port in the IPC space */
2661 	kr = ipc_port_alloc(space, init_flags, name, &port);
2662 	if (kr != KERN_SUCCESS) {
2663 		if (port_splabel != NULL) {
2664 			ipc_service_port_label_dealloc(port_splabel,
2665 			    (options->flags & MPO_SERVICE_PORT));
2666 		}
2667 		return kr;
2668 	}
2669 
2670 	/* Port locked and active */
2671 	if (port_splabel != NULL) {
2672 		port->ip_service_port = (bool)(options->flags & MPO_SERVICE_PORT);
2673 		port->ip_splabel = port_splabel;
2674 	}
2675 
2676 	if (options->flags & MPO_CONTEXT_AS_GUARD) {
2677 		uint64_t flags = 0;
2678 		if (options->flags & MPO_STRICT) {
2679 			flags |= MPG_STRICT;
2680 		}
2681 		if (options->flags & MPO_IMMOVABLE_RECEIVE) {
2682 			flags |= MPG_IMMOVABLE_RECEIVE;
2683 		}
2684 		kr = mach_port_guard_locked(port, context, flags);
2685 		/* A newly allocated and locked port should always be guarded successfully */
2686 		assert(kr == KERN_SUCCESS);
2687 		if (options->flags & MPO_SERVICE_PORT) {
2688 			/*
2689 			 * Setting the guard on a service port triggers a special port destroyed notification
2690 			 * that restores the guard when the receive right moves back to launchd. This
2691 			 * must be a strict guard.
2692 			 */
2693 			assert((options->flags & MPO_STRICT) == MPO_STRICT);
2694 			ipc_service_port_label_set_attr(port_splabel, *name, (mach_port_context_t)context);
2695 		}
2696 	} else {
2697 		port->ip_context = context;
2698 		if (options->flags & MPO_SERVICE_PORT) {
2699 			ipc_service_port_label_set_attr(port_splabel, *name, 0);
2700 		}
2701 	}
2702 
2703 	/* Unlock port */
2704 	ip_mq_unlock(port);
2705 
2706 	/* Set port attributes as requested */
2707 
2708 	if (options->flags & MPO_QLIMIT) {
2709 		kr = mach_port_set_attributes(space, *name, MACH_PORT_LIMITS_INFO,
2710 		    (mach_port_info_t)&options->mpl, sizeof(options->mpl) / sizeof(int));
2711 		if (kr != KERN_SUCCESS) {
2712 			goto cleanup;
2713 		}
2714 	}
2715 
2716 	if (options->flags & MPO_TEMPOWNER) {
2717 		kr = mach_port_set_attributes(space, *name, MACH_PORT_TEMPOWNER, NULL, 0);
2718 		if (kr != KERN_SUCCESS) {
2719 			goto cleanup;
2720 		}
2721 	}
2722 
2723 	if (options->flags & MPO_IMPORTANCE_RECEIVER) {
2724 		kr = mach_port_set_attributes(space, *name, MACH_PORT_IMPORTANCE_RECEIVER, NULL, 0);
2725 		if (kr != KERN_SUCCESS) {
2726 			goto cleanup;
2727 		}
2728 	}
2729 
2730 	if (options->flags & MPO_DENAP_RECEIVER) {
2731 		kr = mach_port_set_attributes(space, *name, MACH_PORT_DENAP_RECEIVER, NULL, 0);
2732 		if (kr != KERN_SUCCESS) {
2733 			goto cleanup;
2734 		}
2735 	}
2736 
2737 	return KERN_SUCCESS;
2738 
2739 cleanup:
2740 	/* Attempt to destroy port. If its already destroyed by some other thread, we're done */
2741 	(void) mach_port_destruct(space, *name,
2742 	    (options->flags & MPO_INSERT_SEND_RIGHT) ? -1 : 0, context);
2743 	return kr;
2744 }
2745 
2746 /*
2747  *	Routine:	mach_port_destruct [kernel call]
2748  *	Purpose:
2749  *		Destroys a mach port with appropriate guard
2750  *	Conditions:
2751  *		None.
2752  *	Returns:
2753  *		KERN_SUCCESS		The name is destroyed.
2754  *		KERN_INVALID_TASK	The space is null.
2755  *		KERN_INVALID_TASK	The space is dead.
2756  *		KERN_INVALID_NAME	The name doesn't denote a right.
2757  *		KERN_INVALID_RIGHT	The right isn't correct.
2758  *		KERN_INVALID_VALUE	The delta for send right is incorrect.
2759  *		KERN_INVALID_ARGUMENT	Port is either unguarded already or guard mismatch.
2760  *					This also raises a EXC_GUARD exception.
2761  */
2762 
2763 kern_return_t
mach_port_destruct(ipc_space_t space,mach_port_name_t name,mach_port_delta_t srdelta,uint64_t guard)2764 mach_port_destruct(
2765 	ipc_space_t             space,
2766 	mach_port_name_t        name,
2767 	mach_port_delta_t       srdelta,
2768 	uint64_t                guard)
2769 {
2770 	kern_return_t           kr;
2771 	ipc_entry_t             entry;
2772 
2773 	if (space == IS_NULL) {
2774 		return KERN_INVALID_TASK;
2775 	}
2776 
2777 	if (!MACH_PORT_VALID(name)) {
2778 		return KERN_INVALID_NAME;
2779 	}
2780 
2781 	/* Remove reference for receive right */
2782 	kr = ipc_right_lookup_write(space, name, &entry);
2783 	if (kr != KERN_SUCCESS) {
2784 		mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_NAME);
2785 		return kr;
2786 	}
2787 	/* space is write-locked and active */
2788 	kr = ipc_right_destruct(space, name, entry, srdelta, guard);    /* unlocks */
2789 
2790 	return kr;
2791 }
2792 
2793 /*
2794  *	Routine:	mach_port_guard [kernel call]
2795  *	Purpose:
2796  *		Guard a mach port with specified guard value.
2797  *		The context field of the port is used as the guard.
2798  *	Conditions:
2799  *		None.
2800  *	Returns:
2801  *		KERN_SUCCESS		The name is destroyed.
2802  *		KERN_INVALID_TASK	The space is null.
2803  *		KERN_INVALID_TASK	The space is dead.
2804  *		KERN_INVALID_NAME	The name doesn't denote a right.
2805  *		KERN_INVALID_RIGHT	The right isn't correct.
2806  *		KERN_INVALID_ARGUMENT	Port already contains a context/guard.
2807  */
2808 kern_return_t
mach_port_guard(ipc_space_t space,mach_port_name_t name,uint64_t guard,boolean_t strict)2809 mach_port_guard(
2810 	ipc_space_t             space,
2811 	mach_port_name_t        name,
2812 	uint64_t                guard,
2813 	boolean_t               strict)
2814 {
2815 	kern_return_t           kr;
2816 	ipc_port_t              port;
2817 	uint64_t flags = 0;
2818 
2819 	if (space == IS_NULL) {
2820 		return KERN_INVALID_TASK;
2821 	}
2822 
2823 	if (!MACH_PORT_VALID(name)) {
2824 		return KERN_INVALID_NAME;
2825 	}
2826 
2827 	/* Guard can be applied only to receive rights */
2828 	kr = ipc_port_translate_receive(space, name, &port);
2829 	if (kr != KERN_SUCCESS) {
2830 		mach_port_guard_exception(name, 0, 0,
2831 		    ((KERN_INVALID_NAME == kr) ?
2832 		    kGUARD_EXC_INVALID_NAME :
2833 		    kGUARD_EXC_INVALID_RIGHT));
2834 		return kr;
2835 	}
2836 
2837 	/* Port locked and active */
2838 	if (strict) {
2839 		flags = MPG_STRICT;
2840 	}
2841 
2842 	kr = mach_port_guard_locked(port, guard, flags);
2843 	ip_mq_unlock(port);
2844 
2845 	if (KERN_INVALID_ARGUMENT == kr) {
2846 		mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_ARGUMENT);
2847 	}
2848 
2849 	return kr;
2850 }
2851 
2852 /*
2853  *	Routine:	mach_port_unguard [kernel call]
2854  *	Purpose:
2855  *		Unguard a mach port with specified guard value.
2856  *	Conditions:
2857  *		None.
2858  *	Returns:
2859  *		KERN_SUCCESS		The name is destroyed.
2860  *		KERN_INVALID_TASK	The space is null.
2861  *		KERN_INVALID_TASK	The space is dead.
2862  *		KERN_INVALID_NAME	The name doesn't denote a right.
2863  *		KERN_INVALID_RIGHT	The right isn't correct.
2864  *		KERN_INVALID_ARGUMENT	Port is either unguarded already or guard mismatch.
2865  *					This also raises a EXC_GUARD exception.
2866  */
2867 kern_return_t
mach_port_unguard(ipc_space_t space,mach_port_name_t name,uint64_t guard)2868 mach_port_unguard(
2869 	ipc_space_t             space,
2870 	mach_port_name_t        name,
2871 	uint64_t                guard)
2872 {
2873 	kern_return_t           kr;
2874 	ipc_port_t              port;
2875 
2876 	if (space == IS_NULL) {
2877 		return KERN_INVALID_TASK;
2878 	}
2879 
2880 	if (!MACH_PORT_VALID(name)) {
2881 		return KERN_INVALID_NAME;
2882 	}
2883 
2884 	kr = ipc_port_translate_receive(space, name, &port);
2885 	if (kr != KERN_SUCCESS) {
2886 		mach_port_guard_exception(name, 0, 0,
2887 		    ((KERN_INVALID_NAME == kr) ?
2888 		    kGUARD_EXC_INVALID_NAME :
2889 		    kGUARD_EXC_INVALID_RIGHT));
2890 		return kr;
2891 	}
2892 
2893 	/* Port locked and active */
2894 	kr = mach_port_unguard_locked(port, name, guard);
2895 	ip_mq_unlock(port);
2896 
2897 	return kr;
2898 }
2899 
2900 /*
2901  *	Routine:	mach_port_guard_with_flags [kernel call]
2902  *	Purpose:
2903  *		Guard a mach port with specified guard value and guard flags.
2904  *		The context field of the port is used as the guard.
2905  *	Conditions:
2906  *		Should hold receive right for that port
2907  *	Returns:
2908  *		KERN_SUCCESS		The name is destroyed.
2909  *		KERN_INVALID_TASK	The space is null.
2910  *		KERN_INVALID_TASK	The space is dead.
2911  *		KERN_INVALID_NAME	The name doesn't denote a right.
2912  *		KERN_INVALID_RIGHT	The right isn't correct.
2913  *		KERN_INVALID_ARGUMENT	Port already contains a context/guard.
2914  *		KERN_INVALID_CAPABILITY Cannot set MPG_IMMOVABLE_RECEIVE flag for a port with
2915  *					a movable port-destroyed notification port
2916  */
2917 kern_return_t
mach_port_guard_with_flags(ipc_space_t space,mach_port_name_t name,uint64_t guard,uint64_t flags)2918 mach_port_guard_with_flags(
2919 	ipc_space_t             space,
2920 	mach_port_name_t        name,
2921 	uint64_t                guard,
2922 	uint64_t                flags)
2923 {
2924 	kern_return_t           kr;
2925 	ipc_port_t              port;
2926 
2927 	if (space == IS_NULL) {
2928 		return KERN_INVALID_TASK;
2929 	}
2930 
2931 	if (!MACH_PORT_VALID(name)) {
2932 		return KERN_INVALID_NAME;
2933 	}
2934 
2935 	kr = ipc_port_translate_receive(space, name, &port);
2936 	if (kr != KERN_SUCCESS) {
2937 		mach_port_guard_exception(name, 0, 0,
2938 		    ((KERN_INVALID_NAME == kr) ?
2939 		    kGUARD_EXC_INVALID_NAME :
2940 		    kGUARD_EXC_INVALID_RIGHT));
2941 		return kr;
2942 	}
2943 
2944 	/* Port locked and active */
2945 	kr = mach_port_guard_locked(port, guard, flags);
2946 	ip_mq_unlock(port);
2947 
2948 	if (KERN_INVALID_ARGUMENT == kr) {
2949 		mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_ARGUMENT);
2950 	}
2951 
2952 	return kr;
2953 }
2954 
2955 /*
2956  *	Routine:	mach_port_swap_guard [kernel call]
2957  *	Purpose:
2958  *		Swap guard value.
2959  *	Conditions:
2960  *		Port should already be guarded.
2961  *	Returns:
2962  *		KERN_SUCCESS		The name is destroyed.
2963  *		KERN_INVALID_TASK	The space is null.
2964  *		KERN_INVALID_TASK	The space is dead.
2965  *		KERN_INVALID_NAME	The name doesn't denote a right.
2966  *		KERN_INVALID_RIGHT	The right isn't correct.
2967  *		KERN_INVALID_ARGUMENT	Port doesn't contain a guard; is strictly guarded
2968  *					or the old_guard doesnt match the context
2969  */
2970 kern_return_t
mach_port_swap_guard(ipc_space_t space,mach_port_name_t name,uint64_t old_guard,uint64_t new_guard)2971 mach_port_swap_guard(
2972 	ipc_space_t             space,
2973 	mach_port_name_t        name,
2974 	uint64_t                old_guard,
2975 	uint64_t                new_guard)
2976 {
2977 	kern_return_t           kr;
2978 	ipc_port_t              port;
2979 
2980 	if (space == IS_NULL) {
2981 		return KERN_INVALID_TASK;
2982 	}
2983 
2984 	if (!MACH_PORT_VALID(name)) {
2985 		return KERN_INVALID_NAME;
2986 	}
2987 
2988 	kr = ipc_port_translate_receive(space, name, &port);
2989 	if (kr != KERN_SUCCESS) {
2990 		mach_port_guard_exception(name, 0, 0,
2991 		    ((KERN_INVALID_NAME == kr) ?
2992 		    kGUARD_EXC_INVALID_NAME :
2993 		    kGUARD_EXC_INVALID_RIGHT));
2994 		return kr;
2995 	}
2996 
2997 	/* Port locked and active */
2998 	if (!port->ip_guarded) {
2999 		ip_mq_unlock(port);
3000 		mach_port_guard_exception(name, old_guard, 0, kGUARD_EXC_UNGUARDED);
3001 		return KERN_INVALID_ARGUMENT;
3002 	}
3003 
3004 	if (port->ip_strict_guard) {
3005 		uint64_t portguard = port->ip_context;
3006 		ip_mq_unlock(port);
3007 		/* For strictly guarded ports, disallow overwriting context; Raise Exception */
3008 		mach_port_guard_exception(name, old_guard, portguard, kGUARD_EXC_SET_CONTEXT);
3009 		return KERN_INVALID_ARGUMENT;
3010 	}
3011 
3012 	if (port->ip_context != old_guard) {
3013 		uint64_t portguard = port->ip_context;
3014 		ip_mq_unlock(port);
3015 		mach_port_guard_exception(name, old_guard, portguard, kGUARD_EXC_INCORRECT_GUARD);
3016 		return KERN_INVALID_ARGUMENT;
3017 	}
3018 
3019 	port->ip_context = new_guard;
3020 
3021 	ip_mq_unlock(port);
3022 
3023 	return KERN_SUCCESS;
3024 }
3025 
3026 kern_return_t
mach_port_is_connection_for_service(ipc_space_t space,mach_port_name_t connection_port_name,mach_port_name_t service_port_name,uint64_t * filter_policy_id)3027 mach_port_is_connection_for_service(
3028 	ipc_space_t space,
3029 	mach_port_name_t connection_port_name,
3030 	mach_port_name_t service_port_name,
3031 	uint64_t *filter_policy_id)
3032 {
3033 	mach_port_t service_port;
3034 	mach_port_t connection_port;
3035 	void *service_port_sblabel = NULL;
3036 	void *conn_port_sblabel = NULL;
3037 
3038 	kern_return_t ret;
3039 
3040 	if (space == IS_NULL) {
3041 		return KERN_INVALID_TASK;
3042 	}
3043 
3044 	if (!MACH_PORT_VALID(connection_port_name) || !MACH_PORT_VALID(service_port_name)) {
3045 		return KERN_INVALID_NAME;
3046 	}
3047 
3048 	if (!filter_policy_id) {
3049 		return KERN_INVALID_ARGUMENT;
3050 	}
3051 
3052 	if (!mach_msg_filter_at_least(MACH_MSG_FILTER_CALLBACKS_VERSION_1)) {
3053 		return KERN_NOT_SUPPORTED;
3054 	}
3055 
3056 	ret = ipc_port_translate_receive(space, service_port_name, &service_port);
3057 	if (ret) {
3058 		return ret;
3059 	}
3060 
3061 	if (!service_port->ip_service_port) {
3062 		ip_mq_unlock(service_port);
3063 		return KERN_INVALID_CAPABILITY;
3064 	}
3065 
3066 	/* Port is locked and active */
3067 	service_port_sblabel = ipc_service_port_get_sblabel(service_port);
3068 	if (service_port_sblabel) {
3069 		mach_msg_filter_retain_sblabel_callback(service_port_sblabel);
3070 	}
3071 	ip_mq_unlock(service_port);
3072 
3073 	if (!service_port_sblabel) {
3074 		/* Nothing to check */
3075 		*filter_policy_id = 0;
3076 		return KERN_SUCCESS;
3077 	}
3078 
3079 	ret = ipc_port_translate_receive(space, connection_port_name, &connection_port);
3080 	if (ret) {
3081 		mach_msg_filter_dealloc_service_port_sblabel_callback(service_port_sblabel);
3082 		return ret;
3083 	}
3084 	/* Port is locked and active */
3085 	conn_port_sblabel = ipc_service_port_get_sblabel(connection_port);
3086 	if (conn_port_sblabel) {
3087 		mach_msg_filter_retain_sblabel_callback(conn_port_sblabel);
3088 	}
3089 	ip_mq_unlock(connection_port);
3090 
3091 	/* This callback will release the sblabel references */
3092 	ret = mach_msg_filter_get_connection_port_filter_policy_callback(service_port_sblabel,
3093 	    conn_port_sblabel, filter_policy_id);
3094 
3095 	return ret;
3096 }
3097 
3098 #if CONFIG_SERVICE_PORT_INFO
3099 kern_return_t
mach_port_get_service_port_info(ipc_space_read_t space,mach_port_name_t name,mach_service_port_info_t sp_info)3100 mach_port_get_service_port_info(
3101 	ipc_space_read_t           space,
3102 	mach_port_name_t           name,
3103 	mach_service_port_info_t   sp_info)
3104 {
3105 	ipc_port_t port;
3106 	kern_return_t kr;
3107 
3108 	if (space == IS_NULL) {
3109 		return KERN_INVALID_TASK;
3110 	}
3111 
3112 	if (sp_info == NULL) {
3113 		return KERN_INVALID_ARGUMENT;
3114 	}
3115 
3116 	if (!MACH_PORT_VALID(name)) {
3117 		return KERN_INVALID_RIGHT;
3118 	}
3119 
3120 	kr = ipc_port_translate_receive(space, name, &port);
3121 	if (kr != KERN_SUCCESS) {
3122 		return kr;
3123 	}
3124 	/* port is locked and active */
3125 
3126 	if (!port->ip_service_port) {
3127 		ip_mq_unlock(port);
3128 		return KERN_INVALID_CAPABILITY;
3129 	}
3130 
3131 	assert(port->ip_splabel != NULL);
3132 	ipc_service_port_label_get_info((ipc_service_port_label_t)port->ip_splabel, sp_info);
3133 	ip_mq_unlock(port);
3134 
3135 	return KERN_SUCCESS;
3136 }
3137 
3138 #else /* CONFIG_SERVICE_PORT_INFO */
3139 
3140 kern_return_t
mach_port_get_service_port_info(__unused ipc_space_read_t space,__unused mach_port_name_t name,__unused mach_service_port_info_t sp_info)3141 mach_port_get_service_port_info(
3142 	__unused ipc_space_read_t           space,
3143 	__unused mach_port_name_t           name,
3144 	__unused mach_service_port_info_t   sp_info)
3145 {
3146 	return KERN_NOT_SUPPORTED;
3147 }
3148 #endif /* CONFIG_SERVICE_PORT_INFO */
3149 
3150 kern_return_t
mach_port_assert_attributes(ipc_space_t space,mach_port_name_t name,int flavor,mach_port_info_t info,mach_msg_type_number_t count)3151 mach_port_assert_attributes(
3152 	ipc_space_t             space,
3153 	mach_port_name_t        name,
3154 	int                     flavor,
3155 	mach_port_info_t        info,
3156 	mach_msg_type_number_t  count)
3157 {
3158 	ipc_port_t port;
3159 	kern_return_t kr;
3160 
3161 	if (space == IS_NULL) {
3162 		return KERN_INVALID_TASK;
3163 	}
3164 
3165 	switch (flavor) {
3166 	case MACH_PORT_GUARD_INFO: {
3167 		mach_port_guard_info_t *mpgi = (mach_port_guard_info_t *)(void *)info;
3168 
3169 		if (count < MACH_PORT_GUARD_INFO_COUNT) {
3170 			return KERN_FAILURE;
3171 		}
3172 
3173 		if (!MACH_PORT_VALID(name)) {
3174 			return KERN_INVALID_RIGHT;
3175 		}
3176 
3177 		kr = ipc_port_translate_receive(space, name, &port);
3178 		if (kr != KERN_SUCCESS) {
3179 			return kr;
3180 		}
3181 		/* port is locked and active */
3182 
3183 		/* Check if guard value matches else kill the process using fatal guard exception */
3184 		if (!port->ip_guarded) {
3185 			ip_mq_unlock(port);
3186 			/* Port already unguarded; Raise exception */
3187 			mach_port_guard_exception(name, mpgi->mpgi_guard, 0, kGUARD_EXC_UNGUARDED);
3188 			return KERN_INVALID_ARGUMENT;
3189 		}
3190 
3191 		if (!port->ip_strict_guard || (port->ip_context != mpgi->mpgi_guard)) {
3192 			ip_mq_unlock(port);
3193 			/* Incorrect guard; Raise exception */
3194 			mach_port_guard_exception(name, mpgi->mpgi_guard, port->ip_context, kGUARD_EXC_INCORRECT_GUARD);
3195 			return KERN_INVALID_ARGUMENT;
3196 		}
3197 
3198 		ip_mq_unlock(port);
3199 		break;
3200 	}
3201 	default:
3202 		return KERN_INVALID_ARGUMENT;
3203 	}
3204 	return KERN_SUCCESS;
3205 }
3206