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 #if CONFIG_EMBEDDED && !SECURE_KERNEL
102 extern int cs_relax_platform_task_ports
;
105 /* forward declarations */
106 task_t
convert_port_to_locked_task(ipc_port_t port
);
107 task_inspect_t
convert_port_to_locked_task_inspect(ipc_port_t port
);
108 static void ipc_port_bind_special_reply_port_locked(ipc_port_t port
);
109 static kern_return_t
ipc_port_unbind_special_reply_port(thread_t thread
, boolean_t unbind_active_port
);
110 kern_return_t
task_conversion_eval(task_t caller
, task_t victim
);
113 * Routine: ipc_task_init
115 * Initialize a task's IPC state.
117 * If non-null, some state will be inherited from the parent.
118 * The parent must be appropriately initialized.
135 kr
= ipc_space_create(&ipc_table_entries
[0], &space
);
136 if (kr
!= KERN_SUCCESS
) {
137 panic("ipc_task_init");
140 space
->is_task
= task
;
142 kport
= ipc_port_alloc_kernel();
143 if (kport
== IP_NULL
) {
144 panic("ipc_task_init");
147 nport
= ipc_port_alloc_kernel();
148 if (nport
== IP_NULL
) {
149 panic("ipc_task_init");
153 task
->itk_self
= kport
;
154 task
->itk_nself
= nport
;
155 task
->itk_resume
= IP_NULL
; /* Lazily allocated on-demand */
156 if (task_is_a_corpse_fork(task
)) {
158 * No sender's notification for corpse would not
159 * work with a naked send right in kernel.
161 task
->itk_sself
= IP_NULL
;
163 task
->itk_sself
= ipc_port_make_send(kport
);
165 task
->itk_debug_control
= IP_NULL
;
166 task
->itk_space
= space
;
169 task
->exc_actions
[0].label
= NULL
;
170 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
171 mac_exc_associate_action_label(&task
->exc_actions
[i
], mac_exc_create_label());
175 /* always zero-out the first (unused) array element */
176 bzero(&task
->exc_actions
[0], sizeof(task
->exc_actions
[0]));
178 if (parent
== TASK_NULL
) {
180 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
181 task
->exc_actions
[i
].port
= IP_NULL
;
182 task
->exc_actions
[i
].flavor
= 0;
183 task
->exc_actions
[i
].behavior
= 0;
184 task
->exc_actions
[i
].privileged
= FALSE
;
187 kr
= host_get_host_port(host_priv_self(), &port
);
188 assert(kr
== KERN_SUCCESS
);
189 task
->itk_host
= port
;
191 task
->itk_bootstrap
= IP_NULL
;
192 task
->itk_seatbelt
= IP_NULL
;
193 task
->itk_gssd
= IP_NULL
;
194 task
->itk_task_access
= IP_NULL
;
196 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++) {
197 task
->itk_registered
[i
] = IP_NULL
;
201 assert(parent
->itk_self
!= IP_NULL
);
203 /* inherit registered ports */
205 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++) {
206 task
->itk_registered
[i
] =
207 ipc_port_copy_send(parent
->itk_registered
[i
]);
210 /* inherit exception and bootstrap ports */
212 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
213 task
->exc_actions
[i
].port
=
214 ipc_port_copy_send(parent
->exc_actions
[i
].port
);
215 task
->exc_actions
[i
].flavor
=
216 parent
->exc_actions
[i
].flavor
;
217 task
->exc_actions
[i
].behavior
=
218 parent
->exc_actions
[i
].behavior
;
219 task
->exc_actions
[i
].privileged
=
220 parent
->exc_actions
[i
].privileged
;
222 mac_exc_inherit_action_label(parent
->exc_actions
+ i
, task
->exc_actions
+ i
);
226 ipc_port_copy_send(parent
->itk_host
);
228 task
->itk_bootstrap
=
229 ipc_port_copy_send(parent
->itk_bootstrap
);
232 ipc_port_copy_send(parent
->itk_seatbelt
);
235 ipc_port_copy_send(parent
->itk_gssd
);
237 task
->itk_task_access
=
238 ipc_port_copy_send(parent
->itk_task_access
);
245 * Routine: ipc_task_enable
247 * Enable a task for IPC access.
260 kport
= task
->itk_self
;
261 if (kport
!= IP_NULL
) {
262 ipc_kobject_set(kport
, (ipc_kobject_t
) task
, IKOT_TASK
);
264 nport
= task
->itk_nself
;
265 if (nport
!= IP_NULL
) {
266 ipc_kobject_set(nport
, (ipc_kobject_t
) task
, IKOT_TASK_NAME
);
272 * Routine: ipc_task_disable
274 * Disable IPC access to a task.
288 kport
= task
->itk_self
;
289 if (kport
!= IP_NULL
) {
290 ipc_kobject_set(kport
, IKO_NULL
, IKOT_NONE
);
292 nport
= task
->itk_nself
;
293 if (nport
!= IP_NULL
) {
294 ipc_kobject_set(nport
, IKO_NULL
, IKOT_NONE
);
297 rport
= task
->itk_resume
;
298 if (rport
!= IP_NULL
) {
300 * From this point onwards this task is no longer accepting
303 * There are still outstanding suspensions on this task,
304 * even as it is being torn down. Disconnect the task
305 * from the rport, thereby "orphaning" the rport. The rport
306 * itself will go away only when the last suspension holder
307 * destroys his SO right to it -- when he either
308 * exits, or tries to actually use that last SO right to
309 * resume this (now non-existent) task.
311 ipc_kobject_set(rport
, IKO_NULL
, IKOT_NONE
);
317 * Routine: ipc_task_terminate
319 * Clean up and destroy a task's IPC state.
321 * Nothing locked. The task must be suspended.
322 * (Or the current thread must be in the task.)
335 kport
= task
->itk_self
;
337 if (kport
== IP_NULL
) {
338 /* the task is already terminated (can this happen?) */
342 task
->itk_self
= IP_NULL
;
344 nport
= task
->itk_nself
;
345 assert(nport
!= IP_NULL
);
346 task
->itk_nself
= IP_NULL
;
348 rport
= task
->itk_resume
;
349 task
->itk_resume
= IP_NULL
;
353 /* release the naked send rights */
355 if (IP_VALID(task
->itk_sself
)) {
356 ipc_port_release_send(task
->itk_sself
);
359 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
360 if (IP_VALID(task
->exc_actions
[i
].port
)) {
361 ipc_port_release_send(task
->exc_actions
[i
].port
);
364 mac_exc_free_action_label(task
->exc_actions
+ i
);
368 if (IP_VALID(task
->itk_host
)) {
369 ipc_port_release_send(task
->itk_host
);
372 if (IP_VALID(task
->itk_bootstrap
)) {
373 ipc_port_release_send(task
->itk_bootstrap
);
376 if (IP_VALID(task
->itk_seatbelt
)) {
377 ipc_port_release_send(task
->itk_seatbelt
);
380 if (IP_VALID(task
->itk_gssd
)) {
381 ipc_port_release_send(task
->itk_gssd
);
384 if (IP_VALID(task
->itk_task_access
)) {
385 ipc_port_release_send(task
->itk_task_access
);
388 if (IP_VALID(task
->itk_debug_control
)) {
389 ipc_port_release_send(task
->itk_debug_control
);
392 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++) {
393 if (IP_VALID(task
->itk_registered
[i
])) {
394 ipc_port_release_send(task
->itk_registered
[i
]);
398 /* destroy the kernel ports */
399 ipc_port_dealloc_kernel(kport
);
400 ipc_port_dealloc_kernel(nport
);
401 if (rport
!= IP_NULL
) {
402 ipc_port_dealloc_kernel(rport
);
405 itk_lock_destroy(task
);
409 * Routine: ipc_task_reset
411 * Reset a task's IPC state to protect it when
412 * it enters an elevated security context. The
413 * task name port can remain the same - since
414 * it represents no specific privilege.
416 * Nothing locked. The task must be suspended.
417 * (Or the current thread must be in the task.)
424 ipc_port_t old_kport
, new_kport
;
425 ipc_port_t old_sself
;
426 ipc_port_t old_exc_actions
[EXC_TYPES_COUNT
];
430 /* Fresh label to unset credentials in existing labels. */
431 struct label
*unset_label
= mac_exc_create_label();
434 new_kport
= ipc_kobject_alloc_port((ipc_kobject_t
)task
, IKOT_TASK
,
435 IPC_KOBJECT_ALLOC_MAKE_SEND
);
439 old_kport
= task
->itk_self
;
441 if (old_kport
== IP_NULL
) {
442 /* the task is already terminated (can this happen?) */
444 ipc_port_release_send(new_kport
);
445 ipc_port_dealloc_kernel(new_kport
);
447 mac_exc_free_label(unset_label
);
452 old_sself
= task
->itk_sself
;
453 task
->itk_sself
= task
->itk_self
= new_kport
;
455 /* Set the old kport to IKOT_NONE and update the exec token while under the port lock */
457 ipc_kobject_set_atomically(old_kport
, IKO_NULL
, IKOT_NONE
);
458 task
->exec_token
+= 1;
459 ip_unlock(old_kport
);
461 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
462 old_exc_actions
[i
] = IP_NULL
;
464 if (i
== EXC_CORPSE_NOTIFY
&& task_corpse_pending_report(task
)) {
468 if (!task
->exc_actions
[i
].privileged
) {
470 mac_exc_update_action_label(task
->exc_actions
+ i
, unset_label
);
472 old_exc_actions
[i
] = task
->exc_actions
[i
].port
;
473 task
->exc_actions
[i
].port
= IP_NULL
;
477 if (IP_VALID(task
->itk_debug_control
)) {
478 ipc_port_release_send(task
->itk_debug_control
);
480 task
->itk_debug_control
= IP_NULL
;
485 mac_exc_free_label(unset_label
);
488 /* release the naked send rights */
490 if (IP_VALID(old_sself
)) {
491 ipc_port_release_send(old_sself
);
494 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
495 if (IP_VALID(old_exc_actions
[i
])) {
496 ipc_port_release_send(old_exc_actions
[i
]);
500 /* destroy the kernel port */
501 ipc_port_dealloc_kernel(old_kport
);
505 * Routine: ipc_thread_init
507 * Initialize a thread's IPC state.
518 kport
= ipc_kobject_alloc_port((ipc_kobject_t
)thread
, IKOT_THREAD
,
519 IPC_KOBJECT_ALLOC_MAKE_SEND
);
521 thread
->ith_sself
= thread
->ith_self
= kport
;
522 thread
->ith_special_reply_port
= NULL
;
523 thread
->exc_actions
= NULL
;
525 #if IMPORTANCE_INHERITANCE
526 thread
->ith_assertions
= 0;
529 ipc_kmsg_queue_init(&thread
->ith_messages
);
531 thread
->ith_rpc_reply
= IP_NULL
;
535 ipc_thread_init_exc_actions(
538 assert(thread
->exc_actions
== NULL
);
540 thread
->exc_actions
= kalloc(sizeof(struct exception_action
) * EXC_TYPES_COUNT
);
541 bzero(thread
->exc_actions
, sizeof(struct exception_action
) * EXC_TYPES_COUNT
);
544 for (size_t i
= 0; i
< EXC_TYPES_COUNT
; ++i
) {
545 mac_exc_associate_action_label(thread
->exc_actions
+ i
, mac_exc_create_label());
551 ipc_thread_destroy_exc_actions(
554 if (thread
->exc_actions
!= NULL
) {
556 for (size_t i
= 0; i
< EXC_TYPES_COUNT
; ++i
) {
557 mac_exc_free_action_label(thread
->exc_actions
+ i
);
561 kfree(thread
->exc_actions
,
562 sizeof(struct exception_action
) * EXC_TYPES_COUNT
);
563 thread
->exc_actions
= NULL
;
571 ipc_port_t kport
= thread
->ith_self
;
573 if (kport
!= IP_NULL
) {
574 ipc_kobject_set(kport
, IKO_NULL
, IKOT_NONE
);
577 /* unbind the thread special reply port */
578 if (IP_VALID(thread
->ith_special_reply_port
)) {
579 ipc_port_unbind_special_reply_port(thread
, TRUE
);
584 * Routine: ipc_thread_terminate
586 * Clean up and destroy a thread's IPC state.
592 ipc_thread_terminate(
595 ipc_port_t kport
= thread
->ith_self
;
597 if (kport
!= IP_NULL
) {
600 if (IP_VALID(thread
->ith_sself
)) {
601 ipc_port_release_send(thread
->ith_sself
);
604 thread
->ith_sself
= thread
->ith_self
= IP_NULL
;
606 if (thread
->exc_actions
!= NULL
) {
607 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
608 if (IP_VALID(thread
->exc_actions
[i
].port
)) {
609 ipc_port_release_send(thread
->exc_actions
[i
].port
);
612 ipc_thread_destroy_exc_actions(thread
);
615 ipc_port_dealloc_kernel(kport
);
618 #if IMPORTANCE_INHERITANCE
619 assert(thread
->ith_assertions
== 0);
622 assert(ipc_kmsg_queue_empty(&thread
->ith_messages
));
624 if (thread
->ith_rpc_reply
!= IP_NULL
) {
625 ipc_port_dealloc_reply(thread
->ith_rpc_reply
);
628 thread
->ith_rpc_reply
= IP_NULL
;
632 * Routine: ipc_thread_reset
634 * Reset the IPC state for a given Mach thread when
635 * its task enters an elevated security context.
636 * Both the thread port and its exception ports have
637 * to be reset. Its RPC reply port cannot have any
638 * rights outstanding, so it should be fine.
647 ipc_port_t old_kport
, new_kport
;
648 ipc_port_t old_sself
;
649 ipc_port_t old_exc_actions
[EXC_TYPES_COUNT
];
650 boolean_t has_old_exc_actions
= FALSE
;
654 struct label
*new_label
= mac_exc_create_label();
657 new_kport
= ipc_kobject_alloc_port((ipc_kobject_t
)thread
, IKOT_THREAD
,
658 IPC_KOBJECT_ALLOC_MAKE_SEND
);
660 thread_mtx_lock(thread
);
662 old_kport
= thread
->ith_self
;
663 old_sself
= thread
->ith_sself
;
665 if (old_kport
== IP_NULL
&& thread
->inspection
== FALSE
) {
666 /* the is already terminated (can this happen?) */
667 thread_mtx_unlock(thread
);
668 ipc_port_release_send(new_kport
);
669 ipc_port_dealloc_kernel(new_kport
);
671 mac_exc_free_label(new_label
);
676 thread
->ith_sself
= thread
->ith_self
= new_kport
;
677 if (old_kport
!= IP_NULL
) {
678 ipc_kobject_set(old_kport
, IKO_NULL
, IKOT_NONE
);
682 * Only ports that were set by root-owned processes
683 * (privileged ports) should survive
685 if (thread
->exc_actions
!= NULL
) {
686 has_old_exc_actions
= TRUE
;
687 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
688 if (thread
->exc_actions
[i
].privileged
) {
689 old_exc_actions
[i
] = IP_NULL
;
692 mac_exc_update_action_label(thread
->exc_actions
+ i
, new_label
);
694 old_exc_actions
[i
] = thread
->exc_actions
[i
].port
;
695 thread
->exc_actions
[i
].port
= IP_NULL
;
700 thread_mtx_unlock(thread
);
703 mac_exc_free_label(new_label
);
706 /* release the naked send rights */
708 if (IP_VALID(old_sself
)) {
709 ipc_port_release_send(old_sself
);
712 if (has_old_exc_actions
) {
713 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
714 ipc_port_release_send(old_exc_actions
[i
]);
718 /* destroy the kernel port */
719 if (old_kport
!= IP_NULL
) {
720 ipc_port_dealloc_kernel(old_kport
);
723 /* unbind the thread special reply port */
724 if (IP_VALID(thread
->ith_special_reply_port
)) {
725 ipc_port_unbind_special_reply_port(thread
, TRUE
);
730 * Routine: retrieve_task_self_fast
732 * Optimized version of retrieve_task_self,
733 * that only works for the current task.
735 * Return a send right (possibly null/dead)
736 * for the task's user-visible self port.
742 retrieve_task_self_fast(
745 __assert_only ipc_port_t sright
;
748 assert(task
== current_task());
751 assert(task
->itk_self
!= IP_NULL
);
753 if ((port
= task
->itk_sself
) == task
->itk_self
) {
755 sright
= ipc_port_copy_send(port
);
756 assert(sright
== port
);
758 port
= ipc_port_copy_send(port
);
766 * Routine: retrieve_thread_self_fast
768 * Return a send right (possibly null/dead)
769 * for the thread's user-visible self port.
771 * Only works for the current thread.
778 retrieve_thread_self_fast(
781 __assert_only ipc_port_t sright
;
784 assert(thread
== current_thread());
786 thread_mtx_lock(thread
);
788 assert(thread
->ith_self
!= IP_NULL
);
790 if ((port
= thread
->ith_sself
) == thread
->ith_self
) {
792 sright
= ipc_port_copy_send(port
);
793 assert(sright
== port
);
795 port
= ipc_port_copy_send(port
);
798 thread_mtx_unlock(thread
);
804 * Routine: task_self_trap [mach trap]
806 * Give the caller send rights for his own task port.
810 * MACH_PORT_NULL if there are any resource failures
816 __unused
struct task_self_trap_args
*args
)
818 task_t task
= current_task();
820 mach_port_name_t name
;
822 sright
= retrieve_task_self_fast(task
);
823 name
= ipc_port_copyout_send(sright
, task
->itk_space
);
828 * Routine: thread_self_trap [mach trap]
830 * Give the caller send rights for his own thread port.
834 * MACH_PORT_NULL if there are any resource failures
840 __unused
struct thread_self_trap_args
*args
)
842 thread_t thread
= current_thread();
843 task_t task
= thread
->task
;
845 mach_port_name_t name
;
847 sright
= retrieve_thread_self_fast(thread
);
848 name
= ipc_port_copyout_send(sright
, task
->itk_space
);
853 * Routine: mach_reply_port [mach trap]
855 * Allocate a port for the caller.
859 * MACH_PORT_NULL if there are any resource failures
865 __unused
struct mach_reply_port_args
*args
)
868 mach_port_name_t name
;
871 kr
= ipc_port_alloc(current_task()->itk_space
, FALSE
, &name
, &port
);
872 if (kr
== KERN_SUCCESS
) {
875 name
= MACH_PORT_NULL
;
881 * Routine: thread_get_special_reply_port [mach trap]
883 * Allocate a special reply port for the calling thread.
887 * mach_port_name_t: send right & receive right for special reply port.
888 * MACH_PORT_NULL if there are any resource failures
893 thread_get_special_reply_port(
894 __unused
struct thread_get_special_reply_port_args
*args
)
897 mach_port_name_t name
;
899 thread_t thread
= current_thread();
901 /* unbind the thread special reply port */
902 if (IP_VALID(thread
->ith_special_reply_port
)) {
903 kr
= ipc_port_unbind_special_reply_port(thread
, TRUE
);
904 if (kr
!= KERN_SUCCESS
) {
905 return MACH_PORT_NULL
;
909 kr
= ipc_port_alloc(current_task()->itk_space
, TRUE
, &name
, &port
);
910 if (kr
== KERN_SUCCESS
) {
911 ipc_port_bind_special_reply_port_locked(port
);
914 name
= MACH_PORT_NULL
;
920 * Routine: ipc_port_bind_special_reply_port_locked
922 * Bind the given port to current thread as a special reply port.
930 ipc_port_bind_special_reply_port_locked(
933 thread_t thread
= current_thread();
934 assert(thread
->ith_special_reply_port
== NULL
);
937 thread
->ith_special_reply_port
= port
;
938 port
->ip_specialreply
= 1;
939 port
->ip_sync_link_state
= PORT_SYNC_LINK_ANY
;
940 port
->ip_messages
.imq_srp_owner_thread
= thread
;
942 ipc_special_reply_port_bits_reset(port
);
946 * Routine: ipc_port_unbind_special_reply_port
948 * Unbind the thread's special reply port.
949 * If the special port has threads waiting on turnstile,
950 * update it's inheritor.
957 ipc_port_unbind_special_reply_port(
959 boolean_t unbind_active_port
)
961 ipc_port_t special_reply_port
= thread
->ith_special_reply_port
;
963 ip_lock(special_reply_port
);
965 /* Return error if port active and unbind_active_port set to FALSE */
966 if (unbind_active_port
== FALSE
&& ip_active(special_reply_port
)) {
967 ip_unlock(special_reply_port
);
971 thread
->ith_special_reply_port
= NULL
;
972 ipc_port_adjust_special_reply_port_locked(special_reply_port
, NULL
,
973 IPC_PORT_ADJUST_UNLINK_THREAD
, FALSE
);
976 ip_release(special_reply_port
);
981 * Routine: thread_get_special_port [kernel call]
983 * Clones a send right for one of the thread's
988 * KERN_SUCCESS Extracted a send right.
989 * KERN_INVALID_ARGUMENT The thread is null.
990 * KERN_FAILURE The thread is dead.
991 * KERN_INVALID_ARGUMENT Invalid special port.
995 thread_get_special_port(
1000 kern_return_t result
= KERN_SUCCESS
;
1003 if (thread
== THREAD_NULL
) {
1004 return KERN_INVALID_ARGUMENT
;
1008 case THREAD_KERNEL_PORT
:
1009 whichp
= &thread
->ith_sself
;
1013 return KERN_INVALID_ARGUMENT
;
1016 thread_mtx_lock(thread
);
1018 if (thread
->active
) {
1019 *portp
= ipc_port_copy_send(*whichp
);
1021 result
= KERN_FAILURE
;
1024 thread_mtx_unlock(thread
);
1030 * Routine: thread_set_special_port [kernel call]
1032 * Changes one of the thread's special ports,
1033 * setting it to the supplied send right.
1035 * Nothing locked. If successful, consumes
1036 * the supplied send right.
1038 * KERN_SUCCESS Changed the special port.
1039 * KERN_INVALID_ARGUMENT The thread is null.
1040 * KERN_FAILURE The thread is dead.
1041 * KERN_INVALID_ARGUMENT Invalid special port.
1045 thread_set_special_port(
1050 kern_return_t result
= KERN_SUCCESS
;
1051 ipc_port_t
*whichp
, old
= IP_NULL
;
1053 if (thread
== THREAD_NULL
) {
1054 return KERN_INVALID_ARGUMENT
;
1058 case THREAD_KERNEL_PORT
:
1059 whichp
= &thread
->ith_sself
;
1063 return KERN_INVALID_ARGUMENT
;
1066 thread_mtx_lock(thread
);
1068 if (thread
->active
) {
1072 result
= KERN_FAILURE
;
1075 thread_mtx_unlock(thread
);
1077 if (IP_VALID(old
)) {
1078 ipc_port_release_send(old
);
1085 * Routine: task_get_special_port [kernel call]
1087 * Clones a send right for one of the task's
1092 * KERN_SUCCESS Extracted a send right.
1093 * KERN_INVALID_ARGUMENT The task is null.
1094 * KERN_FAILURE The task/space is dead.
1095 * KERN_INVALID_ARGUMENT Invalid special port.
1099 task_get_special_port(
1106 if (task
== TASK_NULL
) {
1107 return KERN_INVALID_ARGUMENT
;
1111 if (task
->itk_self
== IP_NULL
) {
1113 return KERN_FAILURE
;
1117 case TASK_KERNEL_PORT
:
1118 port
= ipc_port_copy_send(task
->itk_sself
);
1121 case TASK_NAME_PORT
:
1122 port
= ipc_port_make_send(task
->itk_nself
);
1125 case TASK_HOST_PORT
:
1126 port
= ipc_port_copy_send(task
->itk_host
);
1129 case TASK_BOOTSTRAP_PORT
:
1130 port
= ipc_port_copy_send(task
->itk_bootstrap
);
1133 case TASK_SEATBELT_PORT
:
1134 port
= ipc_port_copy_send(task
->itk_seatbelt
);
1137 case TASK_ACCESS_PORT
:
1138 port
= ipc_port_copy_send(task
->itk_task_access
);
1141 case TASK_DEBUG_CONTROL_PORT
:
1142 port
= ipc_port_copy_send(task
->itk_debug_control
);
1147 return KERN_INVALID_ARGUMENT
;
1152 return KERN_SUCCESS
;
1156 * Routine: task_set_special_port [kernel call]
1158 * Changes one of the task's special ports,
1159 * setting it to the supplied send right.
1161 * Nothing locked. If successful, consumes
1162 * the supplied send right.
1164 * KERN_SUCCESS Changed the special port.
1165 * KERN_INVALID_ARGUMENT The task is null.
1166 * KERN_FAILURE The task/space is dead.
1167 * KERN_INVALID_ARGUMENT Invalid special port.
1168 * KERN_NO_ACCESS Attempted overwrite of seatbelt port.
1172 task_set_special_port(
1180 if (task
== TASK_NULL
) {
1181 return KERN_INVALID_ARGUMENT
;
1184 if (task_is_driver(current_task())) {
1185 return KERN_NO_ACCESS
;
1189 case TASK_KERNEL_PORT
:
1190 whichp
= &task
->itk_sself
;
1193 case TASK_HOST_PORT
:
1194 whichp
= &task
->itk_host
;
1197 case TASK_BOOTSTRAP_PORT
:
1198 whichp
= &task
->itk_bootstrap
;
1201 case TASK_SEATBELT_PORT
:
1202 whichp
= &task
->itk_seatbelt
;
1205 case TASK_ACCESS_PORT
:
1206 whichp
= &task
->itk_task_access
;
1209 case TASK_DEBUG_CONTROL_PORT
:
1210 whichp
= &task
->itk_debug_control
;
1214 return KERN_INVALID_ARGUMENT
;
1218 if (task
->itk_self
== IP_NULL
) {
1220 return KERN_FAILURE
;
1223 /* do not allow overwrite of seatbelt or task access ports */
1224 if ((TASK_SEATBELT_PORT
== which
|| TASK_ACCESS_PORT
== which
)
1225 && IP_VALID(*whichp
)) {
1227 return KERN_NO_ACCESS
;
1234 if (IP_VALID(old
)) {
1235 ipc_port_release_send(old
);
1237 return KERN_SUCCESS
;
1242 * Routine: mach_ports_register [kernel call]
1244 * Stash a handful of port send rights in the task.
1245 * Child tasks will inherit these rights, but they
1246 * must use mach_ports_lookup to acquire them.
1248 * The rights are supplied in a (wired) kalloc'd segment.
1249 * Rights which aren't supplied are assumed to be null.
1251 * Nothing locked. If successful, consumes
1252 * the supplied rights and memory.
1254 * KERN_SUCCESS Stashed the port rights.
1255 * KERN_INVALID_ARGUMENT The task is null.
1256 * KERN_INVALID_ARGUMENT The task is dead.
1257 * KERN_INVALID_ARGUMENT The memory param is null.
1258 * KERN_INVALID_ARGUMENT Too many port rights supplied.
1262 mach_ports_register(
1264 mach_port_array_t memory
,
1265 mach_msg_type_number_t portsCnt
)
1267 ipc_port_t ports
[TASK_PORT_REGISTER_MAX
];
1270 if ((task
== TASK_NULL
) ||
1271 (portsCnt
> TASK_PORT_REGISTER_MAX
) ||
1272 (portsCnt
&& memory
== NULL
)) {
1273 return KERN_INVALID_ARGUMENT
;
1277 * Pad the port rights with nulls.
1280 for (i
= 0; i
< portsCnt
; i
++) {
1281 ports
[i
] = memory
[i
];
1283 for (; i
< TASK_PORT_REGISTER_MAX
; i
++) {
1288 if (task
->itk_self
== IP_NULL
) {
1290 return KERN_INVALID_ARGUMENT
;
1294 * Replace the old send rights with the new.
1295 * Release the old rights after unlocking.
1298 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++) {
1301 old
= task
->itk_registered
[i
];
1302 task
->itk_registered
[i
] = ports
[i
];
1308 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++) {
1309 if (IP_VALID(ports
[i
])) {
1310 ipc_port_release_send(ports
[i
]);
1315 * Now that the operation is known to be successful,
1316 * we can free the memory.
1319 if (portsCnt
!= 0) {
1321 (vm_size_t
) (portsCnt
* sizeof(mach_port_t
)));
1324 return KERN_SUCCESS
;
1328 * Routine: mach_ports_lookup [kernel call]
1330 * Retrieves (clones) the stashed port send rights.
1332 * Nothing locked. If successful, the caller gets
1333 * rights and memory.
1335 * KERN_SUCCESS Retrieved the send rights.
1336 * KERN_INVALID_ARGUMENT The task is null.
1337 * KERN_INVALID_ARGUMENT The task is dead.
1338 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1344 mach_port_array_t
*portsp
,
1345 mach_msg_type_number_t
*portsCnt
)
1352 if (task
== TASK_NULL
) {
1353 return KERN_INVALID_ARGUMENT
;
1356 size
= (vm_size_t
) (TASK_PORT_REGISTER_MAX
* sizeof(ipc_port_t
));
1358 memory
= kalloc(size
);
1360 return KERN_RESOURCE_SHORTAGE
;
1364 if (task
->itk_self
== IP_NULL
) {
1367 kfree(memory
, size
);
1368 return KERN_INVALID_ARGUMENT
;
1371 ports
= (ipc_port_t
*) memory
;
1374 * Clone port rights. Because kalloc'd memory
1375 * is wired, we won't fault while holding the task lock.
1378 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++) {
1379 ports
[i
] = ipc_port_copy_send(task
->itk_registered
[i
]);
1384 *portsp
= (mach_port_array_t
) ports
;
1385 *portsCnt
= TASK_PORT_REGISTER_MAX
;
1386 return KERN_SUCCESS
;
1390 task_conversion_eval(task_t caller
, task_t victim
)
1393 * Tasks are allowed to resolve their own task ports, and the kernel is
1394 * allowed to resolve anyone's task port.
1396 if (caller
== kernel_task
) {
1397 return KERN_SUCCESS
;
1400 if (caller
== victim
) {
1401 return KERN_SUCCESS
;
1405 * Only the kernel can can resolve the kernel's task port. We've established
1406 * by this point that the caller is not kernel_task.
1408 if (victim
== TASK_NULL
|| victim
== kernel_task
) {
1409 return KERN_INVALID_SECURITY
;
1414 * On embedded platforms, only a platform binary can resolve the task port
1415 * of another platform binary.
1417 if ((victim
->t_flags
& TF_PLATFORM
) && !(caller
->t_flags
& TF_PLATFORM
)) {
1419 return KERN_INVALID_SECURITY
;
1421 if (cs_relax_platform_task_ports
) {
1422 return KERN_SUCCESS
;
1424 return KERN_INVALID_SECURITY
;
1426 #endif /* SECURE_KERNEL */
1428 #endif /* CONFIG_EMBEDDED */
1430 return KERN_SUCCESS
;
1434 * Routine: convert_port_to_locked_task
1436 * Internal helper routine to convert from a port to a locked
1437 * task. Used by several routines that try to convert from a
1438 * task port to a reference on some task related object.
1440 * Nothing locked, blocking OK.
1443 convert_port_to_locked_task(ipc_port_t port
)
1445 int try_failed_count
= 0;
1447 while (IP_VALID(port
)) {
1448 task_t ct
= current_task();
1452 if (!ip_active(port
) || (ip_kotype(port
) != IKOT_TASK
)) {
1456 task
= (task_t
) port
->ip_kobject
;
1457 assert(task
!= TASK_NULL
);
1459 if (task_conversion_eval(ct
, task
)) {
1465 * Normal lock ordering puts task_lock() before ip_lock().
1466 * Attempt out-of-order locking here.
1468 if (task_lock_try(task
)) {
1475 mutex_pause(try_failed_count
);
1481 * Routine: convert_port_to_locked_task_inspect
1483 * Internal helper routine to convert from a port to a locked
1484 * task inspect right. Used by internal routines that try to convert from a
1485 * task inspect port to a reference on some task related object.
1487 * Nothing locked, blocking OK.
1490 convert_port_to_locked_task_inspect(ipc_port_t port
)
1492 int try_failed_count
= 0;
1494 while (IP_VALID(port
)) {
1495 task_inspect_t task
;
1498 if (!ip_active(port
) || (ip_kotype(port
) != IKOT_TASK
)) {
1500 return TASK_INSPECT_NULL
;
1502 task
= (task_inspect_t
)port
->ip_kobject
;
1503 assert(task
!= TASK_INSPECT_NULL
);
1505 * Normal lock ordering puts task_lock() before ip_lock().
1506 * Attempt out-of-order locking here.
1508 if (task_lock_try((task_t
)task
)) {
1515 mutex_pause(try_failed_count
);
1517 return TASK_INSPECT_NULL
;
1521 convert_port_to_task_locked(
1523 uint32_t *exec_token
)
1525 task_t task
= TASK_NULL
;
1528 require_ip_active(port
);
1530 if (ip_kotype(port
) == IKOT_TASK
) {
1531 task_t ct
= current_task();
1532 task
= (task_t
)port
->ip_kobject
;
1533 assert(task
!= TASK_NULL
);
1535 if (task_conversion_eval(ct
, task
)) {
1540 *exec_token
= task
->exec_token
;
1542 task_reference_internal(task
);
1549 * Routine: convert_port_to_task_with_exec_token
1551 * Convert from a port to a task and return
1552 * the exec token stored in the task.
1553 * Doesn't consume the port ref; produces a task ref,
1554 * which may be null.
1559 convert_port_to_task_with_exec_token(
1561 uint32_t *exec_token
)
1563 task_t task
= TASK_NULL
;
1565 if (IP_VALID(port
)) {
1567 if (ip_active(port
)) {
1568 task
= convert_port_to_task_locked(port
, exec_token
);
1577 * Routine: convert_port_to_task
1579 * Convert from a port to a task.
1580 * Doesn't consume the port ref; produces a task ref,
1581 * which may be null.
1586 convert_port_to_task(
1589 return convert_port_to_task_with_exec_token(port
, NULL
);
1594 * Routine: convert_port_to_task_name
1596 * Convert from a port to a task name.
1597 * Doesn't consume the port ref; produces a task name ref,
1598 * which may be null.
1603 convert_port_to_task_name(
1606 task_name_t task
= TASK_NULL
;
1608 if (IP_VALID(port
)) {
1611 if (ip_active(port
) &&
1612 (ip_kotype(port
) == IKOT_TASK
||
1613 ip_kotype(port
) == IKOT_TASK_NAME
)) {
1614 task
= (task_name_t
)port
->ip_kobject
;
1615 assert(task
!= TASK_NAME_NULL
);
1617 task_reference_internal(task
);
1626 static task_inspect_t
1627 convert_port_to_task_inspect_locked(
1630 task_inspect_t task
= TASK_INSPECT_NULL
;
1633 require_ip_active(port
);
1635 if (ip_kotype(port
) == IKOT_TASK
) {
1636 task
= (task_inspect_t
)port
->ip_kobject
;
1637 assert(task
!= TASK_INSPECT_NULL
);
1639 task_reference_internal(task
);
1646 * Routine: convert_port_to_task_inspect
1648 * Convert from a port to a task inspection right
1649 * Doesn't consume the port ref; produces a task ref,
1650 * which may be null.
1655 convert_port_to_task_inspect(
1658 task_inspect_t task
= TASK_INSPECT_NULL
;
1660 if (IP_VALID(port
)) {
1662 if (ip_active(port
)) {
1663 task
= convert_port_to_task_inspect_locked(port
);
1672 * Routine: convert_port_to_task_suspension_token
1674 * Convert from a port to a task suspension token.
1675 * Doesn't consume the port ref; produces a suspension token ref,
1676 * which may be null.
1680 task_suspension_token_t
1681 convert_port_to_task_suspension_token(
1684 task_suspension_token_t task
= TASK_NULL
;
1686 if (IP_VALID(port
)) {
1689 if (ip_active(port
) &&
1690 ip_kotype(port
) == IKOT_TASK_RESUME
) {
1691 task
= (task_suspension_token_t
)port
->ip_kobject
;
1692 assert(task
!= TASK_NULL
);
1694 task_reference_internal(task
);
1704 * Routine: convert_port_to_space
1706 * Convert from a port to a space.
1707 * Doesn't consume the port ref; produces a space ref,
1708 * which may be null.
1713 convert_port_to_space(
1719 task
= convert_port_to_locked_task(port
);
1721 if (task
== TASK_NULL
) {
1722 return IPC_SPACE_NULL
;
1725 if (!task
->active
) {
1727 return IPC_SPACE_NULL
;
1730 space
= task
->itk_space
;
1731 is_reference(space
);
1737 * Routine: convert_port_to_space_inspect
1739 * Convert from a port to a space inspect right.
1740 * Doesn't consume the port ref; produces a space inspect ref,
1741 * which may be null.
1746 convert_port_to_space_inspect(
1749 ipc_space_inspect_t space
;
1750 task_inspect_t task
;
1752 task
= convert_port_to_locked_task_inspect(port
);
1754 if (task
== TASK_INSPECT_NULL
) {
1755 return IPC_SPACE_INSPECT_NULL
;
1758 if (!task
->active
) {
1760 return IPC_SPACE_INSPECT_NULL
;
1763 space
= (ipc_space_inspect_t
)task
->itk_space
;
1764 is_reference((ipc_space_t
)space
);
1765 task_unlock((task_t
)task
);
1770 * Routine: convert_port_to_map
1772 * Convert from a port to a map.
1773 * Doesn't consume the port ref; produces a map ref,
1774 * which may be null.
1780 convert_port_to_map(
1786 task
= convert_port_to_locked_task(port
);
1788 if (task
== TASK_NULL
) {
1792 if (!task
->active
) {
1798 vm_map_reference_swap(map
);
1805 * Routine: convert_port_to_thread
1807 * Convert from a port to a thread.
1808 * Doesn't consume the port ref; produces an thread ref,
1809 * which may be null.
1815 convert_port_to_thread_locked(
1817 port_to_thread_options_t options
)
1819 thread_t thread
= THREAD_NULL
;
1822 require_ip_active(port
);
1824 if (ip_kotype(port
) == IKOT_THREAD
) {
1825 thread
= (thread_t
)port
->ip_kobject
;
1826 assert(thread
!= THREAD_NULL
);
1828 if (options
& PORT_TO_THREAD_NOT_CURRENT_THREAD
) {
1829 if (thread
== current_thread()) {
1834 if (options
& PORT_TO_THREAD_IN_CURRENT_TASK
) {
1835 if (thread
->task
!= current_task()) {
1839 /* Use task conversion rules for thread control conversions */
1840 if (task_conversion_eval(current_task(), thread
->task
) != KERN_SUCCESS
) {
1845 thread_reference_internal(thread
);
1852 convert_port_to_thread(
1855 thread_t thread
= THREAD_NULL
;
1857 if (IP_VALID(port
)) {
1859 if (ip_active(port
)) {
1860 thread
= convert_port_to_thread_locked(port
, PORT_TO_THREAD_NONE
);
1869 * Routine: convert_port_to_thread_inspect
1871 * Convert from a port to a thread inspection right
1872 * Doesn't consume the port ref; produces a thread ref,
1873 * which may be null.
1878 convert_port_to_thread_inspect(
1881 thread_inspect_t thread
= THREAD_INSPECT_NULL
;
1883 if (IP_VALID(port
)) {
1886 if (ip_active(port
) &&
1887 ip_kotype(port
) == IKOT_THREAD
) {
1888 thread
= (thread_inspect_t
)port
->ip_kobject
;
1889 assert(thread
!= THREAD_INSPECT_NULL
);
1890 thread_reference_internal((thread_t
)thread
);
1899 * Routine: convert_thread_inspect_to_port
1901 * Convert from a thread inspect reference to a port.
1902 * Consumes a thread ref;
1903 * As we never export thread inspect ports, always
1904 * creates a NULL port.
1910 convert_thread_inspect_to_port(thread_inspect_t thread
)
1912 thread_deallocate(thread
);
1918 * Routine: port_name_to_thread
1920 * Convert from a port name to an thread reference
1921 * A name of MACH_PORT_NULL is valid for the null thread.
1926 port_name_to_thread(
1927 mach_port_name_t name
,
1928 port_to_thread_options_t options
)
1930 thread_t thread
= THREAD_NULL
;
1934 if (MACH_PORT_VALID(name
)) {
1935 kr
= ipc_port_translate_send(current_space(), name
, &kport
);
1936 if (kr
== KERN_SUCCESS
) {
1937 thread
= convert_port_to_thread_locked(kport
, options
);
1947 mach_port_name_t name
)
1951 task_t task
= TASK_NULL
;
1953 if (MACH_PORT_VALID(name
)) {
1954 kr
= ipc_port_translate_send(current_space(), name
, &kport
);
1955 if (kr
== KERN_SUCCESS
) {
1956 task
= convert_port_to_task_locked(kport
, NULL
);
1964 port_name_to_task_inspect(
1965 mach_port_name_t name
)
1969 task_inspect_t ti
= TASK_INSPECT_NULL
;
1971 if (MACH_PORT_VALID(name
)) {
1972 kr
= ipc_port_translate_send(current_space(), name
, &kport
);
1973 if (kr
== KERN_SUCCESS
) {
1974 ti
= convert_port_to_task_inspect_locked(kport
);
1982 * Routine: port_name_to_host
1984 * Convert from a port name to a host pointer.
1985 * NOTE: This does _not_ return a +1 reference to the host_t
1991 mach_port_name_t name
)
1993 host_t host
= HOST_NULL
;
1997 if (MACH_PORT_VALID(name
)) {
1998 kr
= ipc_port_translate_send(current_space(), name
, &port
);
1999 if (kr
== KERN_SUCCESS
) {
2000 host
= convert_port_to_host(port
);
2008 * Routine: convert_task_to_port
2010 * Convert from a task to a port.
2011 * Consumes a task ref; produces a naked send right
2012 * which may be invalid.
2018 convert_task_to_port(
2025 if (task
->itk_self
!= IP_NULL
) {
2026 port
= ipc_port_make_send(task
->itk_self
);
2033 task_deallocate(task
);
2038 * Routine: convert_task_inspect_to_port
2040 * Convert from a task inspect reference to a port.
2041 * Consumes a task ref;
2042 * As we never export task inspect ports, always
2043 * creates a NULL port.
2048 convert_task_inspect_to_port(
2049 task_inspect_t task
)
2051 task_deallocate(task
);
2057 * Routine: convert_task_suspend_token_to_port
2059 * Convert from a task suspension token to a port.
2060 * Consumes a task suspension token ref; produces a naked send-once right
2061 * which may be invalid.
2066 convert_task_suspension_token_to_port(
2067 task_suspension_token_t task
)
2073 if (task
->itk_resume
== IP_NULL
) {
2074 task
->itk_resume
= ipc_kobject_alloc_port((ipc_kobject_t
) task
,
2075 IKOT_TASK_RESUME
, IPC_KOBJECT_ALLOC_NONE
);
2079 * Create a send-once right for each instance of a direct user-called
2080 * task_suspend2 call. Each time one of these send-once rights is abandoned,
2081 * the notification handler will resume the target task.
2083 port
= ipc_port_make_sonce(task
->itk_resume
);
2084 assert(IP_VALID(port
));
2090 task_suspension_token_deallocate(task
);
2097 * Routine: convert_task_name_to_port
2099 * Convert from a task name ref to a port.
2100 * Consumes a task name ref; produces a naked send right
2101 * which may be invalid.
2107 convert_task_name_to_port(
2108 task_name_t task_name
)
2112 itk_lock(task_name
);
2113 if (task_name
->itk_nself
!= IP_NULL
) {
2114 port
= ipc_port_make_send(task_name
->itk_nself
);
2118 itk_unlock(task_name
);
2120 task_name_deallocate(task_name
);
2125 * Routine: convert_thread_to_port
2127 * Convert from a thread to a port.
2128 * Consumes an thread ref; produces a naked send right
2129 * which may be invalid.
2135 convert_thread_to_port(
2140 thread_mtx_lock(thread
);
2142 if (thread
->ith_self
!= IP_NULL
) {
2143 port
= ipc_port_make_send(thread
->ith_self
);
2148 thread_mtx_unlock(thread
);
2150 thread_deallocate(thread
);
2156 * Routine: space_deallocate
2158 * Deallocate a space ref produced by convert_port_to_space.
2167 if (space
!= IS_NULL
) {
2173 * Routine: space_inspect_deallocate
2175 * Deallocate a space inspect ref produced by convert_port_to_space_inspect.
2181 space_inspect_deallocate(
2182 ipc_space_inspect_t space
)
2184 if (space
!= IS_INSPECT_NULL
) {
2185 is_release((ipc_space_t
)space
);
2190 * Routine: thread/task_set_exception_ports [kernel call]
2192 * Sets the thread/task exception port, flavor and
2193 * behavior for the exception types specified by the mask.
2194 * There will be one send right per exception per valid
2197 * Nothing locked. If successful, consumes
2198 * the supplied send right.
2200 * KERN_SUCCESS Changed the special port.
2201 * KERN_INVALID_ARGUMENT The thread is null,
2202 * Illegal mask bit set.
2203 * Illegal exception behavior
2204 * KERN_FAILURE The thread is dead.
2208 thread_set_exception_ports(
2210 exception_mask_t exception_mask
,
2211 ipc_port_t new_port
,
2212 exception_behavior_t new_behavior
,
2213 thread_state_flavor_t new_flavor
)
2215 ipc_port_t old_port
[EXC_TYPES_COUNT
];
2216 boolean_t privileged
= current_task()->sec_token
.val
[0] == 0;
2220 struct label
*new_label
;
2223 if (thread
== THREAD_NULL
) {
2224 return KERN_INVALID_ARGUMENT
;
2227 if (exception_mask
& ~EXC_MASK_VALID
) {
2228 return KERN_INVALID_ARGUMENT
;
2231 if (IP_VALID(new_port
)) {
2232 switch (new_behavior
& ~MACH_EXCEPTION_MASK
) {
2233 case EXCEPTION_DEFAULT
:
2234 case EXCEPTION_STATE
:
2235 case EXCEPTION_STATE_IDENTITY
:
2239 return KERN_INVALID_ARGUMENT
;
2244 * Check the validity of the thread_state_flavor by calling the
2245 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in
2246 * osfmk/mach/ARCHITECTURE/thread_status.h
2248 if (new_flavor
!= 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor
)) {
2249 return KERN_INVALID_ARGUMENT
;
2253 new_label
= mac_exc_create_label_for_current_proc();
2256 thread_mtx_lock(thread
);
2258 if (!thread
->active
) {
2259 thread_mtx_unlock(thread
);
2261 return KERN_FAILURE
;
2264 if (thread
->exc_actions
== NULL
) {
2265 ipc_thread_init_exc_actions(thread
);
2267 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
2268 if ((exception_mask
& (1 << i
))
2270 && mac_exc_update_action_label(&thread
->exc_actions
[i
], new_label
) == 0
2273 old_port
[i
] = thread
->exc_actions
[i
].port
;
2274 thread
->exc_actions
[i
].port
= ipc_port_copy_send(new_port
);
2275 thread
->exc_actions
[i
].behavior
= new_behavior
;
2276 thread
->exc_actions
[i
].flavor
= new_flavor
;
2277 thread
->exc_actions
[i
].privileged
= privileged
;
2279 old_port
[i
] = IP_NULL
;
2283 thread_mtx_unlock(thread
);
2286 mac_exc_free_label(new_label
);
2289 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
2290 if (IP_VALID(old_port
[i
])) {
2291 ipc_port_release_send(old_port
[i
]);
2295 if (IP_VALID(new_port
)) { /* consume send right */
2296 ipc_port_release_send(new_port
);
2299 return KERN_SUCCESS
;
2303 task_set_exception_ports(
2305 exception_mask_t exception_mask
,
2306 ipc_port_t new_port
,
2307 exception_behavior_t new_behavior
,
2308 thread_state_flavor_t new_flavor
)
2310 ipc_port_t old_port
[EXC_TYPES_COUNT
];
2311 boolean_t privileged
= current_task()->sec_token
.val
[0] == 0;
2315 struct label
*new_label
;
2318 if (task
== TASK_NULL
) {
2319 return KERN_INVALID_ARGUMENT
;
2322 if (exception_mask
& ~EXC_MASK_VALID
) {
2323 return KERN_INVALID_ARGUMENT
;
2326 if (IP_VALID(new_port
)) {
2327 switch (new_behavior
& ~MACH_EXCEPTION_MASK
) {
2328 case EXCEPTION_DEFAULT
:
2329 case EXCEPTION_STATE
:
2330 case EXCEPTION_STATE_IDENTITY
:
2334 return KERN_INVALID_ARGUMENT
;
2339 * Check the validity of the thread_state_flavor by calling the
2340 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in
2341 * osfmk/mach/ARCHITECTURE/thread_status.h
2343 if (new_flavor
!= 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor
)) {
2344 return KERN_INVALID_ARGUMENT
;
2348 new_label
= mac_exc_create_label_for_current_proc();
2353 if (task
->itk_self
== IP_NULL
) {
2356 return KERN_FAILURE
;
2359 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
2360 if ((exception_mask
& (1 << i
))
2362 && mac_exc_update_action_label(&task
->exc_actions
[i
], new_label
) == 0
2365 old_port
[i
] = task
->exc_actions
[i
].port
;
2366 task
->exc_actions
[i
].port
=
2367 ipc_port_copy_send(new_port
);
2368 task
->exc_actions
[i
].behavior
= new_behavior
;
2369 task
->exc_actions
[i
].flavor
= new_flavor
;
2370 task
->exc_actions
[i
].privileged
= privileged
;
2372 old_port
[i
] = IP_NULL
;
2379 mac_exc_free_label(new_label
);
2382 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
2383 if (IP_VALID(old_port
[i
])) {
2384 ipc_port_release_send(old_port
[i
]);
2388 if (IP_VALID(new_port
)) { /* consume send right */
2389 ipc_port_release_send(new_port
);
2392 return KERN_SUCCESS
;
2396 * Routine: thread/task_swap_exception_ports [kernel call]
2398 * Sets the thread/task exception port, flavor and
2399 * behavior for the exception types specified by the
2402 * The old ports, behavior and flavors are returned
2403 * Count specifies the array sizes on input and
2404 * the number of returned ports etc. on output. The
2405 * arrays must be large enough to hold all the returned
2406 * data, MIG returnes an error otherwise. The masks
2407 * array specifies the corresponding exception type(s).
2410 * Nothing locked. If successful, consumes
2411 * the supplied send right.
2413 * Returns upto [in} CountCnt elements.
2415 * KERN_SUCCESS Changed the special port.
2416 * KERN_INVALID_ARGUMENT The thread is null,
2417 * Illegal mask bit set.
2418 * Illegal exception behavior
2419 * KERN_FAILURE The thread is dead.
2423 thread_swap_exception_ports(
2425 exception_mask_t exception_mask
,
2426 ipc_port_t new_port
,
2427 exception_behavior_t new_behavior
,
2428 thread_state_flavor_t new_flavor
,
2429 exception_mask_array_t masks
,
2430 mach_msg_type_number_t
*CountCnt
,
2431 exception_port_array_t ports
,
2432 exception_behavior_array_t behaviors
,
2433 thread_state_flavor_array_t flavors
)
2435 ipc_port_t old_port
[EXC_TYPES_COUNT
];
2436 boolean_t privileged
= current_task()->sec_token
.val
[0] == 0;
2437 unsigned int i
, j
, count
;
2440 struct label
*new_label
;
2443 if (thread
== THREAD_NULL
) {
2444 return KERN_INVALID_ARGUMENT
;
2447 if (exception_mask
& ~EXC_MASK_VALID
) {
2448 return KERN_INVALID_ARGUMENT
;
2451 if (IP_VALID(new_port
)) {
2452 switch (new_behavior
& ~MACH_EXCEPTION_MASK
) {
2453 case EXCEPTION_DEFAULT
:
2454 case EXCEPTION_STATE
:
2455 case EXCEPTION_STATE_IDENTITY
:
2459 return KERN_INVALID_ARGUMENT
;
2463 if (new_flavor
!= 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor
)) {
2464 return KERN_INVALID_ARGUMENT
;
2468 new_label
= mac_exc_create_label_for_current_proc();
2471 thread_mtx_lock(thread
);
2473 if (!thread
->active
) {
2474 thread_mtx_unlock(thread
);
2476 return KERN_FAILURE
;
2479 if (thread
->exc_actions
== NULL
) {
2480 ipc_thread_init_exc_actions(thread
);
2483 assert(EXC_TYPES_COUNT
> FIRST_EXCEPTION
);
2484 for (count
= 0, i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
&& count
< *CountCnt
; ++i
) {
2485 if ((exception_mask
& (1 << i
))
2487 && mac_exc_update_action_label(&thread
->exc_actions
[i
], new_label
) == 0
2490 for (j
= 0; j
< count
; ++j
) {
2492 * search for an identical entry, if found
2493 * set corresponding mask for this exception.
2495 if (thread
->exc_actions
[i
].port
== ports
[j
] &&
2496 thread
->exc_actions
[i
].behavior
== behaviors
[j
] &&
2497 thread
->exc_actions
[i
].flavor
== flavors
[j
]) {
2498 masks
[j
] |= (1 << i
);
2504 masks
[j
] = (1 << i
);
2505 ports
[j
] = ipc_port_copy_send(thread
->exc_actions
[i
].port
);
2507 behaviors
[j
] = thread
->exc_actions
[i
].behavior
;
2508 flavors
[j
] = thread
->exc_actions
[i
].flavor
;
2512 old_port
[i
] = thread
->exc_actions
[i
].port
;
2513 thread
->exc_actions
[i
].port
= ipc_port_copy_send(new_port
);
2514 thread
->exc_actions
[i
].behavior
= new_behavior
;
2515 thread
->exc_actions
[i
].flavor
= new_flavor
;
2516 thread
->exc_actions
[i
].privileged
= privileged
;
2518 old_port
[i
] = IP_NULL
;
2522 thread_mtx_unlock(thread
);
2525 mac_exc_free_label(new_label
);
2528 while (--i
>= FIRST_EXCEPTION
) {
2529 if (IP_VALID(old_port
[i
])) {
2530 ipc_port_release_send(old_port
[i
]);
2534 if (IP_VALID(new_port
)) { /* consume send right */
2535 ipc_port_release_send(new_port
);
2540 return KERN_SUCCESS
;
2544 task_swap_exception_ports(
2546 exception_mask_t exception_mask
,
2547 ipc_port_t new_port
,
2548 exception_behavior_t new_behavior
,
2549 thread_state_flavor_t new_flavor
,
2550 exception_mask_array_t masks
,
2551 mach_msg_type_number_t
*CountCnt
,
2552 exception_port_array_t ports
,
2553 exception_behavior_array_t behaviors
,
2554 thread_state_flavor_array_t flavors
)
2556 ipc_port_t old_port
[EXC_TYPES_COUNT
];
2557 boolean_t privileged
= current_task()->sec_token
.val
[0] == 0;
2558 unsigned int i
, j
, count
;
2561 struct label
*new_label
;
2564 if (task
== TASK_NULL
) {
2565 return KERN_INVALID_ARGUMENT
;
2568 if (exception_mask
& ~EXC_MASK_VALID
) {
2569 return KERN_INVALID_ARGUMENT
;
2572 if (IP_VALID(new_port
)) {
2573 switch (new_behavior
& ~MACH_EXCEPTION_MASK
) {
2574 case EXCEPTION_DEFAULT
:
2575 case EXCEPTION_STATE
:
2576 case EXCEPTION_STATE_IDENTITY
:
2580 return KERN_INVALID_ARGUMENT
;
2584 if (new_flavor
!= 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor
)) {
2585 return KERN_INVALID_ARGUMENT
;
2589 new_label
= mac_exc_create_label_for_current_proc();
2594 if (task
->itk_self
== IP_NULL
) {
2597 return KERN_FAILURE
;
2600 assert(EXC_TYPES_COUNT
> FIRST_EXCEPTION
);
2601 for (count
= 0, i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
&& count
< *CountCnt
; ++i
) {
2602 if ((exception_mask
& (1 << i
))
2604 && mac_exc_update_action_label(&task
->exc_actions
[i
], new_label
) == 0
2607 for (j
= 0; j
< count
; j
++) {
2609 * search for an identical entry, if found
2610 * set corresponding mask for this exception.
2612 if (task
->exc_actions
[i
].port
== ports
[j
] &&
2613 task
->exc_actions
[i
].behavior
== behaviors
[j
] &&
2614 task
->exc_actions
[i
].flavor
== flavors
[j
]) {
2615 masks
[j
] |= (1 << i
);
2621 masks
[j
] = (1 << i
);
2622 ports
[j
] = ipc_port_copy_send(task
->exc_actions
[i
].port
);
2623 behaviors
[j
] = task
->exc_actions
[i
].behavior
;
2624 flavors
[j
] = task
->exc_actions
[i
].flavor
;
2628 old_port
[i
] = task
->exc_actions
[i
].port
;
2630 task
->exc_actions
[i
].port
= ipc_port_copy_send(new_port
);
2631 task
->exc_actions
[i
].behavior
= new_behavior
;
2632 task
->exc_actions
[i
].flavor
= new_flavor
;
2633 task
->exc_actions
[i
].privileged
= privileged
;
2635 old_port
[i
] = IP_NULL
;
2642 mac_exc_free_label(new_label
);
2645 while (--i
>= FIRST_EXCEPTION
) {
2646 if (IP_VALID(old_port
[i
])) {
2647 ipc_port_release_send(old_port
[i
]);
2651 if (IP_VALID(new_port
)) { /* consume send right */
2652 ipc_port_release_send(new_port
);
2657 return KERN_SUCCESS
;
2661 * Routine: thread/task_get_exception_ports [kernel call]
2663 * Clones a send right for each of the thread/task's exception
2664 * ports specified in the mask and returns the behaviour
2665 * and flavor of said port.
2667 * Returns upto [in} CountCnt elements.
2672 * KERN_SUCCESS Extracted a send right.
2673 * KERN_INVALID_ARGUMENT The thread is null,
2674 * Invalid special port,
2675 * Illegal mask bit set.
2676 * KERN_FAILURE The thread is dead.
2680 thread_get_exception_ports(
2682 exception_mask_t exception_mask
,
2683 exception_mask_array_t masks
,
2684 mach_msg_type_number_t
*CountCnt
,
2685 exception_port_array_t ports
,
2686 exception_behavior_array_t behaviors
,
2687 thread_state_flavor_array_t flavors
)
2689 unsigned int i
, j
, count
;
2691 if (thread
== THREAD_NULL
) {
2692 return KERN_INVALID_ARGUMENT
;
2695 if (exception_mask
& ~EXC_MASK_VALID
) {
2696 return KERN_INVALID_ARGUMENT
;
2699 thread_mtx_lock(thread
);
2701 if (!thread
->active
) {
2702 thread_mtx_unlock(thread
);
2704 return KERN_FAILURE
;
2709 if (thread
->exc_actions
== NULL
) {
2713 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
2714 if (exception_mask
& (1 << i
)) {
2715 for (j
= 0; j
< count
; ++j
) {
2717 * search for an identical entry, if found
2718 * set corresponding mask for this exception.
2720 if (thread
->exc_actions
[i
].port
== ports
[j
] &&
2721 thread
->exc_actions
[i
].behavior
== behaviors
[j
] &&
2722 thread
->exc_actions
[i
].flavor
== flavors
[j
]) {
2723 masks
[j
] |= (1 << i
);
2729 masks
[j
] = (1 << i
);
2730 ports
[j
] = ipc_port_copy_send(thread
->exc_actions
[i
].port
);
2731 behaviors
[j
] = thread
->exc_actions
[i
].behavior
;
2732 flavors
[j
] = thread
->exc_actions
[i
].flavor
;
2734 if (count
>= *CountCnt
) {
2742 thread_mtx_unlock(thread
);
2746 return KERN_SUCCESS
;
2750 task_get_exception_ports(
2752 exception_mask_t exception_mask
,
2753 exception_mask_array_t masks
,
2754 mach_msg_type_number_t
*CountCnt
,
2755 exception_port_array_t ports
,
2756 exception_behavior_array_t behaviors
,
2757 thread_state_flavor_array_t flavors
)
2759 unsigned int i
, j
, count
;
2761 if (task
== TASK_NULL
) {
2762 return KERN_INVALID_ARGUMENT
;
2765 if (exception_mask
& ~EXC_MASK_VALID
) {
2766 return KERN_INVALID_ARGUMENT
;
2771 if (task
->itk_self
== IP_NULL
) {
2774 return KERN_FAILURE
;
2779 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
2780 if (exception_mask
& (1 << i
)) {
2781 for (j
= 0; j
< count
; ++j
) {
2783 * search for an identical entry, if found
2784 * set corresponding mask for this exception.
2786 if (task
->exc_actions
[i
].port
== ports
[j
] &&
2787 task
->exc_actions
[i
].behavior
== behaviors
[j
] &&
2788 task
->exc_actions
[i
].flavor
== flavors
[j
]) {
2789 masks
[j
] |= (1 << i
);
2795 masks
[j
] = (1 << i
);
2796 ports
[j
] = ipc_port_copy_send(task
->exc_actions
[i
].port
);
2797 behaviors
[j
] = task
->exc_actions
[i
].behavior
;
2798 flavors
[j
] = task
->exc_actions
[i
].flavor
;
2800 if (count
> *CountCnt
) {
2811 return KERN_SUCCESS
;