]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/ipc_tt.c
9a870298f9f48e4a89845cef2f47f4445e17bf41
[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 /* forward declarations */
102 task_t convert_port_to_locked_task(ipc_port_t port);
103
104
105 /*
106 * Routine: ipc_task_init
107 * Purpose:
108 * Initialize a task's IPC state.
109 *
110 * If non-null, some state will be inherited from the parent.
111 * The parent must be appropriately initialized.
112 * Conditions:
113 * Nothing locked.
114 */
115
116 void
117 ipc_task_init(
118 task_t task,
119 task_t parent)
120 {
121 ipc_space_t space;
122 ipc_port_t kport;
123 ipc_port_t nport;
124 kern_return_t kr;
125 int i;
126
127
128 kr = ipc_space_create(&ipc_table_entries[0], &space);
129 if (kr != KERN_SUCCESS)
130 panic("ipc_task_init");
131
132 space->is_task = task;
133
134 kport = ipc_port_alloc_kernel();
135 if (kport == IP_NULL)
136 panic("ipc_task_init");
137
138 nport = ipc_port_alloc_kernel();
139 if (nport == IP_NULL)
140 panic("ipc_task_init");
141
142 itk_lock_init(task);
143 task->itk_self = kport;
144 task->itk_nself = nport;
145 task->itk_resume = IP_NULL; /* Lazily allocated on-demand */
146 task->itk_sself = ipc_port_make_send(kport);
147 task->itk_debug_control = IP_NULL;
148 task->itk_space = space;
149
150 if (parent == TASK_NULL) {
151 ipc_port_t port;
152
153 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
154 task->exc_actions[i].port = IP_NULL;
155 }/* for */
156
157 kr = host_get_host_port(host_priv_self(), &port);
158 assert(kr == KERN_SUCCESS);
159 task->itk_host = port;
160
161 task->itk_bootstrap = IP_NULL;
162 task->itk_seatbelt = IP_NULL;
163 task->itk_gssd = IP_NULL;
164 task->itk_task_access = IP_NULL;
165
166 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
167 task->itk_registered[i] = IP_NULL;
168 } else {
169 itk_lock(parent);
170 assert(parent->itk_self != IP_NULL);
171
172 /* inherit registered ports */
173
174 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
175 task->itk_registered[i] =
176 ipc_port_copy_send(parent->itk_registered[i]);
177
178 /* inherit exception and bootstrap ports */
179
180 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
181 task->exc_actions[i].port =
182 ipc_port_copy_send(parent->exc_actions[i].port);
183 task->exc_actions[i].flavor =
184 parent->exc_actions[i].flavor;
185 task->exc_actions[i].behavior =
186 parent->exc_actions[i].behavior;
187 task->exc_actions[i].privileged =
188 parent->exc_actions[i].privileged;
189 }/* for */
190 task->itk_host =
191 ipc_port_copy_send(parent->itk_host);
192
193 task->itk_bootstrap =
194 ipc_port_copy_send(parent->itk_bootstrap);
195
196 task->itk_seatbelt =
197 ipc_port_copy_send(parent->itk_seatbelt);
198
199 task->itk_gssd =
200 ipc_port_copy_send(parent->itk_gssd);
201
202 task->itk_task_access =
203 ipc_port_copy_send(parent->itk_task_access);
204
205 itk_unlock(parent);
206 }
207 }
208
209 /*
210 * Routine: ipc_task_enable
211 * Purpose:
212 * Enable a task for IPC access.
213 * Conditions:
214 * Nothing locked.
215 */
216
217 void
218 ipc_task_enable(
219 task_t task)
220 {
221 ipc_port_t kport;
222 ipc_port_t nport;
223
224 itk_lock(task);
225 kport = task->itk_self;
226 if (kport != IP_NULL)
227 ipc_kobject_set(kport, (ipc_kobject_t) task, IKOT_TASK);
228 nport = task->itk_nself;
229 if (nport != IP_NULL)
230 ipc_kobject_set(nport, (ipc_kobject_t) task, IKOT_TASK_NAME);
231 itk_unlock(task);
232 }
233
234 /*
235 * Routine: ipc_task_disable
236 * Purpose:
237 * Disable IPC access to a task.
238 * Conditions:
239 * Nothing locked.
240 */
241
242 void
243 ipc_task_disable(
244 task_t task)
245 {
246 ipc_port_t kport;
247 ipc_port_t nport;
248 ipc_port_t rport;
249
250 itk_lock(task);
251 kport = task->itk_self;
252 if (kport != IP_NULL)
253 ipc_kobject_set(kport, IKO_NULL, IKOT_NONE);
254 nport = task->itk_nself;
255 if (nport != IP_NULL)
256 ipc_kobject_set(nport, IKO_NULL, IKOT_NONE);
257
258 rport = task->itk_resume;
259 if (rport != IP_NULL) {
260 /*
261 * From this point onwards this task is no longer accepting
262 * resumptions.
263 *
264 * There are still outstanding suspensions on this task,
265 * even as it is being torn down. Disconnect the task
266 * from the rport, thereby "orphaning" the rport. The rport
267 * itself will go away only when the last suspension holder
268 * destroys his SO right to it -- when he either
269 * exits, or tries to actually use that last SO right to
270 * resume this (now non-existent) task.
271 */
272 ipc_kobject_set(rport, IKO_NULL, IKOT_NONE);
273 }
274 itk_unlock(task);
275 }
276
277 /*
278 * Routine: ipc_task_terminate
279 * Purpose:
280 * Clean up and destroy a task's IPC state.
281 * Conditions:
282 * Nothing locked. The task must be suspended.
283 * (Or the current thread must be in the task.)
284 */
285
286 void
287 ipc_task_terminate(
288 task_t task)
289 {
290 ipc_port_t kport;
291 ipc_port_t nport;
292 ipc_port_t rport;
293 int i;
294
295 itk_lock(task);
296 kport = task->itk_self;
297
298 if (kport == IP_NULL) {
299 /* the task is already terminated (can this happen?) */
300 itk_unlock(task);
301 return;
302 }
303 task->itk_self = IP_NULL;
304
305 nport = task->itk_nself;
306 assert(nport != IP_NULL);
307 task->itk_nself = IP_NULL;
308
309 rport = task->itk_resume;
310 task->itk_resume = IP_NULL;
311
312 itk_unlock(task);
313
314 /* release the naked send rights */
315
316 if (IP_VALID(task->itk_sself))
317 ipc_port_release_send(task->itk_sself);
318
319 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
320 if (IP_VALID(task->exc_actions[i].port)) {
321 ipc_port_release_send(task->exc_actions[i].port);
322 }
323 }
324
325 if (IP_VALID(task->itk_host))
326 ipc_port_release_send(task->itk_host);
327
328 if (IP_VALID(task->itk_bootstrap))
329 ipc_port_release_send(task->itk_bootstrap);
330
331 if (IP_VALID(task->itk_seatbelt))
332 ipc_port_release_send(task->itk_seatbelt);
333
334 if (IP_VALID(task->itk_gssd))
335 ipc_port_release_send(task->itk_gssd);
336
337 if (IP_VALID(task->itk_task_access))
338 ipc_port_release_send(task->itk_task_access);
339
340 if (IP_VALID(task->itk_debug_control))
341 ipc_port_release_send(task->itk_debug_control);
342
343 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
344 if (IP_VALID(task->itk_registered[i]))
345 ipc_port_release_send(task->itk_registered[i]);
346
347 /* destroy the kernel ports */
348 ipc_port_dealloc_kernel(kport);
349 ipc_port_dealloc_kernel(nport);
350 if (rport != IP_NULL)
351 ipc_port_dealloc_kernel(rport);
352
353 itk_lock_destroy(task);
354 }
355
356 /*
357 * Routine: ipc_task_reset
358 * Purpose:
359 * Reset a task's IPC state to protect it when
360 * it enters an elevated security context. The
361 * task name port can remain the same - since
362 * it represents no specific privilege.
363 * Conditions:
364 * Nothing locked. The task must be suspended.
365 * (Or the current thread must be in the task.)
366 */
367
368 void
369 ipc_task_reset(
370 task_t task)
371 {
372 ipc_port_t old_kport, new_kport;
373 ipc_port_t old_sself;
374 ipc_port_t old_exc_actions[EXC_TYPES_COUNT];
375 int i;
376
377 new_kport = ipc_port_alloc_kernel();
378 if (new_kport == IP_NULL)
379 panic("ipc_task_reset");
380
381 itk_lock(task);
382
383 old_kport = task->itk_self;
384
385 if (old_kport == IP_NULL) {
386 /* the task is already terminated (can this happen?) */
387 itk_unlock(task);
388 ipc_port_dealloc_kernel(new_kport);
389 return;
390 }
391
392 task->itk_self = new_kport;
393 old_sself = task->itk_sself;
394 task->itk_sself = ipc_port_make_send(new_kport);
395 ipc_kobject_set(old_kport, IKO_NULL, IKOT_NONE);
396 ipc_kobject_set(new_kport, (ipc_kobject_t) task, IKOT_TASK);
397
398 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
399 if (!task->exc_actions[i].privileged) {
400 old_exc_actions[i] = task->exc_actions[i].port;
401 task->exc_actions[i].port = IP_NULL;
402 } else {
403 old_exc_actions[i] = IP_NULL;
404 }
405 }/* for */
406
407 if (IP_VALID(task->itk_debug_control)) {
408 ipc_port_release_send(task->itk_debug_control);
409 }
410 task->itk_debug_control = IP_NULL;
411
412 itk_unlock(task);
413
414 /* release the naked send rights */
415
416 if (IP_VALID(old_sself))
417 ipc_port_release_send(old_sself);
418
419 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
420 if (IP_VALID(old_exc_actions[i])) {
421 ipc_port_release_send(old_exc_actions[i]);
422 }
423 }/* for */
424
425 /* destroy the kernel port */
426 ipc_port_dealloc_kernel(old_kport);
427 }
428
429 /*
430 * Routine: ipc_thread_init
431 * Purpose:
432 * Initialize a thread's IPC state.
433 * Conditions:
434 * Nothing locked.
435 */
436
437 void
438 ipc_thread_init(
439 thread_t thread)
440 {
441 ipc_port_t kport;
442
443 kport = ipc_port_alloc_kernel();
444 if (kport == IP_NULL)
445 panic("ipc_thread_init");
446
447 thread->ith_self = kport;
448 thread->ith_sself = ipc_port_make_send(kport);
449 thread->exc_actions = NULL;
450
451 ipc_kobject_set(kport, (ipc_kobject_t)thread, IKOT_THREAD);
452
453 #if IMPORTANCE_INHERITANCE
454 thread->ith_assertions = 0;
455 #endif
456
457 ipc_kmsg_queue_init(&thread->ith_messages);
458
459 thread->ith_rpc_reply = IP_NULL;
460 }
461
462 void
463 ipc_thread_init_exc_actions(
464 thread_t thread)
465 {
466 assert(thread->exc_actions == NULL);
467
468 thread->exc_actions = kalloc(sizeof(struct exception_action) * EXC_TYPES_COUNT);
469 bzero(thread->exc_actions, sizeof(struct exception_action) * EXC_TYPES_COUNT);
470 }
471
472 void
473 ipc_thread_destroy_exc_actions(
474 thread_t thread)
475 {
476 if (thread->exc_actions != NULL) {
477 kfree(thread->exc_actions,
478 sizeof(struct exception_action) * EXC_TYPES_COUNT);
479 thread->exc_actions = NULL;
480 }
481 }
482
483 void
484 ipc_thread_disable(
485 thread_t thread)
486 {
487 ipc_port_t kport = thread->ith_self;
488
489 if (kport != IP_NULL)
490 ipc_kobject_set(kport, IKO_NULL, IKOT_NONE);
491 }
492
493 /*
494 * Routine: ipc_thread_terminate
495 * Purpose:
496 * Clean up and destroy a thread's IPC state.
497 * Conditions:
498 * Nothing locked.
499 */
500
501 void
502 ipc_thread_terminate(
503 thread_t thread)
504 {
505 ipc_port_t kport = thread->ith_self;
506
507 if (kport != IP_NULL) {
508 int i;
509
510 if (IP_VALID(thread->ith_sself))
511 ipc_port_release_send(thread->ith_sself);
512
513 thread->ith_sself = thread->ith_self = IP_NULL;
514
515 if (thread->exc_actions != NULL) {
516 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
517 if (IP_VALID(thread->exc_actions[i].port))
518 ipc_port_release_send(thread->exc_actions[i].port);
519 }
520 ipc_thread_destroy_exc_actions(thread);
521 }
522
523 ipc_port_dealloc_kernel(kport);
524 }
525
526 #if IMPORTANCE_INHERITANCE
527 assert(thread->ith_assertions == 0);
528 #endif
529
530 assert(ipc_kmsg_queue_empty(&thread->ith_messages));
531
532 if (thread->ith_rpc_reply != IP_NULL)
533 ipc_port_dealloc_reply(thread->ith_rpc_reply);
534
535 thread->ith_rpc_reply = IP_NULL;
536 }
537
538 /*
539 * Routine: ipc_thread_reset
540 * Purpose:
541 * Reset the IPC state for a given Mach thread when
542 * its task enters an elevated security context.
543 * Both the thread port and its exception ports have
544 * to be reset. Its RPC reply port cannot have any
545 * rights outstanding, so it should be fine.
546 * Conditions:
547 * Nothing locked.
548 */
549
550 void
551 ipc_thread_reset(
552 thread_t thread)
553 {
554 ipc_port_t old_kport, new_kport;
555 ipc_port_t old_sself;
556 ipc_port_t old_exc_actions[EXC_TYPES_COUNT];
557 boolean_t has_old_exc_actions = FALSE;
558 int i;
559
560 new_kport = ipc_port_alloc_kernel();
561 if (new_kport == IP_NULL)
562 panic("ipc_task_reset");
563
564 thread_mtx_lock(thread);
565
566 old_kport = thread->ith_self;
567
568 if (old_kport == IP_NULL) {
569 /* the is already terminated (can this happen?) */
570 thread_mtx_unlock(thread);
571 ipc_port_dealloc_kernel(new_kport);
572 return;
573 }
574
575 thread->ith_self = new_kport;
576 old_sself = thread->ith_sself;
577 thread->ith_sself = ipc_port_make_send(new_kport);
578 ipc_kobject_set(old_kport, IKO_NULL, IKOT_NONE);
579 ipc_kobject_set(new_kport, (ipc_kobject_t) thread, IKOT_THREAD);
580
581 /*
582 * Only ports that were set by root-owned processes
583 * (privileged ports) should survive
584 */
585 if (thread->exc_actions != NULL) {
586 has_old_exc_actions = TRUE;
587 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
588 if (thread->exc_actions[i].privileged) {
589 old_exc_actions[i] = IP_NULL;
590 } else {
591 old_exc_actions[i] = thread->exc_actions[i].port;
592 thread->exc_actions[i].port = IP_NULL;
593 }
594 }
595 }
596
597 thread_mtx_unlock(thread);
598
599 /* release the naked send rights */
600
601 if (IP_VALID(old_sself))
602 ipc_port_release_send(old_sself);
603
604 if (has_old_exc_actions) {
605 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
606 ipc_port_release_send(old_exc_actions[i]);
607 }
608 }
609
610 /* destroy the kernel port */
611 ipc_port_dealloc_kernel(old_kport);
612 }
613
614 /*
615 * Routine: retrieve_task_self_fast
616 * Purpose:
617 * Optimized version of retrieve_task_self,
618 * that only works for the current task.
619 *
620 * Return a send right (possibly null/dead)
621 * for the task's user-visible self port.
622 * Conditions:
623 * Nothing locked.
624 */
625
626 ipc_port_t
627 retrieve_task_self_fast(
628 register task_t task)
629 {
630 register ipc_port_t port;
631
632 assert(task == current_task());
633
634 itk_lock(task);
635 assert(task->itk_self != IP_NULL);
636
637 if ((port = task->itk_sself) == task->itk_self) {
638 /* no interposing */
639
640 ip_lock(port);
641 assert(ip_active(port));
642 ip_reference(port);
643 port->ip_srights++;
644 ip_unlock(port);
645 } else
646 port = ipc_port_copy_send(port);
647 itk_unlock(task);
648
649 return port;
650 }
651
652 /*
653 * Routine: retrieve_thread_self_fast
654 * Purpose:
655 * Return a send right (possibly null/dead)
656 * for the thread's user-visible self port.
657 *
658 * Only works for the current thread.
659 *
660 * Conditions:
661 * Nothing locked.
662 */
663
664 ipc_port_t
665 retrieve_thread_self_fast(
666 thread_t thread)
667 {
668 register ipc_port_t port;
669
670 assert(thread == current_thread());
671
672 thread_mtx_lock(thread);
673
674 assert(thread->ith_self != IP_NULL);
675
676 if ((port = thread->ith_sself) == thread->ith_self) {
677 /* no interposing */
678
679 ip_lock(port);
680 assert(ip_active(port));
681 ip_reference(port);
682 port->ip_srights++;
683 ip_unlock(port);
684 }
685 else
686 port = ipc_port_copy_send(port);
687
688 thread_mtx_unlock(thread);
689
690 return port;
691 }
692
693 /*
694 * Routine: task_self_trap [mach trap]
695 * Purpose:
696 * Give the caller send rights for his own task port.
697 * Conditions:
698 * Nothing locked.
699 * Returns:
700 * MACH_PORT_NULL if there are any resource failures
701 * or other errors.
702 */
703
704 mach_port_name_t
705 task_self_trap(
706 __unused struct task_self_trap_args *args)
707 {
708 task_t task = current_task();
709 ipc_port_t sright;
710 mach_port_name_t name;
711
712 sright = retrieve_task_self_fast(task);
713 name = ipc_port_copyout_send(sright, task->itk_space);
714 return name;
715 }
716
717 /*
718 * Routine: thread_self_trap [mach trap]
719 * Purpose:
720 * Give the caller send rights for his own thread port.
721 * Conditions:
722 * Nothing locked.
723 * Returns:
724 * MACH_PORT_NULL if there are any resource failures
725 * or other errors.
726 */
727
728 mach_port_name_t
729 thread_self_trap(
730 __unused struct thread_self_trap_args *args)
731 {
732 thread_t thread = current_thread();
733 task_t task = thread->task;
734 ipc_port_t sright;
735 mach_port_name_t name;
736
737 sright = retrieve_thread_self_fast(thread);
738 name = ipc_port_copyout_send(sright, task->itk_space);
739 return name;
740
741 }
742
743 /*
744 * Routine: mach_reply_port [mach trap]
745 * Purpose:
746 * Allocate a port for the caller.
747 * Conditions:
748 * Nothing locked.
749 * Returns:
750 * MACH_PORT_NULL if there are any resource failures
751 * or other errors.
752 */
753
754 mach_port_name_t
755 mach_reply_port(
756 __unused struct mach_reply_port_args *args)
757 {
758 ipc_port_t port;
759 mach_port_name_t name;
760 kern_return_t kr;
761
762 kr = ipc_port_alloc(current_task()->itk_space, &name, &port);
763 if (kr == KERN_SUCCESS)
764 ip_unlock(port);
765 else
766 name = MACH_PORT_NULL;
767 return name;
768 }
769
770 /*
771 * Routine: thread_get_special_port [kernel call]
772 * Purpose:
773 * Clones a send right for one of the thread's
774 * special ports.
775 * Conditions:
776 * Nothing locked.
777 * Returns:
778 * KERN_SUCCESS Extracted a send right.
779 * KERN_INVALID_ARGUMENT The thread is null.
780 * KERN_FAILURE The thread is dead.
781 * KERN_INVALID_ARGUMENT Invalid special port.
782 */
783
784 kern_return_t
785 thread_get_special_port(
786 thread_t thread,
787 int which,
788 ipc_port_t *portp)
789 {
790 kern_return_t result = KERN_SUCCESS;
791 ipc_port_t *whichp;
792
793 if (thread == THREAD_NULL)
794 return (KERN_INVALID_ARGUMENT);
795
796 switch (which) {
797
798 case THREAD_KERNEL_PORT:
799 whichp = &thread->ith_sself;
800 break;
801
802 default:
803 return (KERN_INVALID_ARGUMENT);
804 }
805
806 thread_mtx_lock(thread);
807
808 if (thread->active)
809 *portp = ipc_port_copy_send(*whichp);
810 else
811 result = KERN_FAILURE;
812
813 thread_mtx_unlock(thread);
814
815 return (result);
816 }
817
818 /*
819 * Routine: thread_set_special_port [kernel call]
820 * Purpose:
821 * Changes one of the thread's special ports,
822 * setting it to the supplied send right.
823 * Conditions:
824 * Nothing locked. If successful, consumes
825 * the supplied send right.
826 * Returns:
827 * KERN_SUCCESS Changed the special port.
828 * KERN_INVALID_ARGUMENT The thread is null.
829 * KERN_FAILURE The thread is dead.
830 * KERN_INVALID_ARGUMENT Invalid special port.
831 */
832
833 kern_return_t
834 thread_set_special_port(
835 thread_t thread,
836 int which,
837 ipc_port_t port)
838 {
839 kern_return_t result = KERN_SUCCESS;
840 ipc_port_t *whichp, old = IP_NULL;
841
842 if (thread == THREAD_NULL)
843 return (KERN_INVALID_ARGUMENT);
844
845 switch (which) {
846
847 case THREAD_KERNEL_PORT:
848 whichp = &thread->ith_sself;
849 break;
850
851 default:
852 return (KERN_INVALID_ARGUMENT);
853 }
854
855 thread_mtx_lock(thread);
856
857 if (thread->active) {
858 old = *whichp;
859 *whichp = port;
860 }
861 else
862 result = KERN_FAILURE;
863
864 thread_mtx_unlock(thread);
865
866 if (IP_VALID(old))
867 ipc_port_release_send(old);
868
869 return (result);
870 }
871
872 /*
873 * Routine: task_get_special_port [kernel call]
874 * Purpose:
875 * Clones a send right for one of the task's
876 * special ports.
877 * Conditions:
878 * Nothing locked.
879 * Returns:
880 * KERN_SUCCESS Extracted a send right.
881 * KERN_INVALID_ARGUMENT The task is null.
882 * KERN_FAILURE The task/space is dead.
883 * KERN_INVALID_ARGUMENT Invalid special port.
884 */
885
886 kern_return_t
887 task_get_special_port(
888 task_t task,
889 int which,
890 ipc_port_t *portp)
891 {
892 ipc_port_t port;
893
894 if (task == TASK_NULL)
895 return KERN_INVALID_ARGUMENT;
896
897 itk_lock(task);
898 if (task->itk_self == IP_NULL) {
899 itk_unlock(task);
900 return KERN_FAILURE;
901 }
902
903 switch (which) {
904 case TASK_KERNEL_PORT:
905 port = ipc_port_copy_send(task->itk_sself);
906 break;
907
908 case TASK_NAME_PORT:
909 port = ipc_port_make_send(task->itk_nself);
910 break;
911
912 case TASK_HOST_PORT:
913 port = ipc_port_copy_send(task->itk_host);
914 break;
915
916 case TASK_BOOTSTRAP_PORT:
917 port = ipc_port_copy_send(task->itk_bootstrap);
918 break;
919
920 case TASK_SEATBELT_PORT:
921 port = ipc_port_copy_send(task->itk_seatbelt);
922 break;
923
924 case TASK_ACCESS_PORT:
925 port = ipc_port_copy_send(task->itk_task_access);
926 break;
927
928 case TASK_DEBUG_CONTROL_PORT:
929 port = ipc_port_copy_send(task->itk_debug_control);
930 break;
931
932 default:
933 itk_unlock(task);
934 return KERN_INVALID_ARGUMENT;
935 }
936 itk_unlock(task);
937
938 *portp = port;
939 return KERN_SUCCESS;
940 }
941
942 /*
943 * Routine: task_set_special_port [kernel call]
944 * Purpose:
945 * Changes one of the task's special ports,
946 * setting it to the supplied send right.
947 * Conditions:
948 * Nothing locked. If successful, consumes
949 * the supplied send right.
950 * Returns:
951 * KERN_SUCCESS Changed the special port.
952 * KERN_INVALID_ARGUMENT The task is null.
953 * KERN_FAILURE The task/space is dead.
954 * KERN_INVALID_ARGUMENT Invalid special port.
955 * KERN_NO_ACCESS Attempted overwrite of seatbelt port.
956 */
957
958 kern_return_t
959 task_set_special_port(
960 task_t task,
961 int which,
962 ipc_port_t port)
963 {
964 ipc_port_t *whichp;
965 ipc_port_t old;
966
967 if (task == TASK_NULL)
968 return KERN_INVALID_ARGUMENT;
969
970 switch (which) {
971 case TASK_KERNEL_PORT:
972 whichp = &task->itk_sself;
973 break;
974
975 case TASK_HOST_PORT:
976 whichp = &task->itk_host;
977 break;
978
979 case TASK_BOOTSTRAP_PORT:
980 whichp = &task->itk_bootstrap;
981 break;
982
983 case TASK_SEATBELT_PORT:
984 whichp = &task->itk_seatbelt;
985 break;
986
987 case TASK_ACCESS_PORT:
988 whichp = &task->itk_task_access;
989 break;
990
991 case TASK_DEBUG_CONTROL_PORT:
992 whichp = &task->itk_debug_control;
993 break;
994
995
996 default:
997 return KERN_INVALID_ARGUMENT;
998 }/* switch */
999
1000 itk_lock(task);
1001 if (task->itk_self == IP_NULL) {
1002 itk_unlock(task);
1003 return KERN_FAILURE;
1004 }
1005
1006 /* do not allow overwrite of seatbelt or task access ports */
1007 if ((TASK_SEATBELT_PORT == which || TASK_ACCESS_PORT == which)
1008 && IP_VALID(*whichp)) {
1009 itk_unlock(task);
1010 return KERN_NO_ACCESS;
1011 }
1012
1013 old = *whichp;
1014 *whichp = port;
1015 itk_unlock(task);
1016
1017 if (IP_VALID(old))
1018 ipc_port_release_send(old);
1019 return KERN_SUCCESS;
1020 }
1021
1022
1023 /*
1024 * Routine: mach_ports_register [kernel call]
1025 * Purpose:
1026 * Stash a handful of port send rights in the task.
1027 * Child tasks will inherit these rights, but they
1028 * must use mach_ports_lookup to acquire them.
1029 *
1030 * The rights are supplied in a (wired) kalloc'd segment.
1031 * Rights which aren't supplied are assumed to be null.
1032 * Conditions:
1033 * Nothing locked. If successful, consumes
1034 * the supplied rights and memory.
1035 * Returns:
1036 * KERN_SUCCESS Stashed the port rights.
1037 * KERN_INVALID_ARGUMENT The task is null.
1038 * KERN_INVALID_ARGUMENT The task is dead.
1039 * KERN_INVALID_ARGUMENT The memory param is null.
1040 * KERN_INVALID_ARGUMENT Too many port rights supplied.
1041 */
1042
1043 kern_return_t
1044 mach_ports_register(
1045 task_t task,
1046 mach_port_array_t memory,
1047 mach_msg_type_number_t portsCnt)
1048 {
1049 ipc_port_t ports[TASK_PORT_REGISTER_MAX];
1050 unsigned int i;
1051
1052 if ((task == TASK_NULL) ||
1053 (portsCnt > TASK_PORT_REGISTER_MAX) ||
1054 (portsCnt && memory == NULL))
1055 return KERN_INVALID_ARGUMENT;
1056
1057 /*
1058 * Pad the port rights with nulls.
1059 */
1060
1061 for (i = 0; i < portsCnt; i++)
1062 ports[i] = memory[i];
1063 for (; i < TASK_PORT_REGISTER_MAX; i++)
1064 ports[i] = IP_NULL;
1065
1066 itk_lock(task);
1067 if (task->itk_self == IP_NULL) {
1068 itk_unlock(task);
1069 return KERN_INVALID_ARGUMENT;
1070 }
1071
1072 /*
1073 * Replace the old send rights with the new.
1074 * Release the old rights after unlocking.
1075 */
1076
1077 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) {
1078 ipc_port_t old;
1079
1080 old = task->itk_registered[i];
1081 task->itk_registered[i] = ports[i];
1082 ports[i] = old;
1083 }
1084
1085 itk_unlock(task);
1086
1087 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
1088 if (IP_VALID(ports[i]))
1089 ipc_port_release_send(ports[i]);
1090
1091 /*
1092 * Now that the operation is known to be successful,
1093 * we can free the memory.
1094 */
1095
1096 if (portsCnt != 0)
1097 kfree(memory,
1098 (vm_size_t) (portsCnt * sizeof(mach_port_t)));
1099
1100 return KERN_SUCCESS;
1101 }
1102
1103 /*
1104 * Routine: mach_ports_lookup [kernel call]
1105 * Purpose:
1106 * Retrieves (clones) the stashed port send rights.
1107 * Conditions:
1108 * Nothing locked. If successful, the caller gets
1109 * rights and memory.
1110 * Returns:
1111 * KERN_SUCCESS Retrieved the send rights.
1112 * KERN_INVALID_ARGUMENT The task is null.
1113 * KERN_INVALID_ARGUMENT The task is dead.
1114 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1115 */
1116
1117 kern_return_t
1118 mach_ports_lookup(
1119 task_t task,
1120 mach_port_array_t *portsp,
1121 mach_msg_type_number_t *portsCnt)
1122 {
1123 void *memory;
1124 vm_size_t size;
1125 ipc_port_t *ports;
1126 int i;
1127
1128 if (task == TASK_NULL)
1129 return KERN_INVALID_ARGUMENT;
1130
1131 size = (vm_size_t) (TASK_PORT_REGISTER_MAX * sizeof(ipc_port_t));
1132
1133 memory = kalloc(size);
1134 if (memory == 0)
1135 return KERN_RESOURCE_SHORTAGE;
1136
1137 itk_lock(task);
1138 if (task->itk_self == IP_NULL) {
1139 itk_unlock(task);
1140
1141 kfree(memory, size);
1142 return KERN_INVALID_ARGUMENT;
1143 }
1144
1145 ports = (ipc_port_t *) memory;
1146
1147 /*
1148 * Clone port rights. Because kalloc'd memory
1149 * is wired, we won't fault while holding the task lock.
1150 */
1151
1152 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
1153 ports[i] = ipc_port_copy_send(task->itk_registered[i]);
1154
1155 itk_unlock(task);
1156
1157 *portsp = (mach_port_array_t) ports;
1158 *portsCnt = TASK_PORT_REGISTER_MAX;
1159 return KERN_SUCCESS;
1160 }
1161
1162 /*
1163 * Routine: convert_port_to_locked_task
1164 * Purpose:
1165 * Internal helper routine to convert from a port to a locked
1166 * task. Used by several routines that try to convert from a
1167 * task port to a reference on some task related object.
1168 * Conditions:
1169 * Nothing locked, blocking OK.
1170 */
1171 task_t
1172 convert_port_to_locked_task(ipc_port_t port)
1173 {
1174 int try_failed_count = 0;
1175
1176 while (IP_VALID(port)) {
1177 task_t task;
1178
1179 ip_lock(port);
1180 if (!ip_active(port) || (ip_kotype(port) != IKOT_TASK)) {
1181 ip_unlock(port);
1182 return TASK_NULL;
1183 }
1184 task = (task_t) port->ip_kobject;
1185 assert(task != TASK_NULL);
1186
1187 /*
1188 * Normal lock ordering puts task_lock() before ip_lock().
1189 * Attempt out-of-order locking here.
1190 */
1191 if (task_lock_try(task)) {
1192 ip_unlock(port);
1193 return(task);
1194 }
1195 try_failed_count++;
1196
1197 ip_unlock(port);
1198 mutex_pause(try_failed_count);
1199 }
1200 return TASK_NULL;
1201 }
1202
1203 /*
1204 * Routine: convert_port_to_task
1205 * Purpose:
1206 * Convert from a port to a task.
1207 * Doesn't consume the port ref; produces a task ref,
1208 * which may be null.
1209 * Conditions:
1210 * Nothing locked.
1211 */
1212 task_t
1213 convert_port_to_task(
1214 ipc_port_t port)
1215 {
1216 task_t task = TASK_NULL;
1217
1218 if (IP_VALID(port)) {
1219 ip_lock(port);
1220
1221 if ( ip_active(port) &&
1222 ip_kotype(port) == IKOT_TASK ) {
1223 task = (task_t)port->ip_kobject;
1224 assert(task != TASK_NULL);
1225
1226 task_reference_internal(task);
1227 }
1228
1229 ip_unlock(port);
1230 }
1231
1232 return (task);
1233 }
1234
1235 /*
1236 * Routine: convert_port_to_task_name
1237 * Purpose:
1238 * Convert from a port to a task name.
1239 * Doesn't consume the port ref; produces a task name ref,
1240 * which may be null.
1241 * Conditions:
1242 * Nothing locked.
1243 */
1244 task_name_t
1245 convert_port_to_task_name(
1246 ipc_port_t port)
1247 {
1248 task_name_t task = TASK_NULL;
1249
1250 if (IP_VALID(port)) {
1251 ip_lock(port);
1252
1253 if ( ip_active(port) &&
1254 (ip_kotype(port) == IKOT_TASK ||
1255 ip_kotype(port) == IKOT_TASK_NAME)) {
1256 task = (task_name_t)port->ip_kobject;
1257 assert(task != TASK_NAME_NULL);
1258
1259 task_reference_internal(task);
1260 }
1261
1262 ip_unlock(port);
1263 }
1264
1265 return (task);
1266 }
1267
1268 /*
1269 * Routine: convert_port_to_task_suspension_token
1270 * Purpose:
1271 * Convert from a port to a task suspension token.
1272 * Doesn't consume the port ref; produces a suspension token ref,
1273 * which may be null.
1274 * Conditions:
1275 * Nothing locked.
1276 */
1277 task_suspension_token_t
1278 convert_port_to_task_suspension_token(
1279 ipc_port_t port)
1280 {
1281 task_suspension_token_t task = TASK_NULL;
1282
1283 if (IP_VALID(port)) {
1284 ip_lock(port);
1285
1286 if ( ip_active(port) &&
1287 ip_kotype(port) == IKOT_TASK_RESUME) {
1288 task = (task_suspension_token_t)port->ip_kobject;
1289 assert(task != TASK_NULL);
1290
1291 task_reference_internal(task);
1292 }
1293
1294 ip_unlock(port);
1295 }
1296
1297 return (task);
1298 }
1299
1300 /*
1301 * Routine: convert_port_to_space
1302 * Purpose:
1303 * Convert from a port to a space.
1304 * Doesn't consume the port ref; produces a space ref,
1305 * which may be null.
1306 * Conditions:
1307 * Nothing locked.
1308 */
1309 ipc_space_t
1310 convert_port_to_space(
1311 ipc_port_t port)
1312 {
1313 ipc_space_t space;
1314 task_t task;
1315
1316 task = convert_port_to_locked_task(port);
1317
1318 if (task == TASK_NULL)
1319 return IPC_SPACE_NULL;
1320
1321 if (!task->active) {
1322 task_unlock(task);
1323 return IPC_SPACE_NULL;
1324 }
1325
1326 space = task->itk_space;
1327 is_reference(space);
1328 task_unlock(task);
1329 return (space);
1330 }
1331
1332 /*
1333 * Routine: convert_port_to_map
1334 * Purpose:
1335 * Convert from a port to a map.
1336 * Doesn't consume the port ref; produces a map ref,
1337 * which may be null.
1338 * Conditions:
1339 * Nothing locked.
1340 */
1341
1342 vm_map_t
1343 convert_port_to_map(
1344 ipc_port_t port)
1345 {
1346 task_t task;
1347 vm_map_t map;
1348
1349 task = convert_port_to_locked_task(port);
1350
1351 if (task == TASK_NULL)
1352 return VM_MAP_NULL;
1353
1354 if (!task->active) {
1355 task_unlock(task);
1356 return VM_MAP_NULL;
1357 }
1358
1359 map = task->map;
1360 vm_map_reference_swap(map);
1361 task_unlock(task);
1362 return map;
1363 }
1364
1365
1366 /*
1367 * Routine: convert_port_to_thread
1368 * Purpose:
1369 * Convert from a port to a thread.
1370 * Doesn't consume the port ref; produces an thread ref,
1371 * which may be null.
1372 * Conditions:
1373 * Nothing locked.
1374 */
1375
1376 thread_t
1377 convert_port_to_thread(
1378 ipc_port_t port)
1379 {
1380 thread_t thread = THREAD_NULL;
1381
1382 if (IP_VALID(port)) {
1383 ip_lock(port);
1384
1385 if ( ip_active(port) &&
1386 ip_kotype(port) == IKOT_THREAD ) {
1387 thread = (thread_t)port->ip_kobject;
1388 assert(thread != THREAD_NULL);
1389
1390 thread_reference_internal(thread);
1391 }
1392
1393 ip_unlock(port);
1394 }
1395
1396 return (thread);
1397 }
1398
1399 /*
1400 * Routine: port_name_to_thread
1401 * Purpose:
1402 * Convert from a port name to an thread reference
1403 * A name of MACH_PORT_NULL is valid for the null thread.
1404 * Conditions:
1405 * Nothing locked.
1406 */
1407 thread_t
1408 port_name_to_thread(
1409 mach_port_name_t name)
1410 {
1411 thread_t thread = THREAD_NULL;
1412 ipc_port_t kport;
1413
1414 if (MACH_PORT_VALID(name)) {
1415 if (ipc_object_copyin(current_space(), name,
1416 MACH_MSG_TYPE_COPY_SEND,
1417 (ipc_object_t *)&kport) != KERN_SUCCESS)
1418 return (THREAD_NULL);
1419
1420 thread = convert_port_to_thread(kport);
1421
1422 if (IP_VALID(kport))
1423 ipc_port_release_send(kport);
1424 }
1425
1426 return (thread);
1427 }
1428
1429 task_t
1430 port_name_to_task(
1431 mach_port_name_t name)
1432 {
1433 ipc_port_t kern_port;
1434 kern_return_t kr;
1435 task_t task = TASK_NULL;
1436
1437 if (MACH_PORT_VALID(name)) {
1438 kr = ipc_object_copyin(current_space(), name,
1439 MACH_MSG_TYPE_COPY_SEND,
1440 (ipc_object_t *) &kern_port);
1441 if (kr != KERN_SUCCESS)
1442 return TASK_NULL;
1443
1444 task = convert_port_to_task(kern_port);
1445
1446 if (IP_VALID(kern_port))
1447 ipc_port_release_send(kern_port);
1448 }
1449 return task;
1450 }
1451
1452 /*
1453 * Routine: convert_task_to_port
1454 * Purpose:
1455 * Convert from a task to a port.
1456 * Consumes a task ref; produces a naked send right
1457 * which may be invalid.
1458 * Conditions:
1459 * Nothing locked.
1460 */
1461
1462 ipc_port_t
1463 convert_task_to_port(
1464 task_t task)
1465 {
1466 ipc_port_t port;
1467
1468 itk_lock(task);
1469 if (task->itk_self != IP_NULL)
1470 port = ipc_port_make_send(task->itk_self);
1471 else
1472 port = IP_NULL;
1473 itk_unlock(task);
1474
1475 task_deallocate(task);
1476 return port;
1477 }
1478
1479 /*
1480 * Routine: convert_task_suspend_token_to_port
1481 * Purpose:
1482 * Convert from a task suspension token to a port.
1483 * Consumes a task suspension token ref; produces a naked send-once right
1484 * which may be invalid.
1485 * Conditions:
1486 * Nothing locked.
1487 */
1488 ipc_port_t
1489 convert_task_suspension_token_to_port(
1490 task_suspension_token_t task)
1491 {
1492 ipc_port_t port;
1493
1494 task_lock(task);
1495 if (task->active) {
1496 if (task->itk_resume == IP_NULL) {
1497 task->itk_resume = ipc_port_alloc_kernel();
1498 if (!IP_VALID(task->itk_resume)) {
1499 panic("failed to create resume port");
1500 }
1501
1502 ipc_kobject_set(task->itk_resume, (ipc_kobject_t) task, IKOT_TASK_RESUME);
1503 }
1504
1505 /*
1506 * Create a send-once right for each instance of a direct user-called
1507 * task_suspend2 call. Each time one of these send-once rights is abandoned,
1508 * the notification handler will resume the target task.
1509 */
1510 port = ipc_port_make_sonce(task->itk_resume);
1511 assert(IP_VALID(port));
1512 } else {
1513 port = IP_NULL;
1514 }
1515
1516 task_unlock(task);
1517 task_suspension_token_deallocate(task);
1518
1519 return port;
1520 }
1521
1522
1523 /*
1524 * Routine: convert_task_name_to_port
1525 * Purpose:
1526 * Convert from a task name ref to a port.
1527 * Consumes a task name ref; produces a naked send right
1528 * which may be invalid.
1529 * Conditions:
1530 * Nothing locked.
1531 */
1532
1533 ipc_port_t
1534 convert_task_name_to_port(
1535 task_name_t task_name)
1536 {
1537 ipc_port_t port;
1538
1539 itk_lock(task_name);
1540 if (task_name->itk_nself != IP_NULL)
1541 port = ipc_port_make_send(task_name->itk_nself);
1542 else
1543 port = IP_NULL;
1544 itk_unlock(task_name);
1545
1546 task_name_deallocate(task_name);
1547 return port;
1548 }
1549
1550 /*
1551 * Routine: convert_thread_to_port
1552 * Purpose:
1553 * Convert from a thread to a port.
1554 * Consumes an thread ref; produces a naked send right
1555 * which may be invalid.
1556 * Conditions:
1557 * Nothing locked.
1558 */
1559
1560 ipc_port_t
1561 convert_thread_to_port(
1562 thread_t thread)
1563 {
1564 ipc_port_t port;
1565
1566 thread_mtx_lock(thread);
1567
1568 if (thread->ith_self != IP_NULL)
1569 port = ipc_port_make_send(thread->ith_self);
1570 else
1571 port = IP_NULL;
1572
1573 thread_mtx_unlock(thread);
1574
1575 thread_deallocate(thread);
1576
1577 return (port);
1578 }
1579
1580 /*
1581 * Routine: space_deallocate
1582 * Purpose:
1583 * Deallocate a space ref produced by convert_port_to_space.
1584 * Conditions:
1585 * Nothing locked.
1586 */
1587
1588 void
1589 space_deallocate(
1590 ipc_space_t space)
1591 {
1592 if (space != IS_NULL)
1593 is_release(space);
1594 }
1595
1596 /*
1597 * Routine: thread/task_set_exception_ports [kernel call]
1598 * Purpose:
1599 * Sets the thread/task exception port, flavor and
1600 * behavior for the exception types specified by the mask.
1601 * There will be one send right per exception per valid
1602 * port.
1603 * Conditions:
1604 * Nothing locked. If successful, consumes
1605 * the supplied send right.
1606 * Returns:
1607 * KERN_SUCCESS Changed the special port.
1608 * KERN_INVALID_ARGUMENT The thread is null,
1609 * Illegal mask bit set.
1610 * Illegal exception behavior
1611 * KERN_FAILURE The thread is dead.
1612 */
1613
1614 kern_return_t
1615 thread_set_exception_ports(
1616 thread_t thread,
1617 exception_mask_t exception_mask,
1618 ipc_port_t new_port,
1619 exception_behavior_t new_behavior,
1620 thread_state_flavor_t new_flavor)
1621 {
1622 ipc_port_t old_port[EXC_TYPES_COUNT];
1623 boolean_t privileged = current_task()->sec_token.val[0] == 0;
1624 register int i;
1625
1626 if (thread == THREAD_NULL)
1627 return (KERN_INVALID_ARGUMENT);
1628
1629 if (exception_mask & ~EXC_MASK_VALID)
1630 return (KERN_INVALID_ARGUMENT);
1631
1632 if (IP_VALID(new_port)) {
1633 switch (new_behavior & ~MACH_EXCEPTION_CODES) {
1634
1635 case EXCEPTION_DEFAULT:
1636 case EXCEPTION_STATE:
1637 case EXCEPTION_STATE_IDENTITY:
1638 break;
1639
1640 default:
1641 return (KERN_INVALID_ARGUMENT);
1642 }
1643 }
1644
1645 /*
1646 * Check the validity of the thread_state_flavor by calling the
1647 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in
1648 * osfmk/mach/ARCHITECTURE/thread_status.h
1649 */
1650 if (new_flavor != 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor))
1651 return (KERN_INVALID_ARGUMENT);
1652
1653 thread_mtx_lock(thread);
1654
1655 if (!thread->active) {
1656 thread_mtx_unlock(thread);
1657
1658 return (KERN_FAILURE);
1659 }
1660
1661 if (thread->exc_actions == NULL) {
1662 ipc_thread_init_exc_actions(thread);
1663 }
1664 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
1665 if (exception_mask & (1 << i)) {
1666 old_port[i] = thread->exc_actions[i].port;
1667 thread->exc_actions[i].port = ipc_port_copy_send(new_port);
1668 thread->exc_actions[i].behavior = new_behavior;
1669 thread->exc_actions[i].flavor = new_flavor;
1670 thread->exc_actions[i].privileged = privileged;
1671 }
1672 else
1673 old_port[i] = IP_NULL;
1674 }
1675
1676 thread_mtx_unlock(thread);
1677
1678 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i)
1679 if (IP_VALID(old_port[i]))
1680 ipc_port_release_send(old_port[i]);
1681
1682 if (IP_VALID(new_port)) /* consume send right */
1683 ipc_port_release_send(new_port);
1684
1685 return (KERN_SUCCESS);
1686 }
1687
1688 kern_return_t
1689 task_set_exception_ports(
1690 task_t task,
1691 exception_mask_t exception_mask,
1692 ipc_port_t new_port,
1693 exception_behavior_t new_behavior,
1694 thread_state_flavor_t new_flavor)
1695 {
1696 ipc_port_t old_port[EXC_TYPES_COUNT];
1697 boolean_t privileged = current_task()->sec_token.val[0] == 0;
1698 register int i;
1699
1700 if (task == TASK_NULL)
1701 return (KERN_INVALID_ARGUMENT);
1702
1703 if (exception_mask & ~EXC_MASK_VALID)
1704 return (KERN_INVALID_ARGUMENT);
1705
1706 if (IP_VALID(new_port)) {
1707 switch (new_behavior & ~MACH_EXCEPTION_CODES) {
1708
1709 case EXCEPTION_DEFAULT:
1710 case EXCEPTION_STATE:
1711 case EXCEPTION_STATE_IDENTITY:
1712 break;
1713
1714 default:
1715 return (KERN_INVALID_ARGUMENT);
1716 }
1717 }
1718
1719 /*
1720 * Check the validity of the thread_state_flavor by calling the
1721 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in
1722 * osfmk/mach/ARCHITECTURE/thread_status.h
1723 */
1724 if (new_flavor != 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor))
1725 return (KERN_INVALID_ARGUMENT);
1726
1727 itk_lock(task);
1728
1729 if (task->itk_self == IP_NULL) {
1730 itk_unlock(task);
1731
1732 return (KERN_FAILURE);
1733 }
1734
1735 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
1736 if (exception_mask & (1 << i)) {
1737 old_port[i] = task->exc_actions[i].port;
1738 task->exc_actions[i].port =
1739 ipc_port_copy_send(new_port);
1740 task->exc_actions[i].behavior = new_behavior;
1741 task->exc_actions[i].flavor = new_flavor;
1742 task->exc_actions[i].privileged = privileged;
1743 }
1744 else
1745 old_port[i] = IP_NULL;
1746 }
1747
1748 itk_unlock(task);
1749
1750 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i)
1751 if (IP_VALID(old_port[i]))
1752 ipc_port_release_send(old_port[i]);
1753
1754 if (IP_VALID(new_port)) /* consume send right */
1755 ipc_port_release_send(new_port);
1756
1757 return (KERN_SUCCESS);
1758 }
1759
1760 /*
1761 * Routine: thread/task_swap_exception_ports [kernel call]
1762 * Purpose:
1763 * Sets the thread/task exception port, flavor and
1764 * behavior for the exception types specified by the
1765 * mask.
1766 *
1767 * The old ports, behavior and flavors are returned
1768 * Count specifies the array sizes on input and
1769 * the number of returned ports etc. on output. The
1770 * arrays must be large enough to hold all the returned
1771 * data, MIG returnes an error otherwise. The masks
1772 * array specifies the corresponding exception type(s).
1773 *
1774 * Conditions:
1775 * Nothing locked. If successful, consumes
1776 * the supplied send right.
1777 *
1778 * Returns upto [in} CountCnt elements.
1779 * Returns:
1780 * KERN_SUCCESS Changed the special port.
1781 * KERN_INVALID_ARGUMENT The thread is null,
1782 * Illegal mask bit set.
1783 * Illegal exception behavior
1784 * KERN_FAILURE The thread is dead.
1785 */
1786
1787 kern_return_t
1788 thread_swap_exception_ports(
1789 thread_t thread,
1790 exception_mask_t exception_mask,
1791 ipc_port_t new_port,
1792 exception_behavior_t new_behavior,
1793 thread_state_flavor_t new_flavor,
1794 exception_mask_array_t masks,
1795 mach_msg_type_number_t *CountCnt,
1796 exception_port_array_t ports,
1797 exception_behavior_array_t behaviors,
1798 thread_state_flavor_array_t flavors)
1799 {
1800 ipc_port_t old_port[EXC_TYPES_COUNT];
1801 boolean_t privileged = current_task()->sec_token.val[0] == 0;
1802 unsigned int i, j, count;
1803
1804 if (thread == THREAD_NULL)
1805 return (KERN_INVALID_ARGUMENT);
1806
1807 if (exception_mask & ~EXC_MASK_VALID)
1808 return (KERN_INVALID_ARGUMENT);
1809
1810 if (IP_VALID(new_port)) {
1811 switch (new_behavior & ~MACH_EXCEPTION_CODES) {
1812
1813 case EXCEPTION_DEFAULT:
1814 case EXCEPTION_STATE:
1815 case EXCEPTION_STATE_IDENTITY:
1816 break;
1817
1818 default:
1819 return (KERN_INVALID_ARGUMENT);
1820 }
1821 }
1822
1823 if (new_flavor != 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor))
1824 return (KERN_INVALID_ARGUMENT);
1825
1826 thread_mtx_lock(thread);
1827
1828 if (!thread->active) {
1829 thread_mtx_unlock(thread);
1830
1831 return (KERN_FAILURE);
1832 }
1833
1834 if (thread->exc_actions == NULL) {
1835 ipc_thread_init_exc_actions(thread);
1836 }
1837
1838 assert(EXC_TYPES_COUNT > FIRST_EXCEPTION);
1839 for (count = 0, i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT && count < *CountCnt; ++i) {
1840 if (exception_mask & (1 << i)) {
1841 for (j = 0; j < count; ++j) {
1842 /*
1843 * search for an identical entry, if found
1844 * set corresponding mask for this exception.
1845 */
1846 if ( thread->exc_actions[i].port == ports[j] &&
1847 thread->exc_actions[i].behavior == behaviors[j] &&
1848 thread->exc_actions[i].flavor == flavors[j] ) {
1849 masks[j] |= (1 << i);
1850 break;
1851 }
1852 }
1853
1854 if (j == count) {
1855 masks[j] = (1 << i);
1856 ports[j] = ipc_port_copy_send(thread->exc_actions[i].port);
1857
1858 behaviors[j] = thread->exc_actions[i].behavior;
1859 flavors[j] = thread->exc_actions[i].flavor;
1860 ++count;
1861 }
1862
1863 old_port[i] = thread->exc_actions[i].port;
1864 thread->exc_actions[i].port = ipc_port_copy_send(new_port);
1865 thread->exc_actions[i].behavior = new_behavior;
1866 thread->exc_actions[i].flavor = new_flavor;
1867 thread->exc_actions[i].privileged = privileged;
1868 }
1869 else
1870 old_port[i] = IP_NULL;
1871 }
1872
1873 thread_mtx_unlock(thread);
1874
1875 while (--i >= FIRST_EXCEPTION) {
1876 if (IP_VALID(old_port[i]))
1877 ipc_port_release_send(old_port[i]);
1878 }
1879
1880 if (IP_VALID(new_port)) /* consume send right */
1881 ipc_port_release_send(new_port);
1882
1883 *CountCnt = count;
1884
1885 return (KERN_SUCCESS);
1886 }
1887
1888 kern_return_t
1889 task_swap_exception_ports(
1890 task_t task,
1891 exception_mask_t exception_mask,
1892 ipc_port_t new_port,
1893 exception_behavior_t new_behavior,
1894 thread_state_flavor_t new_flavor,
1895 exception_mask_array_t masks,
1896 mach_msg_type_number_t *CountCnt,
1897 exception_port_array_t ports,
1898 exception_behavior_array_t behaviors,
1899 thread_state_flavor_array_t flavors)
1900 {
1901 ipc_port_t old_port[EXC_TYPES_COUNT];
1902 boolean_t privileged = current_task()->sec_token.val[0] == 0;
1903 unsigned int i, j, count;
1904
1905 if (task == TASK_NULL)
1906 return (KERN_INVALID_ARGUMENT);
1907
1908 if (exception_mask & ~EXC_MASK_VALID)
1909 return (KERN_INVALID_ARGUMENT);
1910
1911 if (IP_VALID(new_port)) {
1912 switch (new_behavior & ~MACH_EXCEPTION_CODES) {
1913
1914 case EXCEPTION_DEFAULT:
1915 case EXCEPTION_STATE:
1916 case EXCEPTION_STATE_IDENTITY:
1917 break;
1918
1919 default:
1920 return (KERN_INVALID_ARGUMENT);
1921 }
1922 }
1923
1924 if (new_flavor != 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor))
1925 return (KERN_INVALID_ARGUMENT);
1926
1927 itk_lock(task);
1928
1929 if (task->itk_self == IP_NULL) {
1930 itk_unlock(task);
1931
1932 return (KERN_FAILURE);
1933 }
1934
1935 assert(EXC_TYPES_COUNT > FIRST_EXCEPTION);
1936 for (count = 0, i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT && count < *CountCnt; ++i) {
1937 if (exception_mask & (1 << i)) {
1938 for (j = 0; j < count; j++) {
1939 /*
1940 * search for an identical entry, if found
1941 * set corresponding mask for this exception.
1942 */
1943 if ( task->exc_actions[i].port == ports[j] &&
1944 task->exc_actions[i].behavior == behaviors[j] &&
1945 task->exc_actions[i].flavor == flavors[j] ) {
1946 masks[j] |= (1 << i);
1947 break;
1948 }
1949 }
1950
1951 if (j == count) {
1952 masks[j] = (1 << i);
1953 ports[j] = ipc_port_copy_send(task->exc_actions[i].port);
1954 behaviors[j] = task->exc_actions[i].behavior;
1955 flavors[j] = task->exc_actions[i].flavor;
1956 ++count;
1957 }
1958
1959 old_port[i] = task->exc_actions[i].port;
1960
1961 task->exc_actions[i].port = ipc_port_copy_send(new_port);
1962 task->exc_actions[i].behavior = new_behavior;
1963 task->exc_actions[i].flavor = new_flavor;
1964 task->exc_actions[i].privileged = privileged;
1965 }
1966 else
1967 old_port[i] = IP_NULL;
1968 }
1969
1970 itk_unlock(task);
1971
1972 while (--i >= FIRST_EXCEPTION) {
1973 if (IP_VALID(old_port[i]))
1974 ipc_port_release_send(old_port[i]);
1975 }
1976
1977 if (IP_VALID(new_port)) /* consume send right */
1978 ipc_port_release_send(new_port);
1979
1980 *CountCnt = count;
1981
1982 return (KERN_SUCCESS);
1983 }
1984
1985 /*
1986 * Routine: thread/task_get_exception_ports [kernel call]
1987 * Purpose:
1988 * Clones a send right for each of the thread/task's exception
1989 * ports specified in the mask and returns the behaviour
1990 * and flavor of said port.
1991 *
1992 * Returns upto [in} CountCnt elements.
1993 *
1994 * Conditions:
1995 * Nothing locked.
1996 * Returns:
1997 * KERN_SUCCESS Extracted a send right.
1998 * KERN_INVALID_ARGUMENT The thread is null,
1999 * Invalid special port,
2000 * Illegal mask bit set.
2001 * KERN_FAILURE The thread is dead.
2002 */
2003
2004 kern_return_t
2005 thread_get_exception_ports(
2006 thread_t thread,
2007 exception_mask_t exception_mask,
2008 exception_mask_array_t masks,
2009 mach_msg_type_number_t *CountCnt,
2010 exception_port_array_t ports,
2011 exception_behavior_array_t behaviors,
2012 thread_state_flavor_array_t flavors)
2013 {
2014 unsigned int i, j, count;
2015
2016 if (thread == THREAD_NULL)
2017 return (KERN_INVALID_ARGUMENT);
2018
2019 if (exception_mask & ~EXC_MASK_VALID)
2020 return (KERN_INVALID_ARGUMENT);
2021
2022 thread_mtx_lock(thread);
2023
2024 if (!thread->active) {
2025 thread_mtx_unlock(thread);
2026
2027 return (KERN_FAILURE);
2028 }
2029
2030 count = 0;
2031
2032 if (thread->exc_actions == NULL) {
2033 goto done;
2034 }
2035
2036 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
2037 if (exception_mask & (1 << i)) {
2038 for (j = 0; j < count; ++j) {
2039 /*
2040 * search for an identical entry, if found
2041 * set corresponding mask for this exception.
2042 */
2043 if ( thread->exc_actions[i].port == ports[j] &&
2044 thread->exc_actions[i].behavior ==behaviors[j] &&
2045 thread->exc_actions[i].flavor == flavors[j] ) {
2046 masks[j] |= (1 << i);
2047 break;
2048 }
2049 }
2050
2051 if (j == count) {
2052 masks[j] = (1 << i);
2053 ports[j] = ipc_port_copy_send(thread->exc_actions[i].port);
2054 behaviors[j] = thread->exc_actions[i].behavior;
2055 flavors[j] = thread->exc_actions[i].flavor;
2056 ++count;
2057 if (count >= *CountCnt)
2058 break;
2059 }
2060 }
2061 }
2062
2063 done:
2064 thread_mtx_unlock(thread);
2065
2066 *CountCnt = count;
2067
2068 return (KERN_SUCCESS);
2069 }
2070
2071 kern_return_t
2072 task_get_exception_ports(
2073 task_t task,
2074 exception_mask_t exception_mask,
2075 exception_mask_array_t masks,
2076 mach_msg_type_number_t *CountCnt,
2077 exception_port_array_t ports,
2078 exception_behavior_array_t behaviors,
2079 thread_state_flavor_array_t flavors)
2080 {
2081 unsigned int i, j, count;
2082
2083 if (task == TASK_NULL)
2084 return (KERN_INVALID_ARGUMENT);
2085
2086 if (exception_mask & ~EXC_MASK_VALID)
2087 return (KERN_INVALID_ARGUMENT);
2088
2089 itk_lock(task);
2090
2091 if (task->itk_self == IP_NULL) {
2092 itk_unlock(task);
2093
2094 return (KERN_FAILURE);
2095 }
2096
2097 count = 0;
2098
2099 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
2100 if (exception_mask & (1 << i)) {
2101 for (j = 0; j < count; ++j) {
2102 /*
2103 * search for an identical entry, if found
2104 * set corresponding mask for this exception.
2105 */
2106 if ( task->exc_actions[i].port == ports[j] &&
2107 task->exc_actions[i].behavior == behaviors[j] &&
2108 task->exc_actions[i].flavor == flavors[j] ) {
2109 masks[j] |= (1 << i);
2110 break;
2111 }
2112 }
2113
2114 if (j == count) {
2115 masks[j] = (1 << i);
2116 ports[j] = ipc_port_copy_send(task->exc_actions[i].port);
2117 behaviors[j] = task->exc_actions[i].behavior;
2118 flavors[j] = task->exc_actions[i].flavor;
2119 ++count;
2120 if (count > *CountCnt)
2121 break;
2122 }
2123 }
2124 }
2125
2126 itk_unlock(task);
2127
2128 *CountCnt = count;
2129
2130 return (KERN_SUCCESS);
2131 }