2 * Copyright (c) 2000-2007 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_sself
= ipc_port_make_send(kport
);
146 task
->itk_space
= space
;
147 space
->is_fast
= FALSE
;
151 mac_task_label_associate(parent
, task
, &parent
->maclabel
,
152 &task
->maclabel
, &kport
->ip_label
);
154 mac_task_label_associate_kernel(task
, &task
->maclabel
, &kport
->ip_label
);
157 if (parent
== TASK_NULL
) {
160 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
161 task
->exc_actions
[i
].port
= IP_NULL
;
164 kr
= host_get_host_port(host_priv_self(), &port
);
165 assert(kr
== KERN_SUCCESS
);
166 task
->itk_host
= port
;
168 task
->itk_bootstrap
= IP_NULL
;
169 task
->itk_seatbelt
= IP_NULL
;
170 task
->itk_gssd
= IP_NULL
;
171 task
->itk_task_access
= IP_NULL
;
173 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
174 task
->itk_registered
[i
] = IP_NULL
;
177 assert(parent
->itk_self
!= IP_NULL
);
179 /* inherit registered ports */
181 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
182 task
->itk_registered
[i
] =
183 ipc_port_copy_send(parent
->itk_registered
[i
]);
185 /* inherit exception and bootstrap ports */
187 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
188 task
->exc_actions
[i
].port
=
189 ipc_port_copy_send(parent
->exc_actions
[i
].port
);
190 task
->exc_actions
[i
].flavor
=
191 parent
->exc_actions
[i
].flavor
;
192 task
->exc_actions
[i
].behavior
=
193 parent
->exc_actions
[i
].behavior
;
194 task
->exc_actions
[i
].privileged
=
195 parent
->exc_actions
[i
].privileged
;
198 ipc_port_copy_send(parent
->itk_host
);
200 task
->itk_bootstrap
=
201 ipc_port_copy_send(parent
->itk_bootstrap
);
204 ipc_port_copy_send(parent
->itk_seatbelt
);
207 ipc_port_copy_send(parent
->itk_gssd
);
209 task
->itk_task_access
=
210 ipc_port_copy_send(parent
->itk_task_access
);
217 * Routine: ipc_task_enable
219 * Enable a task for IPC access.
232 kport
= task
->itk_self
;
233 if (kport
!= IP_NULL
)
234 ipc_kobject_set(kport
, (ipc_kobject_t
) task
, IKOT_TASK
);
235 nport
= task
->itk_nself
;
236 if (nport
!= IP_NULL
)
237 ipc_kobject_set(nport
, (ipc_kobject_t
) task
, IKOT_TASK_NAME
);
242 * Routine: ipc_task_disable
244 * Disable IPC access to a task.
257 kport
= task
->itk_self
;
258 if (kport
!= IP_NULL
)
259 ipc_kobject_set(kport
, IKO_NULL
, IKOT_NONE
);
260 nport
= task
->itk_nself
;
261 if (nport
!= IP_NULL
)
262 ipc_kobject_set(nport
, IKO_NULL
, IKOT_NONE
);
267 * Routine: ipc_task_terminate
269 * Clean up and destroy a task's IPC state.
271 * Nothing locked. The task must be suspended.
272 * (Or the current thread must be in the task.)
284 kport
= task
->itk_self
;
286 if (kport
== IP_NULL
) {
287 /* the task is already terminated (can this happen?) */
291 task
->itk_self
= IP_NULL
;
293 nport
= task
->itk_nself
;
294 assert(nport
!= IP_NULL
);
295 task
->itk_nself
= IP_NULL
;
299 /* release the naked send rights */
301 if (IP_VALID(task
->itk_sself
))
302 ipc_port_release_send(task
->itk_sself
);
304 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
305 if (IP_VALID(task
->exc_actions
[i
].port
)) {
306 ipc_port_release_send(task
->exc_actions
[i
].port
);
310 if (IP_VALID(task
->itk_host
))
311 ipc_port_release_send(task
->itk_host
);
313 if (IP_VALID(task
->itk_bootstrap
))
314 ipc_port_release_send(task
->itk_bootstrap
);
316 if (IP_VALID(task
->itk_seatbelt
))
317 ipc_port_release_send(task
->itk_seatbelt
);
319 if (IP_VALID(task
->itk_gssd
))
320 ipc_port_release_send(task
->itk_gssd
);
322 if (IP_VALID(task
->itk_task_access
))
323 ipc_port_release_send(task
->itk_task_access
);
325 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
326 if (IP_VALID(task
->itk_registered
[i
]))
327 ipc_port_release_send(task
->itk_registered
[i
]);
329 ipc_port_release_send(task
->wired_ledger_port
);
330 ipc_port_release_send(task
->paged_ledger_port
);
332 /* destroy the kernel ports */
333 ipc_port_dealloc_kernel(kport
);
334 ipc_port_dealloc_kernel(nport
);
336 itk_lock_destroy(task
);
340 * Routine: ipc_task_reset
342 * Reset a task's IPC state to protect it when
343 * it enters an elevated security context. The
344 * task name port can remain the same - since
345 * it represents no specific privilege.
347 * Nothing locked. The task must be suspended.
348 * (Or the current thread must be in the task.)
355 ipc_port_t old_kport
, new_kport
;
356 ipc_port_t old_sself
;
357 ipc_port_t old_exc_actions
[EXC_TYPES_COUNT
];
360 new_kport
= ipc_port_alloc_kernel();
361 if (new_kport
== IP_NULL
)
362 panic("ipc_task_reset");
366 old_kport
= task
->itk_self
;
368 if (old_kport
== IP_NULL
) {
369 /* the task is already terminated (can this happen?) */
371 ipc_port_dealloc_kernel(new_kport
);
375 task
->itk_self
= new_kport
;
376 old_sself
= task
->itk_sself
;
377 task
->itk_sself
= ipc_port_make_send(new_kport
);
378 ipc_kobject_set(old_kport
, IKO_NULL
, IKOT_NONE
);
379 ipc_kobject_set(new_kport
, (ipc_kobject_t
) task
, IKOT_TASK
);
381 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
382 if (!task
->exc_actions
[i
].privileged
) {
383 old_exc_actions
[i
] = task
->exc_actions
[i
].port
;
384 task
->exc_actions
[i
].port
= IP_NULL
;
386 old_exc_actions
[i
] = IP_NULL
;
392 /* release the naked send rights */
394 if (IP_VALID(old_sself
))
395 ipc_port_release_send(old_sself
);
397 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
398 if (IP_VALID(old_exc_actions
[i
])) {
399 ipc_port_release_send(old_exc_actions
[i
]);
403 /* destroy the kernel port */
404 ipc_port_dealloc_kernel(old_kport
);
408 * Routine: ipc_thread_init
410 * Initialize a thread's IPC state.
422 kport
= ipc_port_alloc_kernel();
423 if (kport
== IP_NULL
)
424 panic("ipc_thread_init");
426 thread
->ith_self
= kport
;
427 thread
->ith_sself
= ipc_port_make_send(kport
);
429 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
)
430 thread
->exc_actions
[i
].port
= IP_NULL
;
432 ipc_kobject_set(kport
, (ipc_kobject_t
)thread
, IKOT_THREAD
);
434 ipc_kmsg_queue_init(&thread
->ith_messages
);
436 thread
->ith_rpc_reply
= IP_NULL
;
443 ipc_port_t kport
= thread
->ith_self
;
445 if (kport
!= IP_NULL
)
446 ipc_kobject_set(kport
, IKO_NULL
, IKOT_NONE
);
450 * Routine: ipc_thread_terminate
452 * Clean up and destroy a thread's IPC state.
458 ipc_thread_terminate(
461 ipc_port_t kport
= thread
->ith_self
;
463 if (kport
!= IP_NULL
) {
466 if (IP_VALID(thread
->ith_sself
))
467 ipc_port_release_send(thread
->ith_sself
);
469 thread
->ith_sself
= thread
->ith_self
= IP_NULL
;
471 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
472 if (IP_VALID(thread
->exc_actions
[i
].port
))
473 ipc_port_release_send(thread
->exc_actions
[i
].port
);
476 ipc_port_dealloc_kernel(kport
);
479 assert(ipc_kmsg_queue_empty(&thread
->ith_messages
));
481 if (thread
->ith_rpc_reply
!= IP_NULL
)
482 ipc_port_dealloc_reply(thread
->ith_rpc_reply
);
484 thread
->ith_rpc_reply
= IP_NULL
;
488 * Routine: ipc_thread_reset
490 * Reset the IPC state for a given Mach thread when
491 * its task enters an elevated security context.
492 * Both the thread port and its exception ports have
493 * to be reset. Its RPC reply port cannot have any
494 * rights outstanding, so it should be fine.
503 ipc_port_t old_kport
, new_kport
;
504 ipc_port_t old_sself
;
505 ipc_port_t old_exc_actions
[EXC_TYPES_COUNT
];
508 new_kport
= ipc_port_alloc_kernel();
509 if (new_kport
== IP_NULL
)
510 panic("ipc_task_reset");
512 thread_mtx_lock(thread
);
514 old_kport
= thread
->ith_self
;
516 if (old_kport
== IP_NULL
) {
517 /* the is already terminated (can this happen?) */
518 thread_mtx_unlock(thread
);
519 ipc_port_dealloc_kernel(new_kport
);
523 thread
->ith_self
= new_kport
;
524 old_sself
= thread
->ith_sself
;
525 thread
->ith_sself
= ipc_port_make_send(new_kport
);
526 ipc_kobject_set(old_kport
, IKO_NULL
, IKOT_NONE
);
527 ipc_kobject_set(new_kport
, (ipc_kobject_t
) thread
, IKOT_THREAD
);
529 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
530 if (!thread
->exc_actions
[i
].privileged
) {
531 old_exc_actions
[i
] = thread
->exc_actions
[i
].port
;
532 thread
->exc_actions
[i
].port
= IP_NULL
;
534 old_exc_actions
[i
] = IP_NULL
;
538 thread_mtx_unlock(thread
);
540 /* release the naked send rights */
542 if (IP_VALID(old_sself
))
543 ipc_port_release_send(old_sself
);
545 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
546 if (IP_VALID(old_exc_actions
[i
])) {
547 ipc_port_release_send(old_exc_actions
[i
]);
551 /* destroy the kernel port */
552 ipc_port_dealloc_kernel(old_kport
);
556 * Routine: retrieve_task_self_fast
558 * Optimized version of retrieve_task_self,
559 * that only works for the current task.
561 * Return a send right (possibly null/dead)
562 * for the task's user-visible self port.
568 retrieve_task_self_fast(
569 register task_t task
)
571 register ipc_port_t port
;
573 assert(task
== current_task());
576 assert(task
->itk_self
!= IP_NULL
);
578 if ((port
= task
->itk_sself
) == task
->itk_self
) {
582 assert(ip_active(port
));
587 port
= ipc_port_copy_send(port
);
594 * Routine: retrieve_thread_self_fast
596 * Return a send right (possibly null/dead)
597 * for the thread's user-visible self port.
599 * Only works for the current thread.
606 retrieve_thread_self_fast(
609 register ipc_port_t port
;
611 assert(thread
== current_thread());
613 thread_mtx_lock(thread
);
615 assert(thread
->ith_self
!= IP_NULL
);
617 if ((port
= thread
->ith_sself
) == thread
->ith_self
) {
621 assert(ip_active(port
));
627 port
= ipc_port_copy_send(port
);
629 thread_mtx_unlock(thread
);
635 * Routine: task_self_trap [mach trap]
637 * Give the caller send rights for his own task port.
641 * MACH_PORT_NULL if there are any resource failures
647 __unused
struct task_self_trap_args
*args
)
649 task_t task
= current_task();
651 mach_port_name_t name
;
653 sright
= retrieve_task_self_fast(task
);
654 name
= ipc_port_copyout_send(sright
, task
->itk_space
);
659 * Routine: thread_self_trap [mach trap]
661 * Give the caller send rights for his own thread port.
665 * MACH_PORT_NULL if there are any resource failures
671 __unused
struct thread_self_trap_args
*args
)
673 thread_t thread
= current_thread();
674 task_t task
= thread
->task
;
676 mach_port_name_t name
;
678 sright
= retrieve_thread_self_fast(thread
);
679 name
= ipc_port_copyout_send(sright
, task
->itk_space
);
685 * Routine: mach_reply_port [mach trap]
687 * Allocate a port for the caller.
691 * MACH_PORT_NULL if there are any resource failures
697 __unused
struct mach_reply_port_args
*args
)
700 mach_port_name_t name
;
703 kr
= ipc_port_alloc(current_task()->itk_space
, &name
, &port
);
704 if (kr
== KERN_SUCCESS
)
707 name
= MACH_PORT_NULL
;
712 * Routine: thread_get_special_port [kernel call]
714 * Clones a send right for one of the thread's
719 * KERN_SUCCESS Extracted a send right.
720 * KERN_INVALID_ARGUMENT The thread is null.
721 * KERN_FAILURE The thread is dead.
722 * KERN_INVALID_ARGUMENT Invalid special port.
726 thread_get_special_port(
731 kern_return_t result
= KERN_SUCCESS
;
734 if (thread
== THREAD_NULL
)
735 return (KERN_INVALID_ARGUMENT
);
739 case THREAD_KERNEL_PORT
:
740 whichp
= &thread
->ith_sself
;
744 return (KERN_INVALID_ARGUMENT
);
747 thread_mtx_lock(thread
);
750 *portp
= ipc_port_copy_send(*whichp
);
752 result
= KERN_FAILURE
;
754 thread_mtx_unlock(thread
);
760 * Routine: thread_set_special_port [kernel call]
762 * Changes one of the thread's special ports,
763 * setting it to the supplied send right.
765 * Nothing locked. If successful, consumes
766 * the supplied send right.
768 * KERN_SUCCESS Changed the special port.
769 * KERN_INVALID_ARGUMENT The thread is null.
770 * KERN_FAILURE The thread is dead.
771 * KERN_INVALID_ARGUMENT Invalid special port.
775 thread_set_special_port(
780 kern_return_t result
= KERN_SUCCESS
;
781 ipc_port_t
*whichp
, old
= IP_NULL
;
783 if (thread
== THREAD_NULL
)
784 return (KERN_INVALID_ARGUMENT
);
788 case THREAD_KERNEL_PORT
:
789 whichp
= &thread
->ith_sself
;
793 return (KERN_INVALID_ARGUMENT
);
796 thread_mtx_lock(thread
);
798 if (thread
->active
) {
803 result
= KERN_FAILURE
;
805 thread_mtx_unlock(thread
);
808 ipc_port_release_send(old
);
814 * Routine: task_get_special_port [kernel call]
816 * Clones a send right for one of the task's
821 * KERN_SUCCESS Extracted a send right.
822 * KERN_INVALID_ARGUMENT The task is null.
823 * KERN_FAILURE The task/space is dead.
824 * KERN_INVALID_ARGUMENT Invalid special port.
828 task_get_special_port(
835 if (task
== TASK_NULL
)
836 return KERN_INVALID_ARGUMENT
;
839 if (task
->itk_self
== IP_NULL
) {
845 case TASK_KERNEL_PORT
:
846 port
= ipc_port_copy_send(task
->itk_sself
);
850 port
= ipc_port_make_send(task
->itk_nself
);
854 port
= ipc_port_copy_send(task
->itk_host
);
857 case TASK_BOOTSTRAP_PORT
:
858 port
= ipc_port_copy_send(task
->itk_bootstrap
);
861 case TASK_WIRED_LEDGER_PORT
:
862 port
= ipc_port_copy_send(task
->wired_ledger_port
);
865 case TASK_PAGED_LEDGER_PORT
:
866 port
= ipc_port_copy_send(task
->paged_ledger_port
);
869 case TASK_SEATBELT_PORT
:
870 port
= ipc_port_copy_send(task
->itk_seatbelt
);
874 port
= ipc_port_copy_send(task
->itk_gssd
);
877 case TASK_ACCESS_PORT
:
878 port
= ipc_port_copy_send(task
->itk_task_access
);
883 return KERN_INVALID_ARGUMENT
;
892 * Routine: task_set_special_port [kernel call]
894 * Changes one of the task's special ports,
895 * setting it to the supplied send right.
897 * Nothing locked. If successful, consumes
898 * the supplied send right.
900 * KERN_SUCCESS Changed the special port.
901 * KERN_INVALID_ARGUMENT The task is null.
902 * KERN_FAILURE The task/space is dead.
903 * KERN_INVALID_ARGUMENT Invalid special port.
904 * KERN_NO_ACCESS Attempted overwrite of seatbelt port.
908 task_set_special_port(
916 if (task
== TASK_NULL
)
917 return KERN_INVALID_ARGUMENT
;
920 case TASK_KERNEL_PORT
:
921 whichp
= &task
->itk_sself
;
925 whichp
= &task
->itk_host
;
928 case TASK_BOOTSTRAP_PORT
:
929 whichp
= &task
->itk_bootstrap
;
932 case TASK_WIRED_LEDGER_PORT
:
933 whichp
= &task
->wired_ledger_port
;
936 case TASK_PAGED_LEDGER_PORT
:
937 whichp
= &task
->paged_ledger_port
;
940 case TASK_SEATBELT_PORT
:
941 whichp
= &task
->itk_seatbelt
;
945 whichp
= &task
->itk_gssd
;
948 case TASK_ACCESS_PORT
:
949 whichp
= &task
->itk_task_access
;
953 return KERN_INVALID_ARGUMENT
;
957 if (task
->itk_self
== IP_NULL
) {
962 /* do not allow overwrite of seatbelt or task access ports */
963 if ((TASK_SEATBELT_PORT
== which
|| TASK_ACCESS_PORT
== which
)
964 && IP_VALID(*whichp
)) {
966 return KERN_NO_ACCESS
;
970 if (mac_task_check_service(current_task(), task
, "set_special_port")) {
972 return KERN_NO_ACCESS
;
981 ipc_port_release_send(old
);
987 * Routine: mach_ports_register [kernel call]
989 * Stash a handful of port send rights in the task.
990 * Child tasks will inherit these rights, but they
991 * must use mach_ports_lookup to acquire them.
993 * The rights are supplied in a (wired) kalloc'd segment.
994 * Rights which aren't supplied are assumed to be null.
996 * Nothing locked. If successful, consumes
997 * the supplied rights and memory.
999 * KERN_SUCCESS Stashed the port rights.
1000 * KERN_INVALID_ARGUMENT The task is null.
1001 * KERN_INVALID_ARGUMENT The task is dead.
1002 * KERN_INVALID_ARGUMENT Too many port rights supplied.
1006 mach_ports_register(
1008 mach_port_array_t memory
,
1009 mach_msg_type_number_t portsCnt
)
1011 ipc_port_t ports
[TASK_PORT_REGISTER_MAX
];
1014 if ((task
== TASK_NULL
) ||
1015 (portsCnt
> TASK_PORT_REGISTER_MAX
))
1016 return KERN_INVALID_ARGUMENT
;
1019 * Pad the port rights with nulls.
1022 for (i
= 0; i
< portsCnt
; i
++)
1023 ports
[i
] = memory
[i
];
1024 for (; i
< TASK_PORT_REGISTER_MAX
; i
++)
1028 if (task
->itk_self
== IP_NULL
) {
1030 return KERN_INVALID_ARGUMENT
;
1034 * Replace the old send rights with the new.
1035 * Release the old rights after unlocking.
1038 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++) {
1041 old
= task
->itk_registered
[i
];
1042 task
->itk_registered
[i
] = ports
[i
];
1048 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
1049 if (IP_VALID(ports
[i
]))
1050 ipc_port_release_send(ports
[i
]);
1053 * Now that the operation is known to be successful,
1054 * we can free the memory.
1059 (vm_size_t
) (portsCnt
* sizeof(mach_port_t
)));
1061 return KERN_SUCCESS
;
1065 * Routine: mach_ports_lookup [kernel call]
1067 * Retrieves (clones) the stashed port send rights.
1069 * Nothing locked. If successful, the caller gets
1070 * rights and memory.
1072 * KERN_SUCCESS Retrieved the send rights.
1073 * KERN_INVALID_ARGUMENT The task is null.
1074 * KERN_INVALID_ARGUMENT The task is dead.
1075 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1081 mach_port_array_t
*portsp
,
1082 mach_msg_type_number_t
*portsCnt
)
1089 if (task
== TASK_NULL
)
1090 return KERN_INVALID_ARGUMENT
;
1092 size
= (vm_size_t
) (TASK_PORT_REGISTER_MAX
* sizeof(ipc_port_t
));
1094 memory
= kalloc(size
);
1096 return KERN_RESOURCE_SHORTAGE
;
1099 if (task
->itk_self
== IP_NULL
) {
1102 kfree(memory
, size
);
1103 return KERN_INVALID_ARGUMENT
;
1106 ports
= (ipc_port_t
*) memory
;
1109 * Clone port rights. Because kalloc'd memory
1110 * is wired, we won't fault while holding the task lock.
1113 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
1114 ports
[i
] = ipc_port_copy_send(task
->itk_registered
[i
]);
1118 *portsp
= (mach_port_array_t
) ports
;
1119 *portsCnt
= TASK_PORT_REGISTER_MAX
;
1120 return KERN_SUCCESS
;
1124 * Routine: convert_port_to_locked_task
1126 * Internal helper routine to convert from a port to a locked
1127 * task. Used by several routines that try to convert from a
1128 * task port to a reference on some task related object.
1130 * Nothing locked, blocking OK.
1133 convert_port_to_locked_task(ipc_port_t port
)
1135 int try_failed_count
= 0;
1137 while (IP_VALID(port
)) {
1141 if (!ip_active(port
) || (ip_kotype(port
) != IKOT_TASK
)) {
1145 task
= (task_t
) port
->ip_kobject
;
1146 assert(task
!= TASK_NULL
);
1149 * Normal lock ordering puts task_lock() before ip_lock().
1150 * Attempt out-of-order locking here.
1152 if (task_lock_try(task
)) {
1159 mutex_pause(try_failed_count
);
1165 * Routine: convert_port_to_task
1167 * Convert from a port to a task.
1168 * Doesn't consume the port ref; produces a task ref,
1169 * which may be null.
1174 convert_port_to_task(
1177 task_t task
= TASK_NULL
;
1179 if (IP_VALID(port
)) {
1182 if ( ip_active(port
) &&
1183 ip_kotype(port
) == IKOT_TASK
) {
1184 task
= (task_t
)port
->ip_kobject
;
1185 assert(task
!= TASK_NULL
);
1187 task_reference_internal(task
);
1197 * Routine: convert_port_to_task_name
1199 * Convert from a port to a task name.
1200 * Doesn't consume the port ref; produces a task name ref,
1201 * which may be null.
1206 convert_port_to_task_name(
1209 task_name_t task
= TASK_NULL
;
1211 if (IP_VALID(port
)) {
1214 if ( ip_active(port
) &&
1215 (ip_kotype(port
) == IKOT_TASK
||
1216 ip_kotype(port
) == IKOT_TASK_NAME
)) {
1217 task
= (task_name_t
)port
->ip_kobject
;
1218 assert(task
!= TASK_NAME_NULL
);
1220 task_reference_internal(task
);
1230 * Routine: convert_port_to_space
1232 * Convert from a port to a space.
1233 * Doesn't consume the port ref; produces a space ref,
1234 * which may be null.
1239 convert_port_to_space(
1245 task
= convert_port_to_locked_task(port
);
1247 if (task
== TASK_NULL
)
1248 return IPC_SPACE_NULL
;
1250 if (!task
->active
) {
1252 return IPC_SPACE_NULL
;
1255 space
= task
->itk_space
;
1256 is_reference(space
);
1262 * Routine: convert_port_to_map
1264 * Convert from a port to a map.
1265 * Doesn't consume the port ref; produces a map ref,
1266 * which may be null.
1272 convert_port_to_map(
1278 task
= convert_port_to_locked_task(port
);
1280 if (task
== TASK_NULL
)
1283 if (!task
->active
) {
1289 vm_map_reference_swap(map
);
1296 * Routine: convert_port_to_thread
1298 * Convert from a port to a thread.
1299 * Doesn't consume the port ref; produces an thread ref,
1300 * which may be null.
1306 convert_port_to_thread(
1309 thread_t thread
= THREAD_NULL
;
1311 if (IP_VALID(port
)) {
1314 if ( ip_active(port
) &&
1315 ip_kotype(port
) == IKOT_THREAD
) {
1316 thread
= (thread_t
)port
->ip_kobject
;
1317 assert(thread
!= THREAD_NULL
);
1319 thread_reference_internal(thread
);
1329 * Routine: port_name_to_thread
1331 * Convert from a port name to an thread reference
1332 * A name of MACH_PORT_NULL is valid for the null thread.
1337 port_name_to_thread(
1338 mach_port_name_t name
)
1340 thread_t thread
= THREAD_NULL
;
1343 if (MACH_PORT_VALID(name
)) {
1344 if (ipc_object_copyin(current_space(), name
,
1345 MACH_MSG_TYPE_COPY_SEND
,
1346 (ipc_object_t
*)&kport
) != KERN_SUCCESS
)
1347 return (THREAD_NULL
);
1349 thread
= convert_port_to_thread(kport
);
1351 if (IP_VALID(kport
))
1352 ipc_port_release_send(kport
);
1360 mach_port_name_t name
)
1362 ipc_port_t kern_port
;
1364 task_t task
= TASK_NULL
;
1366 if (MACH_PORT_VALID(name
)) {
1367 kr
= ipc_object_copyin(current_space(), name
,
1368 MACH_MSG_TYPE_COPY_SEND
,
1369 (ipc_object_t
*) &kern_port
);
1370 if (kr
!= KERN_SUCCESS
)
1373 task
= convert_port_to_task(kern_port
);
1375 if (IP_VALID(kern_port
))
1376 ipc_port_release_send(kern_port
);
1382 * Routine: convert_task_to_port
1384 * Convert from a task to a port.
1385 * Consumes a task ref; produces a naked send right
1386 * which may be invalid.
1392 convert_task_to_port(
1398 if (task
->itk_self
!= IP_NULL
)
1399 port
= ipc_port_make_send(task
->itk_self
);
1404 task_deallocate(task
);
1409 * Routine: convert_task_name_to_port
1411 * Convert from a task name ref to a port.
1412 * Consumes a task name ref; produces a naked send right
1413 * which may be invalid.
1419 convert_task_name_to_port(
1420 task_name_t task_name
)
1424 itk_lock(task_name
);
1425 if (task_name
->itk_nself
!= IP_NULL
)
1426 port
= ipc_port_make_send(task_name
->itk_nself
);
1429 itk_unlock(task_name
);
1431 task_name_deallocate(task_name
);
1436 * Routine: convert_thread_to_port
1438 * Convert from a thread to a port.
1439 * Consumes an thread ref; produces a naked send right
1440 * which may be invalid.
1446 convert_thread_to_port(
1451 thread_mtx_lock(thread
);
1453 if (thread
->ith_self
!= IP_NULL
)
1454 port
= ipc_port_make_send(thread
->ith_self
);
1458 thread_mtx_unlock(thread
);
1460 thread_deallocate(thread
);
1466 * Routine: space_deallocate
1468 * Deallocate a space ref produced by convert_port_to_space.
1477 if (space
!= IS_NULL
)
1482 * Routine: thread/task_set_exception_ports [kernel call]
1484 * Sets the thread/task exception port, flavor and
1485 * behavior for the exception types specified by the mask.
1486 * There will be one send right per exception per valid
1489 * Nothing locked. If successful, consumes
1490 * the supplied send right.
1492 * KERN_SUCCESS Changed the special port.
1493 * KERN_INVALID_ARGUMENT The thread is null,
1494 * Illegal mask bit set.
1495 * Illegal exception behavior
1496 * KERN_FAILURE The thread is dead.
1500 thread_set_exception_ports(
1502 exception_mask_t exception_mask
,
1503 ipc_port_t new_port
,
1504 exception_behavior_t new_behavior
,
1505 thread_state_flavor_t new_flavor
)
1507 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1508 boolean_t privileged
= current_task()->sec_token
.val
[0] == 0;
1511 if (thread
== THREAD_NULL
)
1512 return (KERN_INVALID_ARGUMENT
);
1514 if (exception_mask
& ~EXC_MASK_VALID
)
1515 return (KERN_INVALID_ARGUMENT
);
1517 if (IP_VALID(new_port
)) {
1518 switch (new_behavior
& ~MACH_EXCEPTION_CODES
) {
1520 case EXCEPTION_DEFAULT
:
1521 case EXCEPTION_STATE
:
1522 case EXCEPTION_STATE_IDENTITY
:
1526 return (KERN_INVALID_ARGUMENT
);
1531 * Check the validity of the thread_state_flavor by calling the
1532 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in
1533 * osfmk/mach/ARCHITECTURE/thread_status.h
1535 if (!VALID_THREAD_STATE_FLAVOR(new_flavor
))
1536 return (KERN_INVALID_ARGUMENT
);
1538 thread_mtx_lock(thread
);
1540 if (!thread
->active
) {
1541 thread_mtx_unlock(thread
);
1543 return (KERN_FAILURE
);
1546 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1547 if (exception_mask
& (1 << i
)) {
1548 old_port
[i
] = thread
->exc_actions
[i
].port
;
1549 thread
->exc_actions
[i
].port
= ipc_port_copy_send(new_port
);
1550 thread
->exc_actions
[i
].behavior
= new_behavior
;
1551 thread
->exc_actions
[i
].flavor
= new_flavor
;
1552 thread
->exc_actions
[i
].privileged
= privileged
;
1555 old_port
[i
] = IP_NULL
;
1558 thread_mtx_unlock(thread
);
1560 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
)
1561 if (IP_VALID(old_port
[i
]))
1562 ipc_port_release_send(old_port
[i
]);
1564 if (IP_VALID(new_port
)) /* consume send right */
1565 ipc_port_release_send(new_port
);
1567 return (KERN_SUCCESS
);
1571 task_set_exception_ports(
1573 exception_mask_t exception_mask
,
1574 ipc_port_t new_port
,
1575 exception_behavior_t new_behavior
,
1576 thread_state_flavor_t new_flavor
)
1578 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1579 boolean_t privileged
= current_task()->sec_token
.val
[0] == 0;
1582 if (task
== TASK_NULL
)
1583 return (KERN_INVALID_ARGUMENT
);
1585 if (exception_mask
& ~EXC_MASK_VALID
)
1586 return (KERN_INVALID_ARGUMENT
);
1588 if (IP_VALID(new_port
)) {
1589 switch (new_behavior
& ~MACH_EXCEPTION_CODES
) {
1591 case EXCEPTION_DEFAULT
:
1592 case EXCEPTION_STATE
:
1593 case EXCEPTION_STATE_IDENTITY
:
1597 return (KERN_INVALID_ARGUMENT
);
1603 if (task
->itk_self
== IP_NULL
) {
1606 return (KERN_FAILURE
);
1609 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1610 if (exception_mask
& (1 << i
)) {
1611 old_port
[i
] = task
->exc_actions
[i
].port
;
1612 task
->exc_actions
[i
].port
=
1613 ipc_port_copy_send(new_port
);
1614 task
->exc_actions
[i
].behavior
= new_behavior
;
1615 task
->exc_actions
[i
].flavor
= new_flavor
;
1616 task
->exc_actions
[i
].privileged
= privileged
;
1619 old_port
[i
] = IP_NULL
;
1624 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
)
1625 if (IP_VALID(old_port
[i
]))
1626 ipc_port_release_send(old_port
[i
]);
1628 if (IP_VALID(new_port
)) /* consume send right */
1629 ipc_port_release_send(new_port
);
1631 return (KERN_SUCCESS
);
1635 * Routine: thread/task_swap_exception_ports [kernel call]
1637 * Sets the thread/task exception port, flavor and
1638 * behavior for the exception types specified by the
1641 * The old ports, behavior and flavors are returned
1642 * Count specifies the array sizes on input and
1643 * the number of returned ports etc. on output. The
1644 * arrays must be large enough to hold all the returned
1645 * data, MIG returnes an error otherwise. The masks
1646 * array specifies the corresponding exception type(s).
1649 * Nothing locked. If successful, consumes
1650 * the supplied send right.
1652 * Returns upto [in} CountCnt elements.
1654 * KERN_SUCCESS Changed the special port.
1655 * KERN_INVALID_ARGUMENT The thread is null,
1656 * Illegal mask bit set.
1657 * Illegal exception behavior
1658 * KERN_FAILURE The thread is dead.
1662 thread_swap_exception_ports(
1664 exception_mask_t exception_mask
,
1665 ipc_port_t new_port
,
1666 exception_behavior_t new_behavior
,
1667 thread_state_flavor_t new_flavor
,
1668 exception_mask_array_t masks
,
1669 mach_msg_type_number_t
*CountCnt
,
1670 exception_port_array_t ports
,
1671 exception_behavior_array_t behaviors
,
1672 thread_state_flavor_array_t flavors
)
1674 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1675 boolean_t privileged
= current_task()->sec_token
.val
[0] == 0;
1676 unsigned int i
, j
, count
;
1678 if (thread
== THREAD_NULL
)
1679 return (KERN_INVALID_ARGUMENT
);
1681 if (exception_mask
& ~EXC_MASK_VALID
)
1682 return (KERN_INVALID_ARGUMENT
);
1684 if (IP_VALID(new_port
)) {
1685 switch (new_behavior
& ~MACH_EXCEPTION_CODES
) {
1687 case EXCEPTION_DEFAULT
:
1688 case EXCEPTION_STATE
:
1689 case EXCEPTION_STATE_IDENTITY
:
1693 return (KERN_INVALID_ARGUMENT
);
1697 thread_mtx_lock(thread
);
1699 if (!thread
->active
) {
1700 thread_mtx_unlock(thread
);
1702 return (KERN_FAILURE
);
1707 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1708 if (exception_mask
& (1 << i
)) {
1709 for (j
= 0; j
< count
; ++j
) {
1711 * search for an identical entry, if found
1712 * set corresponding mask for this exception.
1714 if ( thread
->exc_actions
[i
].port
== ports
[j
] &&
1715 thread
->exc_actions
[i
].behavior
== behaviors
[j
] &&
1716 thread
->exc_actions
[i
].flavor
== flavors
[j
] ) {
1717 masks
[j
] |= (1 << i
);
1723 masks
[j
] = (1 << i
);
1724 ports
[j
] = ipc_port_copy_send(thread
->exc_actions
[i
].port
);
1726 behaviors
[j
] = thread
->exc_actions
[i
].behavior
;
1727 flavors
[j
] = thread
->exc_actions
[i
].flavor
;
1731 old_port
[i
] = thread
->exc_actions
[i
].port
;
1732 thread
->exc_actions
[i
].port
= ipc_port_copy_send(new_port
);
1733 thread
->exc_actions
[i
].behavior
= new_behavior
;
1734 thread
->exc_actions
[i
].flavor
= new_flavor
;
1735 thread
->exc_actions
[i
].privileged
= privileged
;
1736 if (count
> *CountCnt
)
1740 old_port
[i
] = IP_NULL
;
1743 thread_mtx_unlock(thread
);
1745 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
)
1746 if (IP_VALID(old_port
[i
]))
1747 ipc_port_release_send(old_port
[i
]);
1749 if (IP_VALID(new_port
)) /* consume send right */
1750 ipc_port_release_send(new_port
);
1754 return (KERN_SUCCESS
);
1758 task_swap_exception_ports(
1760 exception_mask_t exception_mask
,
1761 ipc_port_t new_port
,
1762 exception_behavior_t new_behavior
,
1763 thread_state_flavor_t new_flavor
,
1764 exception_mask_array_t masks
,
1765 mach_msg_type_number_t
*CountCnt
,
1766 exception_port_array_t ports
,
1767 exception_behavior_array_t behaviors
,
1768 thread_state_flavor_array_t flavors
)
1770 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1771 boolean_t privileged
= current_task()->sec_token
.val
[0] == 0;
1772 unsigned int i
, j
, count
;
1774 if (task
== TASK_NULL
)
1775 return (KERN_INVALID_ARGUMENT
);
1777 if (exception_mask
& ~EXC_MASK_VALID
)
1778 return (KERN_INVALID_ARGUMENT
);
1780 if (IP_VALID(new_port
)) {
1781 switch (new_behavior
& ~MACH_EXCEPTION_CODES
) {
1783 case EXCEPTION_DEFAULT
:
1784 case EXCEPTION_STATE
:
1785 case EXCEPTION_STATE_IDENTITY
:
1789 return (KERN_INVALID_ARGUMENT
);
1795 if (task
->itk_self
== IP_NULL
) {
1798 return (KERN_FAILURE
);
1803 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1804 if (exception_mask
& (1 << i
)) {
1805 for (j
= 0; j
< count
; j
++) {
1807 * search for an identical entry, if found
1808 * set corresponding mask for this exception.
1810 if ( task
->exc_actions
[i
].port
== ports
[j
] &&
1811 task
->exc_actions
[i
].behavior
== behaviors
[j
] &&
1812 task
->exc_actions
[i
].flavor
== flavors
[j
] ) {
1813 masks
[j
] |= (1 << i
);
1819 masks
[j
] = (1 << i
);
1820 ports
[j
] = ipc_port_copy_send(task
->exc_actions
[i
].port
);
1821 behaviors
[j
] = task
->exc_actions
[i
].behavior
;
1822 flavors
[j
] = task
->exc_actions
[i
].flavor
;
1826 old_port
[i
] = task
->exc_actions
[i
].port
;
1827 task
->exc_actions
[i
].port
= ipc_port_copy_send(new_port
);
1828 task
->exc_actions
[i
].behavior
= new_behavior
;
1829 task
->exc_actions
[i
].flavor
= new_flavor
;
1830 task
->exc_actions
[i
].privileged
= privileged
;
1831 if (count
> *CountCnt
)
1835 old_port
[i
] = IP_NULL
;
1840 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
1841 if (IP_VALID(old_port
[i
]))
1842 ipc_port_release_send(old_port
[i
]);
1844 if (IP_VALID(new_port
)) /* consume send right */
1845 ipc_port_release_send(new_port
);
1849 return (KERN_SUCCESS
);
1853 * Routine: thread/task_get_exception_ports [kernel call]
1855 * Clones a send right for each of the thread/task's exception
1856 * ports specified in the mask and returns the behaviour
1857 * and flavor of said port.
1859 * Returns upto [in} CountCnt elements.
1864 * KERN_SUCCESS Extracted a send right.
1865 * KERN_INVALID_ARGUMENT The thread is null,
1866 * Invalid special port,
1867 * Illegal mask bit set.
1868 * KERN_FAILURE The thread is dead.
1872 thread_get_exception_ports(
1874 exception_mask_t exception_mask
,
1875 exception_mask_array_t masks
,
1876 mach_msg_type_number_t
*CountCnt
,
1877 exception_port_array_t ports
,
1878 exception_behavior_array_t behaviors
,
1879 thread_state_flavor_array_t flavors
)
1881 unsigned int i
, j
, count
;
1883 if (thread
== THREAD_NULL
)
1884 return (KERN_INVALID_ARGUMENT
);
1886 if (exception_mask
& ~EXC_MASK_VALID
)
1887 return (KERN_INVALID_ARGUMENT
);
1889 thread_mtx_lock(thread
);
1891 if (!thread
->active
) {
1892 thread_mtx_unlock(thread
);
1894 return (KERN_FAILURE
);
1899 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1900 if (exception_mask
& (1 << i
)) {
1901 for (j
= 0; j
< count
; ++j
) {
1903 * search for an identical entry, if found
1904 * set corresponding mask for this exception.
1906 if ( thread
->exc_actions
[i
].port
== ports
[j
] &&
1907 thread
->exc_actions
[i
].behavior
==behaviors
[j
] &&
1908 thread
->exc_actions
[i
].flavor
== flavors
[j
] ) {
1909 masks
[j
] |= (1 << i
);
1915 masks
[j
] = (1 << i
);
1916 ports
[j
] = ipc_port_copy_send(thread
->exc_actions
[i
].port
);
1917 behaviors
[j
] = thread
->exc_actions
[i
].behavior
;
1918 flavors
[j
] = thread
->exc_actions
[i
].flavor
;
1920 if (count
>= *CountCnt
)
1926 thread_mtx_unlock(thread
);
1930 return (KERN_SUCCESS
);
1934 task_get_exception_ports(
1936 exception_mask_t exception_mask
,
1937 exception_mask_array_t masks
,
1938 mach_msg_type_number_t
*CountCnt
,
1939 exception_port_array_t ports
,
1940 exception_behavior_array_t behaviors
,
1941 thread_state_flavor_array_t flavors
)
1943 unsigned int i
, j
, count
;
1945 if (task
== TASK_NULL
)
1946 return (KERN_INVALID_ARGUMENT
);
1948 if (exception_mask
& ~EXC_MASK_VALID
)
1949 return (KERN_INVALID_ARGUMENT
);
1953 if (task
->itk_self
== IP_NULL
) {
1956 return (KERN_FAILURE
);
1961 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1962 if (exception_mask
& (1 << i
)) {
1963 for (j
= 0; j
< count
; ++j
) {
1965 * search for an identical entry, if found
1966 * set corresponding mask for this exception.
1968 if ( task
->exc_actions
[i
].port
== ports
[j
] &&
1969 task
->exc_actions
[i
].behavior
== behaviors
[j
] &&
1970 task
->exc_actions
[i
].flavor
== flavors
[j
] ) {
1971 masks
[j
] |= (1 << i
);
1977 masks
[j
] = (1 << i
);
1978 ports
[j
] = ipc_port_copy_send(task
->exc_actions
[i
].port
);
1979 behaviors
[j
] = task
->exc_actions
[i
].behavior
;
1980 flavors
[j
] = task
->exc_actions
[i
].flavor
;
1982 if (count
> *CountCnt
)
1992 return (KERN_SUCCESS
);