xref: /xnu-10002.1.13/osfmk/ipc/mach_port.c (revision 1031c584a5e37aff177559b9f69dbd3c8c3fd30a)
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 	case MACH_PORT_SERVICE_THROTTLED: {
1938 		boolean_t *is_throttled = info;
1939 
1940 		if (!MACH_PORT_VALID(name)) {
1941 			return KERN_INVALID_RIGHT;
1942 		}
1943 
1944 		kr = ipc_port_translate_receive(space, name, &port);
1945 		if (kr != KERN_SUCCESS) {
1946 			return kr;
1947 		}
1948 		/* port is locked and active */
1949 
1950 		if (!port->ip_service_port) {
1951 			ip_mq_unlock(port);
1952 			return KERN_INVALID_CAPABILITY;
1953 		}
1954 
1955 		assert(port->ip_splabel != NULL);
1956 		*is_throttled = ipc_service_port_label_is_throttled((ipc_service_port_label_t)port->ip_splabel);
1957 		*count = MACH_PORT_SERVICE_THROTTLED_COUNT;
1958 		ip_mq_unlock(port);
1959 		break;
1960 	}
1961 
1962 	default:
1963 		return KERN_INVALID_ARGUMENT;
1964 		/*NOTREACHED*/
1965 	}
1966 
1967 	return KERN_SUCCESS;
1968 }
1969 
1970 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)1971 mach_port_get_attributes_from_user(
1972 	mach_port_t             port,
1973 	mach_port_name_t        name,
1974 	int                     flavor,
1975 	mach_port_info_t        info,
1976 	mach_msg_type_number_t  *count)
1977 {
1978 	kern_return_t kr;
1979 
1980 	ipc_space_t space = convert_port_to_space_read_no_eval(port);
1981 
1982 	if (space == IPC_SPACE_NULL) {
1983 		return KERN_INVALID_ARGUMENT;
1984 	}
1985 
1986 	kr = mach_port_get_attributes(space, name, flavor, info, count);
1987 
1988 	ipc_space_release(space);
1989 	return kr;
1990 }
1991 
1992 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)1993 mach_port_set_attributes(
1994 	ipc_space_t             space,
1995 	mach_port_name_t        name,
1996 	int                     flavor,
1997 	mach_port_info_t        info,
1998 	mach_msg_type_number_t  count)
1999 {
2000 	ipc_port_t port;
2001 	kern_return_t kr;
2002 
2003 	if (space == IS_NULL) {
2004 		return KERN_INVALID_TASK;
2005 	}
2006 
2007 	switch (flavor) {
2008 	case MACH_PORT_LIMITS_INFO: {
2009 		mach_port_limits_t *mplp = (mach_port_limits_t *)info;
2010 
2011 		if (count < MACH_PORT_LIMITS_INFO_COUNT) {
2012 			return KERN_FAILURE;
2013 		}
2014 
2015 		if (mplp->mpl_qlimit > MACH_PORT_QLIMIT_MAX) {
2016 			return KERN_INVALID_VALUE;
2017 		}
2018 
2019 		if (!MACH_PORT_VALID(name)) {
2020 			return KERN_INVALID_RIGHT;
2021 		}
2022 
2023 		kr = ipc_port_translate_receive(space, name, &port);
2024 		if (kr != KERN_SUCCESS) {
2025 			return kr;
2026 		}
2027 		/* port is locked and active */
2028 
2029 		ipc_mqueue_set_qlimit_locked(&port->ip_messages, mplp->mpl_qlimit);
2030 		ip_mq_unlock(port);
2031 		break;
2032 	}
2033 	case MACH_PORT_DNREQUESTS_SIZE: {
2034 		if (count < MACH_PORT_DNREQUESTS_SIZE_COUNT) {
2035 			return KERN_FAILURE;
2036 		}
2037 
2038 		if (!MACH_PORT_VALID(name)) {
2039 			return KERN_INVALID_RIGHT;
2040 		}
2041 
2042 		kr = ipc_port_translate_receive(space, name, &port);
2043 		if (kr != KERN_SUCCESS) {
2044 			return kr;
2045 		}
2046 		/* port is locked and active */
2047 		ip_mq_unlock(port);
2048 		break;
2049 	}
2050 	case MACH_PORT_TEMPOWNER: {
2051 		if (!MACH_PORT_VALID(name)) {
2052 			return KERN_INVALID_RIGHT;
2053 		}
2054 
2055 		ipc_importance_task_t release_imp_task = IIT_NULL;
2056 		natural_t assertcnt = 0;
2057 
2058 		kr = ipc_port_translate_receive(space, name, &port);
2059 		if (kr != KERN_SUCCESS) {
2060 			return kr;
2061 		}
2062 		/* port is locked and active */
2063 
2064 		/*
2065 		 * don't allow temp-owner importance donation if user
2066 		 * associated it with a kobject already (timer, host_notify target),
2067 		 * or is a special reply port.
2068 		 */
2069 		if (ip_is_kobject(port) || port->ip_specialreply) {
2070 			ip_mq_unlock(port);
2071 			return KERN_INVALID_ARGUMENT;
2072 		}
2073 
2074 		if (port->ip_tempowner != 0) {
2075 			if (IIT_NULL != ip_get_imp_task(port)) {
2076 				release_imp_task = ip_get_imp_task(port);
2077 				port->ip_imp_task = IIT_NULL;
2078 				assertcnt = port->ip_impcount;
2079 			}
2080 		} else {
2081 			assertcnt = port->ip_impcount;
2082 		}
2083 
2084 		port->ip_impdonation = 1;
2085 		port->ip_tempowner = 1;
2086 		ip_mq_unlock(port);
2087 
2088 #if IMPORTANCE_INHERITANCE
2089 		/* drop assertions from previous destination task */
2090 		if (release_imp_task != IIT_NULL) {
2091 			assert(ipc_importance_task_is_any_receiver_type(release_imp_task));
2092 			if (assertcnt > 0) {
2093 				ipc_importance_task_drop_internal_assertion(release_imp_task, assertcnt);
2094 			}
2095 			ipc_importance_task_release(release_imp_task);
2096 		} else if (assertcnt > 0) {
2097 			release_imp_task = current_task()->task_imp_base;
2098 			if (release_imp_task != IIT_NULL &&
2099 			    ipc_importance_task_is_any_receiver_type(release_imp_task)) {
2100 				ipc_importance_task_drop_internal_assertion(release_imp_task, assertcnt);
2101 			}
2102 		}
2103 #else
2104 		if (release_imp_task != IIT_NULL) {
2105 			ipc_importance_task_release(release_imp_task);
2106 		}
2107 #endif /* IMPORTANCE_INHERITANCE */
2108 
2109 		break;
2110 
2111 #if IMPORTANCE_INHERITANCE
2112 	case MACH_PORT_DENAP_RECEIVER:
2113 	case MACH_PORT_IMPORTANCE_RECEIVER:
2114 		if (!MACH_PORT_VALID(name)) {
2115 			return KERN_INVALID_RIGHT;
2116 		}
2117 
2118 		kr = ipc_port_translate_receive(space, name, &port);
2119 		if (kr != KERN_SUCCESS) {
2120 			return kr;
2121 		}
2122 
2123 		/*
2124 		 * don't allow importance donation if user associated
2125 		 * it with a kobject already (timer, host_notify target),
2126 		 * or is a special reply port.
2127 		 */
2128 		if (ip_is_kobject(port) || port->ip_specialreply) {
2129 			ip_mq_unlock(port);
2130 			return KERN_INVALID_ARGUMENT;
2131 		}
2132 
2133 		/* port is locked and active */
2134 		port->ip_impdonation = 1;
2135 		ip_mq_unlock(port);
2136 
2137 		break;
2138 #endif /* IMPORTANCE_INHERITANCE */
2139 	}
2140 
2141 	case MACH_PORT_SERVICE_THROTTLED: {
2142 		boolean_t is_throttled = *info;
2143 
2144 		if (!MACH_PORT_VALID(name)) {
2145 			return KERN_INVALID_RIGHT;
2146 		}
2147 
2148 		kr = ipc_port_translate_receive(space, name, &port);
2149 		if (kr != KERN_SUCCESS) {
2150 			return kr;
2151 		}
2152 		/* port is locked and active */
2153 
2154 		if (!port->ip_service_port) {
2155 			ip_mq_unlock(port);
2156 			return KERN_INVALID_CAPABILITY;
2157 		}
2158 
2159 		assert(port->ip_splabel != NULL);
2160 		if (is_throttled) {
2161 			ipc_service_port_label_set_flag(port->ip_splabel, ISPL_FLAGS_THROTTLED);
2162 		} else {
2163 			ipc_service_port_label_clear_flag(port->ip_splabel, ISPL_FLAGS_THROTTLED);
2164 		}
2165 		ip_mq_unlock(port);
2166 		break;
2167 	}
2168 
2169 	default:
2170 		return KERN_INVALID_ARGUMENT;
2171 		/*NOTREACHED*/
2172 	}
2173 	return KERN_SUCCESS;
2174 }
2175 
2176 /*
2177  *	Routine:	mach_port_insert_member [kernel call]
2178  *	Purpose:
2179  *		Add the receive right, specified by name, to
2180  *		a portset.
2181  *		The port cannot already be a member of the set.
2182  *	Conditions:
2183  *		Nothing locked.
2184  *	Returns:
2185  *		KERN_SUCCESS		Moved the port.
2186  *		KERN_INVALID_TASK	The space is null.
2187  *		KERN_INVALID_TASK	The space is dead.
2188  *		KERN_INVALID_NAME	name didn't denote a right.
2189  *		KERN_INVALID_RIGHT	name didn't denote a receive right.
2190  *		KERN_INVALID_NAME	pset_name didn't denote a right.
2191  *		KERN_INVALID_RIGHT	pset_name didn't denote a portset right.
2192  *		KERN_ALREADY_IN_SET	name was already a member of pset.
2193  */
2194 
2195 kern_return_t
mach_port_insert_member(ipc_space_t space,mach_port_name_t name,mach_port_name_t psname)2196 mach_port_insert_member(
2197 	ipc_space_t             space,
2198 	mach_port_name_t        name,
2199 	mach_port_name_t        psname)
2200 {
2201 	ipc_object_t obj;
2202 	ipc_object_t psobj;
2203 	kern_return_t kr;
2204 	ipc_port_t port = IP_NULL;
2205 	ipc_pset_t pset = IPS_NULL;
2206 	waitq_link_t link;
2207 
2208 	if (space == IS_NULL) {
2209 		return KERN_INVALID_TASK;
2210 	}
2211 
2212 	if (!MACH_PORT_VALID(name) || !MACH_PORT_VALID(psname)) {
2213 		return KERN_INVALID_RIGHT;
2214 	}
2215 
2216 	link = waitq_link_alloc(WQT_PORT_SET);
2217 
2218 	kr = ipc_object_translate_two(space,
2219 	    name, MACH_PORT_RIGHT_RECEIVE, &obj,
2220 	    psname, MACH_PORT_RIGHT_PORT_SET, &psobj);
2221 	if (kr != KERN_SUCCESS) {
2222 		goto done;
2223 	}
2224 
2225 	/* obj and psobj are locked (and were locked in that order) */
2226 	assert(psobj != IO_NULL);
2227 	assert(obj != IO_NULL);
2228 
2229 	port = ip_object_to_port(obj);
2230 	pset = ips_object_to_pset(psobj);
2231 
2232 	kr = ipc_mqueue_add_locked(&port->ip_messages, pset, &link);
2233 
2234 	ips_mq_unlock(pset);
2235 	ip_mq_unlock(port);
2236 
2237 done:
2238 	if (link.wqlh) {
2239 		waitq_link_free(WQT_PORT_SET, link);
2240 	}
2241 
2242 	return kr;
2243 }
2244 
2245 /*
2246  *	Routine:	mach_port_extract_member [kernel call]
2247  *	Purpose:
2248  *		Remove a port from one portset that it is a member of.
2249  *	Conditions:
2250  *		Nothing locked.
2251  *	Returns:
2252  *		KERN_SUCCESS		Moved the port.
2253  *		KERN_INVALID_TASK	The space is null.
2254  *		KERN_INVALID_TASK	The space is dead.
2255  *		KERN_INVALID_NAME	Member didn't denote a right.
2256  *		KERN_INVALID_RIGHT	Member didn't denote a receive right.
2257  *		KERN_INVALID_NAME	After didn't denote a right.
2258  *		KERN_INVALID_RIGHT	After didn't denote a port set right.
2259  *		KERN_NOT_IN_SET
2260  *			After is MACH_PORT_NULL and Member isn't in a port set.
2261  */
2262 
2263 kern_return_t
mach_port_extract_member(ipc_space_t space,mach_port_name_t name,mach_port_name_t psname)2264 mach_port_extract_member(
2265 	ipc_space_t             space,
2266 	mach_port_name_t        name,
2267 	mach_port_name_t        psname)
2268 {
2269 	ipc_object_t psobj;
2270 	ipc_object_t obj;
2271 	kern_return_t kr;
2272 	ipc_port_t port = IP_NULL;
2273 	ipc_pset_t pset = IPS_NULL;
2274 	waitq_link_t link;
2275 
2276 	if (space == IS_NULL) {
2277 		return KERN_INVALID_TASK;
2278 	}
2279 
2280 	if (!MACH_PORT_VALID(name) || !MACH_PORT_VALID(psname)) {
2281 		return KERN_INVALID_RIGHT;
2282 	}
2283 
2284 	kr = ipc_object_translate_two(space,
2285 	    name, MACH_PORT_RIGHT_RECEIVE, &obj,
2286 	    psname, MACH_PORT_RIGHT_PORT_SET, &psobj);
2287 	if (kr != KERN_SUCCESS) {
2288 		return kr;
2289 	}
2290 
2291 	/* obj and psobj are both locked (and were locked in that order) */
2292 	assert(psobj != IO_NULL);
2293 	assert(obj != IO_NULL);
2294 
2295 	port = ip_object_to_port(obj);
2296 	pset = ips_object_to_pset(psobj);
2297 
2298 	link = waitq_unlink_locked(&port->ip_waitq, &pset->ips_wqset);
2299 
2300 	ips_mq_unlock(pset);
2301 	ip_mq_unlock(port);
2302 
2303 	if (link.wqlh) {
2304 		waitq_link_free(WQT_PORT_SET, link);
2305 		return KERN_SUCCESS;
2306 	}
2307 
2308 	return KERN_NOT_IN_SET;
2309 }
2310 
2311 /*
2312  *	task_set_port_space:
2313  *
2314  *	Obsolete. Set port name space of task to specified size.
2315  */
2316 kern_return_t
task_set_port_space(ipc_space_t space,__unused int table_entries)2317 task_set_port_space(
2318 	ipc_space_t     space,
2319 	__unused int    table_entries)
2320 {
2321 	if (space == IS_NULL) {
2322 		return KERN_INVALID_TASK;
2323 	}
2324 
2325 	return KERN_SUCCESS;
2326 }
2327 
2328 /*
2329  *	Routine:	mach_port_guard_locked [helper routine]
2330  *	Purpose:
2331  *		Sets a new guard for a locked port.
2332  *	Conditions:
2333  *		Port Locked.
2334  *	Returns:
2335  *		KERN_SUCCESS		Port Guarded.
2336  *		KERN_INVALID_ARGUMENT	Port already contains a context/guard.
2337  */
2338 static kern_return_t
mach_port_guard_locked(ipc_port_t port,uint64_t guard,uint64_t flags)2339 mach_port_guard_locked(
2340 	ipc_port_t              port,
2341 	uint64_t                guard,
2342 	uint64_t                flags)
2343 {
2344 	if (port->ip_context) {
2345 		return KERN_INVALID_ARGUMENT;
2346 	}
2347 
2348 	int strict = (flags & MPG_STRICT)? 1 : 0;
2349 	int immovable_receive = (flags & MPG_IMMOVABLE_RECEIVE)? 1 : 0;
2350 
2351 	port->ip_context = guard;
2352 	port->ip_guarded = 1;
2353 	port->ip_strict_guard = strict;
2354 	/* ip_immovable_receive bit is sticky and can't be un-guarded */
2355 	if (!port->ip_immovable_receive) {
2356 		port->ip_immovable_receive = immovable_receive;
2357 	}
2358 
2359 	return KERN_SUCCESS;
2360 }
2361 
2362 /*
2363  *	Routine:	mach_port_unguard_locked [helper routine]
2364  *	Purpose:
2365  *		Removes guard for a locked port.
2366  *	Conditions:
2367  *		Port Locked.
2368  *	Returns:
2369  *		KERN_SUCCESS		Port Unguarded.
2370  *		KERN_INVALID_ARGUMENT	Port is either unguarded already or guard mismatch.
2371  *					This also raises a EXC_GUARD exception.
2372  */
2373 static kern_return_t
mach_port_unguard_locked(ipc_port_t port,mach_port_name_t name,uint64_t guard)2374 mach_port_unguard_locked(
2375 	ipc_port_t              port,
2376 	mach_port_name_t        name,
2377 	uint64_t                guard)
2378 {
2379 	/* Port locked and active */
2380 	if (!port->ip_guarded) {
2381 		/* Port already unguarded; Raise exception */
2382 		mach_port_guard_exception(name, guard, 0, kGUARD_EXC_UNGUARDED);
2383 		return KERN_INVALID_ARGUMENT;
2384 	}
2385 
2386 	if (port->ip_context != guard) {
2387 		/* Incorrect guard; Raise exception */
2388 		mach_port_guard_exception(name, guard, port->ip_context, kGUARD_EXC_INCORRECT_GUARD);
2389 		return KERN_INVALID_ARGUMENT;
2390 	}
2391 
2392 	port->ip_context = 0;
2393 	port->ip_guarded = port->ip_strict_guard = 0;
2394 	/* Don't clear the ip_immovable_receive bit */
2395 
2396 	return KERN_SUCCESS;
2397 }
2398 
2399 
2400 /*
2401  *	Routine:	mach_port_guard_exception [helper routine]
2402  *	Purpose:
2403  *		Marks the thread with AST_GUARD for mach port guard violation.
2404  *		Also saves exception info in thread structure.
2405  *	Conditions:
2406  *		None.
2407  *	Returns:
2408  *		KERN_FAILURE		Thread marked with AST_GUARD.
2409  */
2410 void
mach_port_guard_exception(mach_port_name_t name,__unused uint64_t inguard,uint64_t portguard,unsigned reason)2411 mach_port_guard_exception(
2412 	mach_port_name_t        name,
2413 	__unused uint64_t       inguard,
2414 	uint64_t                        portguard,
2415 	unsigned                        reason)
2416 {
2417 	mach_exception_code_t code = 0;
2418 	EXC_GUARD_ENCODE_TYPE(code, GUARD_TYPE_MACH_PORT);
2419 	EXC_GUARD_ENCODE_FLAVOR(code, reason);
2420 	EXC_GUARD_ENCODE_TARGET(code, name);
2421 	mach_exception_subcode_t subcode = (uint64_t)portguard;
2422 	thread_t t = current_thread();
2423 	boolean_t fatal = FALSE;
2424 
2425 	if (reason <= MAX_OPTIONAL_kGUARD_EXC_CODE &&
2426 	    (get_threadtask(t)->task_exc_guard & TASK_EXC_GUARD_MP_FATAL)) {
2427 		fatal = TRUE;
2428 	} else if (reason <= MAX_FATAL_kGUARD_EXC_CODE) {
2429 		fatal = TRUE;
2430 	}
2431 	thread_guard_violation(t, code, subcode, fatal);
2432 }
2433 
2434 /*
2435  * Deliver a soft or hard immovable guard exception.
2436  *
2437  * Conditions: port is marked as immovable.
2438  */
2439 void
mach_port_guard_exception_immovable(ipc_space_t space,mach_port_name_t name,mach_port_t port,uint64_t portguard)2440 mach_port_guard_exception_immovable(
2441 	ipc_space_t             space,
2442 	mach_port_name_t        name,
2443 	mach_port_t             port,
2444 	uint64_t                portguard)
2445 {
2446 	if (space == current_space()) {
2447 		assert(ip_is_immovable_send(port));
2448 
2449 		boolean_t hard = task_get_control_port_options(current_task()) & TASK_CONTROL_PORT_IMMOVABLE_HARD;
2450 
2451 		if (ip_is_control(port)) {
2452 			assert(task_is_immovable(current_task()));
2453 			mach_port_guard_exception(name, 0, portguard,
2454 			    hard ? kGUARD_EXC_IMMOVABLE : kGUARD_EXC_IMMOVABLE_NON_FATAL);
2455 		} else {
2456 			/* always fatal exception for non-control port violation */
2457 			mach_port_guard_exception(name, 0, portguard, kGUARD_EXC_IMMOVABLE);
2458 		}
2459 	}
2460 }
2461 
2462 /*
2463  * Deliver a soft or hard immovable guard exception.
2464  *
2465  * Conditions: port is marked as immovable and pinned.
2466  */
2467 void
mach_port_guard_exception_pinned(ipc_space_t space,mach_port_name_t name,__assert_only mach_port_t port,uint64_t portguard)2468 mach_port_guard_exception_pinned(
2469 	ipc_space_t             space,
2470 	mach_port_name_t        name,
2471 	__assert_only mach_port_t port,
2472 	uint64_t                portguard)
2473 {
2474 	if (space == current_space()) {
2475 		assert(ip_is_immovable_send(port));
2476 		assert(ip_is_control(port)); /* only task/thread control ports can be pinned */
2477 
2478 		boolean_t hard = task_get_control_port_options(current_task()) & TASK_CONTROL_PORT_PINNED_HARD;
2479 
2480 		assert(task_is_pinned(current_task()));
2481 
2482 		mach_port_guard_exception(name, 0, portguard,
2483 		    hard ? kGUARD_EXC_MOD_REFS : kGUARD_EXC_MOD_REFS_NON_FATAL);
2484 	}
2485 }
2486 
2487 /*
2488  *	Routine:	mach_port_guard_ast
2489  *	Purpose:
2490  *		Raises an exception for mach port guard violation.
2491  *	Conditions:
2492  *		None.
2493  *	Returns:
2494  *		None.
2495  */
2496 
2497 void
mach_port_guard_ast(thread_t t,mach_exception_data_type_t code,mach_exception_data_type_t subcode)2498 mach_port_guard_ast(thread_t t,
2499     mach_exception_data_type_t code, mach_exception_data_type_t subcode)
2500 {
2501 	unsigned int reason = EXC_GUARD_DECODE_GUARD_FLAVOR(code);
2502 	task_t task = get_threadtask(t);
2503 	unsigned int behavior = task->task_exc_guard;
2504 
2505 	assert(task == current_task());
2506 	assert(task != kernel_task);
2507 
2508 	if (reason <= MAX_FATAL_kGUARD_EXC_CODE) {
2509 		/*
2510 		 * Fatal Mach port guards - always delivered synchronously.
2511 		 * Check if anyone has registered for Synchronous EXC_GUARD, if yes then,
2512 		 * deliver it synchronously and then kill the process, else kill the process
2513 		 * and deliver the exception via EXC_CORPSE_NOTIFY.
2514 		 */
2515 		if (task_exception_notify(EXC_GUARD, code, subcode) == KERN_SUCCESS) {
2516 			task_bsdtask_kill(task);
2517 		} else {
2518 			exit_with_guard_exception(get_bsdtask_info(task), code, subcode);
2519 		}
2520 	} else {
2521 		/*
2522 		 * Mach port guards controlled by task settings.
2523 		 */
2524 
2525 		/* Is delivery enabled */
2526 		if ((behavior & TASK_EXC_GUARD_MP_DELIVER) == 0) {
2527 			return;
2528 		}
2529 
2530 		/* If only once, make sure we're that once */
2531 		while (behavior & TASK_EXC_GUARD_MP_ONCE) {
2532 			uint32_t new_behavior = behavior & ~TASK_EXC_GUARD_MP_DELIVER;
2533 
2534 			if (OSCompareAndSwap(behavior, new_behavior, &task->task_exc_guard)) {
2535 				break;
2536 			}
2537 			behavior = task->task_exc_guard;
2538 			if ((behavior & TASK_EXC_GUARD_MP_DELIVER) == 0) {
2539 				return;
2540 			}
2541 		}
2542 
2543 		kern_return_t sync_exception_result;
2544 		sync_exception_result = task_exception_notify(EXC_GUARD, code, subcode);
2545 
2546 		if (task->task_exc_guard & TASK_EXC_GUARD_MP_FATAL) {
2547 			if (reason > MAX_OPTIONAL_kGUARD_EXC_CODE) {
2548 				/* generate a simulated crash if not handled synchronously */
2549 				if (sync_exception_result != KERN_SUCCESS) {
2550 					task_violated_guard(code, subcode, NULL, TRUE);
2551 				}
2552 			} else {
2553 				/*
2554 				 * Only generate crash report if synchronous EXC_GUARD wasn't handled,
2555 				 * but it has to die regardless.
2556 				 */
2557 				if (sync_exception_result == KERN_SUCCESS) {
2558 					task_bsdtask_kill(task);
2559 				} else {
2560 					exit_with_guard_exception(get_bsdtask_info(task), code, subcode);
2561 				}
2562 			}
2563 		} else if (task->task_exc_guard & TASK_EXC_GUARD_MP_CORPSE) {
2564 			/* Raise exception via corpse fork if not handled synchronously */
2565 			if (sync_exception_result != KERN_SUCCESS) {
2566 				task_violated_guard(code, subcode, NULL, TRUE);
2567 			}
2568 		}
2569 	}
2570 }
2571 
2572 /*
2573  *	Routine:	mach_port_construct [kernel call]
2574  *	Purpose:
2575  *		Constructs a mach port with the provided set of options.
2576  *	Conditions:
2577  *		None.
2578  *	Returns:
2579  *		KERN_SUCCESS		The right is allocated.
2580  *		KERN_INVALID_TASK	The space is null.
2581  *		KERN_INVALID_TASK	The space is dead.
2582  *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
2583  *		KERN_NO_SPACE		No room in space for another right.
2584  *		KERN_FAILURE		Illegal option values requested.
2585  */
2586 
2587 kern_return_t
mach_port_construct(ipc_space_t space,mach_port_options_t * options,uint64_t context,mach_port_name_t * name)2588 mach_port_construct(
2589 	ipc_space_t             space,
2590 	mach_port_options_t     *options,
2591 	uint64_t                context,
2592 	mach_port_name_t        *name)
2593 {
2594 	kern_return_t           kr;
2595 	ipc_port_t              port;
2596 	ipc_port_init_flags_t   init_flags = IPC_PORT_INIT_MESSAGE_QUEUE;
2597 	void *port_splabel = NULL;
2598 	bool filter_msgs = FALSE;
2599 	struct mach_service_port_info sp_info = {};
2600 	size_t sp_name_length = 0;
2601 	user_addr_t service_port_info = 0;
2602 
2603 	uint32_t at_most_one_flags = options->flags & (MPO_SERVICE_PORT | MPO_CONNECTION_PORT | MPO_TG_BLOCK_TRACKING);
2604 	if (at_most_one_flags & (at_most_one_flags - 1)) {
2605 		/* at most one of the listed flags can be set */
2606 		return KERN_INVALID_ARGUMENT;
2607 	}
2608 
2609 	at_most_one_flags = options->flags & (MPO_REPLY_PORT | MPO_ENFORCE_REPLY_PORT_SEMANTICS |
2610 	    MPO_PROVISIONAL_ID_PROT_OPTOUT | MPO_PROVISIONAL_REPLY_PORT);
2611 	if (at_most_one_flags & (at_most_one_flags - 1)) {
2612 		/* at most one of the listed flags can be set */
2613 		return KERN_INVALID_ARGUMENT;
2614 	}
2615 
2616 	if (space == IS_NULL) {
2617 		return KERN_INVALID_TASK;
2618 	}
2619 
2620 	if (options->flags & MPO_INSERT_SEND_RIGHT) {
2621 		init_flags |= IPC_PORT_INIT_MAKE_SEND_RIGHT;
2622 	}
2623 
2624 	if (options->flags & MPO_FILTER_MSG) {
2625 		init_flags |= IPC_PORT_INIT_FILTER_MESSAGE;
2626 	}
2627 
2628 	if (options->flags & MPO_REPLY_PORT) {
2629 		init_flags |= IPC_PORT_INIT_REPLY;
2630 	}
2631 
2632 	if (options->flags & MPO_ENFORCE_REPLY_PORT_SEMANTICS) {
2633 		init_flags |= IPC_PORT_ENFORCE_REPLY_PORT_SEMANTICS;
2634 	}
2635 
2636 	if (options->flags & MPO_PROVISIONAL_ID_PROT_OPTOUT) {
2637 		init_flags |= IPC_PORT_INIT_PROVISIONAL_ID_PROT_OPTOUT;
2638 	}
2639 
2640 	if (options->flags & MPO_PROVISIONAL_REPLY_PORT) {
2641 		if (provisional_reply_port_enforced) {
2642 			init_flags |= IPC_PORT_INIT_REPLY;
2643 		} else {
2644 			init_flags |= IPC_PORT_INIT_PROVISIONAL_REPLY;
2645 		}
2646 	}
2647 
2648 	if (options->flags & MPO_TG_BLOCK_TRACKING) {
2649 		/* Check the task role to allow only TASK_GRAPHICS_SERVER to set this option */
2650 		if (proc_get_effective_task_policy(current_task(),
2651 		    TASK_POLICY_ROLE) != TASK_GRAPHICS_SERVER) {
2652 			return KERN_DENIED;
2653 		}
2654 
2655 		/*
2656 		 * Check the work interval port passed in to make sure it is the render server type.
2657 		 * Since the creation of the render server work interval is privileged, this check
2658 		 * acts as a guard to make sure only the render server is setting the thread group
2659 		 * blocking behavior on the port.
2660 		 */
2661 		mach_port_name_t wi_port_name = options->work_interval_port;
2662 		if (work_interval_port_type_render_server(wi_port_name) == false) {
2663 			return KERN_INVALID_ARGUMENT;
2664 		}
2665 		init_flags |= IPC_PORT_INIT_TG_BLOCK_TRACKING;
2666 	}
2667 
2668 	if (options->flags & MPO_SERVICE_PORT) {
2669 #if !(DEVELOPMENT || DEBUG)
2670 #if CONFIG_COALITIONS
2671 		/*
2672 		 * Allow only launchd to add the service port labels
2673 		 * Not enforcing on development/debug kernels to
2674 		 * support testing
2675 		 */
2676 		if (!task_is_in_privileged_coalition(current_task(), COALITION_TYPE_JETSAM)) {
2677 			return KERN_DENIED;
2678 		}
2679 #else /* CONFIG_COALITIONS */
2680 		/*
2681 		 * This flag is not used by launchd on simulators
2682 		 */
2683 		if (proc_isinitproc(get_bsdtask_info(current_task()))) {
2684 			return KERN_DENIED;
2685 		}
2686 #endif /* CONFIG_COALITIONS */
2687 #endif /* !(DEVELOPMENT || DEBUG) */
2688 
2689 		if (task_has_64Bit_addr(current_task())) {
2690 			service_port_info = CAST_USER_ADDR_T(options->service_port_info64);
2691 		} else {
2692 			service_port_info = CAST_USER_ADDR_T(options->service_port_info32);
2693 		}
2694 
2695 		if (!service_port_info) {
2696 			return KERN_INVALID_ARGUMENT;
2697 		}
2698 
2699 		if (copyin(service_port_info, (void *)&sp_info, sizeof(sp_info))) {
2700 			return KERN_MEMORY_ERROR;
2701 		}
2702 
2703 		sp_name_length = strnlen(sp_info.mspi_string_name, MACH_SERVICE_PORT_INFO_STRING_NAME_MAX_BUF_LEN);
2704 		if (sp_name_length >= (MACH_SERVICE_PORT_INFO_STRING_NAME_MAX_BUF_LEN)) {
2705 			return KERN_INVALID_ARGUMENT;
2706 		}
2707 
2708 		kr = ipc_service_port_label_alloc(&sp_info, &port_splabel);
2709 		if (kr != KERN_SUCCESS) {
2710 			return kr;
2711 		}
2712 		/* Always filter messages on service ports */
2713 		init_flags |= IPC_PORT_INIT_FILTER_MESSAGE;
2714 	}
2715 
2716 	if (options->flags & MPO_CONNECTION_PORT) {
2717 		if (!options->service_port_name) {
2718 			return KERN_INVALID_ARGUMENT;
2719 		}
2720 
2721 		kr = ipc_service_port_derive_sblabel(options->service_port_name, &port_splabel, &filter_msgs);
2722 		if (kr != KERN_SUCCESS) {
2723 			return kr;
2724 		}
2725 		if (filter_msgs) {
2726 			init_flags |= IPC_PORT_INIT_FILTER_MESSAGE;
2727 		}
2728 	}
2729 
2730 
2731 	/* Allocate a new port in the IPC space */
2732 	kr = ipc_port_alloc(space, init_flags, name, &port);
2733 	if (kr != KERN_SUCCESS) {
2734 		if (port_splabel != NULL) {
2735 			ipc_service_port_label_dealloc(port_splabel,
2736 			    (options->flags & MPO_SERVICE_PORT));
2737 		}
2738 		return kr;
2739 	}
2740 
2741 	/* Port locked and active */
2742 	if (port_splabel != NULL) {
2743 		port->ip_service_port = (bool)(options->flags & MPO_SERVICE_PORT);
2744 		port->ip_splabel = port_splabel;
2745 
2746 		/* Check if this is a service port */
2747 		if (service_port_defense_enabled && port->ip_service_port) {
2748 			port->ip_immovable_receive = true;
2749 		}
2750 
2751 		/* Check if this is a libxpc connection port */
2752 		if (!port->ip_service_port) {
2753 			assert(options->flags & MPO_CONNECTION_PORT);
2754 			port->ip_immovable_send = true;
2755 			port->ip_immovable_receive = true;
2756 		}
2757 	}
2758 
2759 	if (options->flags & MPO_CONTEXT_AS_GUARD) {
2760 		uint64_t flags = 0;
2761 		if (options->flags & MPO_STRICT) {
2762 			flags |= MPG_STRICT;
2763 		}
2764 		if (options->flags & MPO_IMMOVABLE_RECEIVE) {
2765 			flags |= MPG_IMMOVABLE_RECEIVE;
2766 		}
2767 		kr = mach_port_guard_locked(port, context, flags);
2768 		/* A newly allocated and locked port should always be guarded successfully */
2769 		assert(kr == KERN_SUCCESS);
2770 		if (options->flags & MPO_SERVICE_PORT) {
2771 			/*
2772 			 * Setting the guard on a service port triggers a special port destroyed notification
2773 			 * that restores the guard when the receive right moves back to launchd. This
2774 			 * must be a strict guard.
2775 			 */
2776 			assert((options->flags & MPO_STRICT) == MPO_STRICT);
2777 			ipc_service_port_label_set_attr(port_splabel, *name, (mach_port_context_t)context);
2778 		}
2779 	} else {
2780 		port->ip_context = context;
2781 		if (options->flags & MPO_SERVICE_PORT) {
2782 			ipc_service_port_label_set_attr(port_splabel, *name, 0);
2783 		}
2784 	}
2785 
2786 	/* Unlock port */
2787 	ip_mq_unlock(port);
2788 
2789 	/* Set port attributes as requested */
2790 
2791 	if (options->flags & MPO_QLIMIT) {
2792 		kr = mach_port_set_attributes(space, *name, MACH_PORT_LIMITS_INFO,
2793 		    (mach_port_info_t)&options->mpl, sizeof(options->mpl) / sizeof(int));
2794 		if (kr != KERN_SUCCESS) {
2795 			goto cleanup;
2796 		}
2797 	}
2798 
2799 	if (options->flags & MPO_TEMPOWNER) {
2800 		kr = mach_port_set_attributes(space, *name, MACH_PORT_TEMPOWNER, NULL, 0);
2801 		if (kr != KERN_SUCCESS) {
2802 			goto cleanup;
2803 		}
2804 	}
2805 
2806 	if (options->flags & MPO_IMPORTANCE_RECEIVER) {
2807 		kr = mach_port_set_attributes(space, *name, MACH_PORT_IMPORTANCE_RECEIVER, NULL, 0);
2808 		if (kr != KERN_SUCCESS) {
2809 			goto cleanup;
2810 		}
2811 	}
2812 
2813 	if (options->flags & MPO_DENAP_RECEIVER) {
2814 		kr = mach_port_set_attributes(space, *name, MACH_PORT_DENAP_RECEIVER, NULL, 0);
2815 		if (kr != KERN_SUCCESS) {
2816 			goto cleanup;
2817 		}
2818 	}
2819 
2820 	return KERN_SUCCESS;
2821 
2822 cleanup:
2823 	/* Attempt to destroy port. If its already destroyed by some other thread, we're done */
2824 	(void) mach_port_destruct(space, *name,
2825 	    (options->flags & MPO_INSERT_SEND_RIGHT) ? -1 : 0, context);
2826 	return kr;
2827 }
2828 
2829 /*
2830  *	Routine:	mach_port_destruct [kernel call]
2831  *	Purpose:
2832  *		Destroys a mach port with appropriate guard
2833  *	Conditions:
2834  *		None.
2835  *	Returns:
2836  *		KERN_SUCCESS		The name is destroyed.
2837  *		KERN_INVALID_TASK	The space is null.
2838  *		KERN_INVALID_TASK	The space is dead.
2839  *		KERN_INVALID_NAME	The name doesn't denote a right.
2840  *		KERN_INVALID_RIGHT	The right isn't correct.
2841  *		KERN_INVALID_VALUE	The delta for send right is incorrect.
2842  *		KERN_INVALID_ARGUMENT	Port is either unguarded already or guard mismatch.
2843  *					This also raises a EXC_GUARD exception.
2844  */
2845 
2846 kern_return_t
mach_port_destruct(ipc_space_t space,mach_port_name_t name,mach_port_delta_t srdelta,uint64_t guard)2847 mach_port_destruct(
2848 	ipc_space_t             space,
2849 	mach_port_name_t        name,
2850 	mach_port_delta_t       srdelta,
2851 	uint64_t                guard)
2852 {
2853 	kern_return_t           kr;
2854 	ipc_entry_t             entry;
2855 
2856 	if (space == IS_NULL) {
2857 		return KERN_INVALID_TASK;
2858 	}
2859 
2860 	if (!MACH_PORT_VALID(name)) {
2861 		return KERN_INVALID_NAME;
2862 	}
2863 
2864 	/* Remove reference for receive right */
2865 	kr = ipc_right_lookup_write(space, name, &entry);
2866 	if (kr != KERN_SUCCESS) {
2867 		mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_NAME);
2868 		return kr;
2869 	}
2870 	/* space is write-locked and active */
2871 	kr = ipc_right_destruct(space, name, entry, srdelta, guard);    /* unlocks */
2872 
2873 	return kr;
2874 }
2875 
2876 /*
2877  *	Routine:	mach_port_guard [kernel call]
2878  *	Purpose:
2879  *		Guard a mach port with specified guard value.
2880  *		The context field of the port is used as the guard.
2881  *	Conditions:
2882  *		None.
2883  *	Returns:
2884  *		KERN_SUCCESS		The name is destroyed.
2885  *		KERN_INVALID_TASK	The space is null.
2886  *		KERN_INVALID_TASK	The space is dead.
2887  *		KERN_INVALID_NAME	The name doesn't denote a right.
2888  *		KERN_INVALID_RIGHT	The right isn't correct.
2889  *		KERN_INVALID_ARGUMENT	Port already contains a context/guard.
2890  */
2891 kern_return_t
mach_port_guard(ipc_space_t space,mach_port_name_t name,uint64_t guard,boolean_t strict)2892 mach_port_guard(
2893 	ipc_space_t             space,
2894 	mach_port_name_t        name,
2895 	uint64_t                guard,
2896 	boolean_t               strict)
2897 {
2898 	kern_return_t           kr;
2899 	ipc_port_t              port;
2900 	uint64_t flags = 0;
2901 
2902 	if (space == IS_NULL) {
2903 		return KERN_INVALID_TASK;
2904 	}
2905 
2906 	if (!MACH_PORT_VALID(name)) {
2907 		return KERN_INVALID_NAME;
2908 	}
2909 
2910 	/* Guard can be applied only to receive rights */
2911 	kr = ipc_port_translate_receive(space, name, &port);
2912 	if (kr != KERN_SUCCESS) {
2913 		mach_port_guard_exception(name, 0, 0,
2914 		    ((KERN_INVALID_NAME == kr) ?
2915 		    kGUARD_EXC_INVALID_NAME :
2916 		    kGUARD_EXC_INVALID_RIGHT));
2917 		return kr;
2918 	}
2919 
2920 	/* Port locked and active */
2921 	if (strict) {
2922 		flags = MPG_STRICT;
2923 	}
2924 
2925 	kr = mach_port_guard_locked(port, guard, flags);
2926 	ip_mq_unlock(port);
2927 
2928 	if (KERN_INVALID_ARGUMENT == kr) {
2929 		mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_ARGUMENT);
2930 	}
2931 
2932 	return kr;
2933 }
2934 
2935 /*
2936  *	Routine:	mach_port_unguard [kernel call]
2937  *	Purpose:
2938  *		Unguard a mach port with specified guard value.
2939  *	Conditions:
2940  *		None.
2941  *	Returns:
2942  *		KERN_SUCCESS		The name is destroyed.
2943  *		KERN_INVALID_TASK	The space is null.
2944  *		KERN_INVALID_TASK	The space is dead.
2945  *		KERN_INVALID_NAME	The name doesn't denote a right.
2946  *		KERN_INVALID_RIGHT	The right isn't correct.
2947  *		KERN_INVALID_ARGUMENT	Port is either unguarded already or guard mismatch.
2948  *					This also raises a EXC_GUARD exception.
2949  */
2950 kern_return_t
mach_port_unguard(ipc_space_t space,mach_port_name_t name,uint64_t guard)2951 mach_port_unguard(
2952 	ipc_space_t             space,
2953 	mach_port_name_t        name,
2954 	uint64_t                guard)
2955 {
2956 	kern_return_t           kr;
2957 	ipc_port_t              port;
2958 
2959 	if (space == IS_NULL) {
2960 		return KERN_INVALID_TASK;
2961 	}
2962 
2963 	if (!MACH_PORT_VALID(name)) {
2964 		return KERN_INVALID_NAME;
2965 	}
2966 
2967 	kr = ipc_port_translate_receive(space, name, &port);
2968 	if (kr != KERN_SUCCESS) {
2969 		mach_port_guard_exception(name, 0, 0,
2970 		    ((KERN_INVALID_NAME == kr) ?
2971 		    kGUARD_EXC_INVALID_NAME :
2972 		    kGUARD_EXC_INVALID_RIGHT));
2973 		return kr;
2974 	}
2975 
2976 	/* Port locked and active */
2977 	kr = mach_port_unguard_locked(port, name, guard);
2978 	ip_mq_unlock(port);
2979 
2980 	return kr;
2981 }
2982 
2983 /*
2984  *	Routine:	mach_port_guard_with_flags [kernel call]
2985  *	Purpose:
2986  *		Guard a mach port with specified guard value and guard flags.
2987  *		The context field of the port is used as the guard.
2988  *	Conditions:
2989  *		Should hold receive right for that port
2990  *	Returns:
2991  *		KERN_SUCCESS		The name is destroyed.
2992  *		KERN_INVALID_TASK	The space is null.
2993  *		KERN_INVALID_TASK	The space is dead.
2994  *		KERN_INVALID_NAME	The name doesn't denote a right.
2995  *		KERN_INVALID_RIGHT	The right isn't correct.
2996  *		KERN_INVALID_ARGUMENT	Port already contains a context/guard.
2997  *		KERN_INVALID_CAPABILITY Cannot set MPG_IMMOVABLE_RECEIVE flag for a port with
2998  *					a movable port-destroyed notification port
2999  */
3000 kern_return_t
mach_port_guard_with_flags(ipc_space_t space,mach_port_name_t name,uint64_t guard,uint64_t flags)3001 mach_port_guard_with_flags(
3002 	ipc_space_t             space,
3003 	mach_port_name_t        name,
3004 	uint64_t                guard,
3005 	uint64_t                flags)
3006 {
3007 	kern_return_t           kr;
3008 	ipc_port_t              port;
3009 
3010 	if (space == IS_NULL) {
3011 		return KERN_INVALID_TASK;
3012 	}
3013 
3014 	if (!MACH_PORT_VALID(name)) {
3015 		return KERN_INVALID_NAME;
3016 	}
3017 
3018 	kr = ipc_port_translate_receive(space, name, &port);
3019 	if (kr != KERN_SUCCESS) {
3020 		mach_port_guard_exception(name, 0, 0,
3021 		    ((KERN_INVALID_NAME == kr) ?
3022 		    kGUARD_EXC_INVALID_NAME :
3023 		    kGUARD_EXC_INVALID_RIGHT));
3024 		return kr;
3025 	}
3026 
3027 	/* Port locked and active */
3028 	kr = mach_port_guard_locked(port, guard, flags);
3029 	ip_mq_unlock(port);
3030 
3031 	if (KERN_INVALID_ARGUMENT == kr) {
3032 		mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_ARGUMENT);
3033 	}
3034 
3035 	return kr;
3036 }
3037 
3038 /*
3039  *	Routine:	mach_port_swap_guard [kernel call]
3040  *	Purpose:
3041  *		Swap guard value.
3042  *	Conditions:
3043  *		Port should already be guarded.
3044  *	Returns:
3045  *		KERN_SUCCESS		The name is destroyed.
3046  *		KERN_INVALID_TASK	The space is null.
3047  *		KERN_INVALID_TASK	The space is dead.
3048  *		KERN_INVALID_NAME	The name doesn't denote a right.
3049  *		KERN_INVALID_RIGHT	The right isn't correct.
3050  *		KERN_INVALID_ARGUMENT	Port doesn't contain a guard; is strictly guarded
3051  *					or the old_guard doesnt match the context
3052  */
3053 kern_return_t
mach_port_swap_guard(ipc_space_t space,mach_port_name_t name,uint64_t old_guard,uint64_t new_guard)3054 mach_port_swap_guard(
3055 	ipc_space_t             space,
3056 	mach_port_name_t        name,
3057 	uint64_t                old_guard,
3058 	uint64_t                new_guard)
3059 {
3060 	kern_return_t           kr;
3061 	ipc_port_t              port;
3062 
3063 	if (space == IS_NULL) {
3064 		return KERN_INVALID_TASK;
3065 	}
3066 
3067 	if (!MACH_PORT_VALID(name)) {
3068 		return KERN_INVALID_NAME;
3069 	}
3070 
3071 	kr = ipc_port_translate_receive(space, name, &port);
3072 	if (kr != KERN_SUCCESS) {
3073 		mach_port_guard_exception(name, 0, 0,
3074 		    ((KERN_INVALID_NAME == kr) ?
3075 		    kGUARD_EXC_INVALID_NAME :
3076 		    kGUARD_EXC_INVALID_RIGHT));
3077 		return kr;
3078 	}
3079 
3080 	/* Port locked and active */
3081 	if (!port->ip_guarded) {
3082 		ip_mq_unlock(port);
3083 		mach_port_guard_exception(name, old_guard, 0, kGUARD_EXC_UNGUARDED);
3084 		return KERN_INVALID_ARGUMENT;
3085 	}
3086 
3087 	if (port->ip_strict_guard) {
3088 		uint64_t portguard = port->ip_context;
3089 		ip_mq_unlock(port);
3090 		/* For strictly guarded ports, disallow overwriting context; Raise Exception */
3091 		mach_port_guard_exception(name, old_guard, portguard, kGUARD_EXC_SET_CONTEXT);
3092 		return KERN_INVALID_ARGUMENT;
3093 	}
3094 
3095 	if (port->ip_context != old_guard) {
3096 		uint64_t portguard = port->ip_context;
3097 		ip_mq_unlock(port);
3098 		mach_port_guard_exception(name, old_guard, portguard, kGUARD_EXC_INCORRECT_GUARD);
3099 		return KERN_INVALID_ARGUMENT;
3100 	}
3101 
3102 	port->ip_context = new_guard;
3103 
3104 	ip_mq_unlock(port);
3105 
3106 	return KERN_SUCCESS;
3107 }
3108 
3109 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)3110 mach_port_is_connection_for_service(
3111 	ipc_space_t space,
3112 	mach_port_name_t connection_port_name,
3113 	mach_port_name_t service_port_name,
3114 	uint64_t *filter_policy_id)
3115 {
3116 	mach_port_t service_port;
3117 	mach_port_t connection_port;
3118 	void *service_port_sblabel = NULL;
3119 	void *conn_port_sblabel = NULL;
3120 
3121 	kern_return_t ret;
3122 
3123 	if (space == IS_NULL) {
3124 		return KERN_INVALID_TASK;
3125 	}
3126 
3127 	if (!MACH_PORT_VALID(connection_port_name) || !MACH_PORT_VALID(service_port_name)) {
3128 		return KERN_INVALID_NAME;
3129 	}
3130 
3131 	if (!filter_policy_id) {
3132 		return KERN_INVALID_ARGUMENT;
3133 	}
3134 
3135 	if (!mach_msg_filter_at_least(MACH_MSG_FILTER_CALLBACKS_VERSION_1)) {
3136 		return KERN_NOT_SUPPORTED;
3137 	}
3138 
3139 	ret = ipc_port_translate_receive(space, service_port_name, &service_port);
3140 	if (ret) {
3141 		return ret;
3142 	}
3143 
3144 	if (!service_port->ip_service_port) {
3145 		ip_mq_unlock(service_port);
3146 		return KERN_INVALID_CAPABILITY;
3147 	}
3148 
3149 	/* Port is locked and active */
3150 	service_port_sblabel = ipc_service_port_get_sblabel(service_port);
3151 	if (service_port_sblabel) {
3152 		mach_msg_filter_retain_sblabel_callback(service_port_sblabel);
3153 	}
3154 	ip_mq_unlock(service_port);
3155 
3156 	if (!service_port_sblabel) {
3157 		/* Nothing to check */
3158 		*filter_policy_id = 0;
3159 		return KERN_SUCCESS;
3160 	}
3161 
3162 	ret = ipc_port_translate_receive(space, connection_port_name, &connection_port);
3163 	if (ret) {
3164 		mach_msg_filter_dealloc_service_port_sblabel_callback(service_port_sblabel);
3165 		return ret;
3166 	}
3167 	/* Port is locked and active */
3168 	conn_port_sblabel = ipc_service_port_get_sblabel(connection_port);
3169 	if (conn_port_sblabel) {
3170 		mach_msg_filter_retain_sblabel_callback(conn_port_sblabel);
3171 	}
3172 	ip_mq_unlock(connection_port);
3173 
3174 	/* This callback will release the sblabel references */
3175 	ret = mach_msg_filter_get_connection_port_filter_policy_callback(service_port_sblabel,
3176 	    conn_port_sblabel, filter_policy_id);
3177 
3178 	return ret;
3179 }
3180 
3181 #if CONFIG_SERVICE_PORT_INFO
3182 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)3183 mach_port_get_service_port_info(
3184 	ipc_space_read_t           space,
3185 	mach_port_name_t           name,
3186 	mach_service_port_info_t   sp_info)
3187 {
3188 	ipc_port_t port;
3189 	kern_return_t kr;
3190 
3191 	if (space == IS_NULL) {
3192 		return KERN_INVALID_TASK;
3193 	}
3194 
3195 	if (sp_info == NULL) {
3196 		return KERN_INVALID_ARGUMENT;
3197 	}
3198 
3199 	if (!MACH_PORT_VALID(name)) {
3200 		return KERN_INVALID_RIGHT;
3201 	}
3202 
3203 	kr = ipc_port_translate_receive(space, name, &port);
3204 	if (kr != KERN_SUCCESS) {
3205 		return kr;
3206 	}
3207 	/* port is locked and active */
3208 
3209 	if (!port->ip_service_port) {
3210 		ip_mq_unlock(port);
3211 		return KERN_INVALID_CAPABILITY;
3212 	}
3213 
3214 	assert(port->ip_splabel != NULL);
3215 	ipc_service_port_label_get_info((ipc_service_port_label_t)port->ip_splabel, sp_info);
3216 	ip_mq_unlock(port);
3217 
3218 	return KERN_SUCCESS;
3219 }
3220 
3221 #else /* CONFIG_SERVICE_PORT_INFO */
3222 
3223 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)3224 mach_port_get_service_port_info(
3225 	__unused ipc_space_read_t           space,
3226 	__unused mach_port_name_t           name,
3227 	__unused mach_service_port_info_t   sp_info)
3228 {
3229 	return KERN_NOT_SUPPORTED;
3230 }
3231 #endif /* CONFIG_SERVICE_PORT_INFO */
3232 
3233 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)3234 mach_port_assert_attributes(
3235 	ipc_space_t             space,
3236 	mach_port_name_t        name,
3237 	int                     flavor,
3238 	mach_port_info_t        info,
3239 	mach_msg_type_number_t  count)
3240 {
3241 	ipc_port_t port;
3242 	kern_return_t kr;
3243 
3244 	if (space == IS_NULL) {
3245 		return KERN_INVALID_TASK;
3246 	}
3247 
3248 	switch (flavor) {
3249 	case MACH_PORT_GUARD_INFO: {
3250 		mach_port_guard_info_t *mpgi = (mach_port_guard_info_t *)(void *)info;
3251 
3252 		if (count < MACH_PORT_GUARD_INFO_COUNT) {
3253 			return KERN_FAILURE;
3254 		}
3255 
3256 		if (!MACH_PORT_VALID(name)) {
3257 			return KERN_INVALID_RIGHT;
3258 		}
3259 
3260 		kr = ipc_port_translate_receive(space, name, &port);
3261 		if (kr != KERN_SUCCESS) {
3262 			return kr;
3263 		}
3264 		/* port is locked and active */
3265 
3266 		/* Check if guard value matches else kill the process using fatal guard exception */
3267 		if (!port->ip_guarded) {
3268 			ip_mq_unlock(port);
3269 			/* Port already unguarded; Raise exception */
3270 			mach_port_guard_exception(name, mpgi->mpgi_guard, 0, kGUARD_EXC_UNGUARDED);
3271 			return KERN_INVALID_ARGUMENT;
3272 		}
3273 
3274 		if (!port->ip_strict_guard || (port->ip_context != mpgi->mpgi_guard)) {
3275 			ip_mq_unlock(port);
3276 			/* Incorrect guard; Raise exception */
3277 			mach_port_guard_exception(name, mpgi->mpgi_guard, port->ip_context, kGUARD_EXC_INCORRECT_GUARD);
3278 			return KERN_INVALID_ARGUMENT;
3279 		}
3280 
3281 		ip_mq_unlock(port);
3282 		break;
3283 	}
3284 	default:
3285 		return KERN_INVALID_ARGUMENT;
3286 	}
3287 	return KERN_SUCCESS;
3288 }
3289