1/*
2 * Copyright (c) 2000-2010 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,1988,1987 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 Software.Distribution@CS.CMU.EDU
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 */
62/*
63 */
64
65/*
66 * File: ipc_tt.c
67 * Purpose:
68 * Task and thread related IPC functions.
69 */
70
71#include <mach/mach_types.h>
72#include <mach/boolean.h>
73#include <mach/kern_return.h>
74#include <mach/mach_param.h>
75#include <mach/task_special_ports.h>
76#include <mach/thread_special_ports.h>
77#include <mach/thread_status.h>
78#include <mach/exception_types.h>
79#include <mach/memory_object_types.h>
80#include <mach/mach_traps.h>
81#include <mach/task_server.h>
82#include <mach/thread_act_server.h>
83#include <mach/mach_host_server.h>
84#include <mach/host_priv_server.h>
85#include <mach/vm_map_server.h>
86
87#include <kern/kern_types.h>
88#include <kern/host.h>
89#include <kern/ipc_kobject.h>
90#include <kern/ipc_tt.h>
91#include <kern/kalloc.h>
92#include <kern/thread.h>
93#include <kern/misc_protos.h>
94
95#include <vm/vm_map.h>
96#include <vm/vm_pageout.h>
97#include <vm/vm_protos.h>
98
99#include <security/mac_mach_internal.h>
100
101#if CONFIG_EMBEDDED && !SECURE_KERNEL
102extern int cs_relax_platform_task_ports;
103#endif
104
105/* forward declarations */
106task_t convert_port_to_locked_task(ipc_port_t port);
107task_inspect_t convert_port_to_locked_task_inspect(ipc_port_t port);
108static void ipc_port_bind_special_reply_port_locked(ipc_port_t port);
109static kern_return_t ipc_port_unbind_special_reply_port(thread_t thread, boolean_t unbind_active_port);
110kern_return_t task_conversion_eval(task_t caller, task_t victim);
111
112/*
113 * Routine: ipc_task_init
114 * Purpose:
115 * Initialize a task's IPC state.
116 *
117 * If non-null, some state will be inherited from the parent.
118 * The parent must be appropriately initialized.
119 * Conditions:
120 * Nothing locked.
121 */
122
123void
124ipc_task_init(
125 task_t task,
126 task_t parent)
127{
128 ipc_space_t space;
129 ipc_port_t kport;
130 ipc_port_t nport;
131 kern_return_t kr;
132 int i;
133
134
135 kr = ipc_space_create(&ipc_table_entries[0], &space);
136 if (kr != KERN_SUCCESS)
137 panic("ipc_task_init");
138
139 space->is_task = task;
140
141 kport = ipc_port_alloc_kernel();
142 if (kport == IP_NULL)
143 panic("ipc_task_init");
144
145 nport = ipc_port_alloc_kernel();
146 if (nport == IP_NULL)
147 panic("ipc_task_init");
148
149 itk_lock_init(task);
150 task->itk_self = kport;
151 task->itk_nself = nport;
152 task->itk_resume = IP_NULL; /* Lazily allocated on-demand */
153 if (task_is_a_corpse_fork(task)) {
154 /*
155 * No sender's notification for corpse would not
156 * work with a naked send right in kernel.
157 */
158 task->itk_sself = IP_NULL;
159 } else {
160 task->itk_sself = ipc_port_make_send(kport);
161 }
162 task->itk_debug_control = IP_NULL;
163 task->itk_space = space;
164
165#if CONFIG_MACF
166 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
167 mac_exc_associate_action_label(&task->exc_actions[i], mac_exc_create_label());
168 }
169#endif
170
171 if (parent == TASK_NULL) {
172 ipc_port_t port;
173
174 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
175 task->exc_actions[i].port = IP_NULL;
176 }/* for */
177
178 kr = host_get_host_port(host_priv_self(), &port);
179 assert(kr == KERN_SUCCESS);
180 task->itk_host = port;
181
182 task->itk_bootstrap = IP_NULL;
183 task->itk_seatbelt = IP_NULL;
184 task->itk_gssd = IP_NULL;
185 task->itk_task_access = IP_NULL;
186
187 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
188 task->itk_registered[i] = IP_NULL;
189 } else {
190 itk_lock(parent);
191 assert(parent->itk_self != IP_NULL);
192
193 /* inherit registered ports */
194
195 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
196 task->itk_registered[i] =
197 ipc_port_copy_send(parent->itk_registered[i]);
198
199 /* inherit exception and bootstrap ports */
200
201 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
202 task->exc_actions[i].port =
203 ipc_port_copy_send(parent->exc_actions[i].port);
204 task->exc_actions[i].flavor =
205 parent->exc_actions[i].flavor;
206 task->exc_actions[i].behavior =
207 parent->exc_actions[i].behavior;
208 task->exc_actions[i].privileged =
209 parent->exc_actions[i].privileged;
210#if CONFIG_MACF
211 mac_exc_inherit_action_label(parent->exc_actions + i, task->exc_actions + i);
212#endif
213 }/* for */
214 task->itk_host =
215 ipc_port_copy_send(parent->itk_host);
216
217 task->itk_bootstrap =
218 ipc_port_copy_send(parent->itk_bootstrap);
219
220 task->itk_seatbelt =
221 ipc_port_copy_send(parent->itk_seatbelt);
222
223 task->itk_gssd =
224 ipc_port_copy_send(parent->itk_gssd);
225
226 task->itk_task_access =
227 ipc_port_copy_send(parent->itk_task_access);
228
229 itk_unlock(parent);
230 }
231}
232
233/*
234 * Routine: ipc_task_enable
235 * Purpose:
236 * Enable a task for IPC access.
237 * Conditions:
238 * Nothing locked.
239 */
240
241void
242ipc_task_enable(
243 task_t task)
244{
245 ipc_port_t kport;
246 ipc_port_t nport;
247
248 itk_lock(task);
249 kport = task->itk_self;
250 if (kport != IP_NULL)
251 ipc_kobject_set(kport, (ipc_kobject_t) task, IKOT_TASK);
252 nport = task->itk_nself;
253 if (nport != IP_NULL)
254 ipc_kobject_set(nport, (ipc_kobject_t) task, IKOT_TASK_NAME);
255 itk_unlock(task);
256}
257
258/*
259 * Routine: ipc_task_disable
260 * Purpose:
261 * Disable IPC access to a task.
262 * Conditions:
263 * Nothing locked.
264 */
265
266void
267ipc_task_disable(
268 task_t task)
269{
270 ipc_port_t kport;
271 ipc_port_t nport;
272 ipc_port_t rport;
273
274 itk_lock(task);
275 kport = task->itk_self;
276 if (kport != IP_NULL)
277 ipc_kobject_set(kport, IKO_NULL, IKOT_NONE);
278 nport = task->itk_nself;
279 if (nport != IP_NULL)
280 ipc_kobject_set(nport, IKO_NULL, IKOT_NONE);
281
282 rport = task->itk_resume;
283 if (rport != IP_NULL) {
284 /*
285 * From this point onwards this task is no longer accepting
286 * resumptions.
287 *
288 * There are still outstanding suspensions on this task,
289 * even as it is being torn down. Disconnect the task
290 * from the rport, thereby "orphaning" the rport. The rport
291 * itself will go away only when the last suspension holder
292 * destroys his SO right to it -- when he either
293 * exits, or tries to actually use that last SO right to
294 * resume this (now non-existent) task.
295 */
296 ipc_kobject_set(rport, IKO_NULL, IKOT_NONE);
297 }
298 itk_unlock(task);
299}
300
301/*
302 * Routine: ipc_task_terminate
303 * Purpose:
304 * Clean up and destroy a task's IPC state.
305 * Conditions:
306 * Nothing locked. The task must be suspended.
307 * (Or the current thread must be in the task.)
308 */
309
310void
311ipc_task_terminate(
312 task_t task)
313{
314 ipc_port_t kport;
315 ipc_port_t nport;
316 ipc_port_t rport;
317 int i;
318
319 itk_lock(task);
320 kport = task->itk_self;
321
322 if (kport == IP_NULL) {
323 /* the task is already terminated (can this happen?) */
324 itk_unlock(task);
325 return;
326 }
327 task->itk_self = IP_NULL;
328
329 nport = task->itk_nself;
330 assert(nport != IP_NULL);
331 task->itk_nself = IP_NULL;
332
333 rport = task->itk_resume;
334 task->itk_resume = IP_NULL;
335
336 itk_unlock(task);
337
338 /* release the naked send rights */
339
340 if (IP_VALID(task->itk_sself))
341 ipc_port_release_send(task->itk_sself);
342
343 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
344 if (IP_VALID(task->exc_actions[i].port)) {
345 ipc_port_release_send(task->exc_actions[i].port);
346 }
347#if CONFIG_MACF
348 mac_exc_free_action_label(task->exc_actions + i);
349#endif
350 }
351
352 if (IP_VALID(task->itk_host))
353 ipc_port_release_send(task->itk_host);
354
355 if (IP_VALID(task->itk_bootstrap))
356 ipc_port_release_send(task->itk_bootstrap);
357
358 if (IP_VALID(task->itk_seatbelt))
359 ipc_port_release_send(task->itk_seatbelt);
360
361 if (IP_VALID(task->itk_gssd))
362 ipc_port_release_send(task->itk_gssd);
363
364 if (IP_VALID(task->itk_task_access))
365 ipc_port_release_send(task->itk_task_access);
366
367 if (IP_VALID(task->itk_debug_control))
368 ipc_port_release_send(task->itk_debug_control);
369
370 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
371 if (IP_VALID(task->itk_registered[i]))
372 ipc_port_release_send(task->itk_registered[i]);
373
374 /* destroy the kernel ports */
375 ipc_port_dealloc_kernel(kport);
376 ipc_port_dealloc_kernel(nport);
377 if (rport != IP_NULL)
378 ipc_port_dealloc_kernel(rport);
379
380 itk_lock_destroy(task);
381}
382
383/*
384 * Routine: ipc_task_reset
385 * Purpose:
386 * Reset a task's IPC state to protect it when
387 * it enters an elevated security context. The
388 * task name port can remain the same - since
389 * it represents no specific privilege.
390 * Conditions:
391 * Nothing locked. The task must be suspended.
392 * (Or the current thread must be in the task.)
393 */
394
395void
396ipc_task_reset(
397 task_t task)
398{
399 ipc_port_t old_kport, new_kport;
400 ipc_port_t old_sself;
401 ipc_port_t old_exc_actions[EXC_TYPES_COUNT];
402 int i;
403
404#if CONFIG_MACF
405 /* Fresh label to unset credentials in existing labels. */
406 struct label *unset_label = mac_exc_create_label();
407#endif
408
409 new_kport = ipc_port_alloc_kernel();
410 if (new_kport == IP_NULL)
411 panic("ipc_task_reset");
412
413 itk_lock(task);
414
415 old_kport = task->itk_self;
416
417 if (old_kport == IP_NULL) {
418 /* the task is already terminated (can this happen?) */
419 itk_unlock(task);
420 ipc_port_dealloc_kernel(new_kport);
421#if CONFIG_MACF
422 mac_exc_free_label(unset_label);
423#endif
424 return;
425 }
426
427 task->itk_self = new_kport;
428 old_sself = task->itk_sself;
429 task->itk_sself = ipc_port_make_send(new_kport);
430
431 /* Set the old kport to IKOT_NONE and update the exec token while under the port lock */
432 ip_lock(old_kport);
433 ipc_kobject_set_atomically(old_kport, IKO_NULL, IKOT_NONE);
434 task->exec_token += 1;
435 ip_unlock(old_kport);
436
437 ipc_kobject_set(new_kport, (ipc_kobject_t) task, IKOT_TASK);
438
439 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
440 old_exc_actions[i] = IP_NULL;
441
442 if (i == EXC_CORPSE_NOTIFY && task_corpse_pending_report(task)) {
443 continue;
444 }
445
446 if (!task->exc_actions[i].privileged) {
447#if CONFIG_MACF
448 mac_exc_update_action_label(task->exc_actions + i, unset_label);
449#endif
450 old_exc_actions[i] = task->exc_actions[i].port;
451 task->exc_actions[i].port = IP_NULL;
452 }
453 }/* for */
454
455 if (IP_VALID(task->itk_debug_control)) {
456 ipc_port_release_send(task->itk_debug_control);
457 }
458 task->itk_debug_control = IP_NULL;
459
460 itk_unlock(task);
461
462#if CONFIG_MACF
463 mac_exc_free_label(unset_label);
464#endif
465
466 /* release the naked send rights */
467
468 if (IP_VALID(old_sself))
469 ipc_port_release_send(old_sself);
470
471 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
472 if (IP_VALID(old_exc_actions[i])) {
473 ipc_port_release_send(old_exc_actions[i]);
474 }
475 }/* for */
476
477 /* destroy the kernel port */
478 ipc_port_dealloc_kernel(old_kport);
479}
480
481/*
482 * Routine: ipc_thread_init
483 * Purpose:
484 * Initialize a thread's IPC state.
485 * Conditions:
486 * Nothing locked.
487 */
488
489void
490ipc_thread_init(
491 thread_t thread)
492{
493 ipc_port_t kport;
494
495 kport = ipc_port_alloc_kernel();
496 if (kport == IP_NULL)
497 panic("ipc_thread_init");
498
499 thread->ith_self = kport;
500 thread->ith_sself = ipc_port_make_send(kport);
501 thread->ith_special_reply_port = NULL;
502 thread->exc_actions = NULL;
503
504 ipc_kobject_set(kport, (ipc_kobject_t)thread, IKOT_THREAD);
505
506#if IMPORTANCE_INHERITANCE
507 thread->ith_assertions = 0;
508#endif
509
510 ipc_kmsg_queue_init(&thread->ith_messages);
511
512 thread->ith_rpc_reply = IP_NULL;
513}
514
515void
516ipc_thread_init_exc_actions(
517 thread_t thread)
518{
519 assert(thread->exc_actions == NULL);
520
521 thread->exc_actions = kalloc(sizeof(struct exception_action) * EXC_TYPES_COUNT);
522 bzero(thread->exc_actions, sizeof(struct exception_action) * EXC_TYPES_COUNT);
523
524#if CONFIG_MACF
525 for (size_t i = 0; i < EXC_TYPES_COUNT; ++i) {
526 mac_exc_associate_action_label(thread->exc_actions + i, mac_exc_create_label());
527 }
528#endif
529}
530
531void
532ipc_thread_destroy_exc_actions(
533 thread_t thread)
534{
535 if (thread->exc_actions != NULL) {
536#if CONFIG_MACF
537 for (size_t i = 0; i < EXC_TYPES_COUNT; ++i) {
538 mac_exc_free_action_label(thread->exc_actions + i);
539 }
540#endif
541
542 kfree(thread->exc_actions,
543 sizeof(struct exception_action) * EXC_TYPES_COUNT);
544 thread->exc_actions = NULL;
545 }
546}
547
548void
549ipc_thread_disable(
550 thread_t thread)
551{
552 ipc_port_t kport = thread->ith_self;
553
554 if (kport != IP_NULL)
555 ipc_kobject_set(kport, IKO_NULL, IKOT_NONE);
556}
557
558/*
559 * Routine: ipc_thread_terminate
560 * Purpose:
561 * Clean up and destroy a thread's IPC state.
562 * Conditions:
563 * Nothing locked.
564 */
565
566void
567ipc_thread_terminate(
568 thread_t thread)
569{
570 ipc_port_t kport = thread->ith_self;
571
572 if (kport != IP_NULL) {
573 int i;
574
575 if (IP_VALID(thread->ith_sself))
576 ipc_port_release_send(thread->ith_sself);
577
578 thread->ith_sself = thread->ith_self = IP_NULL;
579
580 if (thread->exc_actions != NULL) {
581 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
582 if (IP_VALID(thread->exc_actions[i].port))
583 ipc_port_release_send(thread->exc_actions[i].port);
584 }
585 ipc_thread_destroy_exc_actions(thread);
586 }
587
588 ipc_port_dealloc_kernel(kport);
589 }
590
591#if IMPORTANCE_INHERITANCE
592 assert(thread->ith_assertions == 0);
593#endif
594
595 /* unbind the thread special reply port */
596 if (IP_VALID(thread->ith_special_reply_port)) {
597 ipc_port_unbind_special_reply_port(thread, TRUE);
598 }
599
600 assert(ipc_kmsg_queue_empty(&thread->ith_messages));
601
602 if (thread->ith_rpc_reply != IP_NULL)
603 ipc_port_dealloc_reply(thread->ith_rpc_reply);
604
605 thread->ith_rpc_reply = IP_NULL;
606}
607
608/*
609 * Routine: ipc_thread_reset
610 * Purpose:
611 * Reset the IPC state for a given Mach thread when
612 * its task enters an elevated security context.
613 * Both the thread port and its exception ports have
614 * to be reset. Its RPC reply port cannot have any
615 * rights outstanding, so it should be fine.
616 * Conditions:
617 * Nothing locked.
618 */
619
620void
621ipc_thread_reset(
622 thread_t thread)
623{
624 ipc_port_t old_kport, new_kport;
625 ipc_port_t old_sself;
626 ipc_port_t old_exc_actions[EXC_TYPES_COUNT];
627 boolean_t has_old_exc_actions = FALSE;
628 int i;
629
630#if CONFIG_MACF
631 struct label *new_label = mac_exc_create_label();
632#endif
633
634 new_kport = ipc_port_alloc_kernel();
635 if (new_kport == IP_NULL)
636 panic("ipc_task_reset");
637
638 thread_mtx_lock(thread);
639
640 old_kport = thread->ith_self;
641
642 if (old_kport == IP_NULL && thread->inspection == FALSE) {
643 /* the is already terminated (can this happen?) */
644 thread_mtx_unlock(thread);
645 ipc_port_dealloc_kernel(new_kport);
646#if CONFIG_MACF
647 mac_exc_free_label(new_label);
648#endif
649 return;
650 }
651
652 thread->ith_self = new_kport;
653 old_sself = thread->ith_sself;
654 thread->ith_sself = ipc_port_make_send(new_kport);
655 if (old_kport != IP_NULL) {
656 ipc_kobject_set(old_kport, IKO_NULL, IKOT_NONE);
657 }
658 ipc_kobject_set(new_kport, (ipc_kobject_t) thread, IKOT_THREAD);
659
660 /*
661 * Only ports that were set by root-owned processes
662 * (privileged ports) should survive
663 */
664 if (thread->exc_actions != NULL) {
665 has_old_exc_actions = TRUE;
666 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
667 if (thread->exc_actions[i].privileged) {
668 old_exc_actions[i] = IP_NULL;
669 } else {
670#if CONFIG_MACF
671 mac_exc_update_action_label(thread->exc_actions + i, new_label);
672#endif
673 old_exc_actions[i] = thread->exc_actions[i].port;
674 thread->exc_actions[i].port = IP_NULL;
675 }
676 }
677 }
678
679 thread_mtx_unlock(thread);
680
681#if CONFIG_MACF
682 mac_exc_free_label(new_label);
683#endif
684
685 /* release the naked send rights */
686
687 if (IP_VALID(old_sself))
688 ipc_port_release_send(old_sself);
689
690 if (has_old_exc_actions) {
691 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
692 ipc_port_release_send(old_exc_actions[i]);
693 }
694 }
695
696 /* destroy the kernel port */
697 if (old_kport != IP_NULL) {
698 ipc_port_dealloc_kernel(old_kport);
699 }
700
701 /* unbind the thread special reply port */
702 if (IP_VALID(thread->ith_special_reply_port)) {
703 ipc_port_unbind_special_reply_port(thread, TRUE);
704 }
705}
706
707/*
708 * Routine: retrieve_task_self_fast
709 * Purpose:
710 * Optimized version of retrieve_task_self,
711 * that only works for the current task.
712 *
713 * Return a send right (possibly null/dead)
714 * for the task's user-visible self port.
715 * Conditions:
716 * Nothing locked.
717 */
718
719ipc_port_t
720retrieve_task_self_fast(
721 task_t task)
722{
723 ipc_port_t port;
724
725 assert(task == current_task());
726
727 itk_lock(task);
728 assert(task->itk_self != IP_NULL);
729
730 if ((port = task->itk_sself) == task->itk_self) {
731 /* no interposing */
732
733 ip_lock(port);
734 assert(ip_active(port));
735 ip_reference(port);
736 port->ip_srights++;
737 ip_unlock(port);
738 } else
739 port = ipc_port_copy_send(port);
740 itk_unlock(task);
741
742 return port;
743}
744
745/*
746 * Routine: retrieve_thread_self_fast
747 * Purpose:
748 * Return a send right (possibly null/dead)
749 * for the thread's user-visible self port.
750 *
751 * Only works for the current thread.
752 *
753 * Conditions:
754 * Nothing locked.
755 */
756
757ipc_port_t
758retrieve_thread_self_fast(
759 thread_t thread)
760{
761 ipc_port_t port;
762
763 assert(thread == current_thread());
764
765 thread_mtx_lock(thread);
766
767 assert(thread->ith_self != IP_NULL);
768
769 if ((port = thread->ith_sself) == thread->ith_self) {
770 /* no interposing */
771
772 ip_lock(port);
773 assert(ip_active(port));
774 ip_reference(port);
775 port->ip_srights++;
776 ip_unlock(port);
777 }
778 else
779 port = ipc_port_copy_send(port);
780
781 thread_mtx_unlock(thread);
782
783 return port;
784}
785
786/*
787 * Routine: task_self_trap [mach trap]
788 * Purpose:
789 * Give the caller send rights for his own task port.
790 * Conditions:
791 * Nothing locked.
792 * Returns:
793 * MACH_PORT_NULL if there are any resource failures
794 * or other errors.
795 */
796
797mach_port_name_t
798task_self_trap(
799 __unused struct task_self_trap_args *args)
800{
801 task_t task = current_task();
802 ipc_port_t sright;
803 mach_port_name_t name;
804
805 sright = retrieve_task_self_fast(task);
806 name = ipc_port_copyout_send(sright, task->itk_space);
807 return name;
808}
809
810/*
811 * Routine: thread_self_trap [mach trap]
812 * Purpose:
813 * Give the caller send rights for his own thread port.
814 * Conditions:
815 * Nothing locked.
816 * Returns:
817 * MACH_PORT_NULL if there are any resource failures
818 * or other errors.
819 */
820
821mach_port_name_t
822thread_self_trap(
823 __unused struct thread_self_trap_args *args)
824{
825 thread_t thread = current_thread();
826 task_t task = thread->task;
827 ipc_port_t sright;
828 mach_port_name_t name;
829
830 sright = retrieve_thread_self_fast(thread);
831 name = ipc_port_copyout_send(sright, task->itk_space);
832 return name;
833
834}
835
836/*
837 * Routine: mach_reply_port [mach trap]
838 * Purpose:
839 * Allocate a port for the caller.
840 * Conditions:
841 * Nothing locked.
842 * Returns:
843 * MACH_PORT_NULL if there are any resource failures
844 * or other errors.
845 */
846
847mach_port_name_t
848mach_reply_port(
849 __unused struct mach_reply_port_args *args)
850{
851 ipc_port_t port;
852 mach_port_name_t name;
853 kern_return_t kr;
854
855 kr = ipc_port_alloc(current_task()->itk_space, &name, &port);
856 if (kr == KERN_SUCCESS)
857 ip_unlock(port);
858 else
859 name = MACH_PORT_NULL;
860 return name;
861}
862
863/*
864 * Routine: thread_get_special_reply_port [mach trap]
865 * Purpose:
866 * Allocate a special reply port for the calling thread.
867 * Conditions:
868 * Nothing locked.
869 * Returns:
870 * mach_port_name_t: send right & receive right for special reply port.
871 * MACH_PORT_NULL if there are any resource failures
872 * or other errors.
873 */
874
875mach_port_name_t
876thread_get_special_reply_port(
877 __unused struct thread_get_special_reply_port_args *args)
878{
879 ipc_port_t port;
880 mach_port_name_t name;
881 mach_port_name_t send_name;
882 kern_return_t kr;
883 thread_t thread = current_thread();
884
885 /* unbind the thread special reply port */
886 if (IP_VALID(thread->ith_special_reply_port)) {
887 kr = ipc_port_unbind_special_reply_port(thread, TRUE);
888 if (kr != KERN_SUCCESS) {
889 return MACH_PORT_NULL;
890 }
891 }
892
893 kr = ipc_port_alloc(current_task()->itk_space, &name, &port);
894 if (kr == KERN_SUCCESS) {
895 ipc_port_bind_special_reply_port_locked(port);
896
897 /* Make a send right and insert it in the space at specified name */
898 ipc_port_make_send_locked(port);
899 ip_unlock(port);
900 send_name = ipc_port_copyout_name_send(port, current_task()->itk_space, name);
901 /*
902 * If insertion of send right failed, userland is doing something bad, error out.
903 * The space was marked inactive or the receive right just inserted above at the
904 * given name was moved, in either case do not try to deallocate the receive right.
905 */
906 if (send_name == MACH_PORT_NULL || send_name == MACH_PORT_DEAD) {
907 if (IP_VALID(thread->ith_special_reply_port)) {
908 ipc_port_unbind_special_reply_port(thread, TRUE);
909 }
910 name = MACH_PORT_NULL;
911 }
912 } else {
913 name = MACH_PORT_NULL;
914 }
915 return name;
916}
917
918/*
919 * Routine: ipc_port_bind_special_reply_port_locked
920 * Purpose:
921 * Bind the given port to current thread as a special reply port.
922 * Conditions:
923 * Port locked.
924 * Returns:
925 * None.
926 */
927
928static void
929ipc_port_bind_special_reply_port_locked(
930 ipc_port_t port)
931{
932 thread_t thread = current_thread();
933 assert(thread->ith_special_reply_port == NULL);
934
935 ip_reference(port);
936 thread->ith_special_reply_port = port;
937 port->ip_specialreply = 1;
938 port->ip_sync_link_state = PORT_SYNC_LINK_ANY;
939
940 reset_ip_srp_bits(port);
941}
942
943/*
944 * Routine: ipc_port_unbind_special_reply_port
945 * Purpose:
946 * Unbind the thread's special reply port.
947 * If the special port has threads waiting on turnstile,
948 * update it's inheritor.
949 * Condition:
950 * Nothing locked.
951 * Returns:
952 * None.
953 */
954static kern_return_t
955ipc_port_unbind_special_reply_port(
956 thread_t thread,
957 boolean_t unbind_active_port)
958{
959 ipc_port_t special_reply_port = thread->ith_special_reply_port;
960
961 ip_lock(special_reply_port);
962
963 /* Return error if port active and unbind_active_port set to FALSE */
964 if (unbind_active_port == FALSE && ip_active(special_reply_port)) {
965 ip_unlock(special_reply_port);
966 return KERN_FAILURE;
967 }
968
969 thread->ith_special_reply_port = NULL;
970 ipc_port_adjust_special_reply_port_locked(special_reply_port, NULL,
971 IPC_PORT_ADJUST_SR_CLEAR_SPECIAL_REPLY, FALSE);
972 /* port unlocked */
973
974 ip_release(special_reply_port);
975 return KERN_SUCCESS;
976}
977
978/*
979 * Routine: thread_get_special_port [kernel call]
980 * Purpose:
981 * Clones a send right for one of the thread's
982 * special ports.
983 * Conditions:
984 * Nothing locked.
985 * Returns:
986 * KERN_SUCCESS Extracted a send right.
987 * KERN_INVALID_ARGUMENT The thread is null.
988 * KERN_FAILURE The thread is dead.
989 * KERN_INVALID_ARGUMENT Invalid special port.
990 */
991
992kern_return_t
993thread_get_special_port(
994 thread_t thread,
995 int which,
996 ipc_port_t *portp)
997{
998 kern_return_t result = KERN_SUCCESS;
999 ipc_port_t *whichp;
1000
1001 if (thread == THREAD_NULL)
1002 return (KERN_INVALID_ARGUMENT);
1003
1004 switch (which) {
1005
1006 case THREAD_KERNEL_PORT:
1007 whichp = &thread->ith_sself;
1008 break;
1009
1010 default:
1011 return (KERN_INVALID_ARGUMENT);
1012 }
1013
1014 thread_mtx_lock(thread);
1015
1016 if (thread->active)
1017 *portp = ipc_port_copy_send(*whichp);
1018 else
1019 result = KERN_FAILURE;
1020
1021 thread_mtx_unlock(thread);
1022
1023 return (result);
1024}
1025
1026/*
1027 * Routine: thread_set_special_port [kernel call]
1028 * Purpose:
1029 * Changes one of the thread's special ports,
1030 * setting it to the supplied send right.
1031 * Conditions:
1032 * Nothing locked. If successful, consumes
1033 * the supplied send right.
1034 * Returns:
1035 * KERN_SUCCESS Changed the special port.
1036 * KERN_INVALID_ARGUMENT The thread is null.
1037 * KERN_FAILURE The thread is dead.
1038 * KERN_INVALID_ARGUMENT Invalid special port.
1039 */
1040
1041kern_return_t
1042thread_set_special_port(
1043 thread_t thread,
1044 int which,
1045 ipc_port_t port)
1046{
1047 kern_return_t result = KERN_SUCCESS;
1048 ipc_port_t *whichp, old = IP_NULL;
1049
1050 if (thread == THREAD_NULL)
1051 return (KERN_INVALID_ARGUMENT);
1052
1053 switch (which) {
1054
1055 case THREAD_KERNEL_PORT:
1056 whichp = &thread->ith_sself;
1057 break;
1058
1059 default:
1060 return (KERN_INVALID_ARGUMENT);
1061 }
1062
1063 thread_mtx_lock(thread);
1064
1065 if (thread->active) {
1066 old = *whichp;
1067 *whichp = port;
1068 }
1069 else
1070 result = KERN_FAILURE;
1071
1072 thread_mtx_unlock(thread);
1073
1074 if (IP_VALID(old))
1075 ipc_port_release_send(old);
1076
1077 return (result);
1078}
1079
1080/*
1081 * Routine: task_get_special_port [kernel call]
1082 * Purpose:
1083 * Clones a send right for one of the task's
1084 * special ports.
1085 * Conditions:
1086 * Nothing locked.
1087 * Returns:
1088 * KERN_SUCCESS Extracted a send right.
1089 * KERN_INVALID_ARGUMENT The task is null.
1090 * KERN_FAILURE The task/space is dead.
1091 * KERN_INVALID_ARGUMENT Invalid special port.
1092 */
1093
1094kern_return_t
1095task_get_special_port(
1096 task_t task,
1097 int which,
1098 ipc_port_t *portp)
1099{
1100 ipc_port_t port;
1101
1102 if (task == TASK_NULL)
1103 return KERN_INVALID_ARGUMENT;
1104
1105 itk_lock(task);
1106 if (task->itk_self == IP_NULL) {
1107 itk_unlock(task);
1108 return KERN_FAILURE;
1109 }
1110
1111 switch (which) {
1112 case TASK_KERNEL_PORT:
1113 port = ipc_port_copy_send(task->itk_sself);
1114 break;
1115
1116 case TASK_NAME_PORT:
1117 port = ipc_port_make_send(task->itk_nself);
1118 break;
1119
1120 case TASK_HOST_PORT:
1121 port = ipc_port_copy_send(task->itk_host);
1122 break;
1123
1124 case TASK_BOOTSTRAP_PORT:
1125 port = ipc_port_copy_send(task->itk_bootstrap);
1126 break;
1127
1128 case TASK_SEATBELT_PORT:
1129 port = ipc_port_copy_send(task->itk_seatbelt);
1130 break;
1131
1132 case TASK_ACCESS_PORT:
1133 port = ipc_port_copy_send(task->itk_task_access);
1134 break;
1135
1136 case TASK_DEBUG_CONTROL_PORT:
1137 port = ipc_port_copy_send(task->itk_debug_control);
1138 break;
1139
1140 default:
1141 itk_unlock(task);
1142 return KERN_INVALID_ARGUMENT;
1143 }
1144 itk_unlock(task);
1145
1146 *portp = port;
1147 return KERN_SUCCESS;
1148}
1149
1150/*
1151 * Routine: task_set_special_port [kernel call]
1152 * Purpose:
1153 * Changes one of the task's special ports,
1154 * setting it to the supplied send right.
1155 * Conditions:
1156 * Nothing locked. If successful, consumes
1157 * the supplied send right.
1158 * Returns:
1159 * KERN_SUCCESS Changed the special port.
1160 * KERN_INVALID_ARGUMENT The task is null.
1161 * KERN_FAILURE The task/space is dead.
1162 * KERN_INVALID_ARGUMENT Invalid special port.
1163 * KERN_NO_ACCESS Attempted overwrite of seatbelt port.
1164 */
1165
1166kern_return_t
1167task_set_special_port(
1168 task_t task,
1169 int which,
1170 ipc_port_t port)
1171{
1172 ipc_port_t *whichp;
1173 ipc_port_t old;
1174
1175 if (task == TASK_NULL)
1176 return KERN_INVALID_ARGUMENT;
1177
1178 switch (which) {
1179 case TASK_KERNEL_PORT:
1180 whichp = &task->itk_sself;
1181 break;
1182
1183 case TASK_HOST_PORT:
1184 whichp = &task->itk_host;
1185 break;
1186
1187 case TASK_BOOTSTRAP_PORT:
1188 whichp = &task->itk_bootstrap;
1189 break;
1190
1191 case TASK_SEATBELT_PORT:
1192 whichp = &task->itk_seatbelt;
1193 break;
1194
1195 case TASK_ACCESS_PORT:
1196 whichp = &task->itk_task_access;
1197 break;
1198
1199 case TASK_DEBUG_CONTROL_PORT:
1200 whichp = &task->itk_debug_control;
1201 break;
1202
1203 default:
1204 return KERN_INVALID_ARGUMENT;
1205 }/* switch */
1206
1207 itk_lock(task);
1208 if (task->itk_self == IP_NULL) {
1209 itk_unlock(task);
1210 return KERN_FAILURE;
1211 }
1212
1213 /* do not allow overwrite of seatbelt or task access ports */
1214 if ((TASK_SEATBELT_PORT == which || TASK_ACCESS_PORT == which)
1215 && IP_VALID(*whichp)) {
1216 itk_unlock(task);
1217 return KERN_NO_ACCESS;
1218 }
1219
1220 old = *whichp;
1221 *whichp = port;
1222 itk_unlock(task);
1223
1224 if (IP_VALID(old))
1225 ipc_port_release_send(old);
1226 return KERN_SUCCESS;
1227}
1228
1229
1230/*
1231 * Routine: mach_ports_register [kernel call]
1232 * Purpose:
1233 * Stash a handful of port send rights in the task.
1234 * Child tasks will inherit these rights, but they
1235 * must use mach_ports_lookup to acquire them.
1236 *
1237 * The rights are supplied in a (wired) kalloc'd segment.
1238 * Rights which aren't supplied are assumed to be null.
1239 * Conditions:
1240 * Nothing locked. If successful, consumes
1241 * the supplied rights and memory.
1242 * Returns:
1243 * KERN_SUCCESS Stashed the port rights.
1244 * KERN_INVALID_ARGUMENT The task is null.
1245 * KERN_INVALID_ARGUMENT The task is dead.
1246 * KERN_INVALID_ARGUMENT The memory param is null.
1247 * KERN_INVALID_ARGUMENT Too many port rights supplied.
1248 */
1249
1250kern_return_t
1251mach_ports_register(
1252 task_t task,
1253 mach_port_array_t memory,
1254 mach_msg_type_number_t portsCnt)
1255{
1256 ipc_port_t ports[TASK_PORT_REGISTER_MAX];
1257 unsigned int i;
1258
1259 if ((task == TASK_NULL) ||
1260 (portsCnt > TASK_PORT_REGISTER_MAX) ||
1261 (portsCnt && memory == NULL))
1262 return KERN_INVALID_ARGUMENT;
1263
1264 /*
1265 * Pad the port rights with nulls.
1266 */
1267
1268 for (i = 0; i < portsCnt; i++)
1269 ports[i] = memory[i];
1270 for (; i < TASK_PORT_REGISTER_MAX; i++)
1271 ports[i] = IP_NULL;
1272
1273 itk_lock(task);
1274 if (task->itk_self == IP_NULL) {
1275 itk_unlock(task);
1276 return KERN_INVALID_ARGUMENT;
1277 }
1278
1279 /*
1280 * Replace the old send rights with the new.
1281 * Release the old rights after unlocking.
1282 */
1283
1284 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) {
1285 ipc_port_t old;
1286
1287 old = task->itk_registered[i];
1288 task->itk_registered[i] = ports[i];
1289 ports[i] = old;
1290 }
1291
1292 itk_unlock(task);
1293
1294 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
1295 if (IP_VALID(ports[i]))
1296 ipc_port_release_send(ports[i]);
1297
1298 /*
1299 * Now that the operation is known to be successful,
1300 * we can free the memory.
1301 */
1302
1303 if (portsCnt != 0)
1304 kfree(memory,
1305 (vm_size_t) (portsCnt * sizeof(mach_port_t)));
1306
1307 return KERN_SUCCESS;
1308}
1309
1310/*
1311 * Routine: mach_ports_lookup [kernel call]
1312 * Purpose:
1313 * Retrieves (clones) the stashed port send rights.
1314 * Conditions:
1315 * Nothing locked. If successful, the caller gets
1316 * rights and memory.
1317 * Returns:
1318 * KERN_SUCCESS Retrieved the send rights.
1319 * KERN_INVALID_ARGUMENT The task is null.
1320 * KERN_INVALID_ARGUMENT The task is dead.
1321 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1322 */
1323
1324kern_return_t
1325mach_ports_lookup(
1326 task_t task,
1327 mach_port_array_t *portsp,
1328 mach_msg_type_number_t *portsCnt)
1329{
1330 void *memory;
1331 vm_size_t size;
1332 ipc_port_t *ports;
1333 int i;
1334
1335 if (task == TASK_NULL)
1336 return KERN_INVALID_ARGUMENT;
1337
1338 size = (vm_size_t) (TASK_PORT_REGISTER_MAX * sizeof(ipc_port_t));
1339
1340 memory = kalloc(size);
1341 if (memory == 0)
1342 return KERN_RESOURCE_SHORTAGE;
1343
1344 itk_lock(task);
1345 if (task->itk_self == IP_NULL) {
1346 itk_unlock(task);
1347
1348 kfree(memory, size);
1349 return KERN_INVALID_ARGUMENT;
1350 }
1351
1352 ports = (ipc_port_t *) memory;
1353
1354 /*
1355 * Clone port rights. Because kalloc'd memory
1356 * is wired, we won't fault while holding the task lock.
1357 */
1358
1359 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
1360 ports[i] = ipc_port_copy_send(task->itk_registered[i]);
1361
1362 itk_unlock(task);
1363
1364 *portsp = (mach_port_array_t) ports;
1365 *portsCnt = TASK_PORT_REGISTER_MAX;
1366 return KERN_SUCCESS;
1367}
1368
1369kern_return_t
1370task_conversion_eval(task_t caller, task_t victim)
1371{
1372 /*
1373 * Tasks are allowed to resolve their own task ports, and the kernel is
1374 * allowed to resolve anyone's task port.
1375 */
1376 if (caller == kernel_task) {
1377 return KERN_SUCCESS;
1378 }
1379
1380 if (caller == victim) {
1381 return KERN_SUCCESS;
1382 }
1383
1384 /*
1385 * Only the kernel can can resolve the kernel's task port. We've established
1386 * by this point that the caller is not kernel_task.
1387 */
1388 if (victim == TASK_NULL || victim == kernel_task) {
1389 return KERN_INVALID_SECURITY;
1390 }
1391
1392#if CONFIG_EMBEDDED
1393 /*
1394 * On embedded platforms, only a platform binary can resolve the task port
1395 * of another platform binary.
1396 */
1397 if ((victim->t_flags & TF_PLATFORM) && !(caller->t_flags & TF_PLATFORM)) {
1398#if SECURE_KERNEL
1399 return KERN_INVALID_SECURITY;
1400#else
1401 if (cs_relax_platform_task_ports) {
1402 return KERN_SUCCESS;
1403 } else {
1404 return KERN_INVALID_SECURITY;
1405 }
1406#endif /* SECURE_KERNEL */
1407 }
1408#endif /* CONFIG_EMBEDDED */
1409
1410 return KERN_SUCCESS;
1411}
1412
1413/*
1414 * Routine: convert_port_to_locked_task
1415 * Purpose:
1416 * Internal helper routine to convert from a port to a locked
1417 * task. Used by several routines that try to convert from a
1418 * task port to a reference on some task related object.
1419 * Conditions:
1420 * Nothing locked, blocking OK.
1421 */
1422task_t
1423convert_port_to_locked_task(ipc_port_t port)
1424{
1425 int try_failed_count = 0;
1426
1427 while (IP_VALID(port)) {
1428 task_t ct = current_task();
1429 task_t task;
1430
1431 ip_lock(port);
1432 if (!ip_active(port) || (ip_kotype(port) != IKOT_TASK)) {
1433 ip_unlock(port);
1434 return TASK_NULL;
1435 }
1436 task = (task_t) port->ip_kobject;
1437 assert(task != TASK_NULL);
1438
1439 if (task_conversion_eval(ct, task)) {
1440 ip_unlock(port);
1441 return TASK_NULL;
1442 }
1443
1444 /*
1445 * Normal lock ordering puts task_lock() before ip_lock().
1446 * Attempt out-of-order locking here.
1447 */
1448 if (task_lock_try(task)) {
1449 ip_unlock(port);
1450 return(task);
1451 }
1452 try_failed_count++;
1453
1454 ip_unlock(port);
1455 mutex_pause(try_failed_count);
1456 }
1457 return TASK_NULL;
1458}
1459
1460/*
1461 * Routine: convert_port_to_locked_task_inspect
1462 * Purpose:
1463 * Internal helper routine to convert from a port to a locked
1464 * task inspect right. Used by internal routines that try to convert from a
1465 * task inspect port to a reference on some task related object.
1466 * Conditions:
1467 * Nothing locked, blocking OK.
1468 */
1469task_inspect_t
1470convert_port_to_locked_task_inspect(ipc_port_t port)
1471{
1472 int try_failed_count = 0;
1473
1474 while (IP_VALID(port)) {
1475 task_inspect_t task;
1476
1477 ip_lock(port);
1478 if (!ip_active(port) || (ip_kotype(port) != IKOT_TASK)) {
1479 ip_unlock(port);
1480 return TASK_INSPECT_NULL;
1481 }
1482 task = (task_inspect_t)port->ip_kobject;
1483 assert(task != TASK_INSPECT_NULL);
1484 /*
1485 * Normal lock ordering puts task_lock() before ip_lock().
1486 * Attempt out-of-order locking here.
1487 */
1488 if (task_lock_try((task_t)task)) {
1489 ip_unlock(port);
1490 return task;
1491 }
1492 try_failed_count++;
1493
1494 ip_unlock(port);
1495 mutex_pause(try_failed_count);
1496 }
1497 return TASK_INSPECT_NULL;
1498}
1499
1500
1501/*
1502 * Routine: convert_port_to_task
1503 * Purpose:
1504 * Convert from a port to a task.
1505 * Doesn't consume the port ref; produces a task ref,
1506 * which may be null.
1507 * Conditions:
1508 * Nothing locked.
1509 */
1510task_t
1511convert_port_to_task(
1512 ipc_port_t port)
1513{
1514 return convert_port_to_task_with_exec_token(port, NULL);
1515}
1516
1517/*
1518 * Routine: convert_port_to_task_with_exec_token
1519 * Purpose:
1520 * Convert from a port to a task and return
1521 * the exec token stored in the task.
1522 * Doesn't consume the port ref; produces a task ref,
1523 * which may be null.
1524 * Conditions:
1525 * Nothing locked.
1526 */
1527task_t
1528convert_port_to_task_with_exec_token(
1529 ipc_port_t port,
1530 uint32_t *exec_token)
1531{
1532 task_t task = TASK_NULL;
1533
1534 if (IP_VALID(port)) {
1535 ip_lock(port);
1536
1537 if ( ip_active(port) &&
1538 ip_kotype(port) == IKOT_TASK ) {
1539 task_t ct = current_task();
1540 task = (task_t)port->ip_kobject;
1541 assert(task != TASK_NULL);
1542
1543 if (task_conversion_eval(ct, task)) {
1544 ip_unlock(port);
1545 return TASK_NULL;
1546 }
1547
1548 if (exec_token) {
1549 *exec_token = task->exec_token;
1550 }
1551 task_reference_internal(task);
1552 }
1553
1554 ip_unlock(port);
1555 }
1556
1557 return (task);
1558}
1559
1560/*
1561 * Routine: convert_port_to_task_name
1562 * Purpose:
1563 * Convert from a port to a task name.
1564 * Doesn't consume the port ref; produces a task name ref,
1565 * which may be null.
1566 * Conditions:
1567 * Nothing locked.
1568 */
1569task_name_t
1570convert_port_to_task_name(
1571 ipc_port_t port)
1572{
1573 task_name_t task = TASK_NULL;
1574
1575 if (IP_VALID(port)) {
1576 ip_lock(port);
1577
1578 if ( ip_active(port) &&
1579 (ip_kotype(port) == IKOT_TASK ||
1580 ip_kotype(port) == IKOT_TASK_NAME)) {
1581 task = (task_name_t)port->ip_kobject;
1582 assert(task != TASK_NAME_NULL);
1583
1584 task_reference_internal(task);
1585 }
1586
1587 ip_unlock(port);
1588 }
1589
1590 return (task);
1591}
1592
1593/*
1594 * Routine: convert_port_to_task_inspect
1595 * Purpose:
1596 * Convert from a port to a task inspection right
1597 * Doesn't consume the port ref; produces a task ref,
1598 * which may be null.
1599 * Conditions:
1600 * Nothing locked.
1601 */
1602task_inspect_t
1603convert_port_to_task_inspect(
1604 ipc_port_t port)
1605{
1606 task_inspect_t task = TASK_INSPECT_NULL;
1607
1608 if (IP_VALID(port)) {
1609 ip_lock(port);
1610
1611 if (ip_active(port) &&
1612 ip_kotype(port) == IKOT_TASK) {
1613 task = (task_inspect_t)port->ip_kobject;
1614 assert(task != TASK_INSPECT_NULL);
1615
1616 task_reference_internal(task);
1617 }
1618
1619 ip_unlock(port);
1620 }
1621
1622 return (task);
1623}
1624
1625/*
1626 * Routine: convert_port_to_task_suspension_token
1627 * Purpose:
1628 * Convert from a port to a task suspension token.
1629 * Doesn't consume the port ref; produces a suspension token ref,
1630 * which may be null.
1631 * Conditions:
1632 * Nothing locked.
1633 */
1634task_suspension_token_t
1635convert_port_to_task_suspension_token(
1636 ipc_port_t port)
1637{
1638 task_suspension_token_t task = TASK_NULL;
1639
1640 if (IP_VALID(port)) {
1641 ip_lock(port);
1642
1643 if ( ip_active(port) &&
1644 ip_kotype(port) == IKOT_TASK_RESUME) {
1645 task = (task_suspension_token_t)port->ip_kobject;
1646 assert(task != TASK_NULL);
1647
1648 task_reference_internal(task);
1649 }
1650
1651 ip_unlock(port);
1652 }
1653
1654 return (task);
1655}
1656
1657/*
1658 * Routine: convert_port_to_space
1659 * Purpose:
1660 * Convert from a port to a space.
1661 * Doesn't consume the port ref; produces a space ref,
1662 * which may be null.
1663 * Conditions:
1664 * Nothing locked.
1665 */
1666ipc_space_t
1667convert_port_to_space(
1668 ipc_port_t port)
1669{
1670 ipc_space_t space;
1671 task_t task;
1672
1673 task = convert_port_to_locked_task(port);
1674
1675 if (task == TASK_NULL)
1676 return IPC_SPACE_NULL;
1677
1678 if (!task->active) {
1679 task_unlock(task);
1680 return IPC_SPACE_NULL;
1681 }
1682
1683 space = task->itk_space;
1684 is_reference(space);
1685 task_unlock(task);
1686 return (space);
1687}
1688
1689/*
1690 * Routine: convert_port_to_space_inspect
1691 * Purpose:
1692 * Convert from a port to a space inspect right.
1693 * Doesn't consume the port ref; produces a space inspect ref,
1694 * which may be null.
1695 * Conditions:
1696 * Nothing locked.
1697 */
1698ipc_space_inspect_t
1699convert_port_to_space_inspect(
1700 ipc_port_t port)
1701{
1702 ipc_space_inspect_t space;
1703 task_inspect_t task;
1704
1705 task = convert_port_to_locked_task_inspect(port);
1706
1707 if (task == TASK_INSPECT_NULL)
1708 return IPC_SPACE_INSPECT_NULL;
1709
1710 if (!task->active) {
1711 task_unlock(task);
1712 return IPC_SPACE_INSPECT_NULL;
1713 }
1714
1715 space = (ipc_space_inspect_t)task->itk_space;
1716 is_reference((ipc_space_t)space);
1717 task_unlock((task_t)task);
1718 return space;
1719}
1720
1721/*
1722 * Routine: convert_port_to_map
1723 * Purpose:
1724 * Convert from a port to a map.
1725 * Doesn't consume the port ref; produces a map ref,
1726 * which may be null.
1727 * Conditions:
1728 * Nothing locked.
1729 */
1730
1731vm_map_t
1732convert_port_to_map(
1733 ipc_port_t port)
1734{
1735 task_t task;
1736 vm_map_t map;
1737
1738 task = convert_port_to_locked_task(port);
1739
1740 if (task == TASK_NULL)
1741 return VM_MAP_NULL;
1742
1743 if (!task->active) {
1744 task_unlock(task);
1745 return VM_MAP_NULL;
1746 }
1747
1748 map = task->map;
1749 vm_map_reference_swap(map);
1750 task_unlock(task);
1751 return map;
1752}
1753
1754
1755/*
1756 * Routine: convert_port_to_thread
1757 * Purpose:
1758 * Convert from a port to a thread.
1759 * Doesn't consume the port ref; produces an thread ref,
1760 * which may be null.
1761 * Conditions:
1762 * Nothing locked.
1763 */
1764
1765thread_t
1766convert_port_to_thread(
1767 ipc_port_t port)
1768{
1769 thread_t thread = THREAD_NULL;
1770
1771 if (IP_VALID(port)) {
1772 ip_lock(port);
1773
1774 if (ip_active(port) &&
1775 ip_kotype(port) == IKOT_THREAD) {
1776 thread = (thread_t)port->ip_kobject;
1777 assert(thread != THREAD_NULL);
1778
1779 /* Use task conversion rules for thread control conversions */
1780 if (task_conversion_eval(current_task(), thread->task) != KERN_SUCCESS) {
1781 ip_unlock(port);
1782 return THREAD_NULL;
1783 }
1784
1785 thread_reference_internal(thread);
1786 }
1787
1788 ip_unlock(port);
1789 }
1790
1791 return (thread);
1792}
1793
1794/*
1795 * Routine: convert_port_to_thread_inspect
1796 * Purpose:
1797 * Convert from a port to a thread inspection right
1798 * Doesn't consume the port ref; produces a thread ref,
1799 * which may be null.
1800 * Conditions:
1801 * Nothing locked.
1802 */
1803thread_inspect_t
1804convert_port_to_thread_inspect(
1805 ipc_port_t port)
1806{
1807 thread_inspect_t thread = THREAD_INSPECT_NULL;
1808
1809 if (IP_VALID(port)) {
1810 ip_lock(port);
1811
1812 if (ip_active(port) &&
1813 ip_kotype(port) == IKOT_THREAD) {
1814 thread = (thread_inspect_t)port->ip_kobject;
1815 assert(thread != THREAD_INSPECT_NULL);
1816 thread_reference_internal((thread_t)thread);
1817 }
1818 ip_unlock(port);
1819 }
1820
1821 return thread;
1822}
1823
1824/*
1825 * Routine: convert_thread_inspect_to_port
1826 * Purpose:
1827 * Convert from a thread inspect reference to a port.
1828 * Consumes a thread ref;
1829 * As we never export thread inspect ports, always
1830 * creates a NULL port.
1831 * Conditions:
1832 * Nothing locked.
1833 */
1834
1835ipc_port_t
1836convert_thread_inspect_to_port(thread_inspect_t thread)
1837{
1838 thread_deallocate(thread);
1839 return IP_NULL;
1840}
1841
1842
1843/*
1844 * Routine: port_name_to_thread
1845 * Purpose:
1846 * Convert from a port name to an thread reference
1847 * A name of MACH_PORT_NULL is valid for the null thread.
1848 * Conditions:
1849 * Nothing locked.
1850 *
1851 * TODO: Could this be faster if it were ipc_port_translate_send based, like thread_switch?
1852 * We could avoid extra lock/unlock and extra ref operations on the port.
1853 */
1854thread_t
1855port_name_to_thread(
1856 mach_port_name_t name)
1857{
1858 thread_t thread = THREAD_NULL;
1859 ipc_port_t kport;
1860
1861 if (MACH_PORT_VALID(name)) {
1862 if (ipc_object_copyin(current_space(), name,
1863 MACH_MSG_TYPE_COPY_SEND,
1864 (ipc_object_t *)&kport) != KERN_SUCCESS)
1865 return (THREAD_NULL);
1866
1867 thread = convert_port_to_thread(kport);
1868
1869 if (IP_VALID(kport))
1870 ipc_port_release_send(kport);
1871 }
1872
1873 return (thread);
1874}
1875
1876task_t
1877port_name_to_task(
1878 mach_port_name_t name)
1879{
1880 ipc_port_t kern_port;
1881 kern_return_t kr;
1882 task_t task = TASK_NULL;
1883
1884 if (MACH_PORT_VALID(name)) {
1885 kr = ipc_object_copyin(current_space(), name,
1886 MACH_MSG_TYPE_COPY_SEND,
1887 (ipc_object_t *) &kern_port);
1888 if (kr != KERN_SUCCESS)
1889 return TASK_NULL;
1890
1891 task = convert_port_to_task(kern_port);
1892
1893 if (IP_VALID(kern_port))
1894 ipc_port_release_send(kern_port);
1895 }
1896 return task;
1897}
1898
1899task_inspect_t
1900port_name_to_task_inspect(
1901 mach_port_name_t name)
1902{
1903 ipc_port_t kern_port;
1904 kern_return_t kr;
1905 task_inspect_t ti = TASK_INSPECT_NULL;
1906
1907 if (MACH_PORT_VALID(name)) {
1908 kr = ipc_object_copyin(current_space(), name,
1909 MACH_MSG_TYPE_COPY_SEND,
1910 (ipc_object_t *)&kern_port);
1911 if (kr != KERN_SUCCESS)
1912 return TASK_NULL;
1913
1914 ti = convert_port_to_task_inspect(kern_port);
1915
1916 if (IP_VALID(kern_port))
1917 ipc_port_release_send(kern_port);
1918 }
1919 return ti;
1920}
1921
1922/*
1923 * Routine: port_name_to_host
1924 * Purpose:
1925 * Convert from a port name to a host pointer.
1926 * NOTE: This does _not_ return a +1 reference to the host_t
1927 * Conditions:
1928 * Nothing locked.
1929 */
1930host_t
1931port_name_to_host(
1932 mach_port_name_t name)
1933{
1934
1935 host_t host = HOST_NULL;
1936 kern_return_t kr;
1937 ipc_port_t port;
1938
1939 if (MACH_PORT_VALID(name)) {
1940 kr = ipc_port_translate_send(current_space(), name, &port);
1941 if (kr == KERN_SUCCESS) {
1942 host = convert_port_to_host(port);
1943 ip_unlock(port);
1944 }
1945 }
1946 return host;
1947}
1948
1949/*
1950 * Routine: convert_task_to_port
1951 * Purpose:
1952 * Convert from a task to a port.
1953 * Consumes a task ref; produces a naked send right
1954 * which may be invalid.
1955 * Conditions:
1956 * Nothing locked.
1957 */
1958
1959ipc_port_t
1960convert_task_to_port(
1961 task_t task)
1962{
1963 ipc_port_t port;
1964
1965 itk_lock(task);
1966
1967 if (task->itk_self != IP_NULL)
1968 port = ipc_port_make_send(task->itk_self);
1969 else
1970 port = IP_NULL;
1971
1972 itk_unlock(task);
1973
1974 task_deallocate(task);
1975 return port;
1976}
1977
1978/*
1979 * Routine: convert_task_inspect_to_port
1980 * Purpose:
1981 * Convert from a task inspect reference to a port.
1982 * Consumes a task ref;
1983 * As we never export task inspect ports, always
1984 * creates a NULL port.
1985 * Conditions:
1986 * Nothing locked.
1987 */
1988ipc_port_t
1989convert_task_inspect_to_port(
1990 task_inspect_t task)
1991{
1992 task_deallocate(task);
1993
1994 return IP_NULL;
1995}
1996
1997/*
1998 * Routine: convert_task_suspend_token_to_port
1999 * Purpose:
2000 * Convert from a task suspension token to a port.
2001 * Consumes a task suspension token ref; produces a naked send-once right
2002 * which may be invalid.
2003 * Conditions:
2004 * Nothing locked.
2005 */
2006ipc_port_t
2007convert_task_suspension_token_to_port(
2008 task_suspension_token_t task)
2009{
2010 ipc_port_t port;
2011
2012 task_lock(task);
2013 if (task->active) {
2014 if (task->itk_resume == IP_NULL) {
2015 task->itk_resume = ipc_port_alloc_kernel();
2016 if (!IP_VALID(task->itk_resume)) {
2017 panic("failed to create resume port");
2018 }
2019
2020 ipc_kobject_set(task->itk_resume, (ipc_kobject_t) task, IKOT_TASK_RESUME);
2021 }
2022
2023 /*
2024 * Create a send-once right for each instance of a direct user-called
2025 * task_suspend2 call. Each time one of these send-once rights is abandoned,
2026 * the notification handler will resume the target task.
2027 */
2028 port = ipc_port_make_sonce(task->itk_resume);
2029 assert(IP_VALID(port));
2030 } else {
2031 port = IP_NULL;
2032 }
2033
2034 task_unlock(task);
2035 task_suspension_token_deallocate(task);
2036
2037 return port;
2038}
2039
2040
2041/*
2042 * Routine: convert_task_name_to_port
2043 * Purpose:
2044 * Convert from a task name ref to a port.
2045 * Consumes a task name ref; produces a naked send right
2046 * which may be invalid.
2047 * Conditions:
2048 * Nothing locked.
2049 */
2050
2051ipc_port_t
2052convert_task_name_to_port(
2053 task_name_t task_name)
2054{
2055 ipc_port_t port;
2056
2057 itk_lock(task_name);
2058 if (task_name->itk_nself != IP_NULL)
2059 port = ipc_port_make_send(task_name->itk_nself);
2060 else
2061 port = IP_NULL;
2062 itk_unlock(task_name);
2063
2064 task_name_deallocate(task_name);
2065 return port;
2066}
2067
2068/*
2069 * Routine: convert_thread_to_port
2070 * Purpose:
2071 * Convert from a thread to a port.
2072 * Consumes an thread ref; produces a naked send right
2073 * which may be invalid.
2074 * Conditions:
2075 * Nothing locked.
2076 */
2077
2078ipc_port_t
2079convert_thread_to_port(
2080 thread_t thread)
2081{
2082 ipc_port_t port;
2083
2084 thread_mtx_lock(thread);
2085
2086 if (thread->ith_self != IP_NULL)
2087 port = ipc_port_make_send(thread->ith_self);
2088 else
2089 port = IP_NULL;
2090
2091 thread_mtx_unlock(thread);
2092
2093 thread_deallocate(thread);
2094
2095 return (port);
2096}
2097
2098/*
2099 * Routine: space_deallocate
2100 * Purpose:
2101 * Deallocate a space ref produced by convert_port_to_space.
2102 * Conditions:
2103 * Nothing locked.
2104 */
2105
2106void
2107space_deallocate(
2108 ipc_space_t space)
2109{
2110 if (space != IS_NULL)
2111 is_release(space);
2112}
2113
2114/*
2115 * Routine: space_inspect_deallocate
2116 * Purpose:
2117 * Deallocate a space inspect ref produced by convert_port_to_space_inspect.
2118 * Conditions:
2119 * Nothing locked.
2120 */
2121
2122void
2123space_inspect_deallocate(
2124 ipc_space_inspect_t space)
2125{
2126 if (space != IS_INSPECT_NULL)
2127 is_release((ipc_space_t)space);
2128}
2129
2130/*
2131 * Routine: thread/task_set_exception_ports [kernel call]
2132 * Purpose:
2133 * Sets the thread/task exception port, flavor and
2134 * behavior for the exception types specified by the mask.
2135 * There will be one send right per exception per valid
2136 * port.
2137 * Conditions:
2138 * Nothing locked. If successful, consumes
2139 * the supplied send right.
2140 * Returns:
2141 * KERN_SUCCESS Changed the special port.
2142 * KERN_INVALID_ARGUMENT The thread is null,
2143 * Illegal mask bit set.
2144 * Illegal exception behavior
2145 * KERN_FAILURE The thread is dead.
2146 */
2147
2148kern_return_t
2149thread_set_exception_ports(
2150 thread_t thread,
2151 exception_mask_t exception_mask,
2152 ipc_port_t new_port,
2153 exception_behavior_t new_behavior,
2154 thread_state_flavor_t new_flavor)
2155{
2156 ipc_port_t old_port[EXC_TYPES_COUNT];
2157 boolean_t privileged = current_task()->sec_token.val[0] == 0;
2158 register int i;
2159
2160#if CONFIG_MACF
2161 struct label *new_label;
2162#endif
2163
2164 if (thread == THREAD_NULL)
2165 return (KERN_INVALID_ARGUMENT);
2166
2167 if (exception_mask & ~EXC_MASK_VALID)
2168 return (KERN_INVALID_ARGUMENT);
2169
2170 if (IP_VALID(new_port)) {
2171 switch (new_behavior & ~MACH_EXCEPTION_CODES) {
2172
2173 case EXCEPTION_DEFAULT:
2174 case EXCEPTION_STATE:
2175 case EXCEPTION_STATE_IDENTITY:
2176 break;
2177
2178 default:
2179 return (KERN_INVALID_ARGUMENT);
2180 }
2181 }
2182
2183 /*
2184 * Check the validity of the thread_state_flavor by calling the
2185 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in
2186 * osfmk/mach/ARCHITECTURE/thread_status.h
2187 */
2188 if (new_flavor != 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor))
2189 return (KERN_INVALID_ARGUMENT);
2190
2191#if CONFIG_MACF
2192 new_label = mac_exc_create_label_for_current_proc();
2193#endif
2194
2195 thread_mtx_lock(thread);
2196
2197 if (!thread->active) {
2198 thread_mtx_unlock(thread);
2199
2200 return (KERN_FAILURE);
2201 }
2202
2203 if (thread->exc_actions == NULL) {
2204 ipc_thread_init_exc_actions(thread);
2205 }
2206 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
2207 if ((exception_mask & (1 << i))
2208#if CONFIG_MACF
2209 && mac_exc_update_action_label(&thread->exc_actions[i], new_label) == 0
2210#endif
2211 ) {
2212 old_port[i] = thread->exc_actions[i].port;
2213 thread->exc_actions[i].port = ipc_port_copy_send(new_port);
2214 thread->exc_actions[i].behavior = new_behavior;
2215 thread->exc_actions[i].flavor = new_flavor;
2216 thread->exc_actions[i].privileged = privileged;
2217 }
2218 else
2219 old_port[i] = IP_NULL;
2220 }
2221
2222 thread_mtx_unlock(thread);
2223
2224#if CONFIG_MACF
2225 mac_exc_free_label(new_label);
2226#endif
2227
2228 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i)
2229 if (IP_VALID(old_port[i]))
2230 ipc_port_release_send(old_port[i]);
2231
2232 if (IP_VALID(new_port)) /* consume send right */
2233 ipc_port_release_send(new_port);
2234
2235 return (KERN_SUCCESS);
2236}
2237
2238kern_return_t
2239task_set_exception_ports(
2240 task_t task,
2241 exception_mask_t exception_mask,
2242 ipc_port_t new_port,
2243 exception_behavior_t new_behavior,
2244 thread_state_flavor_t new_flavor)
2245{
2246 ipc_port_t old_port[EXC_TYPES_COUNT];
2247 boolean_t privileged = current_task()->sec_token.val[0] == 0;
2248 register int i;
2249
2250#if CONFIG_MACF
2251 struct label *new_label;
2252#endif
2253
2254 if (task == TASK_NULL)
2255 return (KERN_INVALID_ARGUMENT);
2256
2257 if (exception_mask & ~EXC_MASK_VALID)
2258 return (KERN_INVALID_ARGUMENT);
2259
2260 if (IP_VALID(new_port)) {
2261 switch (new_behavior & ~MACH_EXCEPTION_CODES) {
2262
2263 case EXCEPTION_DEFAULT:
2264 case EXCEPTION_STATE:
2265 case EXCEPTION_STATE_IDENTITY:
2266 break;
2267
2268 default:
2269 return (KERN_INVALID_ARGUMENT);
2270 }
2271 }
2272
2273 /*
2274 * Check the validity of the thread_state_flavor by calling the
2275 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in
2276 * osfmk/mach/ARCHITECTURE/thread_status.h
2277 */
2278 if (new_flavor != 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor))
2279 return (KERN_INVALID_ARGUMENT);
2280
2281#if CONFIG_MACF
2282 new_label = mac_exc_create_label_for_current_proc();
2283#endif
2284
2285 itk_lock(task);
2286
2287 if (task->itk_self == IP_NULL) {
2288 itk_unlock(task);
2289
2290 return (KERN_FAILURE);
2291 }
2292
2293 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
2294 if ((exception_mask & (1 << i))
2295#if CONFIG_MACF
2296 && mac_exc_update_action_label(&task->exc_actions[i], new_label) == 0
2297#endif
2298 ) {
2299 old_port[i] = task->exc_actions[i].port;
2300 task->exc_actions[i].port =
2301 ipc_port_copy_send(new_port);
2302 task->exc_actions[i].behavior = new_behavior;
2303 task->exc_actions[i].flavor = new_flavor;
2304 task->exc_actions[i].privileged = privileged;
2305 }
2306 else
2307 old_port[i] = IP_NULL;
2308 }
2309
2310 itk_unlock(task);
2311
2312#if CONFIG_MACF
2313 mac_exc_free_label(new_label);
2314#endif
2315
2316 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i)
2317 if (IP_VALID(old_port[i]))
2318 ipc_port_release_send(old_port[i]);
2319
2320 if (IP_VALID(new_port)) /* consume send right */
2321 ipc_port_release_send(new_port);
2322
2323 return (KERN_SUCCESS);
2324}
2325
2326/*
2327 * Routine: thread/task_swap_exception_ports [kernel call]
2328 * Purpose:
2329 * Sets the thread/task exception port, flavor and
2330 * behavior for the exception types specified by the
2331 * mask.
2332 *
2333 * The old ports, behavior and flavors are returned
2334 * Count specifies the array sizes on input and
2335 * the number of returned ports etc. on output. The
2336 * arrays must be large enough to hold all the returned
2337 * data, MIG returnes an error otherwise. The masks
2338 * array specifies the corresponding exception type(s).
2339 *
2340 * Conditions:
2341 * Nothing locked. If successful, consumes
2342 * the supplied send right.
2343 *
2344 * Returns upto [in} CountCnt elements.
2345 * Returns:
2346 * KERN_SUCCESS Changed the special port.
2347 * KERN_INVALID_ARGUMENT The thread is null,
2348 * Illegal mask bit set.
2349 * Illegal exception behavior
2350 * KERN_FAILURE The thread is dead.
2351 */
2352
2353kern_return_t
2354thread_swap_exception_ports(
2355 thread_t thread,
2356 exception_mask_t exception_mask,
2357 ipc_port_t new_port,
2358 exception_behavior_t new_behavior,
2359 thread_state_flavor_t new_flavor,
2360 exception_mask_array_t masks,
2361 mach_msg_type_number_t *CountCnt,
2362 exception_port_array_t ports,
2363 exception_behavior_array_t behaviors,
2364 thread_state_flavor_array_t flavors)
2365{
2366 ipc_port_t old_port[EXC_TYPES_COUNT];
2367 boolean_t privileged = current_task()->sec_token.val[0] == 0;
2368 unsigned int i, j, count;
2369
2370#if CONFIG_MACF
2371 struct label *new_label;
2372#endif
2373
2374 if (thread == THREAD_NULL)
2375 return (KERN_INVALID_ARGUMENT);
2376
2377 if (exception_mask & ~EXC_MASK_VALID)
2378 return (KERN_INVALID_ARGUMENT);
2379
2380 if (IP_VALID(new_port)) {
2381 switch (new_behavior & ~MACH_EXCEPTION_CODES) {
2382
2383 case EXCEPTION_DEFAULT:
2384 case EXCEPTION_STATE:
2385 case EXCEPTION_STATE_IDENTITY:
2386 break;
2387
2388 default:
2389 return (KERN_INVALID_ARGUMENT);
2390 }
2391 }
2392
2393 if (new_flavor != 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor))
2394 return (KERN_INVALID_ARGUMENT);
2395
2396#if CONFIG_MACF
2397 new_label = mac_exc_create_label_for_current_proc();
2398#endif
2399
2400 thread_mtx_lock(thread);
2401
2402 if (!thread->active) {
2403 thread_mtx_unlock(thread);
2404
2405 return (KERN_FAILURE);
2406 }
2407
2408 if (thread->exc_actions == NULL) {
2409 ipc_thread_init_exc_actions(thread);
2410 }
2411
2412 assert(EXC_TYPES_COUNT > FIRST_EXCEPTION);
2413 for (count = 0, i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT && count < *CountCnt; ++i) {
2414 if ((exception_mask & (1 << i))
2415#if CONFIG_MACF
2416 && mac_exc_update_action_label(&thread->exc_actions[i], new_label) == 0
2417#endif
2418 ) {
2419 for (j = 0; j < count; ++j) {
2420 /*
2421 * search for an identical entry, if found
2422 * set corresponding mask for this exception.
2423 */
2424 if ( thread->exc_actions[i].port == ports[j] &&
2425 thread->exc_actions[i].behavior == behaviors[j] &&
2426 thread->exc_actions[i].flavor == flavors[j] ) {
2427 masks[j] |= (1 << i);
2428 break;
2429 }
2430 }
2431
2432 if (j == count) {
2433 masks[j] = (1 << i);
2434 ports[j] = ipc_port_copy_send(thread->exc_actions[i].port);
2435
2436 behaviors[j] = thread->exc_actions[i].behavior;
2437 flavors[j] = thread->exc_actions[i].flavor;
2438 ++count;
2439 }
2440
2441 old_port[i] = thread->exc_actions[i].port;
2442 thread->exc_actions[i].port = ipc_port_copy_send(new_port);
2443 thread->exc_actions[i].behavior = new_behavior;
2444 thread->exc_actions[i].flavor = new_flavor;
2445 thread->exc_actions[i].privileged = privileged;
2446 }
2447 else
2448 old_port[i] = IP_NULL;
2449 }
2450
2451 thread_mtx_unlock(thread);
2452
2453#if CONFIG_MACF
2454 mac_exc_free_label(new_label);
2455#endif
2456
2457 while (--i >= FIRST_EXCEPTION) {
2458 if (IP_VALID(old_port[i]))
2459 ipc_port_release_send(old_port[i]);
2460 }
2461
2462 if (IP_VALID(new_port)) /* consume send right */
2463 ipc_port_release_send(new_port);
2464
2465 *CountCnt = count;
2466
2467 return (KERN_SUCCESS);
2468}
2469
2470kern_return_t
2471task_swap_exception_ports(
2472 task_t task,
2473 exception_mask_t exception_mask,
2474 ipc_port_t new_port,
2475 exception_behavior_t new_behavior,
2476 thread_state_flavor_t new_flavor,
2477 exception_mask_array_t masks,
2478 mach_msg_type_number_t *CountCnt,
2479 exception_port_array_t ports,
2480 exception_behavior_array_t behaviors,
2481 thread_state_flavor_array_t flavors)
2482{
2483 ipc_port_t old_port[EXC_TYPES_COUNT];
2484 boolean_t privileged = current_task()->sec_token.val[0] == 0;
2485 unsigned int i, j, count;
2486
2487#if CONFIG_MACF
2488 struct label *new_label;
2489#endif
2490
2491 if (task == TASK_NULL)
2492 return (KERN_INVALID_ARGUMENT);
2493
2494 if (exception_mask & ~EXC_MASK_VALID)
2495 return (KERN_INVALID_ARGUMENT);
2496
2497 if (IP_VALID(new_port)) {
2498 switch (new_behavior & ~MACH_EXCEPTION_CODES) {
2499
2500 case EXCEPTION_DEFAULT:
2501 case EXCEPTION_STATE:
2502 case EXCEPTION_STATE_IDENTITY:
2503 break;
2504
2505 default:
2506 return (KERN_INVALID_ARGUMENT);
2507 }
2508 }
2509
2510 if (new_flavor != 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor))
2511 return (KERN_INVALID_ARGUMENT);
2512
2513#if CONFIG_MACF
2514 new_label = mac_exc_create_label_for_current_proc();
2515#endif
2516
2517 itk_lock(task);
2518
2519 if (task->itk_self == IP_NULL) {
2520 itk_unlock(task);
2521
2522 return (KERN_FAILURE);
2523 }
2524
2525 assert(EXC_TYPES_COUNT > FIRST_EXCEPTION);
2526 for (count = 0, i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT && count < *CountCnt; ++i) {
2527 if ((exception_mask & (1 << i))
2528#if CONFIG_MACF
2529 && mac_exc_update_action_label(&task->exc_actions[i], new_label) == 0
2530#endif
2531 ) {
2532 for (j = 0; j < count; j++) {
2533 /*
2534 * search for an identical entry, if found
2535 * set corresponding mask for this exception.
2536 */
2537 if ( task->exc_actions[i].port == ports[j] &&
2538 task->exc_actions[i].behavior == behaviors[j] &&
2539 task->exc_actions[i].flavor == flavors[j] ) {
2540 masks[j] |= (1 << i);
2541 break;
2542 }
2543 }
2544
2545 if (j == count) {
2546 masks[j] = (1 << i);
2547 ports[j] = ipc_port_copy_send(task->exc_actions[i].port);
2548 behaviors[j] = task->exc_actions[i].behavior;
2549 flavors[j] = task->exc_actions[i].flavor;
2550 ++count;
2551 }
2552
2553 old_port[i] = task->exc_actions[i].port;
2554
2555 task->exc_actions[i].port = ipc_port_copy_send(new_port);
2556 task->exc_actions[i].behavior = new_behavior;
2557 task->exc_actions[i].flavor = new_flavor;
2558 task->exc_actions[i].privileged = privileged;
2559 }
2560 else
2561 old_port[i] = IP_NULL;
2562 }
2563
2564 itk_unlock(task);
2565
2566#if CONFIG_MACF
2567 mac_exc_free_label(new_label);
2568#endif
2569
2570 while (--i >= FIRST_EXCEPTION) {
2571 if (IP_VALID(old_port[i]))
2572 ipc_port_release_send(old_port[i]);
2573 }
2574
2575 if (IP_VALID(new_port)) /* consume send right */
2576 ipc_port_release_send(new_port);
2577
2578 *CountCnt = count;
2579
2580 return (KERN_SUCCESS);
2581}
2582
2583/*
2584 * Routine: thread/task_get_exception_ports [kernel call]
2585 * Purpose:
2586 * Clones a send right for each of the thread/task's exception
2587 * ports specified in the mask and returns the behaviour
2588 * and flavor of said port.
2589 *
2590 * Returns upto [in} CountCnt elements.
2591 *
2592 * Conditions:
2593 * Nothing locked.
2594 * Returns:
2595 * KERN_SUCCESS Extracted a send right.
2596 * KERN_INVALID_ARGUMENT The thread is null,
2597 * Invalid special port,
2598 * Illegal mask bit set.
2599 * KERN_FAILURE The thread is dead.
2600 */
2601
2602kern_return_t
2603thread_get_exception_ports(
2604 thread_t thread,
2605 exception_mask_t exception_mask,
2606 exception_mask_array_t masks,
2607 mach_msg_type_number_t *CountCnt,
2608 exception_port_array_t ports,
2609 exception_behavior_array_t behaviors,
2610 thread_state_flavor_array_t flavors)
2611{
2612 unsigned int i, j, count;
2613
2614 if (thread == THREAD_NULL)
2615 return (KERN_INVALID_ARGUMENT);
2616
2617 if (exception_mask & ~EXC_MASK_VALID)
2618 return (KERN_INVALID_ARGUMENT);
2619
2620 thread_mtx_lock(thread);
2621
2622 if (!thread->active) {
2623 thread_mtx_unlock(thread);
2624
2625 return (KERN_FAILURE);
2626 }
2627
2628 count = 0;
2629
2630 if (thread->exc_actions == NULL) {
2631 goto done;
2632 }
2633
2634 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
2635 if (exception_mask & (1 << i)) {
2636 for (j = 0; j < count; ++j) {
2637 /*
2638 * search for an identical entry, if found
2639 * set corresponding mask for this exception.
2640 */
2641 if ( thread->exc_actions[i].port == ports[j] &&
2642 thread->exc_actions[i].behavior ==behaviors[j] &&
2643 thread->exc_actions[i].flavor == flavors[j] ) {
2644 masks[j] |= (1 << i);
2645 break;
2646 }
2647 }
2648
2649 if (j == count) {
2650 masks[j] = (1 << i);
2651 ports[j] = ipc_port_copy_send(thread->exc_actions[i].port);
2652 behaviors[j] = thread->exc_actions[i].behavior;
2653 flavors[j] = thread->exc_actions[i].flavor;
2654 ++count;
2655 if (count >= *CountCnt)
2656 break;
2657 }
2658 }
2659 }
2660
2661done:
2662 thread_mtx_unlock(thread);
2663
2664 *CountCnt = count;
2665
2666 return (KERN_SUCCESS);
2667}
2668
2669kern_return_t
2670task_get_exception_ports(
2671 task_t task,
2672 exception_mask_t exception_mask,
2673 exception_mask_array_t masks,
2674 mach_msg_type_number_t *CountCnt,
2675 exception_port_array_t ports,
2676 exception_behavior_array_t behaviors,
2677 thread_state_flavor_array_t flavors)
2678{
2679 unsigned int i, j, count;
2680
2681 if (task == TASK_NULL)
2682 return (KERN_INVALID_ARGUMENT);
2683
2684 if (exception_mask & ~EXC_MASK_VALID)
2685 return (KERN_INVALID_ARGUMENT);
2686
2687 itk_lock(task);
2688
2689 if (task->itk_self == IP_NULL) {
2690 itk_unlock(task);
2691
2692 return (KERN_FAILURE);
2693 }
2694
2695 count = 0;
2696
2697 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
2698 if (exception_mask & (1 << i)) {
2699 for (j = 0; j < count; ++j) {
2700 /*
2701 * search for an identical entry, if found
2702 * set corresponding mask for this exception.
2703 */
2704 if ( task->exc_actions[i].port == ports[j] &&
2705 task->exc_actions[i].behavior == behaviors[j] &&
2706 task->exc_actions[i].flavor == flavors[j] ) {
2707 masks[j] |= (1 << i);
2708 break;
2709 }
2710 }
2711
2712 if (j == count) {
2713 masks[j] = (1 << i);
2714 ports[j] = ipc_port_copy_send(task->exc_actions[i].port);
2715 behaviors[j] = task->exc_actions[i].behavior;
2716 flavors[j] = task->exc_actions[i].flavor;
2717 ++count;
2718 if (count > *CountCnt)
2719 break;
2720 }
2721 }
2722 }
2723
2724 itk_unlock(task);
2725
2726 *CountCnt = count;
2727
2728 return (KERN_SUCCESS);
2729}
2730