2 * Copyright (c) 2000-2010 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
34 * All Rights Reserved.
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.
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.
46 * Carnegie Mellon requests users of this software to return to
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
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,
68 * Task and thread related IPC functions.
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>
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>
95 #include <vm/vm_map.h>
96 #include <vm/vm_pageout.h>
97 #include <vm/vm_protos.h>
99 #include <security/mac_mach_internal.h>
101 /* forward declarations */
102 task_t
convert_port_to_locked_task(ipc_port_t port
);
106 * Routine: ipc_task_init
108 * Initialize a task's IPC state.
110 * If non-null, some state will be inherited from the parent.
111 * The parent must be appropriately initialized.
128 kr
= ipc_space_create(&ipc_table_entries
[0], &space
);
129 if (kr
!= KERN_SUCCESS
)
130 panic("ipc_task_init");
132 space
->is_task
= task
;
134 kport
= ipc_port_alloc_kernel();
135 if (kport
== IP_NULL
)
136 panic("ipc_task_init");
138 nport
= ipc_port_alloc_kernel();
139 if (nport
== IP_NULL
)
140 panic("ipc_task_init");
143 task
->itk_self
= kport
;
144 task
->itk_nself
= nport
;
145 task
->itk_resume
= IP_NULL
; /* Lazily allocated on-demand */
146 if (task_is_a_corpse_fork(task
)) {
148 * No sender's notification for corpse would not
149 * work with a naked send right in kernel.
151 task
->itk_sself
= IP_NULL
;
153 task
->itk_sself
= ipc_port_make_send(kport
);
155 task
->itk_debug_control
= IP_NULL
;
156 task
->itk_space
= space
;
158 if (parent
== TASK_NULL
) {
161 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
162 task
->exc_actions
[i
].port
= IP_NULL
;
164 mac_exc_action_label_init(task
->exc_actions
+ i
);
168 kr
= host_get_host_port(host_priv_self(), &port
);
169 assert(kr
== KERN_SUCCESS
);
170 task
->itk_host
= port
;
172 task
->itk_bootstrap
= IP_NULL
;
173 task
->itk_seatbelt
= IP_NULL
;
174 task
->itk_gssd
= IP_NULL
;
175 task
->itk_task_access
= IP_NULL
;
177 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
178 task
->itk_registered
[i
] = IP_NULL
;
181 assert(parent
->itk_self
!= IP_NULL
);
183 /* inherit registered ports */
185 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
186 task
->itk_registered
[i
] =
187 ipc_port_copy_send(parent
->itk_registered
[i
]);
189 /* inherit exception and bootstrap ports */
191 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
192 task
->exc_actions
[i
].port
=
193 ipc_port_copy_send(parent
->exc_actions
[i
].port
);
194 task
->exc_actions
[i
].flavor
=
195 parent
->exc_actions
[i
].flavor
;
196 task
->exc_actions
[i
].behavior
=
197 parent
->exc_actions
[i
].behavior
;
198 task
->exc_actions
[i
].privileged
=
199 parent
->exc_actions
[i
].privileged
;
201 mac_exc_action_label_inherit(parent
->exc_actions
+ i
, task
->exc_actions
+ i
);
205 ipc_port_copy_send(parent
->itk_host
);
207 task
->itk_bootstrap
=
208 ipc_port_copy_send(parent
->itk_bootstrap
);
211 ipc_port_copy_send(parent
->itk_seatbelt
);
214 ipc_port_copy_send(parent
->itk_gssd
);
216 task
->itk_task_access
=
217 ipc_port_copy_send(parent
->itk_task_access
);
224 * Routine: ipc_task_enable
226 * Enable a task for IPC access.
239 kport
= task
->itk_self
;
240 if (kport
!= IP_NULL
)
241 ipc_kobject_set(kport
, (ipc_kobject_t
) task
, IKOT_TASK
);
242 nport
= task
->itk_nself
;
243 if (nport
!= IP_NULL
)
244 ipc_kobject_set(nport
, (ipc_kobject_t
) task
, IKOT_TASK_NAME
);
249 * Routine: ipc_task_disable
251 * Disable IPC access to a task.
265 kport
= task
->itk_self
;
266 if (kport
!= IP_NULL
)
267 ipc_kobject_set(kport
, IKO_NULL
, IKOT_NONE
);
268 nport
= task
->itk_nself
;
269 if (nport
!= IP_NULL
)
270 ipc_kobject_set(nport
, IKO_NULL
, IKOT_NONE
);
272 rport
= task
->itk_resume
;
273 if (rport
!= IP_NULL
) {
275 * From this point onwards this task is no longer accepting
278 * There are still outstanding suspensions on this task,
279 * even as it is being torn down. Disconnect the task
280 * from the rport, thereby "orphaning" the rport. The rport
281 * itself will go away only when the last suspension holder
282 * destroys his SO right to it -- when he either
283 * exits, or tries to actually use that last SO right to
284 * resume this (now non-existent) task.
286 ipc_kobject_set(rport
, IKO_NULL
, IKOT_NONE
);
292 * Routine: ipc_task_terminate
294 * Clean up and destroy a task's IPC state.
296 * Nothing locked. The task must be suspended.
297 * (Or the current thread must be in the task.)
310 kport
= task
->itk_self
;
312 if (kport
== IP_NULL
) {
313 /* the task is already terminated (can this happen?) */
317 task
->itk_self
= IP_NULL
;
319 nport
= task
->itk_nself
;
320 assert(nport
!= IP_NULL
);
321 task
->itk_nself
= IP_NULL
;
323 rport
= task
->itk_resume
;
324 task
->itk_resume
= IP_NULL
;
328 /* release the naked send rights */
330 if (IP_VALID(task
->itk_sself
))
331 ipc_port_release_send(task
->itk_sself
);
333 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
334 if (IP_VALID(task
->exc_actions
[i
].port
)) {
335 ipc_port_release_send(task
->exc_actions
[i
].port
);
338 mac_exc_action_label_destroy(task
->exc_actions
+ i
);
342 if (IP_VALID(task
->itk_host
))
343 ipc_port_release_send(task
->itk_host
);
345 if (IP_VALID(task
->itk_bootstrap
))
346 ipc_port_release_send(task
->itk_bootstrap
);
348 if (IP_VALID(task
->itk_seatbelt
))
349 ipc_port_release_send(task
->itk_seatbelt
);
351 if (IP_VALID(task
->itk_gssd
))
352 ipc_port_release_send(task
->itk_gssd
);
354 if (IP_VALID(task
->itk_task_access
))
355 ipc_port_release_send(task
->itk_task_access
);
357 if (IP_VALID(task
->itk_debug_control
))
358 ipc_port_release_send(task
->itk_debug_control
);
360 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
361 if (IP_VALID(task
->itk_registered
[i
]))
362 ipc_port_release_send(task
->itk_registered
[i
]);
364 /* destroy the kernel ports */
365 ipc_port_dealloc_kernel(kport
);
366 ipc_port_dealloc_kernel(nport
);
367 if (rport
!= IP_NULL
)
368 ipc_port_dealloc_kernel(rport
);
370 itk_lock_destroy(task
);
374 * Routine: ipc_task_reset
376 * Reset a task's IPC state to protect it when
377 * it enters an elevated security context. The
378 * task name port can remain the same - since
379 * it represents no specific privilege.
381 * Nothing locked. The task must be suspended.
382 * (Or the current thread must be in the task.)
389 ipc_port_t old_kport
, new_kport
;
390 ipc_port_t old_sself
;
391 ipc_port_t old_exc_actions
[EXC_TYPES_COUNT
];
394 new_kport
= ipc_port_alloc_kernel();
395 if (new_kport
== IP_NULL
)
396 panic("ipc_task_reset");
400 old_kport
= task
->itk_self
;
402 if (old_kport
== IP_NULL
) {
403 /* the task is already terminated (can this happen?) */
405 ipc_port_dealloc_kernel(new_kport
);
409 task
->itk_self
= new_kport
;
410 old_sself
= task
->itk_sself
;
411 task
->itk_sself
= ipc_port_make_send(new_kport
);
413 /* Set the old kport to IKOT_NONE and update the exec token while under the port lock */
415 ipc_kobject_set_atomically(old_kport
, IKO_NULL
, IKOT_NONE
);
416 task
->exec_token
+= 1;
417 ip_unlock(old_kport
);
419 ipc_kobject_set(new_kport
, (ipc_kobject_t
) task
, IKOT_TASK
);
421 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
422 old_exc_actions
[i
] = IP_NULL
;
424 if (i
== EXC_CORPSE_NOTIFY
&& task_corpse_pending_report(task
)) {
428 if (!task
->exc_actions
[i
].privileged
) {
430 mac_exc_action_label_reset(task
->exc_actions
+ i
);
432 old_exc_actions
[i
] = task
->exc_actions
[i
].port
;
433 task
->exc_actions
[i
].port
= IP_NULL
;
437 if (IP_VALID(task
->itk_debug_control
)) {
438 ipc_port_release_send(task
->itk_debug_control
);
440 task
->itk_debug_control
= IP_NULL
;
444 /* release the naked send rights */
446 if (IP_VALID(old_sself
))
447 ipc_port_release_send(old_sself
);
449 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
450 if (IP_VALID(old_exc_actions
[i
])) {
451 ipc_port_release_send(old_exc_actions
[i
]);
455 /* destroy the kernel port */
456 ipc_port_dealloc_kernel(old_kport
);
460 * Routine: ipc_thread_init
462 * Initialize a thread's IPC state.
473 kport
= ipc_port_alloc_kernel();
474 if (kport
== IP_NULL
)
475 panic("ipc_thread_init");
477 thread
->ith_self
= kport
;
478 thread
->ith_sself
= ipc_port_make_send(kport
);
479 thread
->exc_actions
= NULL
;
481 ipc_kobject_set(kport
, (ipc_kobject_t
)thread
, IKOT_THREAD
);
483 #if IMPORTANCE_INHERITANCE
484 thread
->ith_assertions
= 0;
487 ipc_kmsg_queue_init(&thread
->ith_messages
);
489 thread
->ith_rpc_reply
= IP_NULL
;
493 ipc_thread_init_exc_actions(
496 assert(thread
->exc_actions
== NULL
);
498 thread
->exc_actions
= kalloc(sizeof(struct exception_action
) * EXC_TYPES_COUNT
);
499 bzero(thread
->exc_actions
, sizeof(struct exception_action
) * EXC_TYPES_COUNT
);
502 for (size_t i
= 0; i
< EXC_TYPES_COUNT
; ++i
) {
503 mac_exc_action_label_init(thread
->exc_actions
+ i
);
509 ipc_thread_destroy_exc_actions(
512 if (thread
->exc_actions
!= NULL
) {
514 for (size_t i
= 0; i
< EXC_TYPES_COUNT
; ++i
) {
515 mac_exc_action_label_destroy(thread
->exc_actions
+ i
);
519 kfree(thread
->exc_actions
,
520 sizeof(struct exception_action
) * EXC_TYPES_COUNT
);
521 thread
->exc_actions
= NULL
;
529 ipc_port_t kport
= thread
->ith_self
;
531 if (kport
!= IP_NULL
)
532 ipc_kobject_set(kport
, IKO_NULL
, IKOT_NONE
);
536 * Routine: ipc_thread_terminate
538 * Clean up and destroy a thread's IPC state.
544 ipc_thread_terminate(
547 ipc_port_t kport
= thread
->ith_self
;
549 if (kport
!= IP_NULL
) {
552 if (IP_VALID(thread
->ith_sself
))
553 ipc_port_release_send(thread
->ith_sself
);
555 thread
->ith_sself
= thread
->ith_self
= IP_NULL
;
557 if (thread
->exc_actions
!= NULL
) {
558 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
559 if (IP_VALID(thread
->exc_actions
[i
].port
))
560 ipc_port_release_send(thread
->exc_actions
[i
].port
);
562 ipc_thread_destroy_exc_actions(thread
);
565 ipc_port_dealloc_kernel(kport
);
568 #if IMPORTANCE_INHERITANCE
569 assert(thread
->ith_assertions
== 0);
572 assert(ipc_kmsg_queue_empty(&thread
->ith_messages
));
574 if (thread
->ith_rpc_reply
!= IP_NULL
)
575 ipc_port_dealloc_reply(thread
->ith_rpc_reply
);
577 thread
->ith_rpc_reply
= IP_NULL
;
581 * Routine: ipc_thread_reset
583 * Reset the IPC state for a given Mach thread when
584 * its task enters an elevated security context.
585 * Both the thread port and its exception ports have
586 * to be reset. Its RPC reply port cannot have any
587 * rights outstanding, so it should be fine.
596 ipc_port_t old_kport
, new_kport
;
597 ipc_port_t old_sself
;
598 ipc_port_t old_exc_actions
[EXC_TYPES_COUNT
];
599 boolean_t has_old_exc_actions
= FALSE
;
602 new_kport
= ipc_port_alloc_kernel();
603 if (new_kport
== IP_NULL
)
604 panic("ipc_task_reset");
606 thread_mtx_lock(thread
);
608 old_kport
= thread
->ith_self
;
610 if (old_kport
== IP_NULL
&& thread
->inspection
== FALSE
) {
611 /* the is already terminated (can this happen?) */
612 thread_mtx_unlock(thread
);
613 ipc_port_dealloc_kernel(new_kport
);
617 thread
->ith_self
= new_kport
;
618 old_sself
= thread
->ith_sself
;
619 thread
->ith_sself
= ipc_port_make_send(new_kport
);
620 if (old_kport
!= IP_NULL
) {
621 ipc_kobject_set(old_kport
, IKO_NULL
, IKOT_NONE
);
623 ipc_kobject_set(new_kport
, (ipc_kobject_t
) thread
, IKOT_THREAD
);
626 * Only ports that were set by root-owned processes
627 * (privileged ports) should survive
629 if (thread
->exc_actions
!= NULL
) {
630 has_old_exc_actions
= TRUE
;
631 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
632 if (thread
->exc_actions
[i
].privileged
) {
633 old_exc_actions
[i
] = IP_NULL
;
636 mac_exc_action_label_reset(thread
->exc_actions
+ i
);
638 old_exc_actions
[i
] = thread
->exc_actions
[i
].port
;
639 thread
->exc_actions
[i
].port
= IP_NULL
;
644 thread_mtx_unlock(thread
);
646 /* release the naked send rights */
648 if (IP_VALID(old_sself
))
649 ipc_port_release_send(old_sself
);
651 if (has_old_exc_actions
) {
652 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
653 ipc_port_release_send(old_exc_actions
[i
]);
657 /* destroy the kernel port */
658 if (old_kport
!= IP_NULL
) {
659 ipc_port_dealloc_kernel(old_kport
);
664 * Routine: retrieve_task_self_fast
666 * Optimized version of retrieve_task_self,
667 * that only works for the current task.
669 * Return a send right (possibly null/dead)
670 * for the task's user-visible self port.
676 retrieve_task_self_fast(
681 assert(task
== current_task());
684 assert(task
->itk_self
!= IP_NULL
);
686 if ((port
= task
->itk_sself
) == task
->itk_self
) {
690 assert(ip_active(port
));
695 port
= ipc_port_copy_send(port
);
702 * Routine: retrieve_thread_self_fast
704 * Return a send right (possibly null/dead)
705 * for the thread's user-visible self port.
707 * Only works for the current thread.
714 retrieve_thread_self_fast(
719 assert(thread
== current_thread());
721 thread_mtx_lock(thread
);
723 assert(thread
->ith_self
!= IP_NULL
);
725 if ((port
= thread
->ith_sself
) == thread
->ith_self
) {
729 assert(ip_active(port
));
735 port
= ipc_port_copy_send(port
);
737 thread_mtx_unlock(thread
);
743 * Routine: task_self_trap [mach trap]
745 * Give the caller send rights for his own task port.
749 * MACH_PORT_NULL if there are any resource failures
755 __unused
struct task_self_trap_args
*args
)
757 task_t task
= current_task();
759 mach_port_name_t name
;
761 sright
= retrieve_task_self_fast(task
);
762 name
= ipc_port_copyout_send(sright
, task
->itk_space
);
767 * Routine: thread_self_trap [mach trap]
769 * Give the caller send rights for his own thread port.
773 * MACH_PORT_NULL if there are any resource failures
779 __unused
struct thread_self_trap_args
*args
)
781 thread_t thread
= current_thread();
782 task_t task
= thread
->task
;
784 mach_port_name_t name
;
786 sright
= retrieve_thread_self_fast(thread
);
787 name
= ipc_port_copyout_send(sright
, task
->itk_space
);
793 * Routine: mach_reply_port [mach trap]
795 * Allocate a port for the caller.
799 * MACH_PORT_NULL if there are any resource failures
805 __unused
struct mach_reply_port_args
*args
)
808 mach_port_name_t name
;
811 kr
= ipc_port_alloc(current_task()->itk_space
, &name
, &port
);
812 if (kr
== KERN_SUCCESS
)
815 name
= MACH_PORT_NULL
;
820 * Routine: thread_get_special_port [kernel call]
822 * Clones a send right for one of the thread's
827 * KERN_SUCCESS Extracted a send right.
828 * KERN_INVALID_ARGUMENT The thread is null.
829 * KERN_FAILURE The thread is dead.
830 * KERN_INVALID_ARGUMENT Invalid special port.
834 thread_get_special_port(
839 kern_return_t result
= KERN_SUCCESS
;
842 if (thread
== THREAD_NULL
)
843 return (KERN_INVALID_ARGUMENT
);
847 case THREAD_KERNEL_PORT
:
848 whichp
= &thread
->ith_sself
;
852 return (KERN_INVALID_ARGUMENT
);
855 thread_mtx_lock(thread
);
858 *portp
= ipc_port_copy_send(*whichp
);
860 result
= KERN_FAILURE
;
862 thread_mtx_unlock(thread
);
868 * Routine: thread_set_special_port [kernel call]
870 * Changes one of the thread's special ports,
871 * setting it to the supplied send right.
873 * Nothing locked. If successful, consumes
874 * the supplied send right.
876 * KERN_SUCCESS Changed the special port.
877 * KERN_INVALID_ARGUMENT The thread is null.
878 * KERN_FAILURE The thread is dead.
879 * KERN_INVALID_ARGUMENT Invalid special port.
883 thread_set_special_port(
888 kern_return_t result
= KERN_SUCCESS
;
889 ipc_port_t
*whichp
, old
= IP_NULL
;
891 if (thread
== THREAD_NULL
)
892 return (KERN_INVALID_ARGUMENT
);
896 case THREAD_KERNEL_PORT
:
897 whichp
= &thread
->ith_sself
;
901 return (KERN_INVALID_ARGUMENT
);
904 thread_mtx_lock(thread
);
906 if (thread
->active
) {
911 result
= KERN_FAILURE
;
913 thread_mtx_unlock(thread
);
916 ipc_port_release_send(old
);
922 * Routine: task_get_special_port [kernel call]
924 * Clones a send right for one of the task's
929 * KERN_SUCCESS Extracted a send right.
930 * KERN_INVALID_ARGUMENT The task is null.
931 * KERN_FAILURE The task/space is dead.
932 * KERN_INVALID_ARGUMENT Invalid special port.
936 task_get_special_port(
943 if (task
== TASK_NULL
)
944 return KERN_INVALID_ARGUMENT
;
947 if (task
->itk_self
== IP_NULL
) {
953 case TASK_KERNEL_PORT
:
954 port
= ipc_port_copy_send(task
->itk_sself
);
958 port
= ipc_port_make_send(task
->itk_nself
);
962 port
= ipc_port_copy_send(task
->itk_host
);
965 case TASK_BOOTSTRAP_PORT
:
966 port
= ipc_port_copy_send(task
->itk_bootstrap
);
969 case TASK_SEATBELT_PORT
:
970 port
= ipc_port_copy_send(task
->itk_seatbelt
);
973 case TASK_ACCESS_PORT
:
974 port
= ipc_port_copy_send(task
->itk_task_access
);
977 case TASK_DEBUG_CONTROL_PORT
:
978 port
= ipc_port_copy_send(task
->itk_debug_control
);
983 return KERN_INVALID_ARGUMENT
;
992 * Routine: task_set_special_port [kernel call]
994 * Changes one of the task's special ports,
995 * setting it to the supplied send right.
997 * Nothing locked. If successful, consumes
998 * the supplied send right.
1000 * KERN_SUCCESS Changed the special port.
1001 * KERN_INVALID_ARGUMENT The task is null.
1002 * KERN_FAILURE The task/space is dead.
1003 * KERN_INVALID_ARGUMENT Invalid special port.
1004 * KERN_NO_ACCESS Attempted overwrite of seatbelt port.
1008 task_set_special_port(
1016 if (task
== TASK_NULL
)
1017 return KERN_INVALID_ARGUMENT
;
1020 case TASK_KERNEL_PORT
:
1021 whichp
= &task
->itk_sself
;
1024 case TASK_HOST_PORT
:
1025 whichp
= &task
->itk_host
;
1028 case TASK_BOOTSTRAP_PORT
:
1029 whichp
= &task
->itk_bootstrap
;
1032 case TASK_SEATBELT_PORT
:
1033 whichp
= &task
->itk_seatbelt
;
1036 case TASK_ACCESS_PORT
:
1037 whichp
= &task
->itk_task_access
;
1040 case TASK_DEBUG_CONTROL_PORT
:
1041 whichp
= &task
->itk_debug_control
;
1045 return KERN_INVALID_ARGUMENT
;
1049 if (task
->itk_self
== IP_NULL
) {
1051 return KERN_FAILURE
;
1054 /* do not allow overwrite of seatbelt or task access ports */
1055 if ((TASK_SEATBELT_PORT
== which
|| TASK_ACCESS_PORT
== which
)
1056 && IP_VALID(*whichp
)) {
1058 return KERN_NO_ACCESS
;
1066 ipc_port_release_send(old
);
1067 return KERN_SUCCESS
;
1072 * Routine: mach_ports_register [kernel call]
1074 * Stash a handful of port send rights in the task.
1075 * Child tasks will inherit these rights, but they
1076 * must use mach_ports_lookup to acquire them.
1078 * The rights are supplied in a (wired) kalloc'd segment.
1079 * Rights which aren't supplied are assumed to be null.
1081 * Nothing locked. If successful, consumes
1082 * the supplied rights and memory.
1084 * KERN_SUCCESS Stashed the port rights.
1085 * KERN_INVALID_ARGUMENT The task is null.
1086 * KERN_INVALID_ARGUMENT The task is dead.
1087 * KERN_INVALID_ARGUMENT The memory param is null.
1088 * KERN_INVALID_ARGUMENT Too many port rights supplied.
1092 mach_ports_register(
1094 mach_port_array_t memory
,
1095 mach_msg_type_number_t portsCnt
)
1097 ipc_port_t ports
[TASK_PORT_REGISTER_MAX
];
1100 if ((task
== TASK_NULL
) ||
1101 (portsCnt
> TASK_PORT_REGISTER_MAX
) ||
1102 (portsCnt
&& memory
== NULL
))
1103 return KERN_INVALID_ARGUMENT
;
1106 * Pad the port rights with nulls.
1109 for (i
= 0; i
< portsCnt
; i
++)
1110 ports
[i
] = memory
[i
];
1111 for (; i
< TASK_PORT_REGISTER_MAX
; i
++)
1115 if (task
->itk_self
== IP_NULL
) {
1117 return KERN_INVALID_ARGUMENT
;
1121 * Replace the old send rights with the new.
1122 * Release the old rights after unlocking.
1125 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++) {
1128 old
= task
->itk_registered
[i
];
1129 task
->itk_registered
[i
] = ports
[i
];
1135 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
1136 if (IP_VALID(ports
[i
]))
1137 ipc_port_release_send(ports
[i
]);
1140 * Now that the operation is known to be successful,
1141 * we can free the memory.
1146 (vm_size_t
) (portsCnt
* sizeof(mach_port_t
)));
1148 return KERN_SUCCESS
;
1152 * Routine: mach_ports_lookup [kernel call]
1154 * Retrieves (clones) the stashed port send rights.
1156 * Nothing locked. If successful, the caller gets
1157 * rights and memory.
1159 * KERN_SUCCESS Retrieved the send rights.
1160 * KERN_INVALID_ARGUMENT The task is null.
1161 * KERN_INVALID_ARGUMENT The task is dead.
1162 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1168 mach_port_array_t
*portsp
,
1169 mach_msg_type_number_t
*portsCnt
)
1176 if (task
== TASK_NULL
)
1177 return KERN_INVALID_ARGUMENT
;
1179 size
= (vm_size_t
) (TASK_PORT_REGISTER_MAX
* sizeof(ipc_port_t
));
1181 memory
= kalloc(size
);
1183 return KERN_RESOURCE_SHORTAGE
;
1186 if (task
->itk_self
== IP_NULL
) {
1189 kfree(memory
, size
);
1190 return KERN_INVALID_ARGUMENT
;
1193 ports
= (ipc_port_t
*) memory
;
1196 * Clone port rights. Because kalloc'd memory
1197 * is wired, we won't fault while holding the task lock.
1200 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
1201 ports
[i
] = ipc_port_copy_send(task
->itk_registered
[i
]);
1205 *portsp
= (mach_port_array_t
) ports
;
1206 *portsCnt
= TASK_PORT_REGISTER_MAX
;
1207 return KERN_SUCCESS
;
1211 * Routine: convert_port_to_locked_task
1213 * Internal helper routine to convert from a port to a locked
1214 * task. Used by several routines that try to convert from a
1215 * task port to a reference on some task related object.
1217 * Nothing locked, blocking OK.
1220 convert_port_to_locked_task(ipc_port_t port
)
1222 int try_failed_count
= 0;
1224 while (IP_VALID(port
)) {
1228 if (!ip_active(port
) || (ip_kotype(port
) != IKOT_TASK
)) {
1232 task
= (task_t
) port
->ip_kobject
;
1233 assert(task
!= TASK_NULL
);
1236 * Normal lock ordering puts task_lock() before ip_lock().
1237 * Attempt out-of-order locking here.
1239 if (task_lock_try(task
)) {
1246 mutex_pause(try_failed_count
);
1252 * Routine: convert_port_to_task
1254 * Convert from a port to a task.
1255 * Doesn't consume the port ref; produces a task ref,
1256 * which may be null.
1261 convert_port_to_task(
1264 return convert_port_to_task_with_exec_token(port
, NULL
);
1268 * Routine: convert_port_to_task_with_exec_token
1270 * Convert from a port to a task and return
1271 * the exec token stored in the task.
1272 * Doesn't consume the port ref; produces a task ref,
1273 * which may be null.
1278 convert_port_to_task_with_exec_token(
1280 uint32_t *exec_token
)
1282 task_t task
= TASK_NULL
;
1284 if (IP_VALID(port
)) {
1287 if ( ip_active(port
) &&
1288 ip_kotype(port
) == IKOT_TASK
) {
1289 task
= (task_t
)port
->ip_kobject
;
1290 assert(task
!= TASK_NULL
);
1293 *exec_token
= task
->exec_token
;
1295 task_reference_internal(task
);
1305 * Routine: convert_port_to_task_name
1307 * Convert from a port to a task name.
1308 * Doesn't consume the port ref; produces a task name ref,
1309 * which may be null.
1314 convert_port_to_task_name(
1317 task_name_t task
= TASK_NULL
;
1319 if (IP_VALID(port
)) {
1322 if ( ip_active(port
) &&
1323 (ip_kotype(port
) == IKOT_TASK
||
1324 ip_kotype(port
) == IKOT_TASK_NAME
)) {
1325 task
= (task_name_t
)port
->ip_kobject
;
1326 assert(task
!= TASK_NAME_NULL
);
1328 task_reference_internal(task
);
1338 * Routine: convert_port_to_task_suspension_token
1340 * Convert from a port to a task suspension token.
1341 * Doesn't consume the port ref; produces a suspension token ref,
1342 * which may be null.
1346 task_suspension_token_t
1347 convert_port_to_task_suspension_token(
1350 task_suspension_token_t task
= TASK_NULL
;
1352 if (IP_VALID(port
)) {
1355 if ( ip_active(port
) &&
1356 ip_kotype(port
) == IKOT_TASK_RESUME
) {
1357 task
= (task_suspension_token_t
)port
->ip_kobject
;
1358 assert(task
!= TASK_NULL
);
1360 task_reference_internal(task
);
1370 * Routine: convert_port_to_space
1372 * Convert from a port to a space.
1373 * Doesn't consume the port ref; produces a space ref,
1374 * which may be null.
1379 convert_port_to_space(
1385 task
= convert_port_to_locked_task(port
);
1387 if (task
== TASK_NULL
)
1388 return IPC_SPACE_NULL
;
1390 if (!task
->active
) {
1392 return IPC_SPACE_NULL
;
1395 space
= task
->itk_space
;
1396 is_reference(space
);
1402 * Routine: convert_port_to_map
1404 * Convert from a port to a map.
1405 * Doesn't consume the port ref; produces a map ref,
1406 * which may be null.
1412 convert_port_to_map(
1418 task
= convert_port_to_locked_task(port
);
1420 if (task
== TASK_NULL
)
1423 if (!task
->active
) {
1429 vm_map_reference_swap(map
);
1436 * Routine: convert_port_to_thread
1438 * Convert from a port to a thread.
1439 * Doesn't consume the port ref; produces an thread ref,
1440 * which may be null.
1446 convert_port_to_thread(
1449 thread_t thread
= THREAD_NULL
;
1451 if (IP_VALID(port
)) {
1454 if ( ip_active(port
) &&
1455 ip_kotype(port
) == IKOT_THREAD
) {
1456 thread
= (thread_t
)port
->ip_kobject
;
1457 assert(thread
!= THREAD_NULL
);
1459 thread_reference_internal(thread
);
1469 * Routine: port_name_to_thread
1471 * Convert from a port name to an thread reference
1472 * A name of MACH_PORT_NULL is valid for the null thread.
1476 * TODO: Could this be faster if it were ipc_port_translate_send based, like thread_switch?
1477 * We could avoid extra lock/unlock and extra ref operations on the port.
1480 port_name_to_thread(
1481 mach_port_name_t name
)
1483 thread_t thread
= THREAD_NULL
;
1486 if (MACH_PORT_VALID(name
)) {
1487 if (ipc_object_copyin(current_space(), name
,
1488 MACH_MSG_TYPE_COPY_SEND
,
1489 (ipc_object_t
*)&kport
) != KERN_SUCCESS
)
1490 return (THREAD_NULL
);
1492 thread
= convert_port_to_thread(kport
);
1494 if (IP_VALID(kport
))
1495 ipc_port_release_send(kport
);
1503 mach_port_name_t name
)
1505 ipc_port_t kern_port
;
1507 task_t task
= TASK_NULL
;
1509 if (MACH_PORT_VALID(name
)) {
1510 kr
= ipc_object_copyin(current_space(), name
,
1511 MACH_MSG_TYPE_COPY_SEND
,
1512 (ipc_object_t
*) &kern_port
);
1513 if (kr
!= KERN_SUCCESS
)
1516 task
= convert_port_to_task(kern_port
);
1518 if (IP_VALID(kern_port
))
1519 ipc_port_release_send(kern_port
);
1525 * Routine: port_name_to_host
1527 * Convert from a port name to a host pointer.
1528 * NOTE: This does _not_ return a +1 reference to the host_t
1534 mach_port_name_t name
)
1537 host_t host
= HOST_NULL
;
1541 if (MACH_PORT_VALID(name
)) {
1542 kr
= ipc_port_translate_send(current_space(), name
, &port
);
1543 if (kr
== KERN_SUCCESS
) {
1544 host
= convert_port_to_host(port
);
1552 * Routine: convert_task_to_port
1554 * Convert from a task to a port.
1555 * Consumes a task ref; produces a naked send right
1556 * which may be invalid.
1562 convert_task_to_port(
1568 if (task
->itk_self
!= IP_NULL
)
1569 port
= ipc_port_make_send(task
->itk_self
);
1574 task_deallocate(task
);
1579 * Routine: convert_task_suspend_token_to_port
1581 * Convert from a task suspension token to a port.
1582 * Consumes a task suspension token ref; produces a naked send-once right
1583 * which may be invalid.
1588 convert_task_suspension_token_to_port(
1589 task_suspension_token_t task
)
1595 if (task
->itk_resume
== IP_NULL
) {
1596 task
->itk_resume
= ipc_port_alloc_kernel();
1597 if (!IP_VALID(task
->itk_resume
)) {
1598 panic("failed to create resume port");
1601 ipc_kobject_set(task
->itk_resume
, (ipc_kobject_t
) task
, IKOT_TASK_RESUME
);
1605 * Create a send-once right for each instance of a direct user-called
1606 * task_suspend2 call. Each time one of these send-once rights is abandoned,
1607 * the notification handler will resume the target task.
1609 port
= ipc_port_make_sonce(task
->itk_resume
);
1610 assert(IP_VALID(port
));
1616 task_suspension_token_deallocate(task
);
1623 * Routine: convert_task_name_to_port
1625 * Convert from a task name ref to a port.
1626 * Consumes a task name ref; produces a naked send right
1627 * which may be invalid.
1633 convert_task_name_to_port(
1634 task_name_t task_name
)
1638 itk_lock(task_name
);
1639 if (task_name
->itk_nself
!= IP_NULL
)
1640 port
= ipc_port_make_send(task_name
->itk_nself
);
1643 itk_unlock(task_name
);
1645 task_name_deallocate(task_name
);
1650 * Routine: convert_thread_to_port
1652 * Convert from a thread to a port.
1653 * Consumes an thread ref; produces a naked send right
1654 * which may be invalid.
1660 convert_thread_to_port(
1665 thread_mtx_lock(thread
);
1667 if (thread
->ith_self
!= IP_NULL
)
1668 port
= ipc_port_make_send(thread
->ith_self
);
1672 thread_mtx_unlock(thread
);
1674 thread_deallocate(thread
);
1680 * Routine: space_deallocate
1682 * Deallocate a space ref produced by convert_port_to_space.
1691 if (space
!= IS_NULL
)
1696 * Routine: thread/task_set_exception_ports [kernel call]
1698 * Sets the thread/task exception port, flavor and
1699 * behavior for the exception types specified by the mask.
1700 * There will be one send right per exception per valid
1703 * Nothing locked. If successful, consumes
1704 * the supplied send right.
1706 * KERN_SUCCESS Changed the special port.
1707 * KERN_INVALID_ARGUMENT The thread is null,
1708 * Illegal mask bit set.
1709 * Illegal exception behavior
1710 * KERN_FAILURE The thread is dead.
1714 thread_set_exception_ports(
1716 exception_mask_t exception_mask
,
1717 ipc_port_t new_port
,
1718 exception_behavior_t new_behavior
,
1719 thread_state_flavor_t new_flavor
)
1721 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1722 boolean_t privileged
= current_task()->sec_token
.val
[0] == 0;
1725 if (thread
== THREAD_NULL
)
1726 return (KERN_INVALID_ARGUMENT
);
1728 if (exception_mask
& ~EXC_MASK_VALID
)
1729 return (KERN_INVALID_ARGUMENT
);
1731 if (IP_VALID(new_port
)) {
1732 switch (new_behavior
& ~MACH_EXCEPTION_CODES
) {
1734 case EXCEPTION_DEFAULT
:
1735 case EXCEPTION_STATE
:
1736 case EXCEPTION_STATE_IDENTITY
:
1740 return (KERN_INVALID_ARGUMENT
);
1745 * Check the validity of the thread_state_flavor by calling the
1746 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in
1747 * osfmk/mach/ARCHITECTURE/thread_status.h
1749 if (new_flavor
!= 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor
))
1750 return (KERN_INVALID_ARGUMENT
);
1752 thread_mtx_lock(thread
);
1754 if (!thread
->active
) {
1755 thread_mtx_unlock(thread
);
1757 return (KERN_FAILURE
);
1760 if (thread
->exc_actions
== NULL
) {
1761 ipc_thread_init_exc_actions(thread
);
1763 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1764 if ((exception_mask
& (1 << i
))
1766 && mac_exc_action_label_update(current_task(), thread
->exc_actions
+ i
) == 0
1769 old_port
[i
] = thread
->exc_actions
[i
].port
;
1770 thread
->exc_actions
[i
].port
= ipc_port_copy_send(new_port
);
1771 thread
->exc_actions
[i
].behavior
= new_behavior
;
1772 thread
->exc_actions
[i
].flavor
= new_flavor
;
1773 thread
->exc_actions
[i
].privileged
= privileged
;
1776 old_port
[i
] = IP_NULL
;
1779 thread_mtx_unlock(thread
);
1781 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
)
1782 if (IP_VALID(old_port
[i
]))
1783 ipc_port_release_send(old_port
[i
]);
1785 if (IP_VALID(new_port
)) /* consume send right */
1786 ipc_port_release_send(new_port
);
1788 return (KERN_SUCCESS
);
1792 task_set_exception_ports(
1794 exception_mask_t exception_mask
,
1795 ipc_port_t new_port
,
1796 exception_behavior_t new_behavior
,
1797 thread_state_flavor_t new_flavor
)
1799 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1800 boolean_t privileged
= current_task()->sec_token
.val
[0] == 0;
1803 if (task
== TASK_NULL
)
1804 return (KERN_INVALID_ARGUMENT
);
1806 if (exception_mask
& ~EXC_MASK_VALID
)
1807 return (KERN_INVALID_ARGUMENT
);
1809 if (IP_VALID(new_port
)) {
1810 switch (new_behavior
& ~MACH_EXCEPTION_CODES
) {
1812 case EXCEPTION_DEFAULT
:
1813 case EXCEPTION_STATE
:
1814 case EXCEPTION_STATE_IDENTITY
:
1818 return (KERN_INVALID_ARGUMENT
);
1823 * Check the validity of the thread_state_flavor by calling the
1824 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in
1825 * osfmk/mach/ARCHITECTURE/thread_status.h
1827 if (new_flavor
!= 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor
))
1828 return (KERN_INVALID_ARGUMENT
);
1832 if (task
->itk_self
== IP_NULL
) {
1835 return (KERN_FAILURE
);
1838 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1839 if ((exception_mask
& (1 << i
))
1841 && mac_exc_action_label_update(current_task(), task
->exc_actions
+ i
) == 0
1844 old_port
[i
] = task
->exc_actions
[i
].port
;
1845 task
->exc_actions
[i
].port
=
1846 ipc_port_copy_send(new_port
);
1847 task
->exc_actions
[i
].behavior
= new_behavior
;
1848 task
->exc_actions
[i
].flavor
= new_flavor
;
1849 task
->exc_actions
[i
].privileged
= privileged
;
1852 old_port
[i
] = IP_NULL
;
1857 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
)
1858 if (IP_VALID(old_port
[i
]))
1859 ipc_port_release_send(old_port
[i
]);
1861 if (IP_VALID(new_port
)) /* consume send right */
1862 ipc_port_release_send(new_port
);
1864 return (KERN_SUCCESS
);
1868 * Routine: thread/task_swap_exception_ports [kernel call]
1870 * Sets the thread/task exception port, flavor and
1871 * behavior for the exception types specified by the
1874 * The old ports, behavior and flavors are returned
1875 * Count specifies the array sizes on input and
1876 * the number of returned ports etc. on output. The
1877 * arrays must be large enough to hold all the returned
1878 * data, MIG returnes an error otherwise. The masks
1879 * array specifies the corresponding exception type(s).
1882 * Nothing locked. If successful, consumes
1883 * the supplied send right.
1885 * Returns upto [in} CountCnt elements.
1887 * KERN_SUCCESS Changed the special port.
1888 * KERN_INVALID_ARGUMENT The thread is null,
1889 * Illegal mask bit set.
1890 * Illegal exception behavior
1891 * KERN_FAILURE The thread is dead.
1895 thread_swap_exception_ports(
1897 exception_mask_t exception_mask
,
1898 ipc_port_t new_port
,
1899 exception_behavior_t new_behavior
,
1900 thread_state_flavor_t new_flavor
,
1901 exception_mask_array_t masks
,
1902 mach_msg_type_number_t
*CountCnt
,
1903 exception_port_array_t ports
,
1904 exception_behavior_array_t behaviors
,
1905 thread_state_flavor_array_t flavors
)
1907 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1908 boolean_t privileged
= current_task()->sec_token
.val
[0] == 0;
1909 unsigned int i
, j
, count
;
1911 if (thread
== THREAD_NULL
)
1912 return (KERN_INVALID_ARGUMENT
);
1914 if (exception_mask
& ~EXC_MASK_VALID
)
1915 return (KERN_INVALID_ARGUMENT
);
1917 if (IP_VALID(new_port
)) {
1918 switch (new_behavior
& ~MACH_EXCEPTION_CODES
) {
1920 case EXCEPTION_DEFAULT
:
1921 case EXCEPTION_STATE
:
1922 case EXCEPTION_STATE_IDENTITY
:
1926 return (KERN_INVALID_ARGUMENT
);
1930 if (new_flavor
!= 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor
))
1931 return (KERN_INVALID_ARGUMENT
);
1933 thread_mtx_lock(thread
);
1935 if (!thread
->active
) {
1936 thread_mtx_unlock(thread
);
1938 return (KERN_FAILURE
);
1941 if (thread
->exc_actions
== NULL
) {
1942 ipc_thread_init_exc_actions(thread
);
1945 assert(EXC_TYPES_COUNT
> FIRST_EXCEPTION
);
1946 for (count
= 0, i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
&& count
< *CountCnt
; ++i
) {
1947 if ((exception_mask
& (1 << i
))
1949 && mac_exc_action_label_update(current_task(), thread
->exc_actions
+ i
) == 0
1952 for (j
= 0; j
< count
; ++j
) {
1954 * search for an identical entry, if found
1955 * set corresponding mask for this exception.
1957 if ( thread
->exc_actions
[i
].port
== ports
[j
] &&
1958 thread
->exc_actions
[i
].behavior
== behaviors
[j
] &&
1959 thread
->exc_actions
[i
].flavor
== flavors
[j
] ) {
1960 masks
[j
] |= (1 << i
);
1966 masks
[j
] = (1 << i
);
1967 ports
[j
] = ipc_port_copy_send(thread
->exc_actions
[i
].port
);
1969 behaviors
[j
] = thread
->exc_actions
[i
].behavior
;
1970 flavors
[j
] = thread
->exc_actions
[i
].flavor
;
1974 old_port
[i
] = thread
->exc_actions
[i
].port
;
1975 thread
->exc_actions
[i
].port
= ipc_port_copy_send(new_port
);
1976 thread
->exc_actions
[i
].behavior
= new_behavior
;
1977 thread
->exc_actions
[i
].flavor
= new_flavor
;
1978 thread
->exc_actions
[i
].privileged
= privileged
;
1981 old_port
[i
] = IP_NULL
;
1984 thread_mtx_unlock(thread
);
1986 while (--i
>= FIRST_EXCEPTION
) {
1987 if (IP_VALID(old_port
[i
]))
1988 ipc_port_release_send(old_port
[i
]);
1991 if (IP_VALID(new_port
)) /* consume send right */
1992 ipc_port_release_send(new_port
);
1996 return (KERN_SUCCESS
);
2000 task_swap_exception_ports(
2002 exception_mask_t exception_mask
,
2003 ipc_port_t new_port
,
2004 exception_behavior_t new_behavior
,
2005 thread_state_flavor_t new_flavor
,
2006 exception_mask_array_t masks
,
2007 mach_msg_type_number_t
*CountCnt
,
2008 exception_port_array_t ports
,
2009 exception_behavior_array_t behaviors
,
2010 thread_state_flavor_array_t flavors
)
2012 ipc_port_t old_port
[EXC_TYPES_COUNT
];
2013 boolean_t privileged
= current_task()->sec_token
.val
[0] == 0;
2014 unsigned int i
, j
, count
;
2016 if (task
== TASK_NULL
)
2017 return (KERN_INVALID_ARGUMENT
);
2019 if (exception_mask
& ~EXC_MASK_VALID
)
2020 return (KERN_INVALID_ARGUMENT
);
2022 if (IP_VALID(new_port
)) {
2023 switch (new_behavior
& ~MACH_EXCEPTION_CODES
) {
2025 case EXCEPTION_DEFAULT
:
2026 case EXCEPTION_STATE
:
2027 case EXCEPTION_STATE_IDENTITY
:
2031 return (KERN_INVALID_ARGUMENT
);
2035 if (new_flavor
!= 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor
))
2036 return (KERN_INVALID_ARGUMENT
);
2040 if (task
->itk_self
== IP_NULL
) {
2043 return (KERN_FAILURE
);
2046 assert(EXC_TYPES_COUNT
> FIRST_EXCEPTION
);
2047 for (count
= 0, i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
&& count
< *CountCnt
; ++i
) {
2048 if ((exception_mask
& (1 << i
))
2050 && mac_exc_action_label_update(current_task(), task
->exc_actions
+ i
) == 0
2053 for (j
= 0; j
< count
; j
++) {
2055 * search for an identical entry, if found
2056 * set corresponding mask for this exception.
2058 if ( task
->exc_actions
[i
].port
== ports
[j
] &&
2059 task
->exc_actions
[i
].behavior
== behaviors
[j
] &&
2060 task
->exc_actions
[i
].flavor
== flavors
[j
] ) {
2061 masks
[j
] |= (1 << i
);
2067 masks
[j
] = (1 << i
);
2068 ports
[j
] = ipc_port_copy_send(task
->exc_actions
[i
].port
);
2069 behaviors
[j
] = task
->exc_actions
[i
].behavior
;
2070 flavors
[j
] = task
->exc_actions
[i
].flavor
;
2074 old_port
[i
] = task
->exc_actions
[i
].port
;
2076 task
->exc_actions
[i
].port
= ipc_port_copy_send(new_port
);
2077 task
->exc_actions
[i
].behavior
= new_behavior
;
2078 task
->exc_actions
[i
].flavor
= new_flavor
;
2079 task
->exc_actions
[i
].privileged
= privileged
;
2082 old_port
[i
] = IP_NULL
;
2087 while (--i
>= FIRST_EXCEPTION
) {
2088 if (IP_VALID(old_port
[i
]))
2089 ipc_port_release_send(old_port
[i
]);
2092 if (IP_VALID(new_port
)) /* consume send right */
2093 ipc_port_release_send(new_port
);
2097 return (KERN_SUCCESS
);
2101 * Routine: thread/task_get_exception_ports [kernel call]
2103 * Clones a send right for each of the thread/task's exception
2104 * ports specified in the mask and returns the behaviour
2105 * and flavor of said port.
2107 * Returns upto [in} CountCnt elements.
2112 * KERN_SUCCESS Extracted a send right.
2113 * KERN_INVALID_ARGUMENT The thread is null,
2114 * Invalid special port,
2115 * Illegal mask bit set.
2116 * KERN_FAILURE The thread is dead.
2120 thread_get_exception_ports(
2122 exception_mask_t exception_mask
,
2123 exception_mask_array_t masks
,
2124 mach_msg_type_number_t
*CountCnt
,
2125 exception_port_array_t ports
,
2126 exception_behavior_array_t behaviors
,
2127 thread_state_flavor_array_t flavors
)
2129 unsigned int i
, j
, count
;
2131 if (thread
== THREAD_NULL
)
2132 return (KERN_INVALID_ARGUMENT
);
2134 if (exception_mask
& ~EXC_MASK_VALID
)
2135 return (KERN_INVALID_ARGUMENT
);
2137 thread_mtx_lock(thread
);
2139 if (!thread
->active
) {
2140 thread_mtx_unlock(thread
);
2142 return (KERN_FAILURE
);
2147 if (thread
->exc_actions
== NULL
) {
2151 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
2152 if (exception_mask
& (1 << i
)) {
2153 for (j
= 0; j
< count
; ++j
) {
2155 * search for an identical entry, if found
2156 * set corresponding mask for this exception.
2158 if ( thread
->exc_actions
[i
].port
== ports
[j
] &&
2159 thread
->exc_actions
[i
].behavior
==behaviors
[j
] &&
2160 thread
->exc_actions
[i
].flavor
== flavors
[j
] ) {
2161 masks
[j
] |= (1 << i
);
2167 masks
[j
] = (1 << i
);
2168 ports
[j
] = ipc_port_copy_send(thread
->exc_actions
[i
].port
);
2169 behaviors
[j
] = thread
->exc_actions
[i
].behavior
;
2170 flavors
[j
] = thread
->exc_actions
[i
].flavor
;
2172 if (count
>= *CountCnt
)
2179 thread_mtx_unlock(thread
);
2183 return (KERN_SUCCESS
);
2187 task_get_exception_ports(
2189 exception_mask_t exception_mask
,
2190 exception_mask_array_t masks
,
2191 mach_msg_type_number_t
*CountCnt
,
2192 exception_port_array_t ports
,
2193 exception_behavior_array_t behaviors
,
2194 thread_state_flavor_array_t flavors
)
2196 unsigned int i
, j
, count
;
2198 if (task
== TASK_NULL
)
2199 return (KERN_INVALID_ARGUMENT
);
2201 if (exception_mask
& ~EXC_MASK_VALID
)
2202 return (KERN_INVALID_ARGUMENT
);
2206 if (task
->itk_self
== IP_NULL
) {
2209 return (KERN_FAILURE
);
2214 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
2215 if (exception_mask
& (1 << i
)) {
2216 for (j
= 0; j
< count
; ++j
) {
2218 * search for an identical entry, if found
2219 * set corresponding mask for this exception.
2221 if ( task
->exc_actions
[i
].port
== ports
[j
] &&
2222 task
->exc_actions
[i
].behavior
== behaviors
[j
] &&
2223 task
->exc_actions
[i
].flavor
== flavors
[j
] ) {
2224 masks
[j
] |= (1 << i
);
2230 masks
[j
] = (1 << i
);
2231 ports
[j
] = ipc_port_copy_send(task
->exc_actions
[i
].port
);
2232 behaviors
[j
] = task
->exc_actions
[i
].behavior
;
2233 flavors
[j
] = task
->exc_actions
[i
].flavor
;
2235 if (count
> *CountCnt
)
2245 return (KERN_SUCCESS
);