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