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