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