xref: /xnu-12377.41.6/osfmk/kern/ipc_kobject.c (revision bbb1b6f9e71b8cdde6e5cd6f4841f207dee3d828)
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 SPARTA, Inc.
62  */
63 /*
64  */
65 /*
66  *	File:	kern/ipc_kobject.c
67  *	Author:	Rich Draves
68  *	Date:	1989
69  *
70  *	Functions for letting a port represent a kernel object.
71  */
72 
73 #include <mach/mig.h>
74 #include <mach/port.h>
75 #include <mach/kern_return.h>
76 #include <mach/message.h>
77 #include <mach/mig_errors.h>
78 #include <mach/mach_notify.h>
79 #include <mach/ndr.h>
80 #include <mach/vm_param.h>
81 
82 #include <mach/mach_vm_server.h>
83 #include <mach/mach_port_server.h>
84 #include <mach/mach_host_server.h>
85 #include <mach/host_priv_server.h>
86 #include <mach/clock_server.h>
87 #include <mach/memory_entry_server.h>
88 #include <mach/processor_server.h>
89 #include <mach/processor_set_server.h>
90 #include <mach/task_server.h>
91 #include <mach/mach_voucher_server.h>
92 #ifdef VM32_SUPPORT
93 #include <mach/vm32_map_server.h>
94 #endif
95 #include <mach/thread_act_server.h>
96 #include <mach/restartable_server.h>
97 
98 #include <mach/exc_server.h>
99 #include <mach/mach_exc_server.h>
100 #include <mach/mach_eventlink_server.h>
101 
102 #include <device/device_types.h>
103 #include <device/device_server.h>
104 
105 #if     CONFIG_USER_NOTIFICATION
106 #include <UserNotification/UNDReplyServer.h>
107 #endif
108 
109 #if     CONFIG_ARCADE
110 #include <mach/arcade_register_server.h>
111 #endif
112 
113 #if     CONFIG_AUDIT
114 #include <kern/audit_sessionport.h>
115 #endif
116 
117 #include <kern/counter.h>
118 #include <kern/ipc_tt.h>
119 #include <kern/ipc_mig.h>
120 #include <kern/ipc_misc.h>
121 #include <kern/ipc_kobject.h>
122 #include <kern/host_notify.h>
123 #include <kern/misc_protos.h>
124 
125 #if CONFIG_ARCADE
126 #include <kern/arcade.h>
127 #endif /* CONFIG_ARCADE */
128 
129 #include <ipc/ipc_kmsg.h>
130 #include <ipc/ipc_policy.h>
131 #include <ipc/ipc_port.h>
132 #include <ipc/ipc_voucher.h>
133 #include <kern/sync_sema.h>
134 #include <kern/work_interval.h>
135 #include <kern/task_ident.h>
136 
137 #if HYPERVISOR
138 #include <kern/hv_support.h>
139 #endif
140 
141 #include <vm/vm_protos.h>
142 
143 #include <security/mac_mach_internal.h>
144 
145 extern char *proc_name_address(void *p);
146 struct proc;
147 extern int proc_pid(struct proc *p);
148 
149 typedef struct {
150 	mach_msg_id_t num;
151 	int kobjidx;
152 	mig_kern_routine_t kroutine;    /* Kernel server routine */
153 	unsigned int kreply_size;       /* Size of kernel reply msg */
154 	unsigned int kreply_desc_cnt;   /* Number of descs in kernel reply msg */
155 } mig_hash_t;
156 
157 IPC_KOBJECT_DEFINE(IKOT_MEMORY_OBJECT);   /* vestigial, no real instance */
158 
159 #define MAX_MIG_ENTRIES 1031
160 #define MIG_HASH(x) (x)
161 
162 #define KOBJ_IDX_NOT_SET (-1)
163 
164 static SECURITY_READ_ONLY_LATE(mig_hash_t) mig_buckets[MAX_MIG_ENTRIES];
165 static SECURITY_READ_ONLY_LATE(int) mig_table_max_displ;
166 SECURITY_READ_ONLY_LATE(int) mach_kobj_count; /* count of total number of kobjects */
167 
168 ZONE_DEFINE_TYPE(ipc_kobject_label_zone, "ipc kobject labels",
169     struct ipc_kobject_label, ZC_ZFREE_CLEARMEM);
170 
171 __startup_const
172 static struct mig_kern_subsystem *mig_e[] = {
173 	(const struct mig_kern_subsystem *)&mach_vm_subsystem,
174 	(const struct mig_kern_subsystem *)&mach_port_subsystem,
175 	(const struct mig_kern_subsystem *)&mach_host_subsystem,
176 	(const struct mig_kern_subsystem *)&host_priv_subsystem,
177 	(const struct mig_kern_subsystem *)&clock_subsystem,
178 	(const struct mig_kern_subsystem *)&processor_subsystem,
179 	(const struct mig_kern_subsystem *)&processor_set_subsystem,
180 	(const struct mig_kern_subsystem *)&is_iokit_subsystem,
181 	(const struct mig_kern_subsystem *)&task_subsystem,
182 	(const struct mig_kern_subsystem *)&thread_act_subsystem,
183 #ifdef VM32_SUPPORT
184 	(const struct mig_kern_subsystem *)&vm32_map_subsystem,
185 #endif
186 #if CONFIG_USER_NOTIFICATION
187 	(const struct mig_kern_subsystem *)&UNDReply_subsystem,
188 #endif
189 	(const struct mig_kern_subsystem *)&mach_voucher_subsystem,
190 	(const struct mig_kern_subsystem *)&memory_entry_subsystem,
191 	(const struct mig_kern_subsystem *)&task_restartable_subsystem,
192 	(const struct mig_kern_subsystem *)&catch_exc_subsystem,
193 	(const struct mig_kern_subsystem *)&catch_mach_exc_subsystem,
194 #if CONFIG_ARCADE
195 	(const struct mig_kern_subsystem *)&arcade_register_subsystem,
196 #endif
197 	(const struct mig_kern_subsystem *)&mach_eventlink_subsystem,
198 };
199 
200 __startup_func
201 static void
mig_init(void)202 mig_init(void)
203 {
204 	unsigned int i, n = sizeof(mig_e) / sizeof(const struct mig_kern_subsystem *);
205 	int howmany;
206 	mach_msg_id_t j, pos, nentry, range;
207 
208 	for (i = 0; i < n; i++) {
209 		range = mig_e[i]->end - mig_e[i]->start;
210 		if (!mig_e[i]->start || range < 0) {
211 			panic("the msgh_ids in mig_e[] aren't valid!");
212 		}
213 
214 		if (mig_e[i]->maxsize > KALLOC_SAFE_ALLOC_SIZE - MAX_TRAILER_SIZE) {
215 			panic("mig subsystem %d (%p) replies are too large (%d > %d)",
216 			    mig_e[i]->start, mig_e[i], mig_e[i]->maxsize,
217 			    KALLOC_SAFE_ALLOC_SIZE - MAX_TRAILER_SIZE);
218 		}
219 
220 		for (j = 0; j < range; j++) {
221 			if (mig_e[i]->kroutine[j].kstub_routine) {
222 				/* Only put real entries in the table */
223 				nentry = j + mig_e[i]->start;
224 				for (pos = MIG_HASH(nentry) % MAX_MIG_ENTRIES, howmany = 1;
225 				    mig_buckets[pos].num;
226 				    pos++, pos = pos % MAX_MIG_ENTRIES, howmany++) {
227 					if (mig_buckets[pos].num == nentry) {
228 						printf("message id = %d\n", nentry);
229 						panic("multiple entries with the same msgh_id");
230 					}
231 					if (howmany == MAX_MIG_ENTRIES) {
232 						panic("the mig dispatch table is too small");
233 					}
234 				}
235 
236 				mig_buckets[pos].num = nentry;
237 				mig_buckets[pos].kroutine = mig_e[i]->kroutine[j].kstub_routine;
238 				if (mig_e[i]->kroutine[j].max_reply_msg) {
239 					mig_buckets[pos].kreply_size = mig_e[i]->kroutine[j].max_reply_msg;
240 					mig_buckets[pos].kreply_desc_cnt = mig_e[i]->kroutine[j].reply_descr_count;
241 					assert3u(mig_e[i]->kroutine[j].descr_count,
242 					    <=, IPC_KOBJECT_DESC_MAX);
243 					assert3u(mig_e[i]->kroutine[j].reply_descr_count,
244 					    <=, IPC_KOBJECT_RDESC_MAX);
245 				} else {
246 					/*
247 					 * Allocating a larger-than-needed kmsg creates hole for
248 					 * inlined kmsgs (IKM_TYPE_ALL_INLINED) during copyout.
249 					 * Disallow that.
250 					 */
251 					panic("kroutine must have precise size %d %d", mig_e[i]->start, j);
252 				}
253 
254 				mig_buckets[pos].kobjidx = KOBJ_IDX_NOT_SET;
255 
256 				if (mig_table_max_displ < howmany) {
257 					mig_table_max_displ = howmany;
258 				}
259 				mach_kobj_count++;
260 			}
261 		}
262 	}
263 
264 	/* 77417305: pad to allow for MIG routines removals/cleanups */
265 	mach_kobj_count += 32;
266 
267 	printf("mig_table_max_displ = %d mach_kobj_count = %d\n",
268 	    mig_table_max_displ, mach_kobj_count);
269 }
270 STARTUP(MACH_IPC, STARTUP_RANK_FIRST, mig_init);
271 
272 /*
273  * Do a hash table lookup for given msgh_id. Return 0
274  * if not found.
275  */
276 static mig_hash_t *
find_mig_hash_entry(int msgh_id)277 find_mig_hash_entry(int msgh_id)
278 {
279 	unsigned int i = (unsigned int)MIG_HASH(msgh_id);
280 	int max_iter = mig_table_max_displ;
281 	mig_hash_t *ptr;
282 
283 	do {
284 		ptr = &mig_buckets[i++ % MAX_MIG_ENTRIES];
285 	} while (msgh_id != ptr->num && ptr->num && --max_iter);
286 
287 	if (!ptr->kroutine || msgh_id != ptr->num) {
288 		ptr = (mig_hash_t *)0;
289 	}
290 
291 	return ptr;
292 }
293 
294 /*
295  * Routine: ipc_kobject_reply_status
296  *
297  * Returns the error/success status from a given kobject call reply message.
298  *
299  * Contract for KernelServer MIG routines is as follows:
300  *
301  * (1) If reply header has complex bit set, kernel server implementation routine
302  *     must have implicitly returned KERN_SUCCESS.
303  *
304  * (2) Otherwise we can always read RetCode from after the header. This is not
305  *     obvious to see, and is discussed below by case.
306  *
307  * MIG can return three types of replies from KernelServer routines.
308  *
309  * (A) Complex Reply (i.e. with Descriptors)
310  *
311  *     E.g.: thread_get_exception_ports()
312  *
313  *       If complex bit is set, we can deduce the call is successful since the bit
314  *     is set at the very end.
315  *       If complex bit is not set, we must have returned from MIG_RETURN_ERROR.
316  *     MIG writes RetCode to immediately after the header, and we know this is
317  *     safe to do for all kmsg layouts. (See discussion in ipc_kmsg_server_internal()).
318  *
319  *  (B) Simple Reply with Out Params
320  *
321  *      E.g.: thread_get_states()
322  *
323  *        If the call failed, we return from MIG_RETURN_ERROR, which writes RetCode
324  *      to immediately after the header.
325  *        If the call succeeded, MIG writes RetCode as KERN_SUCCESS to USER DATA
326  *      buffer. *BUT* since the region after header is always initialized with
327  *      KERN_SUCCESS, reading from there gives us the same result. We rely on
328  *      this behavior to not make a special case.
329  *
330  *  (C) Simple Reply without Out Params
331  *
332  *      E.g.: thread_set_states()
333  *
334  *        For this type of MIG routines we always allocate a mig_reply_error_t
335  *      as reply kmsg, which fits inline in kmsg. RetCode can be found after
336  *      header, and can be KERN_SUCCESS or otherwise a failure code.
337  */
338 static kern_return_t
ipc_kobject_reply_status(ipc_kmsg_t reply)339 ipc_kobject_reply_status(ipc_kmsg_t reply)
340 {
341 	mach_msg_header_t *hdr = ikm_header(reply);
342 
343 	if (hdr->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
344 		return KERN_SUCCESS;
345 	}
346 
347 	return ((mig_reply_error_t *)hdr)->RetCode;
348 }
349 
350 static void
ipc_kobject_set_reply_error_status(ipc_kmsg_t reply,kern_return_t kr)351 ipc_kobject_set_reply_error_status(
352 	ipc_kmsg_t    reply,
353 	kern_return_t kr)
354 {
355 	mig_reply_error_t *error = (mig_reply_error_t *)ikm_header(reply);
356 
357 	assert(!(error->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX));
358 	error->RetCode = kr;
359 }
360 
361 /*
362  *      Routine:	ipc_kobject_set_kobjidx
363  *      Purpose:
364  *              Set the index for the kobject filter
365  *              mask for a given message ID.
366  */
367 kern_return_t
ipc_kobject_set_kobjidx(int msgh_id,int index)368 ipc_kobject_set_kobjidx(
369 	int       msgh_id,
370 	int       index)
371 {
372 	mig_hash_t *ptr = find_mig_hash_entry(msgh_id);
373 
374 	if (ptr == (mig_hash_t *)0) {
375 		return KERN_INVALID_ARGUMENT;
376 	}
377 
378 	assert(index < mach_kobj_count);
379 	ptr->kobjidx = index;
380 
381 	return KERN_SUCCESS;
382 }
383 
384 static void
ipc_kobject_init_reply(ipc_kmsg_t reply,const ipc_kmsg_t request,kern_return_t kr)385 ipc_kobject_init_reply(
386 	ipc_kmsg_t          reply,
387 	const ipc_kmsg_t    request,
388 	kern_return_t       kr)
389 {
390 	mach_msg_header_t *req_hdr   = ikm_header(request);
391 	mach_msg_header_t *reply_hdr = ikm_header(reply);
392 
393 #define InP     ((mach_msg_header_t *) req_hdr)
394 #define OutP    ((mig_reply_error_t *) reply_hdr)
395 
396 	OutP->Head.msgh_size = sizeof(mig_reply_error_t);
397 	OutP->Head.msgh_bits =
398 	    MACH_MSGH_BITS_SET(MACH_MSGH_BITS_LOCAL(InP->msgh_bits), 0, 0, 0);
399 	OutP->Head.msgh_remote_port = InP->msgh_local_port;
400 	OutP->Head.msgh_local_port = MACH_PORT_NULL;
401 	OutP->Head.msgh_voucher_port = MACH_PORT_NULL;
402 	OutP->Head.msgh_id = InP->msgh_id + 100;
403 
404 	OutP->NDR = NDR_record;
405 	OutP->RetCode = kr;
406 
407 #undef  InP
408 #undef  OutP
409 }
410 
411 static void
ipc_kobject_init_new_reply(ipc_kmsg_t new_reply,const ipc_kmsg_t old_reply,kern_return_t kr)412 ipc_kobject_init_new_reply(
413 	ipc_kmsg_t          new_reply,
414 	const ipc_kmsg_t    old_reply,
415 	kern_return_t       kr)
416 {
417 	mach_msg_header_t *new_hdr = ikm_header(new_reply);
418 	mach_msg_header_t *old_hdr = ikm_header(old_reply);
419 
420 #define InP     ((mig_reply_error_t *) old_hdr)
421 #define OutP    ((mig_reply_error_t *) new_hdr)
422 
423 	OutP->Head.msgh_size = sizeof(mig_reply_error_t);
424 	OutP->Head.msgh_bits = InP->Head.msgh_bits & ~MACH_MSGH_BITS_COMPLEX;
425 	OutP->Head.msgh_remote_port = InP->Head.msgh_remote_port;
426 	OutP->Head.msgh_local_port = MACH_PORT_NULL;
427 	OutP->Head.msgh_voucher_port = MACH_PORT_NULL;
428 	OutP->Head.msgh_id = InP->Head.msgh_id;
429 
430 	OutP->NDR = InP->NDR;
431 	OutP->RetCode = kr;
432 
433 #undef  InP
434 #undef  OutP
435 }
436 
437 static ipc_kmsg_t
ipc_kobject_alloc_mig_error(void)438 ipc_kobject_alloc_mig_error(void)
439 {
440 	ipc_kmsg_alloc_flags_t flags = IPC_KMSG_ALLOC_KERNEL |
441 	    IPC_KMSG_ALLOC_ZERO |
442 	    IPC_KMSG_ALLOC_ALL_INLINE |
443 	    IPC_KMSG_ALLOC_NOFAIL;
444 
445 	return ipc_kmsg_alloc(sizeof(mig_reply_error_t), 0, 0, flags);
446 }
447 
448 /*
449  *	Routine:	ipc_kobject_server_internal
450  *	Purpose:
451  *		Handle a message sent to the kernel.
452  *		Generates a reply message.
453  *		Version for Untyped IPC.
454  *	Conditions:
455  *		Nothing locked.
456  */
457 static kern_return_t
ipc_kobject_server_internal(__unused ipc_port_t port,ipc_kmsg_t request,ipc_kmsg_t * replyp)458 ipc_kobject_server_internal(
459 	__unused ipc_port_t port,
460 	ipc_kmsg_t          request,
461 	ipc_kmsg_t          *replyp)
462 {
463 	int request_msgh_id;
464 	ipc_kmsg_t reply = IKM_NULL;
465 	mach_msg_size_t reply_size, reply_desc_cnt;
466 	mig_hash_t *ptr;
467 	mach_msg_header_t *req_hdr, *reply_hdr;
468 	void *req_data, *reply_data;
469 	mach_msg_max_trailer_t *req_trailer;
470 
471 	thread_ro_t tro = current_thread_ro();
472 	task_t curtask = tro->tro_task;
473 	struct proc *curproc = tro->tro_proc;
474 
475 	req_hdr = ikm_header(request);
476 	req_data = ikm_udata_from_header(request);
477 	req_trailer = ipc_kmsg_get_trailer(request);
478 	request_msgh_id = req_hdr->msgh_id;
479 
480 	/* Find corresponding mig_hash entry, if any */
481 	ptr = find_mig_hash_entry(request_msgh_id);
482 
483 	/* Get the reply_size. */
484 	if (ptr == (mig_hash_t *)0) {
485 		reply_size = sizeof(mig_reply_error_t);
486 		reply_desc_cnt = 0;
487 	} else {
488 		reply_size = ptr->kreply_size;
489 		reply_desc_cnt = ptr->kreply_desc_cnt;
490 	}
491 
492 	assert(reply_size >= sizeof(mig_reply_error_t));
493 
494 	/*
495 	 * MIG should really assure no data leakage -
496 	 * but until it does, pessimistically zero the
497 	 * whole reply buffer.
498 	 */
499 	reply = ipc_kmsg_alloc(reply_size, 0, reply_desc_cnt, IPC_KMSG_ALLOC_KERNEL |
500 	    IPC_KMSG_ALLOC_ZERO | IPC_KMSG_ALLOC_NOFAIL);
501 	/* reply can be non-linear */
502 
503 	if (ptr == (mig_hash_t *)0) {
504 #if DEVELOPMENT || DEBUG
505 		printf("ipc_kobject_server: bogus kernel message, id=%d\n",
506 		    req_hdr->msgh_id);
507 #endif  /* DEVELOPMENT || DEBUG */
508 		_MIG_MSGID_INVALID(req_hdr->msgh_id);
509 
510 		ipc_kobject_init_reply(reply, request, MIG_BAD_ID);
511 
512 		*replyp = reply;
513 		return KERN_SUCCESS;
514 	}
515 
516 	/*
517 	 * We found the routine to call. Call it to perform the kernel function.
518 	 */
519 	assert(ptr != (mig_hash_t *)0);
520 
521 	reply_hdr = ikm_header(reply);
522 	/* reply is allocated by kernel. non-zero desc count means complex msg */
523 	reply_data = ikm_udata(reply, reply_desc_cnt, (reply_desc_cnt > 0));
524 
525 	/*
526 	 * Reply can be of layout IKM_TYPE_ALL_INLINED, IKM_TYPE_UDATA_OOL,
527 	 * or IKM_TYPE_ALL_OOL, each of which guarantees kernel/user data segregation.
528 	 *
529 	 * Here is the trick: In each case, there _must_ be enough space in
530 	 * the kdata (header) buffer in `reply` to hold a mig_reply_error_t.
531 	 */
532 	assert(reply->ikm_type != IKM_TYPE_KDATA_OOL);
533 	assert((vm_offset_t)reply_hdr + sizeof(mig_reply_error_t) <= ikm_kdata_end(reply));
534 
535 	/*
536 	 * Discussion by case:
537 	 *
538 	 * (1) IKM_TYPE_ALL_INLINED
539 	 *     - IKM_BIG_MSG_SIZE is large enough for mig_reply_error_t
540 	 * (2) IKM_TYPE_UDATA_OOL
541 	 *     - IKM_SMALL_MSG_SIZE is large enough for mig_reply_error_t
542 	 * (3) IKM_TYPE_ALL_OOL
543 	 *     - This layout is only possible if kdata (header + descs) doesn't fit
544 	 *       in IKM_SMALL_MSG_SIZE. So we must have at least one descriptor
545 	 *       following the header, which is enough to fit mig_reply_error_t.
546 	 */
547 	static_assert(sizeof(mig_reply_error_t) < IKM_BIG_MSG_SIZE);
548 	static_assert(sizeof(mig_reply_error_t) < sizeof(mach_msg_base_t) +
549 	    1 * sizeof(mach_msg_kdescriptor_t));
550 
551 	/*
552 	 * Therefore, we can temporarily treat `reply` as a *simple* message that
553 	 * contains NDR Record + RetCode immediately after the header (which overlaps
554 	 * with descriptors, if the reply msg is supposed to be complex).
555 	 *
556 	 * In doing so we save having a separate allocation specifically for errors.
557 	 */
558 	ipc_kobject_init_reply(reply, request, KERN_SUCCESS);
559 
560 	/* Check if the kobject call should be filtered */
561 #if CONFIG_MACF
562 	int idx = ptr->kobjidx;
563 	uint8_t *filter_mask = task_get_mach_kobj_filter_mask(curtask);
564 
565 	/* Check kobject mig filter mask, if exists. */
566 	if (filter_mask != NULL &&
567 	    (idx == KOBJ_IDX_NOT_SET || !bitstr_test(filter_mask, idx)) &&
568 	    mac_task_kobj_msg_evaluate != NULL) {
569 		/* No index registered by Sandbox, or not in filter mask: evaluate policy. */
570 		kern_return_t kr = mac_task_kobj_msg_evaluate(curproc,
571 		    request_msgh_id, idx);
572 		if (kr != KERN_SUCCESS) {
573 			ipc_kobject_set_reply_error_status(reply, kr);
574 			goto skip_kobjcall;
575 		}
576 	}
577 #endif /* CONFIG_MACF */
578 
579 	__BeforeKobjectServerTrace(idx);
580 	/* See contract in header doc for ipc_kobject_reply_status() */
581 	(*ptr->kroutine)(req_hdr, req_data, req_trailer, reply_hdr, reply_data);
582 	__AfterKobjectServerTrace(idx);
583 
584 #if CONFIG_MACF
585 skip_kobjcall:
586 #endif
587 	counter_inc(&kernel_task->messages_received);
588 
589 	kern_return_t reply_status = ipc_kobject_reply_status(reply);
590 
591 	if (reply_status == MIG_NO_REPLY) {
592 		/*
593 		 *	The server function will send a reply message
594 		 *	using the reply port right, which it has saved.
595 		 */
596 		ipc_kmsg_free(reply);
597 		reply = IKM_NULL;
598 	} else if (reply_status != KERN_SUCCESS && reply_size > sizeof(mig_reply_error_t)) {
599 		assert(ikm_header(reply)->msgh_size == sizeof(mig_reply_error_t));
600 		/*
601 		 * MIG returned an error, and the original kmsg we allocated for reply
602 		 * is oversized. Deallocate it and allocate a smaller, proper kmsg
603 		 * that fits mig_reply_error_t snuggly.
604 		 *
605 		 * We must do so because we used the trick mentioned above which (depending
606 		 * on the kmsg layout) may cause payload in mig_reply_error_t to overlap
607 		 * with kdata buffer meant for descriptors.
608 		 *
609 		 * This will mess with ikm_kdata_size() calculation down the line so
610 		 * reallocate a new buffer immediately here.
611 		 */
612 		ipc_kmsg_t new_reply = ipc_kobject_alloc_mig_error();
613 		ipc_kobject_init_new_reply(new_reply, reply, reply_status);
614 
615 		/* MIG contract: If status is not KERN_SUCCESS, reply must be simple. */
616 		assert(!(ikm_header(reply)->msgh_bits & MACH_MSGH_BITS_COMPLEX));
617 		assert(ikm_header(reply)->msgh_local_port == MACH_PORT_NULL);
618 		assert(ikm_header(reply)->msgh_voucher_port == MACH_PORT_NULL);
619 		/* So we can simply free the original reply message. */
620 		ipc_kmsg_free(reply);
621 		reply = new_reply;
622 	}
623 
624 	*replyp = reply;
625 	return KERN_SUCCESS;
626 }
627 
628 
629 /*
630  *	Routine:	ipc_kobject_server
631  *	Purpose:
632  *		Handle a message sent to the kernel.
633  *		Generates a reply message.
634  *		Version for Untyped IPC.
635  *
636  *		Ownership of the incoming rights (from the request)
637  *		are transferred on success (wether a reply is made or not).
638  *
639  *	Conditions:
640  *		Nothing locked.
641  */
642 ipc_kmsg_t
ipc_kobject_server(ipc_port_t port,ipc_kmsg_t request,mach_msg_option64_t option __unused)643 ipc_kobject_server(
644 	ipc_port_t          port,
645 	ipc_kmsg_t          request,
646 	mach_msg_option64_t option __unused)
647 {
648 	mach_msg_header_t *req_hdr = ikm_header(request);
649 #if DEVELOPMENT || DEBUG
650 	const int request_msgh_id = req_hdr->msgh_id;
651 #endif
652 	ipc_port_t request_voucher_port;
653 	ipc_kmsg_t reply = IKM_NULL;
654 	mach_msg_header_t *reply_hdr;
655 	kern_return_t kr;
656 
657 	ipc_kmsg_trace_send(request, option);
658 
659 	if (ip_type(port) == IKOT_UEXT_OBJECT) {
660 		kr = uext_server(port, request, &reply);
661 	} else {
662 		kr = ipc_kobject_server_internal(port, request, &reply);
663 		assert(kr == KERN_SUCCESS);
664 	}
665 
666 	if (kr != KERN_SUCCESS) {
667 		assert(kr != MACH_SEND_TIMED_OUT &&
668 		    kr != MACH_SEND_INTERRUPTED &&
669 		    kr != MACH_SEND_INVALID_DEST);
670 		assert(reply == IKM_NULL);
671 
672 		/* convert the server error into a MIG error */
673 		reply = ipc_kobject_alloc_mig_error();
674 		ipc_kobject_init_reply(reply, request, kr);
675 	}
676 
677 	counter_inc(&kernel_task->messages_sent);
678 	/*
679 	 *	Destroy destination. The following code differs from
680 	 *	ipc_object_destroy in that we release the send-once
681 	 *	right instead of generating a send-once notification
682 	 *	(which would bring us here again, creating a loop).
683 	 *	It also differs in that we only expect send or
684 	 *	send-once rights, never receive rights.
685 	 */
686 	switch (MACH_MSGH_BITS_REMOTE(req_hdr->msgh_bits)) {
687 	case MACH_MSG_TYPE_PORT_SEND:
688 		ipc_port_release_send(req_hdr->msgh_remote_port);
689 		break;
690 
691 	case MACH_MSG_TYPE_PORT_SEND_ONCE:
692 		ipc_port_release_sonce(req_hdr->msgh_remote_port);
693 		break;
694 
695 	default:
696 		panic("ipc_kobject_server: strange destination rights");
697 	}
698 
699 	/*
700 	 *	Destroy voucher.  The kernel MIG servers never take ownership
701 	 *	of vouchers sent in messages.  Swallow any such rights here.
702 	 */
703 	request_voucher_port = ipc_kmsg_get_voucher_port(request);
704 	if (IP_VALID(request_voucher_port)) {
705 		assert(MACH_MSG_TYPE_PORT_SEND ==
706 		    MACH_MSGH_BITS_VOUCHER(req_hdr->msgh_bits));
707 		ipc_port_release_send(request_voucher_port);
708 		ipc_kmsg_clear_voucher_port(request);
709 	}
710 
711 	if (reply == IKM_NULL ||
712 	    ipc_kobject_reply_status(reply) == KERN_SUCCESS) {
713 		/*
714 		 *	The server function is responsible for the contents
715 		 *	of the message.  The reply port right is moved
716 		 *	to the reply message, and we have deallocated
717 		 *	the destination port right, so we just need
718 		 *	to free the kmsg.
719 		 */
720 		ipc_kmsg_free(request);
721 	} else {
722 		/*
723 		 *	The message contents of the request are intact.
724 		 *  Remote port has been released above. Do not destroy
725 		 *  the reply port right either, which is needed in the reply message.
726 		 */
727 		ipc_kmsg_destroy(request, IPC_KMSG_DESTROY_SKIP_LOCAL | IPC_KMSG_DESTROY_SKIP_REMOTE);
728 	}
729 
730 	if (reply != IKM_NULL) {
731 		reply_hdr = ikm_header(reply);
732 		ipc_port_t reply_port = reply_hdr->msgh_remote_port;
733 
734 		if (!IP_VALID(reply_port)) {
735 			/*
736 			 *	Can't queue the reply message if the destination
737 			 *	(the reply port) isn't valid.
738 			 */
739 			ipc_kmsg_destroy(reply, IPC_KMSG_DESTROY_NOT_SIGNED);
740 			reply = IKM_NULL;
741 		} else if (ip_in_space_noauth(reply_port, ipc_space_kernel)) {
742 			/* do not lock reply port, use raw pointer comparison */
743 
744 			/*
745 			 *	Don't send replies to kobject kernel ports.
746 			 */
747 #if DEVELOPMENT || DEBUG
748 			printf("%s: refusing to send reply to kobject %d port (id:%d)\n",
749 			    __func__, ip_type(reply_port), request_msgh_id);
750 #endif  /* DEVELOPMENT || DEBUG */
751 			ipc_kmsg_destroy(reply, IPC_KMSG_DESTROY_NOT_SIGNED);
752 			reply = IKM_NULL;
753 		}
754 	}
755 
756 	return reply;
757 }
758 
759 static inline void
ipc_kobject_set_raw(ipc_port_t port,ipc_kobject_type_t type,ipc_kobject_t kobject)760 ipc_kobject_set_raw(
761 	ipc_port_t          port,
762 	ipc_kobject_type_t  type,
763 	ipc_kobject_t       kobject)
764 {
765 	uintptr_t *store = &port->ip_kobject;
766 
767 #if __has_feature(ptrauth_calls)
768 	type ^= OS_PTRAUTH_DISCRIMINATOR("ipc_port.ip_kobject");
769 	kobject = ptrauth_sign_unauthenticated(kobject,
770 	    ptrauth_key_process_independent_data,
771 	    ptrauth_blend_discriminator(store, type));
772 #else
773 	(void)type;
774 #endif // __has_feature(ptrauth_calls)
775 
776 	*store = (uintptr_t)kobject;
777 }
778 
779 /*
780  *	Routine:	ipc_kobject_get_raw
781  *	Purpose:
782  *		Returns the kobject pointer of a specified port.
783  *
784  *		This returns the current value of the kobject pointer,
785  *		without any validation (the caller is expected to do
786  *		the validation it needs).
787  *
788  *	Conditions:
789  *		The port is a kobject of the proper type.
790  */
791 __header_always_inline ipc_kobject_t
ipc_kobject_get_raw(ipc_port_t port,ipc_kobject_type_t type)792 ipc_kobject_get_raw(
793 	ipc_port_t              port,
794 	ipc_kobject_type_t      type)
795 {
796 	uintptr_t *store = &port->ip_kobject;
797 	ipc_kobject_t kobject = (ipc_kobject_t)*store;
798 
799 #if __has_feature(ptrauth_calls)
800 	type ^= OS_PTRAUTH_DISCRIMINATOR("ipc_port.ip_kobject");
801 	kobject = ptrauth_auth_data(kobject,
802 	    ptrauth_key_process_independent_data,
803 	    ptrauth_blend_discriminator(store, type));
804 #else
805 	(void)type;
806 #endif // __has_feature(ptrauth_calls)
807 
808 	return kobject;
809 }
810 
811 __abortlike
812 static void
ipc_kobject_require_panic(ipc_port_t port,ipc_kobject_t kobject,ipc_kobject_type_t kotype)813 ipc_kobject_require_panic(
814 	ipc_port_t                  port,
815 	ipc_kobject_t               kobject,
816 	ipc_kobject_type_t          kotype)
817 {
818 	if (ip_type(port) != kotype) {
819 		panic("port %p: invalid kobject type, got %d wanted %d",
820 		    port, ip_type(port), kotype);
821 	}
822 	panic("port %p: invalid kobject, got %p wanted %p",
823 	    port, ipc_kobject_get_raw(port, kotype), kobject);
824 }
825 
826 __header_always_inline void
ipc_kobject_require(ipc_port_t port,ipc_kobject_t kobject,ipc_kobject_type_t kotype)827 ipc_kobject_require(
828 	ipc_port_t                  port,
829 	ipc_kobject_t               kobject,
830 	ipc_kobject_type_t          kotype)
831 {
832 	ipc_kobject_t cur;
833 
834 	if (ip_type(port) != kotype) {
835 		ipc_kobject_require_panic(port, kobject, kotype);
836 	}
837 	cur = ipc_kobject_get_raw(port, kotype);
838 	if (cur && cur != kobject) {
839 		ipc_kobject_require_panic(port, kobject, kotype);
840 	}
841 }
842 
843 /*
844  *	Routine:	ipc_kobject_get_locked
845  *	Purpose:
846  *		Returns the kobject pointer of a specified port,
847  *		for an expected type.
848  *
849  *		Returns IKO_NULL if the port isn't active.
850  *
851  *		This function may be used when:
852  *		- the port lock is held
853  *		- the kobject association stays while there
854  *		  are any outstanding rights.
855  *
856  *	Conditions:
857  *		The port is a kobject of the proper type.
858  */
859 ipc_kobject_t
ipc_kobject_get_locked(ipc_port_t port,ipc_kobject_type_t type)860 ipc_kobject_get_locked(ipc_port_t port, ipc_kobject_type_t type)
861 {
862 	ipc_kobject_t kobject = IKO_NULL;
863 
864 	if (ip_active(port) && ip_type(port) == type) {
865 		kobject = ipc_kobject_get_raw(port, type);
866 	}
867 
868 	return kobject;
869 }
870 
871 /*
872  *	Routine:	ipc_kobject_get_stable
873  *	Purpose:
874  *		Returns the kobject pointer of a specified port,
875  *		for an expected type, for types where the port/kobject
876  *		association is permanent.
877  *
878  *		Returns IKO_NULL if the port isn't active.
879  *
880  *	Conditions:
881  *		The port is a kobject of the proper type.
882  */
883 ipc_kobject_t
ipc_kobject_get_stable(ipc_port_t port,ipc_kobject_type_t type)884 ipc_kobject_get_stable(ipc_port_t port, ipc_kobject_type_t type)
885 {
886 	assert(ipc_policy(type)->pol_kobject_stable);
887 	return ipc_kobject_get_locked(port, type);
888 }
889 
890 ipc_object_label_t
ipc_kobject_label_alloc(ipc_object_type_t otype,ipc_label_t label_tag,ipc_port_t alt_port)891 ipc_kobject_label_alloc(
892 	ipc_object_type_t       otype,
893 	ipc_label_t             label_tag,
894 	ipc_port_t              alt_port)
895 {
896 	ipc_kobject_label_t kolabel;
897 
898 	kolabel = zalloc_flags(ipc_kobject_label_zone, Z_WAITOK | Z_ZERO | Z_NOFAIL);
899 	kolabel->ikol_label = label_tag;
900 	kolabel->ikol_alt_port = alt_port;
901 
902 	return IPC_OBJECT_LABEL(otype, .iol_kobject = kolabel);
903 }
904 
905 void
ipc_kobject_label_free(ipc_object_label_t label)906 ipc_kobject_label_free(ipc_object_label_t label)
907 {
908 	assert(label.iol_kobject->ikol_alt_port == IP_NULL);
909 	zfree(ipc_kobject_label_zone, label.iol_kobject);
910 }
911 
912 /*
913  *	Routine:	ipc_kobject_alloc_port
914  *	Purpose:
915  *		Allocate a kobject port in the kernel space of the specified type.
916  *
917  *		This function never fails.
918  *
919  *	Conditions:
920  *		No locks held (memory is allocated)
921  */
922 ipc_port_t
ipc_kobject_alloc_port(ipc_kobject_t kobject,ipc_object_label_t label,ipc_kobject_alloc_options_t options)923 ipc_kobject_alloc_port(
924 	ipc_kobject_t           kobject,
925 	ipc_object_label_t      label,
926 	ipc_kobject_alloc_options_t options)
927 {
928 	ipc_port_t port;
929 
930 	port = ipc_port_alloc_special(ipc_space_kernel, label, IP_INIT_NONE);
931 
932 	if (options & IPC_KOBJECT_ALLOC_MAKE_SEND) {
933 		ipc_port_make_send_any_locked(port);
934 	}
935 
936 	ipc_kobject_set_raw(port, label.io_type, kobject);
937 
938 	ip_mq_unlock(port);
939 
940 	return port;
941 }
942 
943 bool
ipc_kobject_make_send_lazy_alloc_port(ipc_port_t * port_store,ipc_kobject_t kobject,ipc_kobject_type_t type)944 ipc_kobject_make_send_lazy_alloc_port(
945 	ipc_port_t             *port_store,
946 	ipc_kobject_t           kobject,
947 	ipc_kobject_type_t      type)
948 {
949 	ipc_port_t port, previous;
950 	bool was_armed = false;
951 
952 	assert(ipc_policy(type)->pol_kobject_no_senders &&
953 	    ipc_policy(type)->pol_kobject_stable);
954 
955 	port = os_atomic_load(port_store, dependency);
956 	if (!IP_VALID(port)) {
957 		port = ipc_kobject_alloc_port(kobject, type,
958 		    IPC_KOBJECT_ALLOC_MAKE_SEND);
959 
960 		if (os_atomic_cmpxchgv(port_store,
961 		    IP_NULL, port, &previous, release)) {
962 			return true;
963 		}
964 
965 		/*
966 		 * undo IPC_KOBJECT_ALLOC_MAKE_SEND
967 		 */
968 		port->ip_mscount = 0;
969 		port->ip_srights = 0;
970 		ip_release_live(port);
971 		ipc_kobject_dealloc_port(port, 0, type);
972 
973 		port = previous;
974 	}
975 
976 	ip_mq_lock(port);
977 	ipc_port_make_send_any_locked(port);
978 	was_armed = (port->ip_srights == 1);
979 	ip_mq_unlock(port);
980 
981 	return was_armed;
982 }
983 
984 bool
ipc_kobject_is_mscount_current_locked(ipc_port_t port,mach_port_mscount_t mscount)985 ipc_kobject_is_mscount_current_locked(ipc_port_t port, mach_port_mscount_t mscount)
986 {
987 	return ip_active(port) && port->ip_srights == 0 && port->ip_mscount == mscount;
988 }
989 
990 bool
ipc_kobject_is_mscount_current(ipc_port_t port,mach_port_mscount_t mscount)991 ipc_kobject_is_mscount_current(ipc_port_t port, mach_port_mscount_t mscount)
992 {
993 	bool is_last;
994 
995 	ip_mq_lock(port);
996 	is_last = ipc_kobject_is_mscount_current_locked(port, mscount);
997 	ip_mq_unlock(port);
998 
999 	return is_last;
1000 }
1001 
1002 kern_return_t
ipc_typed_port_copyin_send(ipc_space_t space,mach_port_name_t name,ipc_kobject_type_t kotype,ipc_port_t * portp)1003 ipc_typed_port_copyin_send(
1004 	ipc_space_t             space,
1005 	mach_port_name_t        name,
1006 	ipc_kobject_type_t      kotype,
1007 	ipc_port_t             *portp)
1008 {
1009 	kern_return_t kr;
1010 
1011 	kr = ipc_object_copyin(space, name, MACH_MSG_TYPE_COPY_SEND,
1012 	    IPC_OBJECT_COPYIN_FLAGS_ALLOW_IMMOVABLE_SEND, IPC_COPYIN_KERNEL_DESTINATION, NULL, portp);
1013 	if (kr != KERN_SUCCESS) {
1014 		*portp = IP_NULL;
1015 		return kr;
1016 	}
1017 
1018 	if (kotype != IOT_ANY &&
1019 	    IP_VALID(*portp) &&
1020 	    ip_type(*portp) != kotype) {
1021 		ipc_port_release_send(*portp);
1022 		*portp = IP_NULL;
1023 		return KERN_INVALID_CAPABILITY;
1024 	}
1025 
1026 	return KERN_SUCCESS;
1027 }
1028 
1029 ipc_port_t
ipc_kobject_copy_send(ipc_port_t port,ipc_kobject_t kobject,ipc_kobject_type_t kotype)1030 ipc_kobject_copy_send(
1031 	ipc_port_t              port,
1032 	ipc_kobject_t           kobject,
1033 	ipc_kobject_type_t      kotype)
1034 {
1035 	ipc_port_t sright = port;
1036 
1037 	if (IP_VALID(port)) {
1038 		ip_mq_lock(port);
1039 		if (ip_active(port)) {
1040 			ipc_kobject_require(port, kobject, kotype);
1041 			ipc_port_copy_send_any_locked(port);
1042 		} else {
1043 			sright = IP_DEAD;
1044 		}
1045 		ip_mq_unlock(port);
1046 	}
1047 
1048 	return sright;
1049 }
1050 
1051 ipc_port_t
ipc_kobject_make_send(ipc_port_t port,ipc_kobject_t kobject,ipc_kobject_type_t kotype)1052 ipc_kobject_make_send(
1053 	ipc_port_t              port,
1054 	ipc_kobject_t           kobject,
1055 	ipc_kobject_type_t      kotype)
1056 {
1057 	ipc_port_t sright = port;
1058 
1059 	if (IP_VALID(port)) {
1060 		ip_mq_lock(port);
1061 		if (ip_active(port)) {
1062 			ipc_kobject_require(port, kobject, kotype);
1063 			ipc_port_make_send_any_locked(port);
1064 		} else {
1065 			sright = IP_DEAD;
1066 		}
1067 		ip_mq_unlock(port);
1068 	}
1069 
1070 	return sright;
1071 }
1072 
1073 void
ipc_typed_port_release_send(ipc_port_t port,ipc_kobject_type_t kotype)1074 ipc_typed_port_release_send(
1075 	ipc_port_t              port,
1076 	ipc_kobject_type_t      kotype)
1077 {
1078 	if (kotype != IOT_ANY && IP_VALID(port) && ip_type(port) != kotype) {
1079 		ipc_kobject_require_panic(port, IKO_NULL, kotype);
1080 	}
1081 	ipc_port_release_send(port);
1082 }
1083 
1084 static inline ipc_kobject_t
ipc_kobject_disable_internal(ipc_port_t port,ipc_kobject_label_t kolabel,ipc_kobject_type_t type)1085 ipc_kobject_disable_internal(
1086 	ipc_port_t              port,
1087 	ipc_kobject_label_t     kolabel,
1088 	ipc_kobject_type_t      type)
1089 {
1090 	ipc_kobject_t kobject = ipc_kobject_get_raw(port, type);
1091 
1092 	ipc_kobject_set_raw(port, type, IKO_NULL);
1093 	if (kolabel) {
1094 		kolabel->ikol_alt_port = IP_NULL;
1095 	}
1096 
1097 	return kobject;
1098 }
1099 
1100 /*
1101  *	Routine:	ipc_kobject_dealloc_port_and_unlock
1102  *	Purpose:
1103  *		Destroys a port allocated with any of the ipc_kobject_alloc*
1104  *		functions.
1105  *
1106  *		This will atomically:
1107  *		- make the port inactive,
1108  *		- optionally check the make send count
1109  *		- disable (nil-out) the kobject pointer for kobjects without
1110  *		  a destroy callback.
1111  *
1112  *		The port will retain its kobject-ness and kobject type.
1113  *
1114  *
1115  *	Returns:
1116  *		The kobject pointer that was set prior to this call
1117  *		(possibly NULL if the kobject was already disabled).
1118  *
1119  *	Conditions:
1120  *		The port is active and locked.
1121  *		On return the port is inactive and unlocked.
1122  */
1123 __abortlike
1124 static void
__ipc_kobject_bad_type_panic(ipc_port_t port,ipc_kobject_type_t type)1125 __ipc_kobject_bad_type_panic(ipc_port_t port, ipc_kobject_type_t type)
1126 {
1127 	panic("port %p of type %d, expecting %d", port, ip_type(port), type);
1128 }
1129 
1130 __abortlike
1131 static void
__ipc_kobject_dealloc_bad_mscount_panic(ipc_port_t port,uint64_t mscount,ipc_kobject_type_t type)1132 __ipc_kobject_dealloc_bad_mscount_panic(
1133 	ipc_port_t                  port,
1134 	uint64_t                    mscount,
1135 	ipc_kobject_type_t          type)
1136 {
1137 	panic("unexpected make-send count: %p[%d], %d, %lld",
1138 	    port, type, port->ip_mscount, mscount);
1139 }
1140 
1141 __abortlike
1142 static void
__ipc_kobject_dealloc_bad_srights_panic(ipc_port_t port,ipc_kobject_type_t type)1143 __ipc_kobject_dealloc_bad_srights_panic(
1144 	ipc_port_t                  port,
1145 	ipc_kobject_type_t          type)
1146 {
1147 	panic("unexpected send right count: %p[%d], %d",
1148 	    port, type, port->ip_srights);
1149 }
1150 
1151 ipc_kobject_t
ipc_kobject_dealloc_port_and_unlock(ipc_port_t port,uint64_t mscount,ipc_kobject_type_t type)1152 ipc_kobject_dealloc_port_and_unlock(
1153 	ipc_port_t                  port,
1154 	uint64_t                    mscount,
1155 	ipc_kobject_type_t          type)
1156 {
1157 	ipc_kobject_t kobject = IKO_NULL;
1158 	ipc_object_policy_t pol = ipc_policy(type);
1159 	ipc_object_label_t label = ip_label_get(port, type);
1160 
1161 	ipc_release_assert(io_state_active(label.io_state));
1162 
1163 	if (label.io_type != type) {
1164 		__ipc_kobject_bad_type_panic(port, type);
1165 	}
1166 
1167 	if (mscount != IPC_KOBJECT_NO_MSCOUNT && port->ip_mscount != mscount) {
1168 		__ipc_kobject_dealloc_bad_mscount_panic(port, mscount, type);
1169 	}
1170 	if (port->ip_srights &&
1171 	    (mscount != IPC_KOBJECT_NO_MSCOUNT || pol->pol_kobject_stable)) {
1172 		__ipc_kobject_dealloc_bad_srights_panic(port, type);
1173 	}
1174 
1175 	kobject = ipc_kobject_disable_internal(port, label.iol_kobject, type);
1176 
1177 	ip_label_put(port, &label);
1178 	ipc_port_destroy(port);
1179 
1180 	return kobject;
1181 }
1182 
1183 /*
1184  *	Routine:	ipc_kobject_dealloc_port
1185  *	Purpose:
1186  *		Destroys a port allocated with any of the ipc_kobject_alloc*
1187  *		functions.
1188  *
1189  *		This will atomically:
1190  *		- make the port inactive,
1191  *		- optionally check the make send count
1192  *		- disable (nil-out) the kobject pointer for kobjects without
1193  *		  a destroy callback.
1194  *
1195  *		The port will retain its kobject-ness and kobject type.
1196  *
1197  *
1198  *	Returns:
1199  *		The kobject pointer that was set prior to this call
1200  *		(possibly NULL if the kobject was already disabled).
1201  *
1202  *	Conditions:
1203  *		Nothing is locked.
1204  *		The port is active.
1205  *		On return the port is inactive.
1206  */
1207 ipc_kobject_t
ipc_kobject_dealloc_port(ipc_port_t port,uint64_t mscount,ipc_kobject_type_t type)1208 ipc_kobject_dealloc_port(
1209 	ipc_port_t                  port,
1210 	uint64_t                    mscount,
1211 	ipc_kobject_type_t          type)
1212 {
1213 	ip_mq_lock(port);
1214 	return ipc_kobject_dealloc_port_and_unlock(port, mscount, type);
1215 }
1216 
1217 /*
1218  *	Routine:	ipc_kobject_enable
1219  *	Purpose:
1220  *		Make a port represent a kernel object of the given type.
1221  *		The caller is responsible for handling refs for the
1222  *		kernel object, if necessary.
1223  *	Conditions:
1224  *		Nothing locked.
1225  *		The port must be active.
1226  */
1227 void
ipc_kobject_enable(ipc_port_t port,ipc_kobject_t kobject,ipc_kobject_type_t type)1228 ipc_kobject_enable(
1229 	ipc_port_t              port,
1230 	ipc_kobject_t           kobject,
1231 	ipc_kobject_type_t      type)
1232 {
1233 	assert(!ipc_policy(type)->pol_kobject_stable);
1234 
1235 	ip_mq_lock(port);
1236 	require_ip_active(port);
1237 
1238 	if (ip_type(port) != type) {
1239 		__ipc_kobject_bad_type_panic(port, type);
1240 	}
1241 
1242 	ipc_kobject_set_raw(port, type, kobject);
1243 
1244 	ip_mq_unlock(port);
1245 }
1246 
1247 /*
1248  *	Routine:	ipc_kobject_disable_locked
1249  *	Purpose:
1250  *		Clear the kobject pointer for a port.
1251  *	Conditions:
1252  *		port is locked.
1253  *		Returns the current kobject pointer.
1254  */
1255 ipc_kobject_t
ipc_kobject_disable_locked(ipc_port_t port,ipc_kobject_type_t type)1256 ipc_kobject_disable_locked(ipc_port_t port, ipc_kobject_type_t type)
1257 {
1258 	ipc_object_label_t label;
1259 	ipc_kobject_t kobject;
1260 
1261 	label = ip_label_get(port);
1262 	if (io_state_active(label.io_state)) {
1263 		assert(!ipc_policy(type)->pol_kobject_stable);
1264 	}
1265 
1266 	if (label.io_type != type) {
1267 		__ipc_kobject_bad_type_panic(port, type);
1268 	}
1269 
1270 	kobject = ipc_kobject_disable_internal(port, label.iol_kobject, type);
1271 	ip_label_put(port, &label);
1272 
1273 	return kobject;
1274 }
1275 
1276 /*
1277  *	Routine:	ipc_kobject_disable
1278  *	Purpose:
1279  *		Clear the kobject pointer for a port.
1280  *	Conditions:
1281  *		Nothing locked.
1282  *		Returns the current kobject pointer.
1283  */
1284 ipc_kobject_t
ipc_kobject_disable(ipc_port_t port,ipc_kobject_type_t type)1285 ipc_kobject_disable(ipc_port_t port, ipc_kobject_type_t type)
1286 {
1287 	ipc_kobject_t kobject;
1288 
1289 	ip_mq_lock(port);
1290 	kobject = ipc_kobject_disable_locked(port, type);
1291 	ip_mq_unlock(port);
1292 
1293 	return kobject;
1294 }
1295 
1296 /*
1297  *	Routine:	ipc_kobject_notify_send_once_and_unlock
1298  *	Purpose:
1299  *		Handles a send once notifications
1300  *		sent to a kobject.
1301  *
1302  *		A send-once port reference is consumed.
1303  *
1304  *	Conditions:
1305  *		Port is locked.
1306  */
1307 void
ipc_kobject_notify_send_once_and_unlock(ipc_port_t port)1308 ipc_kobject_notify_send_once_and_unlock(
1309 	ipc_port_t              port)
1310 {
1311 	/*
1312 	 * drop the send once right while we hold the port lock.
1313 	 * we will keep a port reference while we run the possible
1314 	 * callouts to kobjects.
1315 	 *
1316 	 * This a simplified version of ipc_port_release_sonce()
1317 	 * since kobjects can't be special reply ports.
1318 	 */
1319 	assert(!ip_is_special_reply_port(port));
1320 
1321 	ip_sorights_dec(port);
1322 	ip_mq_unlock(port);
1323 
1324 	/*
1325 	 * because there's very few consumers,
1326 	 * the code here isn't generic as it's really not worth it.
1327 	 */
1328 	switch (ip_type(port)) {
1329 	case IKOT_TASK_RESUME:
1330 		task_suspension_send_once(port);
1331 		break;
1332 	default:
1333 		break;
1334 	}
1335 
1336 	ip_release(port);
1337 }
1338 
1339 /*
1340  *	Routine:	ipc_kobject_label_substitute_task_read
1341  *	Purpose:
1342  *		Substitute a task read port for its immovable
1343  *		control equivalent when the receiver is that task.
1344  *	Conditions:
1345  *		Space is write locked and active.
1346  *		Port is locked and active.
1347  *	Returns:
1348  *		- IP_NULL port if no substitution is to be done
1349  *		- a valid port if a substitution needs to happen
1350  */
1351 static ipc_port_t
ipc_kobject_label_substitute_task_read(ipc_space_t space,ipc_kobject_label_t kolabel,ipc_port_t port)1352 ipc_kobject_label_substitute_task_read(
1353 	ipc_space_t             space,
1354 	ipc_kobject_label_t     kolabel,
1355 	ipc_port_t              port)
1356 {
1357 	ipc_port_t subst = IP_NULL;
1358 	task_t task = ipc_kobject_get_raw(port, IKOT_TASK_READ);
1359 
1360 	if (task != TASK_NULL && task == space->is_task) {
1361 		if ((subst = kolabel->ikol_alt_port)) {
1362 			return subst;
1363 		}
1364 	}
1365 
1366 	return IP_NULL;
1367 }
1368 
1369 /*
1370  *	Routine:	ipc_kobject_label_substitute_thread_read
1371  *	Purpose:
1372  *		Substitute a thread read port for its immovable
1373  *		control equivalent when it belongs to the receiver task.
1374  *	Conditions:
1375  *		Space is write locked and active.
1376  *		Port is locked and active.
1377  *	Returns:
1378  *		- IP_NULL port if no substitution is to be done
1379  *		- a valid port if a substitution needs to happen
1380  */
1381 static ipc_port_t
ipc_kobject_label_substitute_thread_read(ipc_space_t space,ipc_kobject_label_t kolabel,ipc_port_t port)1382 ipc_kobject_label_substitute_thread_read(
1383 	ipc_space_t             space,
1384 	ipc_kobject_label_t     kolabel,
1385 	ipc_port_t              port)
1386 {
1387 	ipc_port_t subst = IP_NULL;
1388 	thread_t thread = ipc_kobject_get_raw(port, IKOT_THREAD_READ);
1389 
1390 	if (thread != THREAD_NULL && space->is_task == get_threadtask(thread)) {
1391 		if ((subst = kolabel->ikol_alt_port) != IP_NULL) {
1392 			return subst;
1393 		}
1394 	}
1395 
1396 	return IP_NULL;
1397 }
1398 
1399 /*
1400  *	Routine:	ipc_kobject_label_check_or_substitute
1401  *	Purpose:
1402  *		Check to see if the space is allowed to possess
1403  *		a right for the given port. In order to qualify,
1404  *		the space label must contain all the privileges
1405  *		listed in the port/kobject label.
1406  *
1407  *	Conditions:
1408  *		Space is write locked and active.
1409  *		Port is locked and active.
1410  *
1411  *	Returns:
1412  *		Whether the copyout is authorized.
1413  *
1414  *		If a port substitution is requested, the space is unlocked,
1415  *		the port is unlocked and its "right" consumed.
1416  *
1417  *		As of now, substituted ports only happen for send rights.
1418  */
1419 bool
ipc_kobject_label_check_or_substitute(ipc_space_t space,ipc_port_t port,ipc_object_label_t * label,mach_msg_type_name_t msgt_name,ipc_port_t * subst_portp)1420 ipc_kobject_label_check_or_substitute(
1421 	ipc_space_t             space,
1422 	ipc_port_t              port,
1423 	ipc_object_label_t     *label,
1424 	mach_msg_type_name_t    msgt_name,
1425 	ipc_port_t             *subst_portp)
1426 {
1427 	ipc_kobject_label_t kolabel = label->iol_kobject;
1428 	ipc_label_t label_tag = kolabel->ikol_label;
1429 
1430 	assert(is_active(space));
1431 	assert(ip_active(port));
1432 
1433 	*subst_portp = IP_NULL;
1434 
1435 	/* Never OK to copyout the receive right for a labeled kobject */
1436 	if (msgt_name == MACH_MSG_TYPE_PORT_RECEIVE) {
1437 		panic("attempted receive right copyout for labeled kobject");
1438 	}
1439 
1440 	if ((label_tag & IPC_LABEL_SUBST_MASK)) {
1441 		ipc_port_t subst = IP_NULL;
1442 
1443 		if (msgt_name != MACH_MSG_TYPE_PORT_SEND) {
1444 			return false;
1445 		}
1446 
1447 		switch (label_tag & IPC_LABEL_SUBST_MASK) {
1448 		case IPC_LABEL_SUBST_TASK_READ:
1449 			subst = ipc_kobject_label_substitute_task_read(space,
1450 			    kolabel, port);
1451 			break;
1452 		case IPC_LABEL_SUBST_THREAD_READ:
1453 			subst = ipc_kobject_label_substitute_thread_read(space,
1454 			    kolabel, port);
1455 			break;
1456 		default:
1457 			panic("unexpected label tag: %llx", label_tag);
1458 		}
1459 
1460 		if (subst != IP_NULL) {
1461 			ip_reference(subst);
1462 			is_write_unlock(space);
1463 
1464 			/*
1465 			 * We do not hold a proper send right on `subst`,
1466 			 * only a reference.
1467 			 *
1468 			 * Because of how thread/task termination works,
1469 			 * there is no guarantee copy_send() would work,
1470 			 * so we need to make_send().
1471 			 *
1472 			 * We can do that because ports tagged with
1473 			 * IPC_LABEL_SUBST_{THREAD,TASK} do not use
1474 			 * the no-senders notification.
1475 			 */
1476 
1477 			ip_label_put(port, label);
1478 			ipc_port_release_send_and_unlock(port);
1479 			/* no check: dPAC integrity */
1480 			port = ipc_port_make_send_any(subst);
1481 			ip_release(subst);
1482 			*subst_portp = port;
1483 			return true;
1484 		}
1485 	}
1486 
1487 	return (label_tag & space->is_label & IPC_LABEL_SPACE_MASK) ==
1488 	       (label_tag & IPC_LABEL_SPACE_MASK);
1489 }
1490