2 * Copyright (c) 2000-2010 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
34 * All Rights Reserved.
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
46 * Carnegie Mellon requests users of this software to return to
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
57 * NOTICE: This file was modified by McAfee Research in 2004 to introduce
58 * support for mandatory and extensible security protections. This notice
59 * is included in support of clause 2.2 (b) of the Apple Public License,
68 * Task and thread related IPC functions.
71 #include <mach/mach_types.h>
72 #include <mach/boolean.h>
73 #include <mach/kern_return.h>
74 #include <mach/mach_param.h>
75 #include <mach/task_special_ports.h>
76 #include <mach/thread_special_ports.h>
77 #include <mach/thread_status.h>
78 #include <mach/exception_types.h>
79 #include <mach/memory_object_types.h>
80 #include <mach/mach_traps.h>
81 #include <mach/task_server.h>
82 #include <mach/thread_act_server.h>
83 #include <mach/mach_host_server.h>
84 #include <mach/host_priv_server.h>
85 #include <mach/vm_map_server.h>
87 #include <kern/kern_types.h>
88 #include <kern/host.h>
89 #include <kern/ipc_kobject.h>
90 #include <kern/ipc_tt.h>
91 #include <kern/kalloc.h>
92 #include <kern/thread.h>
93 #include <kern/misc_protos.h>
95 #include <vm/vm_map.h>
96 #include <vm/vm_pageout.h>
97 #include <vm/vm_protos.h>
99 #include <security/mac_mach_internal.h>
101 /* forward declarations */
102 task_t
convert_port_to_locked_task(ipc_port_t port
);
106 * Routine: ipc_task_init
108 * Initialize a task's IPC state.
110 * If non-null, some state will be inherited from the parent.
111 * The parent must be appropriately initialized.
128 kr
= ipc_space_create(&ipc_table_entries
[0], &space
);
129 if (kr
!= KERN_SUCCESS
)
130 panic("ipc_task_init");
132 space
->is_task
= task
;
134 kport
= ipc_port_alloc_kernel();
135 if (kport
== IP_NULL
)
136 panic("ipc_task_init");
138 nport
= ipc_port_alloc_kernel();
139 if (nport
== IP_NULL
)
140 panic("ipc_task_init");
143 task
->itk_self
= kport
;
144 task
->itk_nself
= nport
;
145 task
->itk_sself
= ipc_port_make_send(kport
);
146 task
->itk_space
= space
;
150 mac_task_label_associate(parent
, task
, &parent
->maclabel
,
151 &task
->maclabel
, &kport
->ip_label
);
153 mac_task_label_associate_kernel(task
, &task
->maclabel
, &kport
->ip_label
);
156 if (parent
== TASK_NULL
) {
159 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
160 task
->exc_actions
[i
].port
= IP_NULL
;
163 kr
= host_get_host_port(host_priv_self(), &port
);
164 assert(kr
== KERN_SUCCESS
);
165 task
->itk_host
= port
;
167 task
->itk_bootstrap
= IP_NULL
;
168 task
->itk_seatbelt
= IP_NULL
;
169 task
->itk_gssd
= IP_NULL
;
170 task
->itk_task_access
= IP_NULL
;
172 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
173 task
->itk_registered
[i
] = IP_NULL
;
176 assert(parent
->itk_self
!= IP_NULL
);
178 /* inherit registered ports */
180 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
181 task
->itk_registered
[i
] =
182 ipc_port_copy_send(parent
->itk_registered
[i
]);
184 /* inherit exception and bootstrap ports */
186 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
187 task
->exc_actions
[i
].port
=
188 ipc_port_copy_send(parent
->exc_actions
[i
].port
);
189 task
->exc_actions
[i
].flavor
=
190 parent
->exc_actions
[i
].flavor
;
191 task
->exc_actions
[i
].behavior
=
192 parent
->exc_actions
[i
].behavior
;
193 task
->exc_actions
[i
].privileged
=
194 parent
->exc_actions
[i
].privileged
;
197 ipc_port_copy_send(parent
->itk_host
);
199 task
->itk_bootstrap
=
200 ipc_port_copy_send(parent
->itk_bootstrap
);
203 ipc_port_copy_send(parent
->itk_seatbelt
);
206 ipc_port_copy_send(parent
->itk_gssd
);
208 task
->itk_task_access
=
209 ipc_port_copy_send(parent
->itk_task_access
);
216 * Routine: ipc_task_enable
218 * Enable a task for IPC access.
231 kport
= task
->itk_self
;
232 if (kport
!= IP_NULL
)
233 ipc_kobject_set(kport
, (ipc_kobject_t
) task
, IKOT_TASK
);
234 nport
= task
->itk_nself
;
235 if (nport
!= IP_NULL
)
236 ipc_kobject_set(nport
, (ipc_kobject_t
) task
, IKOT_TASK_NAME
);
241 * Routine: ipc_task_disable
243 * Disable IPC access to a task.
256 kport
= task
->itk_self
;
257 if (kport
!= IP_NULL
)
258 ipc_kobject_set(kport
, IKO_NULL
, IKOT_NONE
);
259 nport
= task
->itk_nself
;
260 if (nport
!= IP_NULL
)
261 ipc_kobject_set(nport
, IKO_NULL
, IKOT_NONE
);
266 * Routine: ipc_task_terminate
268 * Clean up and destroy a task's IPC state.
270 * Nothing locked. The task must be suspended.
271 * (Or the current thread must be in the task.)
283 kport
= task
->itk_self
;
285 if (kport
== IP_NULL
) {
286 /* the task is already terminated (can this happen?) */
290 task
->itk_self
= IP_NULL
;
292 nport
= task
->itk_nself
;
293 assert(nport
!= IP_NULL
);
294 task
->itk_nself
= IP_NULL
;
298 /* release the naked send rights */
300 if (IP_VALID(task
->itk_sself
))
301 ipc_port_release_send(task
->itk_sself
);
303 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
304 if (IP_VALID(task
->exc_actions
[i
].port
)) {
305 ipc_port_release_send(task
->exc_actions
[i
].port
);
309 if (IP_VALID(task
->itk_host
))
310 ipc_port_release_send(task
->itk_host
);
312 if (IP_VALID(task
->itk_bootstrap
))
313 ipc_port_release_send(task
->itk_bootstrap
);
315 if (IP_VALID(task
->itk_seatbelt
))
316 ipc_port_release_send(task
->itk_seatbelt
);
318 if (IP_VALID(task
->itk_gssd
))
319 ipc_port_release_send(task
->itk_gssd
);
321 if (IP_VALID(task
->itk_task_access
))
322 ipc_port_release_send(task
->itk_task_access
);
324 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
325 if (IP_VALID(task
->itk_registered
[i
]))
326 ipc_port_release_send(task
->itk_registered
[i
]);
328 /* destroy the kernel ports */
329 ipc_port_dealloc_kernel(kport
);
330 ipc_port_dealloc_kernel(nport
);
332 itk_lock_destroy(task
);
336 * Routine: ipc_task_reset
338 * Reset a task's IPC state to protect it when
339 * it enters an elevated security context. The
340 * task name port can remain the same - since
341 * it represents no specific privilege.
343 * Nothing locked. The task must be suspended.
344 * (Or the current thread must be in the task.)
351 ipc_port_t old_kport
, new_kport
;
352 ipc_port_t old_sself
;
353 ipc_port_t old_exc_actions
[EXC_TYPES_COUNT
];
356 new_kport
= ipc_port_alloc_kernel();
357 if (new_kport
== IP_NULL
)
358 panic("ipc_task_reset");
362 old_kport
= task
->itk_self
;
364 if (old_kport
== IP_NULL
) {
365 /* the task is already terminated (can this happen?) */
367 ipc_port_dealloc_kernel(new_kport
);
371 task
->itk_self
= new_kport
;
372 old_sself
= task
->itk_sself
;
373 task
->itk_sself
= ipc_port_make_send(new_kport
);
374 ipc_kobject_set(old_kport
, IKO_NULL
, IKOT_NONE
);
375 ipc_kobject_set(new_kport
, (ipc_kobject_t
) task
, IKOT_TASK
);
377 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
378 if (!task
->exc_actions
[i
].privileged
) {
379 old_exc_actions
[i
] = task
->exc_actions
[i
].port
;
380 task
->exc_actions
[i
].port
= IP_NULL
;
382 old_exc_actions
[i
] = IP_NULL
;
388 /* release the naked send rights */
390 if (IP_VALID(old_sself
))
391 ipc_port_release_send(old_sself
);
393 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
394 if (IP_VALID(old_exc_actions
[i
])) {
395 ipc_port_release_send(old_exc_actions
[i
]);
399 /* destroy the kernel port */
400 ipc_port_dealloc_kernel(old_kport
);
404 * Routine: ipc_thread_init
406 * Initialize a thread's IPC state.
418 kport
= ipc_port_alloc_kernel();
419 if (kport
== IP_NULL
)
420 panic("ipc_thread_init");
422 thread
->ith_self
= kport
;
423 thread
->ith_sself
= ipc_port_make_send(kport
);
425 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
)
426 thread
->exc_actions
[i
].port
= IP_NULL
;
428 ipc_kobject_set(kport
, (ipc_kobject_t
)thread
, IKOT_THREAD
);
430 ipc_kmsg_queue_init(&thread
->ith_messages
);
432 thread
->ith_rpc_reply
= IP_NULL
;
439 ipc_port_t kport
= thread
->ith_self
;
441 if (kport
!= IP_NULL
)
442 ipc_kobject_set(kport
, IKO_NULL
, IKOT_NONE
);
446 * Routine: ipc_thread_terminate
448 * Clean up and destroy a thread's IPC state.
454 ipc_thread_terminate(
457 ipc_port_t kport
= thread
->ith_self
;
459 if (kport
!= IP_NULL
) {
462 if (IP_VALID(thread
->ith_sself
))
463 ipc_port_release_send(thread
->ith_sself
);
465 thread
->ith_sself
= thread
->ith_self
= IP_NULL
;
467 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
468 if (IP_VALID(thread
->exc_actions
[i
].port
))
469 ipc_port_release_send(thread
->exc_actions
[i
].port
);
472 ipc_port_dealloc_kernel(kport
);
475 assert(ipc_kmsg_queue_empty(&thread
->ith_messages
));
477 if (thread
->ith_rpc_reply
!= IP_NULL
)
478 ipc_port_dealloc_reply(thread
->ith_rpc_reply
);
480 thread
->ith_rpc_reply
= IP_NULL
;
484 * Routine: ipc_thread_reset
486 * Reset the IPC state for a given Mach thread when
487 * its task enters an elevated security context.
488 * Both the thread port and its exception ports have
489 * to be reset. Its RPC reply port cannot have any
490 * rights outstanding, so it should be fine.
499 ipc_port_t old_kport
, new_kport
;
500 ipc_port_t old_sself
;
501 ipc_port_t old_exc_actions
[EXC_TYPES_COUNT
];
504 new_kport
= ipc_port_alloc_kernel();
505 if (new_kport
== IP_NULL
)
506 panic("ipc_task_reset");
508 thread_mtx_lock(thread
);
510 old_kport
= thread
->ith_self
;
512 if (old_kport
== IP_NULL
) {
513 /* the is already terminated (can this happen?) */
514 thread_mtx_unlock(thread
);
515 ipc_port_dealloc_kernel(new_kport
);
519 thread
->ith_self
= new_kport
;
520 old_sself
= thread
->ith_sself
;
521 thread
->ith_sself
= ipc_port_make_send(new_kport
);
522 ipc_kobject_set(old_kport
, IKO_NULL
, IKOT_NONE
);
523 ipc_kobject_set(new_kport
, (ipc_kobject_t
) thread
, IKOT_THREAD
);
525 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
526 if (!thread
->exc_actions
[i
].privileged
) {
527 old_exc_actions
[i
] = thread
->exc_actions
[i
].port
;
528 thread
->exc_actions
[i
].port
= IP_NULL
;
530 old_exc_actions
[i
] = IP_NULL
;
534 thread_mtx_unlock(thread
);
536 /* release the naked send rights */
538 if (IP_VALID(old_sself
))
539 ipc_port_release_send(old_sself
);
541 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
542 if (IP_VALID(old_exc_actions
[i
])) {
543 ipc_port_release_send(old_exc_actions
[i
]);
547 /* destroy the kernel port */
548 ipc_port_dealloc_kernel(old_kport
);
552 * Routine: retrieve_task_self_fast
554 * Optimized version of retrieve_task_self,
555 * that only works for the current task.
557 * Return a send right (possibly null/dead)
558 * for the task's user-visible self port.
564 retrieve_task_self_fast(
565 register task_t task
)
567 register ipc_port_t port
;
569 assert(task
== current_task());
572 assert(task
->itk_self
!= IP_NULL
);
574 if ((port
= task
->itk_sself
) == task
->itk_self
) {
578 assert(ip_active(port
));
583 port
= ipc_port_copy_send(port
);
590 * Routine: retrieve_thread_self_fast
592 * Return a send right (possibly null/dead)
593 * for the thread's user-visible self port.
595 * Only works for the current thread.
602 retrieve_thread_self_fast(
605 register ipc_port_t port
;
607 assert(thread
== current_thread());
609 thread_mtx_lock(thread
);
611 assert(thread
->ith_self
!= IP_NULL
);
613 if ((port
= thread
->ith_sself
) == thread
->ith_self
) {
617 assert(ip_active(port
));
623 port
= ipc_port_copy_send(port
);
625 thread_mtx_unlock(thread
);
631 * Routine: task_self_trap [mach trap]
633 * Give the caller send rights for his own task port.
637 * MACH_PORT_NULL if there are any resource failures
643 __unused
struct task_self_trap_args
*args
)
645 task_t task
= current_task();
647 mach_port_name_t name
;
649 sright
= retrieve_task_self_fast(task
);
650 name
= ipc_port_copyout_send(sright
, task
->itk_space
);
655 * Routine: thread_self_trap [mach trap]
657 * Give the caller send rights for his own thread port.
661 * MACH_PORT_NULL if there are any resource failures
667 __unused
struct thread_self_trap_args
*args
)
669 thread_t thread
= current_thread();
670 task_t task
= thread
->task
;
672 mach_port_name_t name
;
674 sright
= retrieve_thread_self_fast(thread
);
675 name
= ipc_port_copyout_send(sright
, task
->itk_space
);
681 * Routine: mach_reply_port [mach trap]
683 * Allocate a port for the caller.
687 * MACH_PORT_NULL if there are any resource failures
693 __unused
struct mach_reply_port_args
*args
)
696 mach_port_name_t name
;
699 kr
= ipc_port_alloc(current_task()->itk_space
, &name
, &port
);
700 if (kr
== KERN_SUCCESS
)
703 name
= MACH_PORT_NULL
;
708 * Routine: thread_get_special_port [kernel call]
710 * Clones a send right for one of the thread's
715 * KERN_SUCCESS Extracted a send right.
716 * KERN_INVALID_ARGUMENT The thread is null.
717 * KERN_FAILURE The thread is dead.
718 * KERN_INVALID_ARGUMENT Invalid special port.
722 thread_get_special_port(
727 kern_return_t result
= KERN_SUCCESS
;
730 if (thread
== THREAD_NULL
)
731 return (KERN_INVALID_ARGUMENT
);
735 case THREAD_KERNEL_PORT
:
736 whichp
= &thread
->ith_sself
;
740 return (KERN_INVALID_ARGUMENT
);
743 thread_mtx_lock(thread
);
746 *portp
= ipc_port_copy_send(*whichp
);
748 result
= KERN_FAILURE
;
750 thread_mtx_unlock(thread
);
756 * Routine: thread_set_special_port [kernel call]
758 * Changes one of the thread's special ports,
759 * setting it to the supplied send right.
761 * Nothing locked. If successful, consumes
762 * the supplied send right.
764 * KERN_SUCCESS Changed the special port.
765 * KERN_INVALID_ARGUMENT The thread is null.
766 * KERN_FAILURE The thread is dead.
767 * KERN_INVALID_ARGUMENT Invalid special port.
771 thread_set_special_port(
776 kern_return_t result
= KERN_SUCCESS
;
777 ipc_port_t
*whichp
, old
= IP_NULL
;
779 if (thread
== THREAD_NULL
)
780 return (KERN_INVALID_ARGUMENT
);
784 case THREAD_KERNEL_PORT
:
785 whichp
= &thread
->ith_sself
;
789 return (KERN_INVALID_ARGUMENT
);
792 thread_mtx_lock(thread
);
794 if (thread
->active
) {
799 result
= KERN_FAILURE
;
801 thread_mtx_unlock(thread
);
804 ipc_port_release_send(old
);
810 * Routine: task_get_special_port [kernel call]
812 * Clones a send right for one of the task's
817 * KERN_SUCCESS Extracted a send right.
818 * KERN_INVALID_ARGUMENT The task is null.
819 * KERN_FAILURE The task/space is dead.
820 * KERN_INVALID_ARGUMENT Invalid special port.
824 task_get_special_port(
831 if (task
== TASK_NULL
)
832 return KERN_INVALID_ARGUMENT
;
835 if (task
->itk_self
== IP_NULL
) {
841 case TASK_KERNEL_PORT
:
842 port
= ipc_port_copy_send(task
->itk_sself
);
846 port
= ipc_port_make_send(task
->itk_nself
);
850 port
= ipc_port_copy_send(task
->itk_host
);
853 case TASK_BOOTSTRAP_PORT
:
854 port
= ipc_port_copy_send(task
->itk_bootstrap
);
857 case TASK_SEATBELT_PORT
:
858 port
= ipc_port_copy_send(task
->itk_seatbelt
);
861 case TASK_ACCESS_PORT
:
862 port
= ipc_port_copy_send(task
->itk_task_access
);
867 return KERN_INVALID_ARGUMENT
;
876 * Routine: task_set_special_port [kernel call]
878 * Changes one of the task's special ports,
879 * setting it to the supplied send right.
881 * Nothing locked. If successful, consumes
882 * the supplied send right.
884 * KERN_SUCCESS Changed the special port.
885 * KERN_INVALID_ARGUMENT The task is null.
886 * KERN_FAILURE The task/space is dead.
887 * KERN_INVALID_ARGUMENT Invalid special port.
888 * KERN_NO_ACCESS Attempted overwrite of seatbelt port.
892 task_set_special_port(
900 if (task
== TASK_NULL
)
901 return KERN_INVALID_ARGUMENT
;
904 case TASK_KERNEL_PORT
:
905 whichp
= &task
->itk_sself
;
909 whichp
= &task
->itk_host
;
912 case TASK_BOOTSTRAP_PORT
:
913 whichp
= &task
->itk_bootstrap
;
916 case TASK_SEATBELT_PORT
:
917 whichp
= &task
->itk_seatbelt
;
920 case TASK_ACCESS_PORT
:
921 whichp
= &task
->itk_task_access
;
925 return KERN_INVALID_ARGUMENT
;
929 if (task
->itk_self
== IP_NULL
) {
934 /* do not allow overwrite of seatbelt or task access ports */
935 if ((TASK_SEATBELT_PORT
== which
|| TASK_ACCESS_PORT
== which
)
936 && IP_VALID(*whichp
)) {
938 return KERN_NO_ACCESS
;
942 if (mac_task_check_service(current_task(), task
, "set_special_port")) {
944 return KERN_NO_ACCESS
;
953 ipc_port_release_send(old
);
959 * Routine: mach_ports_register [kernel call]
961 * Stash a handful of port send rights in the task.
962 * Child tasks will inherit these rights, but they
963 * must use mach_ports_lookup to acquire them.
965 * The rights are supplied in a (wired) kalloc'd segment.
966 * Rights which aren't supplied are assumed to be null.
968 * Nothing locked. If successful, consumes
969 * the supplied rights and memory.
971 * KERN_SUCCESS Stashed the port rights.
972 * KERN_INVALID_ARGUMENT The task is null.
973 * KERN_INVALID_ARGUMENT The task is dead.
974 * KERN_INVALID_ARGUMENT Too many port rights supplied.
980 mach_port_array_t memory
,
981 mach_msg_type_number_t portsCnt
)
983 ipc_port_t ports
[TASK_PORT_REGISTER_MAX
];
986 if ((task
== TASK_NULL
) ||
987 (portsCnt
> TASK_PORT_REGISTER_MAX
))
988 return KERN_INVALID_ARGUMENT
;
991 * Pad the port rights with nulls.
994 for (i
= 0; i
< portsCnt
; i
++)
995 ports
[i
] = memory
[i
];
996 for (; i
< TASK_PORT_REGISTER_MAX
; i
++)
1000 if (task
->itk_self
== IP_NULL
) {
1002 return KERN_INVALID_ARGUMENT
;
1006 * Replace the old send rights with the new.
1007 * Release the old rights after unlocking.
1010 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++) {
1013 old
= task
->itk_registered
[i
];
1014 task
->itk_registered
[i
] = ports
[i
];
1020 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
1021 if (IP_VALID(ports
[i
]))
1022 ipc_port_release_send(ports
[i
]);
1025 * Now that the operation is known to be successful,
1026 * we can free the memory.
1031 (vm_size_t
) (portsCnt
* sizeof(mach_port_t
)));
1033 return KERN_SUCCESS
;
1037 * Routine: mach_ports_lookup [kernel call]
1039 * Retrieves (clones) the stashed port send rights.
1041 * Nothing locked. If successful, the caller gets
1042 * rights and memory.
1044 * KERN_SUCCESS Retrieved the send rights.
1045 * KERN_INVALID_ARGUMENT The task is null.
1046 * KERN_INVALID_ARGUMENT The task is dead.
1047 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1053 mach_port_array_t
*portsp
,
1054 mach_msg_type_number_t
*portsCnt
)
1061 if (task
== TASK_NULL
)
1062 return KERN_INVALID_ARGUMENT
;
1064 size
= (vm_size_t
) (TASK_PORT_REGISTER_MAX
* sizeof(ipc_port_t
));
1066 memory
= kalloc(size
);
1068 return KERN_RESOURCE_SHORTAGE
;
1071 if (task
->itk_self
== IP_NULL
) {
1074 kfree(memory
, size
);
1075 return KERN_INVALID_ARGUMENT
;
1078 ports
= (ipc_port_t
*) memory
;
1081 * Clone port rights. Because kalloc'd memory
1082 * is wired, we won't fault while holding the task lock.
1085 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
1086 ports
[i
] = ipc_port_copy_send(task
->itk_registered
[i
]);
1090 *portsp
= (mach_port_array_t
) ports
;
1091 *portsCnt
= TASK_PORT_REGISTER_MAX
;
1092 return KERN_SUCCESS
;
1096 * Routine: convert_port_to_locked_task
1098 * Internal helper routine to convert from a port to a locked
1099 * task. Used by several routines that try to convert from a
1100 * task port to a reference on some task related object.
1102 * Nothing locked, blocking OK.
1105 convert_port_to_locked_task(ipc_port_t port
)
1107 int try_failed_count
= 0;
1109 while (IP_VALID(port
)) {
1113 if (!ip_active(port
) || (ip_kotype(port
) != IKOT_TASK
)) {
1117 task
= (task_t
) port
->ip_kobject
;
1118 assert(task
!= TASK_NULL
);
1121 * Normal lock ordering puts task_lock() before ip_lock().
1122 * Attempt out-of-order locking here.
1124 if (task_lock_try(task
)) {
1131 mutex_pause(try_failed_count
);
1137 * Routine: convert_port_to_task
1139 * Convert from a port to a task.
1140 * Doesn't consume the port ref; produces a task ref,
1141 * which may be null.
1146 convert_port_to_task(
1149 task_t task
= TASK_NULL
;
1151 if (IP_VALID(port
)) {
1154 if ( ip_active(port
) &&
1155 ip_kotype(port
) == IKOT_TASK
) {
1156 task
= (task_t
)port
->ip_kobject
;
1157 assert(task
!= TASK_NULL
);
1159 task_reference_internal(task
);
1169 * Routine: convert_port_to_task_name
1171 * Convert from a port to a task name.
1172 * Doesn't consume the port ref; produces a task name ref,
1173 * which may be null.
1178 convert_port_to_task_name(
1181 task_name_t task
= TASK_NULL
;
1183 if (IP_VALID(port
)) {
1186 if ( ip_active(port
) &&
1187 (ip_kotype(port
) == IKOT_TASK
||
1188 ip_kotype(port
) == IKOT_TASK_NAME
)) {
1189 task
= (task_name_t
)port
->ip_kobject
;
1190 assert(task
!= TASK_NAME_NULL
);
1192 task_reference_internal(task
);
1202 * Routine: convert_port_to_space
1204 * Convert from a port to a space.
1205 * Doesn't consume the port ref; produces a space ref,
1206 * which may be null.
1211 convert_port_to_space(
1217 task
= convert_port_to_locked_task(port
);
1219 if (task
== TASK_NULL
)
1220 return IPC_SPACE_NULL
;
1222 if (!task
->active
) {
1224 return IPC_SPACE_NULL
;
1227 space
= task
->itk_space
;
1228 is_reference(space
);
1234 * Routine: convert_port_to_map
1236 * Convert from a port to a map.
1237 * Doesn't consume the port ref; produces a map ref,
1238 * which may be null.
1244 convert_port_to_map(
1250 task
= convert_port_to_locked_task(port
);
1252 if (task
== TASK_NULL
)
1255 if (!task
->active
) {
1261 vm_map_reference_swap(map
);
1268 * Routine: convert_port_to_thread
1270 * Convert from a port to a thread.
1271 * Doesn't consume the port ref; produces an thread ref,
1272 * which may be null.
1278 convert_port_to_thread(
1281 thread_t thread
= THREAD_NULL
;
1283 if (IP_VALID(port
)) {
1286 if ( ip_active(port
) &&
1287 ip_kotype(port
) == IKOT_THREAD
) {
1288 thread
= (thread_t
)port
->ip_kobject
;
1289 assert(thread
!= THREAD_NULL
);
1291 thread_reference_internal(thread
);
1301 * Routine: port_name_to_thread
1303 * Convert from a port name to an thread reference
1304 * A name of MACH_PORT_NULL is valid for the null thread.
1309 port_name_to_thread(
1310 mach_port_name_t name
)
1312 thread_t thread
= THREAD_NULL
;
1315 if (MACH_PORT_VALID(name
)) {
1316 if (ipc_object_copyin(current_space(), name
,
1317 MACH_MSG_TYPE_COPY_SEND
,
1318 (ipc_object_t
*)&kport
) != KERN_SUCCESS
)
1319 return (THREAD_NULL
);
1321 thread
= convert_port_to_thread(kport
);
1323 if (IP_VALID(kport
))
1324 ipc_port_release_send(kport
);
1332 mach_port_name_t name
)
1334 ipc_port_t kern_port
;
1336 task_t task
= TASK_NULL
;
1338 if (MACH_PORT_VALID(name
)) {
1339 kr
= ipc_object_copyin(current_space(), name
,
1340 MACH_MSG_TYPE_COPY_SEND
,
1341 (ipc_object_t
*) &kern_port
);
1342 if (kr
!= KERN_SUCCESS
)
1345 task
= convert_port_to_task(kern_port
);
1347 if (IP_VALID(kern_port
))
1348 ipc_port_release_send(kern_port
);
1354 * Routine: convert_task_to_port
1356 * Convert from a task to a port.
1357 * Consumes a task ref; produces a naked send right
1358 * which may be invalid.
1364 convert_task_to_port(
1370 if (task
->itk_self
!= IP_NULL
)
1371 port
= ipc_port_make_send(task
->itk_self
);
1376 task_deallocate(task
);
1381 * Routine: convert_task_name_to_port
1383 * Convert from a task name ref to a port.
1384 * Consumes a task name ref; produces a naked send right
1385 * which may be invalid.
1391 convert_task_name_to_port(
1392 task_name_t task_name
)
1396 itk_lock(task_name
);
1397 if (task_name
->itk_nself
!= IP_NULL
)
1398 port
= ipc_port_make_send(task_name
->itk_nself
);
1401 itk_unlock(task_name
);
1403 task_name_deallocate(task_name
);
1408 * Routine: convert_thread_to_port
1410 * Convert from a thread to a port.
1411 * Consumes an thread ref; produces a naked send right
1412 * which may be invalid.
1418 convert_thread_to_port(
1423 thread_mtx_lock(thread
);
1425 if (thread
->ith_self
!= IP_NULL
)
1426 port
= ipc_port_make_send(thread
->ith_self
);
1430 thread_mtx_unlock(thread
);
1432 thread_deallocate(thread
);
1438 * Routine: space_deallocate
1440 * Deallocate a space ref produced by convert_port_to_space.
1449 if (space
!= IS_NULL
)
1454 * Routine: thread/task_set_exception_ports [kernel call]
1456 * Sets the thread/task exception port, flavor and
1457 * behavior for the exception types specified by the mask.
1458 * There will be one send right per exception per valid
1461 * Nothing locked. If successful, consumes
1462 * the supplied send right.
1464 * KERN_SUCCESS Changed the special port.
1465 * KERN_INVALID_ARGUMENT The thread is null,
1466 * Illegal mask bit set.
1467 * Illegal exception behavior
1468 * KERN_FAILURE The thread is dead.
1472 thread_set_exception_ports(
1474 exception_mask_t exception_mask
,
1475 ipc_port_t new_port
,
1476 exception_behavior_t new_behavior
,
1477 thread_state_flavor_t new_flavor
)
1479 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1480 boolean_t privileged
= current_task()->sec_token
.val
[0] == 0;
1483 if (thread
== THREAD_NULL
)
1484 return (KERN_INVALID_ARGUMENT
);
1486 if (exception_mask
& ~EXC_MASK_VALID
)
1487 return (KERN_INVALID_ARGUMENT
);
1489 if (IP_VALID(new_port
)) {
1490 switch (new_behavior
& ~MACH_EXCEPTION_CODES
) {
1492 case EXCEPTION_DEFAULT
:
1493 case EXCEPTION_STATE
:
1494 case EXCEPTION_STATE_IDENTITY
:
1498 return (KERN_INVALID_ARGUMENT
);
1503 * Check the validity of the thread_state_flavor by calling the
1504 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in
1505 * osfmk/mach/ARCHITECTURE/thread_status.h
1507 if (!VALID_THREAD_STATE_FLAVOR(new_flavor
))
1508 return (KERN_INVALID_ARGUMENT
);
1510 thread_mtx_lock(thread
);
1512 if (!thread
->active
) {
1513 thread_mtx_unlock(thread
);
1515 return (KERN_FAILURE
);
1518 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1519 if (exception_mask
& (1 << i
)) {
1520 old_port
[i
] = thread
->exc_actions
[i
].port
;
1521 thread
->exc_actions
[i
].port
= ipc_port_copy_send(new_port
);
1522 thread
->exc_actions
[i
].behavior
= new_behavior
;
1523 thread
->exc_actions
[i
].flavor
= new_flavor
;
1524 thread
->exc_actions
[i
].privileged
= privileged
;
1527 old_port
[i
] = IP_NULL
;
1530 thread_mtx_unlock(thread
);
1532 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
)
1533 if (IP_VALID(old_port
[i
]))
1534 ipc_port_release_send(old_port
[i
]);
1536 if (IP_VALID(new_port
)) /* consume send right */
1537 ipc_port_release_send(new_port
);
1539 return (KERN_SUCCESS
);
1543 task_set_exception_ports(
1545 exception_mask_t exception_mask
,
1546 ipc_port_t new_port
,
1547 exception_behavior_t new_behavior
,
1548 thread_state_flavor_t new_flavor
)
1550 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1551 boolean_t privileged
= current_task()->sec_token
.val
[0] == 0;
1554 if (task
== TASK_NULL
)
1555 return (KERN_INVALID_ARGUMENT
);
1557 if (exception_mask
& ~EXC_MASK_VALID
)
1558 return (KERN_INVALID_ARGUMENT
);
1560 if (IP_VALID(new_port
)) {
1561 switch (new_behavior
& ~MACH_EXCEPTION_CODES
) {
1563 case EXCEPTION_DEFAULT
:
1564 case EXCEPTION_STATE
:
1565 case EXCEPTION_STATE_IDENTITY
:
1569 return (KERN_INVALID_ARGUMENT
);
1575 if (task
->itk_self
== IP_NULL
) {
1578 return (KERN_FAILURE
);
1581 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1582 if (exception_mask
& (1 << i
)) {
1583 old_port
[i
] = task
->exc_actions
[i
].port
;
1584 task
->exc_actions
[i
].port
=
1585 ipc_port_copy_send(new_port
);
1586 task
->exc_actions
[i
].behavior
= new_behavior
;
1587 task
->exc_actions
[i
].flavor
= new_flavor
;
1588 task
->exc_actions
[i
].privileged
= privileged
;
1591 old_port
[i
] = IP_NULL
;
1596 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
)
1597 if (IP_VALID(old_port
[i
]))
1598 ipc_port_release_send(old_port
[i
]);
1600 if (IP_VALID(new_port
)) /* consume send right */
1601 ipc_port_release_send(new_port
);
1603 return (KERN_SUCCESS
);
1607 * Routine: thread/task_swap_exception_ports [kernel call]
1609 * Sets the thread/task exception port, flavor and
1610 * behavior for the exception types specified by the
1613 * The old ports, behavior and flavors are returned
1614 * Count specifies the array sizes on input and
1615 * the number of returned ports etc. on output. The
1616 * arrays must be large enough to hold all the returned
1617 * data, MIG returnes an error otherwise. The masks
1618 * array specifies the corresponding exception type(s).
1621 * Nothing locked. If successful, consumes
1622 * the supplied send right.
1624 * Returns upto [in} CountCnt elements.
1626 * KERN_SUCCESS Changed the special port.
1627 * KERN_INVALID_ARGUMENT The thread is null,
1628 * Illegal mask bit set.
1629 * Illegal exception behavior
1630 * KERN_FAILURE The thread is dead.
1634 thread_swap_exception_ports(
1636 exception_mask_t exception_mask
,
1637 ipc_port_t new_port
,
1638 exception_behavior_t new_behavior
,
1639 thread_state_flavor_t new_flavor
,
1640 exception_mask_array_t masks
,
1641 mach_msg_type_number_t
*CountCnt
,
1642 exception_port_array_t ports
,
1643 exception_behavior_array_t behaviors
,
1644 thread_state_flavor_array_t flavors
)
1646 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1647 boolean_t privileged
= current_task()->sec_token
.val
[0] == 0;
1648 unsigned int i
, j
, count
;
1650 if (thread
== THREAD_NULL
)
1651 return (KERN_INVALID_ARGUMENT
);
1653 if (exception_mask
& ~EXC_MASK_VALID
)
1654 return (KERN_INVALID_ARGUMENT
);
1656 if (IP_VALID(new_port
)) {
1657 switch (new_behavior
& ~MACH_EXCEPTION_CODES
) {
1659 case EXCEPTION_DEFAULT
:
1660 case EXCEPTION_STATE
:
1661 case EXCEPTION_STATE_IDENTITY
:
1665 return (KERN_INVALID_ARGUMENT
);
1669 thread_mtx_lock(thread
);
1671 if (!thread
->active
) {
1672 thread_mtx_unlock(thread
);
1674 return (KERN_FAILURE
);
1679 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1680 if (exception_mask
& (1 << i
)) {
1681 for (j
= 0; j
< count
; ++j
) {
1683 * search for an identical entry, if found
1684 * set corresponding mask for this exception.
1686 if ( thread
->exc_actions
[i
].port
== ports
[j
] &&
1687 thread
->exc_actions
[i
].behavior
== behaviors
[j
] &&
1688 thread
->exc_actions
[i
].flavor
== flavors
[j
] ) {
1689 masks
[j
] |= (1 << i
);
1695 masks
[j
] = (1 << i
);
1696 ports
[j
] = ipc_port_copy_send(thread
->exc_actions
[i
].port
);
1698 behaviors
[j
] = thread
->exc_actions
[i
].behavior
;
1699 flavors
[j
] = thread
->exc_actions
[i
].flavor
;
1703 old_port
[i
] = thread
->exc_actions
[i
].port
;
1704 thread
->exc_actions
[i
].port
= ipc_port_copy_send(new_port
);
1705 thread
->exc_actions
[i
].behavior
= new_behavior
;
1706 thread
->exc_actions
[i
].flavor
= new_flavor
;
1707 thread
->exc_actions
[i
].privileged
= privileged
;
1708 if (count
> *CountCnt
)
1712 old_port
[i
] = IP_NULL
;
1715 thread_mtx_unlock(thread
);
1717 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
)
1718 if (IP_VALID(old_port
[i
]))
1719 ipc_port_release_send(old_port
[i
]);
1721 if (IP_VALID(new_port
)) /* consume send right */
1722 ipc_port_release_send(new_port
);
1726 return (KERN_SUCCESS
);
1730 task_swap_exception_ports(
1732 exception_mask_t exception_mask
,
1733 ipc_port_t new_port
,
1734 exception_behavior_t new_behavior
,
1735 thread_state_flavor_t new_flavor
,
1736 exception_mask_array_t masks
,
1737 mach_msg_type_number_t
*CountCnt
,
1738 exception_port_array_t ports
,
1739 exception_behavior_array_t behaviors
,
1740 thread_state_flavor_array_t flavors
)
1742 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1743 boolean_t privileged
= current_task()->sec_token
.val
[0] == 0;
1744 unsigned int i
, j
, count
;
1746 if (task
== TASK_NULL
)
1747 return (KERN_INVALID_ARGUMENT
);
1749 if (exception_mask
& ~EXC_MASK_VALID
)
1750 return (KERN_INVALID_ARGUMENT
);
1752 if (IP_VALID(new_port
)) {
1753 switch (new_behavior
& ~MACH_EXCEPTION_CODES
) {
1755 case EXCEPTION_DEFAULT
:
1756 case EXCEPTION_STATE
:
1757 case EXCEPTION_STATE_IDENTITY
:
1761 return (KERN_INVALID_ARGUMENT
);
1767 if (task
->itk_self
== IP_NULL
) {
1770 return (KERN_FAILURE
);
1775 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1776 if (exception_mask
& (1 << i
)) {
1777 for (j
= 0; j
< count
; j
++) {
1779 * search for an identical entry, if found
1780 * set corresponding mask for this exception.
1782 if ( task
->exc_actions
[i
].port
== ports
[j
] &&
1783 task
->exc_actions
[i
].behavior
== behaviors
[j
] &&
1784 task
->exc_actions
[i
].flavor
== flavors
[j
] ) {
1785 masks
[j
] |= (1 << i
);
1791 masks
[j
] = (1 << i
);
1792 ports
[j
] = ipc_port_copy_send(task
->exc_actions
[i
].port
);
1793 behaviors
[j
] = task
->exc_actions
[i
].behavior
;
1794 flavors
[j
] = task
->exc_actions
[i
].flavor
;
1798 old_port
[i
] = task
->exc_actions
[i
].port
;
1799 task
->exc_actions
[i
].port
= ipc_port_copy_send(new_port
);
1800 task
->exc_actions
[i
].behavior
= new_behavior
;
1801 task
->exc_actions
[i
].flavor
= new_flavor
;
1802 task
->exc_actions
[i
].privileged
= privileged
;
1803 if (count
> *CountCnt
)
1807 old_port
[i
] = IP_NULL
;
1812 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
1813 if (IP_VALID(old_port
[i
]))
1814 ipc_port_release_send(old_port
[i
]);
1816 if (IP_VALID(new_port
)) /* consume send right */
1817 ipc_port_release_send(new_port
);
1821 return (KERN_SUCCESS
);
1825 * Routine: thread/task_get_exception_ports [kernel call]
1827 * Clones a send right for each of the thread/task's exception
1828 * ports specified in the mask and returns the behaviour
1829 * and flavor of said port.
1831 * Returns upto [in} CountCnt elements.
1836 * KERN_SUCCESS Extracted a send right.
1837 * KERN_INVALID_ARGUMENT The thread is null,
1838 * Invalid special port,
1839 * Illegal mask bit set.
1840 * KERN_FAILURE The thread is dead.
1844 thread_get_exception_ports(
1846 exception_mask_t exception_mask
,
1847 exception_mask_array_t masks
,
1848 mach_msg_type_number_t
*CountCnt
,
1849 exception_port_array_t ports
,
1850 exception_behavior_array_t behaviors
,
1851 thread_state_flavor_array_t flavors
)
1853 unsigned int i
, j
, count
;
1855 if (thread
== THREAD_NULL
)
1856 return (KERN_INVALID_ARGUMENT
);
1858 if (exception_mask
& ~EXC_MASK_VALID
)
1859 return (KERN_INVALID_ARGUMENT
);
1861 thread_mtx_lock(thread
);
1863 if (!thread
->active
) {
1864 thread_mtx_unlock(thread
);
1866 return (KERN_FAILURE
);
1871 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1872 if (exception_mask
& (1 << i
)) {
1873 for (j
= 0; j
< count
; ++j
) {
1875 * search for an identical entry, if found
1876 * set corresponding mask for this exception.
1878 if ( thread
->exc_actions
[i
].port
== ports
[j
] &&
1879 thread
->exc_actions
[i
].behavior
==behaviors
[j
] &&
1880 thread
->exc_actions
[i
].flavor
== flavors
[j
] ) {
1881 masks
[j
] |= (1 << i
);
1887 masks
[j
] = (1 << i
);
1888 ports
[j
] = ipc_port_copy_send(thread
->exc_actions
[i
].port
);
1889 behaviors
[j
] = thread
->exc_actions
[i
].behavior
;
1890 flavors
[j
] = thread
->exc_actions
[i
].flavor
;
1892 if (count
>= *CountCnt
)
1898 thread_mtx_unlock(thread
);
1902 return (KERN_SUCCESS
);
1906 task_get_exception_ports(
1908 exception_mask_t exception_mask
,
1909 exception_mask_array_t masks
,
1910 mach_msg_type_number_t
*CountCnt
,
1911 exception_port_array_t ports
,
1912 exception_behavior_array_t behaviors
,
1913 thread_state_flavor_array_t flavors
)
1915 unsigned int i
, j
, count
;
1917 if (task
== TASK_NULL
)
1918 return (KERN_INVALID_ARGUMENT
);
1920 if (exception_mask
& ~EXC_MASK_VALID
)
1921 return (KERN_INVALID_ARGUMENT
);
1925 if (task
->itk_self
== IP_NULL
) {
1928 return (KERN_FAILURE
);
1933 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1934 if (exception_mask
& (1 << i
)) {
1935 for (j
= 0; j
< count
; ++j
) {
1937 * search for an identical entry, if found
1938 * set corresponding mask for this exception.
1940 if ( task
->exc_actions
[i
].port
== ports
[j
] &&
1941 task
->exc_actions
[i
].behavior
== behaviors
[j
] &&
1942 task
->exc_actions
[i
].flavor
== flavors
[j
] ) {
1943 masks
[j
] |= (1 << i
);
1949 masks
[j
] = (1 << i
);
1950 ports
[j
] = ipc_port_copy_send(task
->exc_actions
[i
].port
);
1951 behaviors
[j
] = task
->exc_actions
[i
].behavior
;
1952 flavors
[j
] = task
->exc_actions
[i
].flavor
;
1954 if (count
> *CountCnt
)
1964 return (KERN_SUCCESS
);