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