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