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_port.h>
131 #include <ipc/ipc_voucher.h>
132 #include <kern/sync_sema.h>
133 #include <kern/work_interval.h>
134 #include <kern/task_ident.h>
135
136 #if HYPERVISOR
137 #include <kern/hv_support.h>
138 #endif
139
140 #if CONFIG_CSR
141 #include <sys/csr.h>
142 #endif
143
144 #include <vm/vm_protos.h>
145
146 #include <security/mac_mach_internal.h>
147
148 extern char *proc_name_address(void *p);
149 struct proc;
150 extern int proc_pid(struct proc *p);
151
152 typedef struct {
153 mach_msg_id_t num;
154 mig_routine_t routine;
155 int size;
156 int kobjidx;
157 } mig_hash_t;
158
159 static void ipc_kobject_subst_once_no_senders(ipc_port_t, mach_msg_type_number_t);
160
161 IPC_KOBJECT_DEFINE(IKOT_MEMORY_OBJECT); /* vestigial, no real instance */
162 IPC_KOBJECT_DEFINE(IKOT_PORT_SUBST_ONCE,
163 .iko_op_no_senders = ipc_kobject_subst_once_no_senders);
164
165 #define MAX_MIG_ENTRIES 1031
166 #define MIG_HASH(x) (x)
167
168 #define KOBJ_IDX_NOT_SET (-1)
169
170 static SECURITY_READ_ONLY_LATE(mig_hash_t) mig_buckets[MAX_MIG_ENTRIES];
171 static SECURITY_READ_ONLY_LATE(int) mig_table_max_displ;
172 SECURITY_READ_ONLY_LATE(int) mach_kobj_count; /* count of total number of kobjects */
173
174 ZONE_DEFINE_TYPE(ipc_kobject_label_zone, "ipc kobject labels",
175 struct ipc_kobject_label, ZC_ZFREE_CLEARMEM);
176
177 __startup_data
178 static const struct mig_subsystem *mig_e[] = {
179 (const struct mig_subsystem *)&mach_vm_subsystem,
180 (const struct mig_subsystem *)&mach_port_subsystem,
181 (const struct mig_subsystem *)&mach_host_subsystem,
182 (const struct mig_subsystem *)&host_priv_subsystem,
183 (const struct mig_subsystem *)&clock_subsystem,
184 (const struct mig_subsystem *)&processor_subsystem,
185 (const struct mig_subsystem *)&processor_set_subsystem,
186 (const struct mig_subsystem *)&is_iokit_subsystem,
187 (const struct mig_subsystem *)&task_subsystem,
188 (const struct mig_subsystem *)&thread_act_subsystem,
189 #ifdef VM32_SUPPORT
190 (const struct mig_subsystem *)&vm32_map_subsystem,
191 #endif
192 #if CONFIG_USER_NOTIFICATION
193 (const struct mig_subsystem *)&UNDReply_subsystem,
194 #endif
195 (const struct mig_subsystem *)&mach_voucher_subsystem,
196 (const struct mig_subsystem *)&memory_entry_subsystem,
197 (const struct mig_subsystem *)&task_restartable_subsystem,
198 (const struct mig_subsystem *)&catch_exc_subsystem,
199 (const struct mig_subsystem *)&catch_mach_exc_subsystem,
200 #if CONFIG_ARCADE
201 (const struct mig_subsystem *)&arcade_register_subsystem,
202 #endif
203 (const struct mig_subsystem *)&mach_eventlink_subsystem,
204 };
205
206 static struct ipc_kobject_ops __security_const_late
207 ipc_kobject_ops_array[IKOT_MAX_TYPE];
208
209 __startup_func
210 void
ipc_kobject_register_startup(ipc_kobject_ops_t ops)211 ipc_kobject_register_startup(ipc_kobject_ops_t ops)
212 {
213 if (ipc_kobject_ops_array[ops->iko_op_type].iko_op_type) {
214 panic("trying to register kobject(%d) twice", ops->iko_op_type);
215 }
216 ipc_kobject_ops_array[ops->iko_op_type] = *ops;
217 }
218
219 static ipc_kobject_ops_t
ipc_kobject_ops_get(ipc_kobject_type_t ikot)220 ipc_kobject_ops_get(ipc_kobject_type_t ikot)
221 {
222 if (ikot < IKOT_NONE || ikot >= IKOT_MAX_TYPE) {
223 panic("invalid kobject type %d", ikot);
224 }
225 return &ipc_kobject_ops_array[ikot];
226 }
227
228 __startup_func
229 static void
mig_init(void)230 mig_init(void)
231 {
232 unsigned int i, n = sizeof(mig_e) / sizeof(const struct mig_subsystem *);
233 int howmany;
234 mach_msg_id_t j, pos, nentry, range;
235
236 for (i = 0; i < n; i++) {
237 range = mig_e[i]->end - mig_e[i]->start;
238 if (!mig_e[i]->start || range < 0) {
239 panic("the msgh_ids in mig_e[] aren't valid!");
240 }
241
242 if (mig_e[i]->maxsize > KALLOC_SAFE_ALLOC_SIZE - MAX_TRAILER_SIZE) {
243 panic("mig subsystem %d (%p) replies are too large (%d > %d)",
244 mig_e[i]->start, mig_e[i], mig_e[i]->maxsize,
245 KALLOC_SAFE_ALLOC_SIZE - MAX_TRAILER_SIZE);
246 }
247
248 for (j = 0; j < range; j++) {
249 if (mig_e[i]->routine[j].stub_routine) {
250 /* Only put real entries in the table */
251 nentry = j + mig_e[i]->start;
252 for (pos = MIG_HASH(nentry) % MAX_MIG_ENTRIES, howmany = 1;
253 mig_buckets[pos].num;
254 pos++, pos = pos % MAX_MIG_ENTRIES, howmany++) {
255 if (mig_buckets[pos].num == nentry) {
256 printf("message id = %d\n", nentry);
257 panic("multiple entries with the same msgh_id");
258 }
259 if (howmany == MAX_MIG_ENTRIES) {
260 panic("the mig dispatch table is too small");
261 }
262 }
263
264 mig_buckets[pos].num = nentry;
265 mig_buckets[pos].routine = mig_e[i]->routine[j].stub_routine;
266 if (mig_e[i]->routine[j].max_reply_msg) {
267 mig_buckets[pos].size = mig_e[i]->routine[j].max_reply_msg;
268 } else {
269 mig_buckets[pos].size = mig_e[i]->maxsize;
270 }
271
272 mig_buckets[pos].kobjidx = KOBJ_IDX_NOT_SET;
273
274 if (mig_table_max_displ < howmany) {
275 mig_table_max_displ = howmany;
276 }
277 mach_kobj_count++;
278 }
279 }
280 }
281
282 /* 77417305: pad to allow for MIG routines removals/cleanups */
283 mach_kobj_count += 32;
284
285 printf("mig_table_max_displ = %d mach_kobj_count = %d\n",
286 mig_table_max_displ, mach_kobj_count);
287 }
288 STARTUP(MACH_IPC, STARTUP_RANK_FIRST, mig_init);
289
290 /*
291 * Do a hash table lookup for given msgh_id. Return 0
292 * if not found.
293 */
294 static mig_hash_t *
find_mig_hash_entry(int msgh_id)295 find_mig_hash_entry(int msgh_id)
296 {
297 unsigned int i = (unsigned int)MIG_HASH(msgh_id);
298 int max_iter = mig_table_max_displ;
299 mig_hash_t *ptr;
300
301 do {
302 ptr = &mig_buckets[i++ % MAX_MIG_ENTRIES];
303 } while (msgh_id != ptr->num && ptr->num && --max_iter);
304
305 if (!ptr->routine || msgh_id != ptr->num) {
306 ptr = (mig_hash_t *)0;
307 }
308
309 return ptr;
310 }
311
312 static kern_return_t
ipc_kobject_reply_status(ipc_kmsg_t kmsg)313 ipc_kobject_reply_status(ipc_kmsg_t kmsg)
314 {
315 mach_msg_header_t *hdr = ikm_header(kmsg);
316
317 if (hdr->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
318 return KERN_SUCCESS;
319 }
320
321 return ((mig_reply_error_t *)hdr)->RetCode;
322 }
323
324 /*
325 * Routine: ipc_kobject_set_kobjidx
326 * Purpose:
327 * Set the index for the kobject filter
328 * mask for a given message ID.
329 */
330 kern_return_t
ipc_kobject_set_kobjidx(int msgh_id,int index)331 ipc_kobject_set_kobjidx(
332 int msgh_id,
333 int index)
334 {
335 mig_hash_t *ptr = find_mig_hash_entry(msgh_id);
336
337 if (ptr == (mig_hash_t *)0) {
338 return KERN_INVALID_ARGUMENT;
339 }
340
341 assert(index < mach_kobj_count);
342 ptr->kobjidx = index;
343
344 return KERN_SUCCESS;
345 }
346
347 static void
ipc_kobject_init_reply(ipc_kmsg_t reply,const ipc_kmsg_t request,kern_return_t kr)348 ipc_kobject_init_reply(
349 ipc_kmsg_t reply,
350 const ipc_kmsg_t request,
351 kern_return_t kr)
352 {
353 mach_msg_header_t *req_hdr = ikm_header(request);
354 mach_msg_header_t *reply_hdr = ikm_header(reply);
355
356 #define InP ((mach_msg_header_t *) req_hdr)
357 #define OutP ((mig_reply_error_t *) reply_hdr)
358
359 OutP->NDR = NDR_record;
360 OutP->Head.msgh_size = sizeof(mig_reply_error_t);
361
362 OutP->Head.msgh_bits =
363 MACH_MSGH_BITS_SET(MACH_MSGH_BITS_LOCAL(InP->msgh_bits), 0, 0, 0);
364 OutP->Head.msgh_remote_port = InP->msgh_local_port;
365 OutP->Head.msgh_local_port = MACH_PORT_NULL;
366 OutP->Head.msgh_voucher_port = MACH_PORT_NULL;
367 OutP->Head.msgh_id = InP->msgh_id + 100;
368
369 OutP->RetCode = kr;
370 #undef InP
371 #undef OutP
372 }
373
374 /*
375 * Routine: ipc_kobject_server_internal
376 * Purpose:
377 * Handle a message sent to the kernel.
378 * Generates a reply message.
379 * Version for Untyped IPC.
380 * Conditions:
381 * Nothing locked.
382 */
383 static kern_return_t
ipc_kobject_server_internal(__unused ipc_port_t port,ipc_kmsg_t request,ipc_kmsg_t * replyp)384 ipc_kobject_server_internal(
385 __unused ipc_port_t port,
386 ipc_kmsg_t request,
387 ipc_kmsg_t *replyp)
388 {
389 int request_msgh_id;
390 ipc_kmsg_t reply = IKM_NULL;
391 mach_msg_size_t reply_size;
392 mig_hash_t *ptr;
393 mach_msg_header_t *req_hdr, *reply_hdr;
394
395 req_hdr = ikm_header(request);
396 request_msgh_id = req_hdr->msgh_id;
397
398 /* Find corresponding mig_hash entry, if any */
399 ptr = find_mig_hash_entry(request_msgh_id);
400
401 /* Get the reply_size. */
402 if (ptr == (mig_hash_t *)0) {
403 reply_size = sizeof(mig_reply_error_t);
404 } else {
405 reply_size = ptr->size;
406 }
407
408 /*
409 * MIG should really assure no data leakage -
410 * but until it does, pessimistically zero the
411 * whole reply buffer.
412 */
413 reply = ipc_kmsg_alloc(reply_size, 0, 0, IPC_KMSG_ALLOC_KERNEL |
414 IPC_KMSG_ALLOC_LINEAR | IPC_KMSG_ALLOC_ZERO | IPC_KMSG_ALLOC_NOFAIL);
415 ipc_kobject_init_reply(reply, request, KERN_SUCCESS);
416 reply_hdr = ikm_header(reply);
417
418 /*
419 * Find the routine to call, and call it
420 * to perform the kernel function
421 */
422 if (ptr) {
423 thread_ro_t tro = current_thread_ro();
424 task_t curtask = tro->tro_task;
425 struct proc *curproc = tro->tro_proc;
426
427 #if CONFIG_MACF
428 int idx = ptr->kobjidx;
429 uint8_t *filter_mask = task_get_mach_kobj_filter_mask(curtask);
430
431 /* Check kobject mig filter mask, if exists. */
432 if (filter_mask != NULL &&
433 idx != KOBJ_IDX_NOT_SET &&
434 !bitstr_test(filter_mask, idx) &&
435 mac_task_kobj_msg_evaluate != NULL) {
436 /* Not in filter mask, evaluate policy. */
437 kern_return_t kr = mac_task_kobj_msg_evaluate(curproc,
438 request_msgh_id, idx);
439 if (kr != KERN_SUCCESS) {
440 ((mig_reply_error_t *)reply_hdr)->RetCode = kr;
441 goto skip_kobjcall;
442 }
443 }
444 #endif /* CONFIG_MACF */
445
446 __BeforeKobjectServerTrace(idx);
447 (*ptr->routine)(req_hdr, reply_hdr);
448 __AfterKobjectServerTrace(idx);
449
450 #if CONFIG_MACF
451 skip_kobjcall:
452 #endif
453
454 counter_inc(&kernel_task->messages_received);
455 } else {
456 #if DEVELOPMENT || DEBUG
457 printf("ipc_kobject_server: bogus kernel message, id=%d\n",
458 req_hdr->msgh_id);
459 #endif /* DEVELOPMENT || DEBUG */
460 _MIG_MSGID_INVALID(req_hdr->msgh_id);
461
462 ((mig_reply_error_t *)reply_hdr)->RetCode = MIG_BAD_ID;
463 }
464
465 if (ipc_kobject_reply_status(reply) == MIG_NO_REPLY) {
466 /*
467 * The server function will send a reply message
468 * using the reply port right, which it has saved.
469 */
470 ipc_kmsg_free(reply);
471 reply = IKM_NULL;
472 }
473
474 *replyp = reply;
475 return KERN_SUCCESS;
476 }
477
478
479 /*
480 * Routine: ipc_kobject_server
481 * Purpose:
482 * Handle a message sent to the kernel.
483 * Generates a reply message.
484 * Version for Untyped IPC.
485 *
486 * Ownership of the incoming rights (from the request)
487 * are transferred on success (wether a reply is made or not).
488 *
489 * Conditions:
490 * Nothing locked.
491 */
492 ipc_kmsg_t
ipc_kobject_server(ipc_port_t port,ipc_kmsg_t request,mach_msg_option_t option __unused)493 ipc_kobject_server(
494 ipc_port_t port,
495 ipc_kmsg_t request,
496 mach_msg_option_t option __unused)
497 {
498 mach_msg_header_t *req_hdr = ikm_header(request);
499 #if DEVELOPMENT || DEBUG
500 const int request_msgh_id = req_hdr->msgh_id;
501 #endif
502 ipc_port_t request_voucher_port;
503 ipc_kmsg_t reply = IKM_NULL;
504 mach_msg_header_t *reply_hdr;
505 kern_return_t kr;
506
507 ipc_kmsg_trace_send(request, option);
508
509 if (ip_kotype(port) == IKOT_UEXT_OBJECT) {
510 kr = uext_server(port, request, &reply);
511 } else {
512 kr = ipc_kobject_server_internal(port, request, &reply);
513 }
514
515 if (kr != KERN_SUCCESS) {
516 assert(kr != MACH_SEND_TIMED_OUT &&
517 kr != MACH_SEND_INTERRUPTED &&
518 kr != MACH_SEND_INVALID_DEST);
519 assert(reply == IKM_NULL);
520
521 /* convert the server error into a MIG error */
522 reply = ipc_kmsg_alloc(sizeof(mig_reply_error_t), 0, 0,
523 IPC_KMSG_ALLOC_KERNEL | IPC_KMSG_ALLOC_SAVED |
524 IPC_KMSG_ALLOC_ZERO | IPC_KMSG_ALLOC_NOFAIL);
525 static_assert(sizeof(mig_reply_error_t) < IKM_SAVED_MSG_SIZE);
526
527 ipc_kobject_init_reply(reply, request, kr);
528 }
529
530 counter_inc(&kernel_task->messages_sent);
531 /*
532 * Destroy destination. The following code differs from
533 * ipc_object_destroy in that we release the send-once
534 * right instead of generating a send-once notification
535 * (which would bring us here again, creating a loop).
536 * It also differs in that we only expect send or
537 * send-once rights, never receive rights.
538 */
539 switch (MACH_MSGH_BITS_REMOTE(req_hdr->msgh_bits)) {
540 case MACH_MSG_TYPE_PORT_SEND:
541 ipc_port_release_send(req_hdr->msgh_remote_port);
542 break;
543
544 case MACH_MSG_TYPE_PORT_SEND_ONCE:
545 ipc_port_release_sonce(req_hdr->msgh_remote_port);
546 break;
547
548 default:
549 panic("ipc_kobject_server: strange destination rights");
550 }
551
552 /*
553 * Destroy voucher. The kernel MIG servers never take ownership
554 * of vouchers sent in messages. Swallow any such rights here.
555 */
556 request_voucher_port = ipc_kmsg_get_voucher_port(request);
557 if (IP_VALID(request_voucher_port)) {
558 assert(MACH_MSG_TYPE_PORT_SEND ==
559 MACH_MSGH_BITS_VOUCHER(req_hdr->msgh_bits));
560 ipc_port_release_send(request_voucher_port);
561 ipc_kmsg_clear_voucher_port(request);
562 }
563
564 if (reply == IKM_NULL ||
565 ipc_kobject_reply_status(reply) == KERN_SUCCESS) {
566 /*
567 * The server function is responsible for the contents
568 * of the message. The reply port right is moved
569 * to the reply message, and we have deallocated
570 * the destination port right, so we just need
571 * to free the kmsg.
572 */
573 ipc_kmsg_free(request);
574 } else {
575 /*
576 * The message contents of the request are intact.
577 * Remote port has been released above. Do not destroy
578 * the reply port right either, which is needed in the reply message.
579 */
580 ipc_kmsg_destroy(request, IPC_KMSG_DESTROY_SKIP_LOCAL | IPC_KMSG_DESTROY_SKIP_REMOTE);
581 }
582
583 if (reply != IKM_NULL) {
584 reply_hdr = ikm_header(reply);
585 ipc_port_t reply_port = reply_hdr->msgh_remote_port;
586
587 if (!IP_VALID(reply_port)) {
588 /*
589 * Can't queue the reply message if the destination
590 * (the reply port) isn't valid.
591 */
592 ipc_kmsg_destroy(reply, IPC_KMSG_DESTROY_NOT_SIGNED);
593 reply = IKM_NULL;
594 } else if (ip_in_space_noauth(reply_port, ipc_space_kernel)) {
595 /* do not lock reply port, use raw pointer comparison */
596
597 /*
598 * Don't send replies to kobject kernel ports.
599 */
600 #if DEVELOPMENT || DEBUG
601 printf("%s: refusing to send reply to kobject %d port (id:%d)\n",
602 __func__, ip_kotype(reply_port), request_msgh_id);
603 #endif /* DEVELOPMENT || DEBUG */
604 ipc_kmsg_destroy(reply, IPC_KMSG_DESTROY_NOT_SIGNED);
605 reply = IKM_NULL;
606 }
607 }
608
609 return reply;
610 }
611
612 static __header_always_inline void
ipc_kobject_set_raw(ipc_port_t port,ipc_kobject_t kobject,ipc_kobject_type_t type)613 ipc_kobject_set_raw(
614 ipc_port_t port,
615 ipc_kobject_t kobject,
616 ipc_kobject_type_t type)
617 {
618 uintptr_t *store = &port->ip_kobject;
619
620 #if __has_feature(ptrauth_calls)
621 type |= port->ip_immovable_receive << 14;
622 type |= port->ip_immovable_send << 15;
623 type ^= OS_PTRAUTH_DISCRIMINATOR("ipc_port.ip_kobject");
624 kobject = ptrauth_sign_unauthenticated(kobject,
625 ptrauth_key_process_independent_data,
626 ptrauth_blend_discriminator(store, type));
627 #else
628 (void)type;
629 #endif // __has_feature(ptrauth_calls)
630
631 *store = (uintptr_t)kobject;
632 }
633
634 static inline void
ipc_kobject_set_internal(ipc_port_t port,ipc_kobject_t kobject,ipc_kobject_type_t type)635 ipc_kobject_set_internal(
636 ipc_port_t port,
637 ipc_kobject_t kobject,
638 ipc_kobject_type_t type)
639 {
640 assert(type != IKOT_NONE);
641 io_bits_or(ip_to_object(port), type);
642 ipc_kobject_set_raw(port, kobject, type);
643 }
644
645 /*
646 * Routine: ipc_kobject_get_raw
647 * Purpose:
648 * Returns the kobject pointer of a specified port.
649 *
650 * This returns the current value of the kobject pointer,
651 * without any validation (the caller is expected to do
652 * the validation it needs).
653 *
654 * Conditions:
655 * The port is a kobject of the proper type.
656 */
657 __header_always_inline ipc_kobject_t
ipc_kobject_get_raw(ipc_port_t port,ipc_kobject_type_t type)658 ipc_kobject_get_raw(
659 ipc_port_t port,
660 ipc_kobject_type_t type)
661 {
662 uintptr_t *store = &port->ip_kobject;
663 ipc_kobject_t kobject = (ipc_kobject_t)*store;
664
665 #if __has_feature(ptrauth_calls)
666 type |= port->ip_immovable_receive << 14;
667 type |= port->ip_immovable_send << 15;
668 type ^= OS_PTRAUTH_DISCRIMINATOR("ipc_port.ip_kobject");
669 kobject = ptrauth_auth_data(kobject,
670 ptrauth_key_process_independent_data,
671 ptrauth_blend_discriminator(store, type));
672 #else
673 (void)type;
674 #endif // __has_feature(ptrauth_calls)
675
676 return kobject;
677 }
678
679 __abortlike
680 static void
ipc_kobject_require_panic(ipc_port_t port,ipc_kobject_t kobject,ipc_kobject_type_t kotype)681 ipc_kobject_require_panic(
682 ipc_port_t port,
683 ipc_kobject_t kobject,
684 ipc_kobject_type_t kotype)
685 {
686 if (ip_kotype(port) != kotype) {
687 panic("port %p: invalid kobject type, got %d wanted %d",
688 port, ip_kotype(port), kotype);
689 }
690 panic("port %p: invalid kobject, got %p wanted %p",
691 port, ipc_kobject_get_raw(port, kotype), kobject);
692 }
693
694 __header_always_inline void
ipc_kobject_require(ipc_port_t port,ipc_kobject_t kobject,ipc_kobject_type_t kotype)695 ipc_kobject_require(
696 ipc_port_t port,
697 ipc_kobject_t kobject,
698 ipc_kobject_type_t kotype)
699 {
700 ipc_kobject_t cur;
701
702 if (__improbable(ip_kotype(port) != kotype)) {
703 ipc_kobject_require_panic(port, kobject, kotype);
704 }
705 cur = ipc_kobject_get_raw(port, kotype);
706 if (cur && cur != kobject) {
707 ipc_kobject_require_panic(port, kobject, kotype);
708 }
709 }
710
711 /*
712 * Routine: ipc_kobject_get_locked
713 * Purpose:
714 * Returns the kobject pointer of a specified port,
715 * for an expected type.
716 *
717 * Returns IKO_NULL if the port isn't active.
718 *
719 * This function may be used when:
720 * - the port lock is held
721 * - the kobject association stays while there
722 * are any outstanding rights.
723 *
724 * Conditions:
725 * The port is a kobject of the proper type.
726 */
727 ipc_kobject_t
ipc_kobject_get_locked(ipc_port_t port,ipc_kobject_type_t type)728 ipc_kobject_get_locked(
729 ipc_port_t port,
730 ipc_kobject_type_t type)
731 {
732 ipc_kobject_t kobject = IKO_NULL;
733
734 if (ip_active(port) && type == ip_kotype(port)) {
735 kobject = ipc_kobject_get_raw(port, type);
736 }
737
738 return kobject;
739 }
740
741 /*
742 * Routine: ipc_kobject_get_stable
743 * Purpose:
744 * Returns the kobject pointer of a specified port,
745 * for an expected type, for types where the port/kobject
746 * association is permanent.
747 *
748 * Returns IKO_NULL if the port isn't active.
749 *
750 * Conditions:
751 * The port is a kobject of the proper type.
752 */
753 ipc_kobject_t
ipc_kobject_get_stable(ipc_port_t port,ipc_kobject_type_t type)754 ipc_kobject_get_stable(
755 ipc_port_t port,
756 ipc_kobject_type_t type)
757 {
758 assert(ipc_kobject_ops_get(type)->iko_op_stable);
759 return ipc_kobject_get_locked(port, type);
760 }
761
762 /*
763 * Routine: ipc_kobject_init_port
764 * Purpose:
765 * Initialize a kobject port with the given types and options.
766 *
767 * This function never fails.
768 */
769 static inline void
ipc_kobject_init_port(ipc_port_t port,ipc_kobject_t kobject,ipc_kobject_type_t type,ipc_kobject_alloc_options_t options)770 ipc_kobject_init_port(
771 ipc_port_t port,
772 ipc_kobject_t kobject,
773 ipc_kobject_type_t type,
774 ipc_kobject_alloc_options_t options)
775 {
776 if (options & IPC_KOBJECT_ALLOC_MAKE_SEND) {
777 ipc_port_make_send_any_locked(port);
778 }
779 if (options & IPC_KOBJECT_ALLOC_NSREQUEST) {
780 port->ip_nsrequest = IP_KOBJECT_NSREQUEST_ARMED;
781 ip_reference(port);
782 }
783 if (options & IPC_KOBJECT_ALLOC_NO_GRANT) {
784 port->ip_no_grant = 1;
785 }
786 if (options & IPC_KOBJECT_ALLOC_IMMOVABLE_SEND) {
787 port->ip_immovable_send = 1;
788 }
789 if (options & IPC_KOBJECT_ALLOC_PINNED) {
790 port->ip_pinned = 1;
791 }
792
793 ipc_kobject_set_internal(port, kobject, type);
794 }
795
796 /*
797 * Routine: ipc_kobject_alloc_port
798 * Purpose:
799 * Allocate a kobject port in the kernel space of the specified type.
800 *
801 * This function never fails.
802 *
803 * Conditions:
804 * No locks held (memory is allocated)
805 */
806 ipc_port_t
ipc_kobject_alloc_port(ipc_kobject_t kobject,ipc_kobject_type_t type,ipc_kobject_alloc_options_t options)807 ipc_kobject_alloc_port(
808 ipc_kobject_t kobject,
809 ipc_kobject_type_t type,
810 ipc_kobject_alloc_options_t options)
811 {
812 ipc_port_t port;
813
814 port = ipc_port_alloc_special(ipc_space_kernel, IPC_PORT_INIT_NONE);
815 if (port == IP_NULL) {
816 panic("ipc_kobject_alloc_port(): failed to allocate port");
817 }
818
819 ipc_kobject_init_port(port, kobject, type, options);
820 return port;
821 }
822
823 /*
824 * Routine: ipc_kobject_alloc_labeled_port
825 * Purpose:
826 * Allocate a kobject port and associated mandatory access label
827 * in the kernel space of the specified type.
828 *
829 * This function never fails.
830 *
831 * Conditions:
832 * No locks held (memory is allocated)
833 */
834
835 ipc_port_t
ipc_kobject_alloc_labeled_port(ipc_kobject_t kobject,ipc_kobject_type_t type,ipc_label_t label,ipc_kobject_alloc_options_t options)836 ipc_kobject_alloc_labeled_port(
837 ipc_kobject_t kobject,
838 ipc_kobject_type_t type,
839 ipc_label_t label,
840 ipc_kobject_alloc_options_t options)
841 {
842 ipc_port_t port;
843
844 port = ipc_kobject_alloc_port(kobject, type, options);
845
846 ipc_port_set_label(port, label);
847
848 return port;
849 }
850
851 static void
ipc_kobject_subst_once_no_senders(ipc_port_t port,mach_port_mscount_t mscount)852 ipc_kobject_subst_once_no_senders(
853 ipc_port_t port,
854 mach_port_mscount_t mscount)
855 {
856 ipc_port_t ko_port;
857
858 ko_port = ipc_kobject_dealloc_port(port, mscount, IKOT_PORT_SUBST_ONCE);
859
860 if (ko_port) {
861 /*
862 * Clean up the right if the wrapper wasn't hollowed out
863 * by ipc_kobject_alloc_subst_once().
864 */
865 ipc_port_release_send(ko_port);
866 }
867 }
868
869 /*
870 * Routine: ipc_kobject_alloc_subst_once
871 * Purpose:
872 * Make a port that will be substituted by the kolabel
873 * rules once, preventing the next substitution (of its target)
874 * to happen if any.
875 *
876 * Returns:
877 * A port with a send right, that will substitute to its "kobject".
878 *
879 * Conditions:
880 * No locks held (memory is allocated).
881 *
882 * `target` holds a send-right donated to this function,
883 * consumed in ipc_kobject_subst_once_no_senders().
884 */
885 ipc_port_t
ipc_kobject_alloc_subst_once(ipc_port_t target)886 ipc_kobject_alloc_subst_once(
887 ipc_port_t target)
888 {
889 if (!IP_VALID(target)) {
890 return target;
891 }
892 return ipc_kobject_alloc_labeled_port(target,
893 IKOT_PORT_SUBST_ONCE, IPC_LABEL_SUBST_ONCE,
894 IPC_KOBJECT_ALLOC_MAKE_SEND | IPC_KOBJECT_ALLOC_NSREQUEST);
895 }
896
897 /*
898 * Routine: ipc_kobject_make_send_lazy_alloc_port
899 * Purpose:
900 * Make a send once for a kobject port.
901 *
902 * A location owning this port is passed in port_store.
903 * If no port exists, a port is made lazily.
904 *
905 * A send right is made for the port, and if this is the first one
906 * (possibly not for the first time), then the no-more-senders
907 * notification is rearmed.
908 *
909 * When a notification is armed, the kobject must donate
910 * one of its references to the port. It is expected
911 * the no-more-senders notification will consume this reference.
912 *
913 * Returns:
914 * TRUE if a notification was armed
915 * FALSE else
916 *
917 * Conditions:
918 * Nothing is locked, memory can be allocated.
919 * The caller must be able to donate a kobject reference to the port.
920 */
921 bool
ipc_kobject_make_send_lazy_alloc_port(ipc_port_t * port_store,ipc_kobject_t kobject,ipc_kobject_type_t type,ipc_kobject_alloc_options_t alloc_opts)922 ipc_kobject_make_send_lazy_alloc_port(
923 ipc_port_t *port_store,
924 ipc_kobject_t kobject,
925 ipc_kobject_type_t type,
926 ipc_kobject_alloc_options_t alloc_opts)
927 {
928 ipc_port_t port, previous;
929 kern_return_t kr;
930
931 alloc_opts |= IPC_KOBJECT_ALLOC_MAKE_SEND | IPC_KOBJECT_ALLOC_NSREQUEST;
932 port = os_atomic_load(port_store, dependency);
933
934 if (!IP_VALID(port)) {
935 port = ipc_kobject_alloc_port(kobject, type, alloc_opts);
936
937 if (os_atomic_cmpxchgv(port_store,
938 IP_NULL, port, &previous, release)) {
939 return TRUE;
940 }
941
942 /*
943 * undo IPC_KOBJECT_ALLOC_MAKE_SEND,
944 * ipc_kobject_dealloc_port will handle
945 * IPC_KOBJECT_ALLOC_NSREQUEST.
946 */
947 port->ip_mscount = 0;
948 port->ip_srights = 0;
949 ip_release_live(port);
950 ipc_kobject_dealloc_port(port, 0, type);
951
952 port = previous;
953 }
954
955 kr = ipc_kobject_make_send_nsrequest(port, kobject, type);
956 assert(kr == KERN_SUCCESS || kr == KERN_ALREADY_WAITING);
957
958 return kr == KERN_SUCCESS;
959 }
960
961 /*
962 * Routine: ipc_kobject_make_send_lazy_alloc_labeled_port
963 * Purpose:
964 * Make a send once for a kobject port.
965 *
966 * A location owning this port is passed in port_store.
967 * If no port exists, a port is made lazily.
968 *
969 * A send right is made for the port, and if this is the first one
970 * (possibly not for the first time), then the no-more-senders
971 * notification is rearmed.
972 *
973 * When a notification is armed, the kobject must donate
974 * one of its references to the port. It is expected
975 * the no-more-senders notification will consume this reference.
976 *
977 * Returns:
978 * TRUE if a notification was armed
979 * FALSE else
980 *
981 * Conditions:
982 * Nothing is locked, memory can be allocated.
983 * The caller must be able to donate a kobject reference to the port.
984 */
985 boolean_t
ipc_kobject_make_send_lazy_alloc_labeled_port(ipc_port_t * port_store,ipc_kobject_t kobject,ipc_kobject_type_t type,ipc_label_t label)986 ipc_kobject_make_send_lazy_alloc_labeled_port(
987 ipc_port_t *port_store,
988 ipc_kobject_t kobject,
989 ipc_kobject_type_t type,
990 ipc_label_t label)
991 {
992 ipc_port_t port, previous;
993 kern_return_t kr;
994
995 port = os_atomic_load(port_store, dependency);
996
997 if (!IP_VALID(port)) {
998 port = ipc_kobject_alloc_labeled_port(kobject, type, label,
999 IPC_KOBJECT_ALLOC_MAKE_SEND | IPC_KOBJECT_ALLOC_NSREQUEST);
1000 if (os_atomic_cmpxchgv(port_store, IP_NULL, port, &previous, release)) {
1001 return TRUE;
1002 }
1003
1004 /*
1005 * undo IPC_KOBJECT_ALLOC_MAKE_SEND,
1006 * ipc_kobject_dealloc_port will handle
1007 * IPC_KOBJECT_ALLOC_NSREQUEST.
1008 */
1009 port->ip_mscount = 0;
1010 port->ip_srights = 0;
1011 ip_release_live(port);
1012 ipc_kobject_dealloc_port(port, 0, type);
1013
1014 port = previous;
1015 assert(ip_is_kolabeled(port));
1016 }
1017
1018 kr = ipc_kobject_make_send_nsrequest(port, kobject, type);
1019 assert(kr == KERN_SUCCESS || kr == KERN_ALREADY_WAITING);
1020
1021 return kr == KERN_SUCCESS;
1022 }
1023
1024 /*
1025 * Routine: ipc_kobject_nsrequest_locked
1026 * Purpose:
1027 * Arm the no-senders notification for the given kobject
1028 * if it doesn't have one armed yet.
1029 *
1030 * Conditions:
1031 * Port is locked and active.
1032 *
1033 * Returns:
1034 * KERN_SUCCESS: the notification was armed
1035 * KERN_ALREADY_WAITING: the notification was already armed
1036 * KERN_FAILURE: the notification would fire immediately
1037 */
1038 static inline kern_return_t
ipc_kobject_nsrequest_locked(ipc_port_t port,mach_port_mscount_t sync)1039 ipc_kobject_nsrequest_locked(
1040 ipc_port_t port,
1041 mach_port_mscount_t sync)
1042 {
1043 if (port->ip_nsrequest == IP_KOBJECT_NSREQUEST_ARMED) {
1044 return KERN_ALREADY_WAITING;
1045 }
1046
1047 if (port->ip_srights == 0 && sync <= port->ip_mscount) {
1048 return KERN_FAILURE;
1049 }
1050
1051 port->ip_nsrequest = IP_KOBJECT_NSREQUEST_ARMED;
1052 ip_reference(port);
1053 return KERN_SUCCESS;
1054 }
1055
1056
1057 /*
1058 * Routine: ipc_kobject_nsrequest
1059 * Purpose:
1060 * Arm the no-senders notification for the given kobject
1061 * if it doesn't have one armed yet.
1062 *
1063 * Returns:
1064 * KERN_SUCCESS: the notification was armed
1065 * KERN_ALREADY_WAITING: the notification was already armed
1066 * KERN_FAILURE: the notification would fire immediately
1067 * KERN_INVALID_RIGHT: the port is dead
1068 */
1069 kern_return_t
ipc_kobject_nsrequest(ipc_port_t port,mach_port_mscount_t sync,mach_port_mscount_t * mscount)1070 ipc_kobject_nsrequest(
1071 ipc_port_t port,
1072 mach_port_mscount_t sync,
1073 mach_port_mscount_t *mscount)
1074 {
1075 kern_return_t kr = KERN_INVALID_RIGHT;
1076
1077 if (IP_VALID(port)) {
1078 ip_mq_lock(port);
1079
1080 if (mscount) {
1081 *mscount = port->ip_mscount;
1082 }
1083 if (ip_active(port)) {
1084 kr = ipc_kobject_nsrequest_locked(port, sync);
1085 }
1086
1087 ip_mq_unlock(port);
1088 } else if (mscount) {
1089 *mscount = 0;
1090 }
1091
1092 return kr;
1093 }
1094
1095 ipc_port_t
ipc_kobject_copy_send(ipc_port_t port,ipc_kobject_t kobject,ipc_kobject_type_t kotype)1096 ipc_kobject_copy_send(
1097 ipc_port_t port,
1098 ipc_kobject_t kobject,
1099 ipc_kobject_type_t kotype)
1100 {
1101 ipc_port_t sright = port;
1102
1103 if (IP_VALID(port)) {
1104 ip_mq_lock(port);
1105 if (ip_active(port)) {
1106 ipc_kobject_require(port, kobject, kotype);
1107 ipc_port_copy_send_any_locked(port);
1108 } else {
1109 sright = IP_DEAD;
1110 }
1111 ip_mq_unlock(port);
1112 }
1113
1114 return sright;
1115 }
1116
1117 ipc_port_t
ipc_kobject_make_send(ipc_port_t port,ipc_kobject_t kobject,ipc_kobject_type_t kotype)1118 ipc_kobject_make_send(
1119 ipc_port_t port,
1120 ipc_kobject_t kobject,
1121 ipc_kobject_type_t kotype)
1122 {
1123 ipc_port_t sright = port;
1124
1125 if (IP_VALID(port)) {
1126 ip_mq_lock(port);
1127 if (ip_active(port)) {
1128 ipc_kobject_require(port, kobject, kotype);
1129 ipc_port_make_send_any_locked(port);
1130 } else {
1131 sright = IP_DEAD;
1132 }
1133 ip_mq_unlock(port);
1134 }
1135
1136 return sright;
1137 }
1138
1139 kern_return_t
ipc_kobject_make_send_nsrequest(ipc_port_t port,ipc_kobject_t kobject,ipc_kobject_type_t kotype)1140 ipc_kobject_make_send_nsrequest(
1141 ipc_port_t port,
1142 ipc_kobject_t kobject,
1143 ipc_kobject_type_t kotype)
1144 {
1145 kern_return_t kr = KERN_INVALID_RIGHT;
1146
1147 if (IP_VALID(port)) {
1148 ip_mq_lock(port);
1149 if (ip_active(port)) {
1150 ipc_kobject_require(port, kobject, kotype);
1151 ipc_port_make_send_any_locked(port);
1152 kr = ipc_kobject_nsrequest_locked(port, 0);
1153 assert(kr != KERN_FAILURE);
1154 }
1155 ip_mq_unlock(port);
1156 }
1157
1158 return kr;
1159 }
1160
1161 static inline ipc_kobject_t
ipc_kobject_disable_internal(ipc_port_t port,ipc_kobject_type_t type)1162 ipc_kobject_disable_internal(
1163 ipc_port_t port,
1164 ipc_kobject_type_t type)
1165 {
1166 ipc_kobject_t kobject = ipc_kobject_get_raw(port, type);
1167
1168 ipc_kobject_set_raw(port, IKO_NULL, type);
1169 if (ip_is_kolabeled(port)) {
1170 port->ip_kolabel->ikol_alt_port = IP_NULL;
1171 }
1172
1173 return kobject;
1174 }
1175
1176 /*
1177 * Routine: ipc_kobject_dealloc_port_and_unlock
1178 * Purpose:
1179 * Destroys a port allocated with any of the ipc_kobject_alloc*
1180 * functions.
1181 *
1182 * This will atomically:
1183 * - make the port inactive,
1184 * - optionally check the make send count
1185 * - disable (nil-out) the kobject pointer for kobjects without
1186 * a destroy callback.
1187 *
1188 * The port will retain its kobject-ness and kobject type.
1189 *
1190 *
1191 * Returns:
1192 * The kobject pointer that was set prior to this call
1193 * (possibly NULL if the kobject was already disabled).
1194 *
1195 * Conditions:
1196 * The port is active and locked.
1197 * On return the port is inactive and unlocked.
1198 */
1199 __abortlike
1200 static void
__ipc_kobject_dealloc_bad_type_panic(ipc_port_t port,ipc_kobject_type_t type)1201 __ipc_kobject_dealloc_bad_type_panic(ipc_port_t port, ipc_kobject_type_t type)
1202 {
1203 panic("port %p of type %d, expecting %d", port, ip_kotype(port), type);
1204 }
1205
1206 __abortlike
1207 static void
__ipc_kobject_dealloc_bad_mscount_panic(ipc_port_t port,mach_port_mscount_t mscount,ipc_kobject_type_t type)1208 __ipc_kobject_dealloc_bad_mscount_panic(
1209 ipc_port_t port,
1210 mach_port_mscount_t mscount,
1211 ipc_kobject_type_t type)
1212 {
1213 panic("unexpected make-send count: %p[%d], %d, %d",
1214 port, type, port->ip_mscount, mscount);
1215 }
1216
1217 __abortlike
1218 static void
__ipc_kobject_dealloc_bad_srights_panic(ipc_port_t port,ipc_kobject_type_t type)1219 __ipc_kobject_dealloc_bad_srights_panic(
1220 ipc_port_t port,
1221 ipc_kobject_type_t type)
1222 {
1223 panic("unexpected send right count: %p[%d], %d",
1224 port, type, port->ip_srights);
1225 }
1226
1227 ipc_kobject_t
ipc_kobject_dealloc_port_and_unlock(ipc_port_t port,mach_port_mscount_t mscount,ipc_kobject_type_t type)1228 ipc_kobject_dealloc_port_and_unlock(
1229 ipc_port_t port,
1230 mach_port_mscount_t mscount,
1231 ipc_kobject_type_t type)
1232 {
1233 ipc_kobject_t kobject = IKO_NULL;
1234 ipc_kobject_ops_t ops = ipc_kobject_ops_get(type);
1235
1236 require_ip_active(port);
1237
1238 if (ip_kotype(port) != type) {
1239 __ipc_kobject_dealloc_bad_type_panic(port, type);
1240 }
1241
1242 if (mscount && port->ip_mscount != mscount) {
1243 __ipc_kobject_dealloc_bad_mscount_panic(port, mscount, type);
1244 }
1245 if ((mscount || ops->iko_op_stable) && port->ip_srights != 0) {
1246 __ipc_kobject_dealloc_bad_srights_panic(port, type);
1247 }
1248
1249 if (!ops->iko_op_destroy) {
1250 kobject = ipc_kobject_disable_internal(port, type);
1251 }
1252
1253 ipc_port_dealloc_special_and_unlock(port, ipc_space_kernel);
1254
1255 return kobject;
1256 }
1257
1258 /*
1259 * Routine: ipc_kobject_dealloc_port
1260 * Purpose:
1261 * Destroys a port allocated with any of the ipc_kobject_alloc*
1262 * functions.
1263 *
1264 * This will atomically:
1265 * - make the port inactive,
1266 * - optionally check the make send count
1267 * - disable (nil-out) the kobject pointer for kobjects without
1268 * a destroy callback.
1269 *
1270 * The port will retain its kobject-ness and kobject type.
1271 *
1272 *
1273 * Returns:
1274 * The kobject pointer that was set prior to this call
1275 * (possibly NULL if the kobject was already disabled).
1276 *
1277 * Conditions:
1278 * Nothing is locked.
1279 * The port is active.
1280 * On return the port is inactive.
1281 */
1282 ipc_kobject_t
ipc_kobject_dealloc_port(ipc_port_t port,mach_port_mscount_t mscount,ipc_kobject_type_t type)1283 ipc_kobject_dealloc_port(
1284 ipc_port_t port,
1285 mach_port_mscount_t mscount,
1286 ipc_kobject_type_t type)
1287 {
1288 ip_mq_lock(port);
1289 return ipc_kobject_dealloc_port_and_unlock(port, mscount, type);
1290 }
1291
1292 /*
1293 * Routine: ipc_kobject_enable
1294 * Purpose:
1295 * Make a port represent a kernel object of the given type.
1296 * The caller is responsible for handling refs for the
1297 * kernel object, if necessary.
1298 * Conditions:
1299 * Nothing locked.
1300 * The port must be active.
1301 */
1302 void
ipc_kobject_enable(ipc_port_t port,ipc_kobject_t kobject,ipc_kobject_type_t type)1303 ipc_kobject_enable(
1304 ipc_port_t port,
1305 ipc_kobject_t kobject,
1306 ipc_kobject_type_t type)
1307 {
1308 assert(!ipc_kobject_ops_get(type)->iko_op_stable);
1309
1310 ip_mq_lock(port);
1311 require_ip_active(port);
1312
1313 if (type != ip_kotype(port)) {
1314 panic("%s: unexpected kotype of port %p: want %d, got %d",
1315 __func__, port, type, ip_kotype(port));
1316 }
1317
1318 ipc_kobject_set_raw(port, kobject, type);
1319
1320 ip_mq_unlock(port);
1321 }
1322
1323 /*
1324 * Routine: ipc_kobject_disable_locked
1325 * Purpose:
1326 * Clear the kobject pointer for a port.
1327 * Conditions:
1328 * The port is locked.
1329 * Returns the current kobject pointer.
1330 */
1331 ipc_kobject_t
ipc_kobject_disable_locked(ipc_port_t port,ipc_kobject_type_t type)1332 ipc_kobject_disable_locked(
1333 ipc_port_t port,
1334 ipc_kobject_type_t type)
1335 {
1336 if (ip_active(port)) {
1337 assert(!ipc_kobject_ops_get(type)->iko_op_stable);
1338 }
1339
1340 if (ip_kotype(port) != type) {
1341 panic("port %p of type %d, expecting %d",
1342 port, ip_kotype(port), type);
1343 }
1344
1345 return ipc_kobject_disable_internal(port, type);
1346 }
1347
1348 /*
1349 * Routine: ipc_kobject_disable
1350 * Purpose:
1351 * Clear the kobject pointer for a port.
1352 * Conditions:
1353 * Nothing locked.
1354 * Returns the current kobject pointer.
1355 */
1356 ipc_kobject_t
ipc_kobject_disable(ipc_port_t port,ipc_kobject_type_t type)1357 ipc_kobject_disable(
1358 ipc_port_t port,
1359 ipc_kobject_type_t type)
1360 {
1361 ipc_kobject_t kobject;
1362
1363 ip_mq_lock(port);
1364 kobject = ipc_kobject_disable_locked(port, type);
1365 ip_mq_unlock(port);
1366
1367 return kobject;
1368 }
1369
1370 /*
1371 * Routine: ipc_kobject_upgrade_mktimer_locked
1372 * Purpose:
1373 * Upgrades a port to mktimer kobject status
1374 *
1375 * This pattern is rather bad as it leads to various
1376 * confusions that need to be special cased with kobject-ness
1377 * of ports. No new port with dual kobject/message-queue
1378 * semantics should be made ever.
1379 *
1380 * Conditions:
1381 * Port is locked
1382 */
1383 void
ipc_kobject_upgrade_mktimer_locked(ipc_port_t port,ipc_kobject_t kobject)1384 ipc_kobject_upgrade_mktimer_locked(
1385 ipc_port_t port,
1386 ipc_kobject_t kobject)
1387 {
1388 ipc_kobject_set_internal(port, kobject, IKOT_TIMER);
1389 }
1390
1391 /*
1392 * Routine: ipc_kobject_notify_no_senders
1393 * Purpose:
1394 * Handles a no-senders notification
1395 * sent to a kobject.
1396 *
1397 * A port reference is consumed.
1398 *
1399 * Conditions:
1400 * Nothing locked.
1401 */
1402 void
ipc_kobject_notify_no_senders(ipc_port_t port,mach_port_mscount_t mscount)1403 ipc_kobject_notify_no_senders(
1404 ipc_port_t port,
1405 mach_port_mscount_t mscount)
1406 {
1407 ipc_kobject_ops_t ops = ipc_kobject_ops_get(ip_kotype(port));
1408
1409 assert(ops->iko_op_no_senders);
1410 ops->iko_op_no_senders(port, mscount);
1411
1412 /* consume the ref ipc_notify_no_senders_prepare left */
1413 ip_release(port);
1414 }
1415
1416 /*
1417 * Routine: ipc_kobject_notify_no_senders
1418 * Purpose:
1419 * Handles a send once notifications
1420 * sent to a kobject.
1421 *
1422 * A send-once port reference is consumed.
1423 *
1424 * Conditions:
1425 * Port is locked.
1426 */
1427 void
ipc_kobject_notify_send_once_and_unlock(ipc_port_t port)1428 ipc_kobject_notify_send_once_and_unlock(
1429 ipc_port_t port)
1430 {
1431 /*
1432 * drop the send once right while we hold the port lock.
1433 * we will keep a port reference while we run the possible
1434 * callouts to kobjects.
1435 *
1436 * This a simplified version of ipc_port_release_sonce()
1437 * since kobjects can't be special reply ports.
1438 */
1439 assert(!port->ip_specialreply);
1440
1441 ip_sorights_dec(port);
1442 ip_mq_unlock(port);
1443
1444 /*
1445 * because there's very few consumers,
1446 * the code here isn't generic as it's really not worth it.
1447 */
1448 switch (ip_kotype(port)) {
1449 case IKOT_TASK_RESUME:
1450 task_suspension_send_once(port);
1451 break;
1452 default:
1453 break;
1454 }
1455
1456 ip_release(port);
1457 }
1458
1459
1460 /*
1461 * Routine: ipc_kobject_destroy
1462 * Purpose:
1463 * Release any kernel object resources associated
1464 * with the port, which is being destroyed.
1465 *
1466 * This path to free object resources should only be
1467 * needed when resources are associated with a user's port.
1468 * In the normal case, when the kernel is the receiver,
1469 * the code calling ipc_kobject_dealloc_port() should clean
1470 * up the object resources.
1471 *
1472 * Cleans up any kobject label that might be present.
1473 * Conditions:
1474 * The port is not locked, but it is dead.
1475 */
1476 void
ipc_kobject_destroy(ipc_port_t port)1477 ipc_kobject_destroy(
1478 ipc_port_t port)
1479 {
1480 ipc_kobject_ops_t ops = ipc_kobject_ops_get(ip_kotype(port));
1481
1482 if (ops->iko_op_permanent) {
1483 panic("trying to destroy an permanent port %p", port);
1484 }
1485 if (ops->iko_op_destroy) {
1486 ops->iko_op_destroy(port);
1487 }
1488
1489 if (ip_is_kolabeled(port)) {
1490 ipc_kobject_label_t labelp = port->ip_kolabel;
1491
1492 assert(labelp != NULL);
1493 assert(labelp->ikol_alt_port == IP_NULL);
1494 assert(ip_is_kobject(port));
1495 port->ip_kolabel = NULL;
1496 io_bits_andnot(ip_to_object(port), IO_BITS_KOLABEL);
1497 zfree(ipc_kobject_label_zone, labelp);
1498 }
1499 }
1500
1501 /*
1502 * Routine: ipc_kobject_label_substitute_task
1503 * Purpose:
1504 * Substitute a task control port for its immovable
1505 * equivalent when the receiver is that task.
1506 * Conditions:
1507 * Space is write locked and active.
1508 * Port is locked and active.
1509 * Returns:
1510 * - IP_NULL port if no substitution is to be done
1511 * - a valid port if a substitution needs to happen
1512 */
1513 static ipc_port_t
ipc_kobject_label_substitute_task(ipc_space_t space,ipc_kobject_label_t kolabel,ipc_port_t port)1514 ipc_kobject_label_substitute_task(
1515 ipc_space_t space,
1516 ipc_kobject_label_t kolabel,
1517 ipc_port_t port)
1518 {
1519 ipc_port_t subst = IP_NULL;
1520 task_t task = ipc_kobject_get_raw(port, IKOT_TASK_CONTROL);
1521
1522 if (task != TASK_NULL && task == space->is_task) {
1523 if ((subst = kolabel->ikol_alt_port)) {
1524 return subst;
1525 }
1526 }
1527
1528 return IP_NULL;
1529 }
1530
1531 /*
1532 * Routine: ipc_kobject_label_substitute_task_read
1533 * Purpose:
1534 * Substitute a task read port for its immovable
1535 * control equivalent when the receiver is that task.
1536 * Conditions:
1537 * Space is write locked and active.
1538 * Port is locked and active.
1539 * Returns:
1540 * - IP_NULL port if no substitution is to be done
1541 * - a valid port if a substitution needs to happen
1542 */
1543 static ipc_port_t
ipc_kobject_label_substitute_task_read(ipc_space_t space,ipc_kobject_label_t kolabel,ipc_port_t port)1544 ipc_kobject_label_substitute_task_read(
1545 ipc_space_t space,
1546 ipc_kobject_label_t kolabel,
1547 ipc_port_t port)
1548 {
1549 ipc_port_t subst = IP_NULL;
1550 task_t task = ipc_kobject_get_raw(port, IKOT_TASK_READ);
1551
1552 if (task != TASK_NULL && task == space->is_task) {
1553 if ((subst = kolabel->ikol_alt_port)) {
1554 return subst;
1555 }
1556 }
1557
1558 return IP_NULL;
1559 }
1560
1561 /*
1562 * Routine: ipc_kobject_label_substitute_thread
1563 * Purpose:
1564 * Substitute a thread control port for its immovable
1565 * equivalent when it belongs to the receiver task.
1566 * Conditions:
1567 * Space is write locked and active.
1568 * Port is locked and active.
1569 * Returns:
1570 * - IP_NULL port if no substitution is to be done
1571 * - a valid port if a substitution needs to happen
1572 */
1573 static ipc_port_t
ipc_kobject_label_substitute_thread(ipc_space_t space,ipc_kobject_label_t kolabel,ipc_port_t port)1574 ipc_kobject_label_substitute_thread(
1575 ipc_space_t space,
1576 ipc_kobject_label_t kolabel,
1577 ipc_port_t port)
1578 {
1579 ipc_port_t subst = IP_NULL;
1580 thread_t thread = ipc_kobject_get_raw(port, IKOT_THREAD_CONTROL);
1581
1582 if (thread != THREAD_NULL && space->is_task == get_threadtask(thread)) {
1583 if ((subst = kolabel->ikol_alt_port) != IP_NULL) {
1584 return subst;
1585 }
1586 }
1587
1588 return IP_NULL;
1589 }
1590
1591 /*
1592 * Routine: ipc_kobject_label_substitute_thread_read
1593 * Purpose:
1594 * Substitute a thread read port for its immovable
1595 * control equivalent when it belongs to the receiver task.
1596 * Conditions:
1597 * Space is write locked and active.
1598 * Port is locked and active.
1599 * Returns:
1600 * - IP_NULL port if no substitution is to be done
1601 * - a valid port if a substitution needs to happen
1602 */
1603 static ipc_port_t
ipc_kobject_label_substitute_thread_read(ipc_space_t space,ipc_kobject_label_t kolabel,ipc_port_t port)1604 ipc_kobject_label_substitute_thread_read(
1605 ipc_space_t space,
1606 ipc_kobject_label_t kolabel,
1607 ipc_port_t port)
1608 {
1609 ipc_port_t subst = IP_NULL;
1610 thread_t thread = ipc_kobject_get_raw(port, IKOT_THREAD_READ);
1611
1612 if (thread != THREAD_NULL && space->is_task == get_threadtask(thread)) {
1613 if ((subst = kolabel->ikol_alt_port) != IP_NULL) {
1614 return subst;
1615 }
1616 }
1617
1618 return IP_NULL;
1619 }
1620
1621 /*
1622 * Routine: ipc_kobject_label_check
1623 * Purpose:
1624 * Check to see if the space is allowed to possess
1625 * a right for the given port. In order to qualify,
1626 * the space label must contain all the privileges
1627 * listed in the port/kobject label.
1628 *
1629 * Conditions:
1630 * Space is write locked and active.
1631 * Port is locked and active.
1632 *
1633 * Returns:
1634 * Whether the copyout is authorized.
1635 *
1636 * If a port substitution is requested, the space is unlocked,
1637 * the port is unlocked and its "right" consumed.
1638 *
1639 * As of now, substituted ports only happen for send rights.
1640 */
1641 bool
ipc_kobject_label_check(ipc_space_t space,ipc_port_t port,mach_msg_type_name_t msgt_name,ipc_object_copyout_flags_t * flags,ipc_port_t * subst_portp)1642 ipc_kobject_label_check(
1643 ipc_space_t space,
1644 ipc_port_t port,
1645 mach_msg_type_name_t msgt_name,
1646 ipc_object_copyout_flags_t *flags,
1647 ipc_port_t *subst_portp)
1648 {
1649 ipc_kobject_label_t kolabel;
1650 ipc_label_t label;
1651
1652 assert(is_active(space));
1653 assert(ip_active(port));
1654
1655 *subst_portp = IP_NULL;
1656
1657 /* Unlabled ports/kobjects are always allowed */
1658 if (!ip_is_kolabeled(port)) {
1659 return true;
1660 }
1661
1662 /* Never OK to copyout the receive right for a labeled kobject */
1663 if (msgt_name == MACH_MSG_TYPE_PORT_RECEIVE) {
1664 panic("ipc_kobject_label_check: attempted receive right "
1665 "copyout for labeled kobject");
1666 }
1667
1668 kolabel = port->ip_kolabel;
1669 label = kolabel->ikol_label;
1670
1671 if ((*flags & IPC_OBJECT_COPYOUT_FLAGS_NO_LABEL_CHECK) == 0 &&
1672 (label & IPC_LABEL_SUBST_MASK)) {
1673 ipc_port_t subst = IP_NULL;
1674
1675 if (msgt_name != MACH_MSG_TYPE_PORT_SEND) {
1676 return false;
1677 }
1678
1679 if ((label & IPC_LABEL_SUBST_MASK) == IPC_LABEL_SUBST_ONCE) {
1680 /*
1681 * The next check will _not_ substitute.
1682 * hollow out our one-time wrapper,
1683 * and steal its send right.
1684 */
1685 *flags |= IPC_OBJECT_COPYOUT_FLAGS_NO_LABEL_CHECK;
1686 subst = ipc_kobject_disable_locked(port,
1687 IKOT_PORT_SUBST_ONCE);
1688 is_write_unlock(space);
1689 ipc_port_release_send_and_unlock(port);
1690 if (subst == IP_NULL) {
1691 panic("subst-once port %p was consumed twice", port);
1692 }
1693 *subst_portp = subst;
1694 return true;
1695 }
1696
1697 switch (label & IPC_LABEL_SUBST_MASK) {
1698 case IPC_LABEL_SUBST_TASK:
1699 subst = ipc_kobject_label_substitute_task(space,
1700 kolabel, port);
1701 break;
1702 case IPC_LABEL_SUBST_TASK_READ:
1703 subst = ipc_kobject_label_substitute_task_read(space,
1704 kolabel, port);
1705 break;
1706 case IPC_LABEL_SUBST_THREAD:
1707 subst = ipc_kobject_label_substitute_thread(space,
1708 kolabel, port);
1709 break;
1710 case IPC_LABEL_SUBST_THREAD_READ:
1711 subst = ipc_kobject_label_substitute_thread_read(space,
1712 kolabel, port);
1713 break;
1714 default:
1715 panic("unexpected label: %llx", label);
1716 }
1717
1718 if (subst != IP_NULL) {
1719 ip_reference(subst);
1720 is_write_unlock(space);
1721
1722 /*
1723 * We do not hold a proper send right on `subst`,
1724 * only a reference.
1725 *
1726 * Because of how thread/task termination works,
1727 * there is no guarantee copy_send() would work,
1728 * so we need to make_send().
1729 *
1730 * We can do that because ports tagged with
1731 * IPC_LABEL_SUBST_{THREAD,TASK} do not use
1732 * the no-senders notification.
1733 */
1734
1735 ipc_port_release_send_and_unlock(port);
1736 /* no check: dPAC integrity */
1737 port = ipc_port_make_send_any(subst);
1738 ip_release(subst);
1739 *subst_portp = port;
1740 return true;
1741 }
1742 }
1743
1744 return (label & space->is_label & IPC_LABEL_SPACE_MASK) ==
1745 (label & IPC_LABEL_SPACE_MASK);
1746 }
1747