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