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>
94 #include <kdp/kdp_dyld.h>
96 #include <vm/vm_map.h>
97 #include <vm/vm_pageout.h>
98 #include <vm/vm_protos.h>
100 #include <security/mac_mach_internal.h>
106 #if !defined(XNU_TARGET_OS_OSX) && !SECURE_KERNEL
107 extern int cs_relax_platform_task_ports
;
110 extern boolean_t
IOTaskHasEntitlement(task_t
, const char *);
112 /* forward declarations */
113 static kern_return_t
port_allowed_with_task_flavor(int which
, mach_task_flavor_t flavor
);
114 static kern_return_t
port_allowed_with_thread_flavor(int which
, mach_thread_flavor_t flavor
);
115 static void ipc_port_bind_special_reply_port_locked(ipc_port_t port
);
116 static kern_return_t
ipc_port_unbind_special_reply_port(thread_t thread
, boolean_t unbind_active_port
);
117 kern_return_t
task_conversion_eval(task_t caller
, task_t victim
);
118 static ipc_space_t
convert_port_to_space_no_eval(ipc_port_t port
);
119 static thread_t
convert_port_to_thread_no_eval(ipc_port_t port
);
120 static ipc_port_t
convert_task_to_port_with_flavor(task_t task
, mach_task_flavor_t flavor
);
121 static ipc_port_t
convert_thread_to_port_with_flavor(thread_t thread
, mach_thread_flavor_t flavor
);
122 static task_read_t
convert_port_to_task_read_no_eval(ipc_port_t port
);
123 static thread_read_t
convert_port_to_thread_read_no_eval(ipc_port_t port
);
124 static ipc_space_read_t
convert_port_to_space_read_no_eval(ipc_port_t port
);
127 * Routine: ipc_task_init
129 * Initialize a task's IPC state.
131 * If non-null, some state will be inherited from the parent.
132 * The parent must be appropriately initialized.
150 kr
= ipc_space_create(&ipc_table_entries
[0], IPC_LABEL_NONE
, &space
);
151 if (kr
!= KERN_SUCCESS
) {
152 panic("ipc_task_init");
155 space
->is_task
= task
;
157 if (immovable_control_port_enabled
) {
158 ipc_kobject_alloc_options_t options
= IPC_KOBJECT_ALLOC_IMMOVABLE_SEND
;
159 if (pinned_control_port_enabled
) {
160 options
|= IPC_KOBJECT_ALLOC_PINNED
;
162 pport
= ipc_kobject_alloc_port(IKO_NULL
, IKOT_NONE
, options
);
164 kport
= ipc_kobject_alloc_labeled_port(IKO_NULL
, IKOT_TASK_CONTROL
,
165 IPC_LABEL_SUBST_TASK
, IPC_KOBJECT_ALLOC_NONE
);
166 kport
->ip_alt_port
= pport
;
168 kport
= ipc_kobject_alloc_port(IKO_NULL
, IKOT_TASK_CONTROL
,
169 IPC_KOBJECT_ALLOC_NONE
);
174 nport
= ipc_port_alloc_kernel();
175 if (nport
== IP_NULL
) {
176 panic("ipc_task_init");
179 if (pport
== IP_NULL
) {
180 panic("ipc_task_init");
184 task
->itk_task_ports
[TASK_FLAVOR_CONTROL
] = kport
;
185 task
->itk_task_ports
[TASK_FLAVOR_NAME
] = nport
;
187 /* Lazily allocated on-demand */
188 task
->itk_task_ports
[TASK_FLAVOR_INSPECT
] = IP_NULL
;
189 task
->itk_task_ports
[TASK_FLAVOR_READ
] = IP_NULL
;
190 task
->itk_dyld_notify
= NULL
;
192 task
->itk_self
= pport
;
193 task
->itk_resume
= IP_NULL
; /* Lazily allocated on-demand */
194 if (task_is_a_corpse_fork(task
)) {
196 * No sender's notification for corpse would not
197 * work with a naked send right in kernel.
199 task
->itk_settable_self
= IP_NULL
;
201 task
->itk_settable_self
= ipc_port_make_send(kport
);
203 task
->itk_debug_control
= IP_NULL
;
204 task
->itk_space
= space
;
207 task
->exc_actions
[0].label
= NULL
;
208 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
209 mac_exc_associate_action_label(&task
->exc_actions
[i
], mac_exc_create_label());
213 /* always zero-out the first (unused) array element */
214 bzero(&task
->exc_actions
[0], sizeof(task
->exc_actions
[0]));
216 if (parent
== TASK_NULL
) {
218 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
219 task
->exc_actions
[i
].port
= IP_NULL
;
220 task
->exc_actions
[i
].flavor
= 0;
221 task
->exc_actions
[i
].behavior
= 0;
222 task
->exc_actions
[i
].privileged
= FALSE
;
225 kr
= host_get_host_port(host_priv_self(), &port
);
226 assert(kr
== KERN_SUCCESS
);
227 task
->itk_host
= port
;
229 task
->itk_bootstrap
= IP_NULL
;
230 task
->itk_seatbelt
= IP_NULL
;
231 task
->itk_gssd
= IP_NULL
;
232 task
->itk_task_access
= IP_NULL
;
234 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++) {
235 task
->itk_registered
[i
] = IP_NULL
;
239 assert(parent
->itk_task_ports
[TASK_FLAVOR_CONTROL
] != IP_NULL
);
241 /* inherit registered ports */
243 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++) {
244 task
->itk_registered
[i
] =
245 ipc_port_copy_send(parent
->itk_registered
[i
]);
248 /* inherit exception and bootstrap ports */
250 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
251 task
->exc_actions
[i
].port
=
252 ipc_port_copy_send(parent
->exc_actions
[i
].port
);
253 task
->exc_actions
[i
].flavor
=
254 parent
->exc_actions
[i
].flavor
;
255 task
->exc_actions
[i
].behavior
=
256 parent
->exc_actions
[i
].behavior
;
257 task
->exc_actions
[i
].privileged
=
258 parent
->exc_actions
[i
].privileged
;
260 mac_exc_inherit_action_label(parent
->exc_actions
+ i
, task
->exc_actions
+ i
);
264 ipc_port_copy_send(parent
->itk_host
);
266 task
->itk_bootstrap
=
267 ipc_port_copy_send(parent
->itk_bootstrap
);
270 ipc_port_copy_send(parent
->itk_seatbelt
);
273 ipc_port_copy_send(parent
->itk_gssd
);
275 task
->itk_task_access
=
276 ipc_port_copy_send(parent
->itk_task_access
);
283 * Routine: ipc_task_enable
285 * Enable a task for IPC access.
302 assert(!task
->ipc_active
|| task_is_a_corpse(task
));
303 task
->ipc_active
= true;
305 kport
= task
->itk_task_ports
[TASK_FLAVOR_CONTROL
];
306 if (kport
!= IP_NULL
) {
307 ipc_kobject_set(kport
, (ipc_kobject_t
) task
, IKOT_TASK_CONTROL
);
309 nport
= task
->itk_task_ports
[TASK_FLAVOR_NAME
];
310 if (nport
!= IP_NULL
) {
311 ipc_kobject_set(nport
, (ipc_kobject_t
) task
, IKOT_TASK_NAME
);
313 iport
= task
->itk_task_ports
[TASK_FLAVOR_INSPECT
];
314 if (iport
!= IP_NULL
) {
315 ipc_kobject_set(iport
, (ipc_kobject_t
) task
, IKOT_TASK_INSPECT
);
317 rdport
= task
->itk_task_ports
[TASK_FLAVOR_READ
];
318 if (rdport
!= IP_NULL
) {
319 ipc_kobject_set(rdport
, (ipc_kobject_t
) task
, IKOT_TASK_READ
);
321 pport
= task
->itk_self
;
322 if (immovable_control_port_enabled
&& pport
!= IP_NULL
) {
323 ipc_kobject_set(pport
, (ipc_kobject_t
) task
, IKOT_TASK_CONTROL
);
330 * Routine: ipc_task_disable
332 * Disable IPC access to a task.
351 * This innocuous looking line is load bearing.
353 * It is used to disable the creation of lazy made ports.
354 * We must do so before we drop the last reference on the task,
355 * as task ports do not own a reference on the task, and
356 * convert_port_to_task* will crash trying to resurect a task.
358 task
->ipc_active
= false;
360 kport
= task
->itk_task_ports
[TASK_FLAVOR_CONTROL
];
361 if (kport
!= IP_NULL
) {
363 kport
->ip_alt_port
= IP_NULL
;
364 ipc_kobject_set_atomically(kport
, IKO_NULL
, IKOT_NONE
);
367 nport
= task
->itk_task_ports
[TASK_FLAVOR_NAME
];
368 if (nport
!= IP_NULL
) {
369 ipc_kobject_set(nport
, IKO_NULL
, IKOT_NONE
);
371 iport
= task
->itk_task_ports
[TASK_FLAVOR_INSPECT
];
372 if (iport
!= IP_NULL
) {
373 ipc_kobject_set(iport
, IKO_NULL
, IKOT_NONE
);
375 rdport
= task
->itk_task_ports
[TASK_FLAVOR_READ
];
376 if (rdport
!= IP_NULL
) {
377 ipc_kobject_set(rdport
, IKO_NULL
, IKOT_NONE
);
379 pport
= task
->itk_self
;
380 if (pport
!= kport
&& pport
!= IP_NULL
) {
381 assert(immovable_control_port_enabled
);
382 assert(pport
->ip_immovable_send
);
383 ipc_kobject_set(pport
, IKO_NULL
, IKOT_NONE
);
386 rport
= task
->itk_resume
;
387 if (rport
!= IP_NULL
) {
389 * From this point onwards this task is no longer accepting
392 * There are still outstanding suspensions on this task,
393 * even as it is being torn down. Disconnect the task
394 * from the rport, thereby "orphaning" the rport. The rport
395 * itself will go away only when the last suspension holder
396 * destroys his SO right to it -- when he either
397 * exits, or tries to actually use that last SO right to
398 * resume this (now non-existent) task.
400 ipc_kobject_set(rport
, IKO_NULL
, IKOT_NONE
);
406 * Routine: ipc_task_terminate
408 * Clean up and destroy a task's IPC state.
410 * Nothing locked. The task must be suspended.
411 * (Or the current thread must be in the task.)
425 ipc_port_t
*notifiers_ptr
= NULL
;
430 * If we ever failed to clear ipc_active before the last reference
431 * was dropped, lazy ports might be made and used after the last
432 * reference is dropped and cause use after free (see comment in
433 * ipc_task_disable()).
435 assert(!task
->ipc_active
);
437 kport
= task
->itk_task_ports
[TASK_FLAVOR_CONTROL
];
438 sself
= task
->itk_settable_self
;
440 if (kport
== IP_NULL
) {
441 /* the task is already terminated (can this happen?) */
445 task
->itk_task_ports
[TASK_FLAVOR_CONTROL
] = IP_NULL
;
447 rdport
= task
->itk_task_ports
[TASK_FLAVOR_READ
];
448 task
->itk_task_ports
[TASK_FLAVOR_READ
] = IP_NULL
;
450 iport
= task
->itk_task_ports
[TASK_FLAVOR_INSPECT
];
451 task
->itk_task_ports
[TASK_FLAVOR_INSPECT
] = IP_NULL
;
453 nport
= task
->itk_task_ports
[TASK_FLAVOR_NAME
];
454 assert(nport
!= IP_NULL
);
455 task
->itk_task_ports
[TASK_FLAVOR_NAME
] = IP_NULL
;
457 if (task
->itk_dyld_notify
) {
458 notifiers_ptr
= task
->itk_dyld_notify
;
459 task
->itk_dyld_notify
= NULL
;
462 if (immovable_control_port_enabled
) {
463 pport
= task
->itk_self
;
464 assert(pport
!= IP_NULL
);
467 task
->itk_self
= IP_NULL
;
469 rport
= task
->itk_resume
;
470 task
->itk_resume
= IP_NULL
;
474 /* release the naked send rights */
475 if (IP_VALID(sself
)) {
476 ipc_port_release_send(sself
);
480 for (int i
= 0; i
< DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
; i
++) {
481 if (IP_VALID(notifiers_ptr
[i
])) {
482 ipc_port_release_send(notifiers_ptr
[i
]);
485 kfree(notifiers_ptr
, DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
* sizeof(ipc_port_t
));
488 for (int i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
489 if (IP_VALID(task
->exc_actions
[i
].port
)) {
490 ipc_port_release_send(task
->exc_actions
[i
].port
);
493 mac_exc_free_action_label(task
->exc_actions
+ i
);
497 if (IP_VALID(task
->itk_host
)) {
498 ipc_port_release_send(task
->itk_host
);
501 if (IP_VALID(task
->itk_bootstrap
)) {
502 ipc_port_release_send(task
->itk_bootstrap
);
505 if (IP_VALID(task
->itk_seatbelt
)) {
506 ipc_port_release_send(task
->itk_seatbelt
);
509 if (IP_VALID(task
->itk_gssd
)) {
510 ipc_port_release_send(task
->itk_gssd
);
513 if (IP_VALID(task
->itk_task_access
)) {
514 ipc_port_release_send(task
->itk_task_access
);
517 if (IP_VALID(task
->itk_debug_control
)) {
518 ipc_port_release_send(task
->itk_debug_control
);
521 for (int i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++) {
522 if (IP_VALID(task
->itk_registered
[i
])) {
523 ipc_port_release_send(task
->itk_registered
[i
]);
527 /* destroy the kernel ports */
528 if (immovable_control_port_enabled
) {
530 kport
->ip_alt_port
= IP_NULL
;
531 ipc_kobject_set_atomically(kport
, IKO_NULL
, IKOT_NONE
);
534 /* pport == kport if immovability is off */
535 ipc_port_dealloc_kernel(pport
);
537 ipc_port_dealloc_kernel(kport
);
538 ipc_port_dealloc_kernel(nport
);
539 if (iport
!= IP_NULL
) {
540 ipc_port_dealloc_kernel(iport
);
542 if (rdport
!= IP_NULL
) {
543 ipc_port_dealloc_kernel(rdport
);
545 if (rport
!= IP_NULL
) {
546 ipc_port_dealloc_kernel(rport
);
549 itk_lock_destroy(task
);
553 * Routine: ipc_task_reset
555 * Reset a task's IPC state to protect it when
556 * it enters an elevated security context. The
557 * task name port can remain the same - since it
558 * represents no specific privilege.
560 * Nothing locked. The task must be suspended.
561 * (Or the current thread must be in the task.)
568 ipc_port_t old_kport
, old_pport
, new_kport
, new_pport
;
569 ipc_port_t old_sself
;
570 ipc_port_t old_rdport
;
571 ipc_port_t old_iport
;
572 ipc_port_t old_exc_actions
[EXC_TYPES_COUNT
];
573 ipc_port_t
*notifiers_ptr
= NULL
;
576 /* Fresh label to unset credentials in existing labels. */
577 struct label
*unset_label
= mac_exc_create_label();
580 if (immovable_control_port_enabled
) {
581 ipc_kobject_alloc_options_t options
= IPC_KOBJECT_ALLOC_IMMOVABLE_SEND
;
582 if (pinned_control_port_enabled
) {
583 options
|= IPC_KOBJECT_ALLOC_PINNED
;
586 new_pport
= ipc_kobject_alloc_port((ipc_kobject_t
)task
,
587 IKOT_TASK_CONTROL
, options
);
589 new_kport
= ipc_kobject_alloc_labeled_port((ipc_kobject_t
)task
,
590 IKOT_TASK_CONTROL
, IPC_LABEL_SUBST_TASK
,
591 IPC_KOBJECT_ALLOC_NONE
);
592 new_kport
->ip_alt_port
= new_pport
;
594 new_kport
= ipc_kobject_alloc_port((ipc_kobject_t
)task
,
595 IKOT_TASK_CONTROL
, IPC_KOBJECT_ALLOC_NONE
);
597 new_pport
= new_kport
;
602 old_kport
= task
->itk_task_ports
[TASK_FLAVOR_CONTROL
];
603 old_rdport
= task
->itk_task_ports
[TASK_FLAVOR_READ
];
604 old_iport
= task
->itk_task_ports
[TASK_FLAVOR_INSPECT
];
606 old_pport
= task
->itk_self
;
608 if (old_pport
== IP_NULL
) {
609 /* the task is already terminated (can this happen?) */
611 ipc_port_dealloc_kernel(new_kport
);
612 if (immovable_control_port_enabled
) {
613 ipc_port_dealloc_kernel(new_pport
);
616 mac_exc_free_label(unset_label
);
621 old_sself
= task
->itk_settable_self
;
622 task
->itk_task_ports
[TASK_FLAVOR_CONTROL
] = new_kport
;
623 task
->itk_self
= new_pport
;
625 task
->itk_settable_self
= ipc_port_make_send(new_kport
);
627 /* Set the old kport to IKOT_NONE and update the exec token while under the port lock */
629 old_kport
->ip_alt_port
= IP_NULL
;
630 ipc_kobject_set_atomically(old_kport
, IKO_NULL
, IKOT_NONE
);
631 task
->exec_token
+= 1;
632 ip_unlock(old_kport
);
634 /* Reset the read and inspect flavors of task port */
635 task
->itk_task_ports
[TASK_FLAVOR_READ
] = IP_NULL
;
636 task
->itk_task_ports
[TASK_FLAVOR_INSPECT
] = IP_NULL
;
638 if (immovable_control_port_enabled
) {
640 ipc_kobject_set_atomically(old_pport
, IKO_NULL
, IKOT_NONE
);
641 task
->exec_token
+= 1;
642 ip_unlock(old_pport
);
645 for (int i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
646 old_exc_actions
[i
] = IP_NULL
;
648 if (i
== EXC_CORPSE_NOTIFY
&& task_corpse_pending_report(task
)) {
652 if (!task
->exc_actions
[i
].privileged
) {
654 mac_exc_update_action_label(task
->exc_actions
+ i
, unset_label
);
656 old_exc_actions
[i
] = task
->exc_actions
[i
].port
;
657 task
->exc_actions
[i
].port
= IP_NULL
;
661 if (IP_VALID(task
->itk_debug_control
)) {
662 ipc_port_release_send(task
->itk_debug_control
);
664 task
->itk_debug_control
= IP_NULL
;
666 if (task
->itk_dyld_notify
) {
667 notifiers_ptr
= task
->itk_dyld_notify
;
668 task
->itk_dyld_notify
= NULL
;
674 mac_exc_free_label(unset_label
);
677 /* release the naked send rights */
679 if (IP_VALID(old_sself
)) {
680 ipc_port_release_send(old_sself
);
684 for (int i
= 0; i
< DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
; i
++) {
685 if (IP_VALID(notifiers_ptr
[i
])) {
686 ipc_port_release_send(notifiers_ptr
[i
]);
689 kfree(notifiers_ptr
, DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
* sizeof(ipc_port_t
));
692 for (int i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
693 if (IP_VALID(old_exc_actions
[i
])) {
694 ipc_port_release_send(old_exc_actions
[i
]);
698 /* destroy all task port flavors */
699 ipc_port_dealloc_kernel(old_kport
);
700 if (immovable_control_port_enabled
) {
701 ipc_port_dealloc_kernel(old_pport
);
703 if (old_rdport
!= IP_NULL
) {
704 ipc_port_dealloc_kernel(old_rdport
);
706 if (old_iport
!= IP_NULL
) {
707 ipc_port_dealloc_kernel(old_iport
);
712 * Routine: ipc_thread_init
714 * Initialize a thread's IPC state.
722 ipc_thread_init_options_t options
)
726 ipc_kobject_alloc_options_t alloc_options
= IPC_KOBJECT_ALLOC_NONE
;
729 * Having immovable_control_port_enabled boot-arg set does not guarantee
730 * thread control port should be made immovable/pinned, also check options.
732 * raw mach threads created via thread_create() have neither of INIT_PINNED
733 * or INIT_IMMOVABLE set.
735 if (immovable_control_port_enabled
&& (options
& IPC_THREAD_INIT_IMMOVABLE
)) {
736 alloc_options
|= IPC_KOBJECT_ALLOC_IMMOVABLE_SEND
;
738 if (pinned_control_port_enabled
&& (options
& IPC_THREAD_INIT_PINNED
)) {
739 alloc_options
|= IPC_KOBJECT_ALLOC_PINNED
;
742 pport
= ipc_kobject_alloc_port((ipc_kobject_t
)thread
,
743 IKOT_THREAD_CONTROL
, alloc_options
);
745 kport
= ipc_kobject_alloc_labeled_port((ipc_kobject_t
)thread
,
746 IKOT_THREAD_CONTROL
, IPC_LABEL_SUBST_THREAD
, IPC_KOBJECT_ALLOC_NONE
);
747 kport
->ip_alt_port
= pport
;
749 kport
= ipc_kobject_alloc_port((ipc_kobject_t
)thread
,
750 IKOT_THREAD_CONTROL
, IPC_KOBJECT_ALLOC_NONE
);
755 thread
->ith_thread_ports
[THREAD_FLAVOR_CONTROL
] = kport
;
757 thread
->ith_settable_self
= ipc_port_make_send(kport
);
759 thread
->ith_self
= pport
;
761 thread
->ith_special_reply_port
= NULL
;
762 thread
->exc_actions
= NULL
;
764 #if IMPORTANCE_INHERITANCE
765 thread
->ith_assertions
= 0;
768 thread
->ipc_active
= true;
769 ipc_kmsg_queue_init(&thread
->ith_messages
);
771 thread
->ith_rpc_reply
= IP_NULL
;
775 ipc_thread_init_exc_actions(
778 assert(thread
->exc_actions
== NULL
);
780 thread
->exc_actions
= kalloc(sizeof(struct exception_action
) * EXC_TYPES_COUNT
);
781 bzero(thread
->exc_actions
, sizeof(struct exception_action
) * EXC_TYPES_COUNT
);
784 for (size_t i
= 0; i
< EXC_TYPES_COUNT
; ++i
) {
785 mac_exc_associate_action_label(thread
->exc_actions
+ i
, mac_exc_create_label());
791 ipc_thread_destroy_exc_actions(
794 if (thread
->exc_actions
!= NULL
) {
796 for (size_t i
= 0; i
< EXC_TYPES_COUNT
; ++i
) {
797 mac_exc_free_action_label(thread
->exc_actions
+ i
);
801 kfree(thread
->exc_actions
,
802 sizeof(struct exception_action
) * EXC_TYPES_COUNT
);
803 thread
->exc_actions
= NULL
;
808 * Routine: ipc_thread_disable
810 * Clean up and destroy a thread's IPC state.
818 ipc_port_t kport
= thread
->ith_thread_ports
[THREAD_FLAVOR_CONTROL
];
819 ipc_port_t iport
= thread
->ith_thread_ports
[THREAD_FLAVOR_INSPECT
];
820 ipc_port_t rdport
= thread
->ith_thread_ports
[THREAD_FLAVOR_READ
];
821 ipc_port_t pport
= thread
->ith_self
;
824 * This innocuous looking line is load bearing.
826 * It is used to disable the creation of lazy made ports.
827 * We must do so before we drop the last reference on the thread,
828 * as thread ports do not own a reference on the thread, and
829 * convert_port_to_thread* will crash trying to resurect a thread.
831 thread
->ipc_active
= false;
833 if (kport
!= IP_NULL
) {
835 kport
->ip_alt_port
= IP_NULL
;
836 ipc_kobject_set_atomically(kport
, IKO_NULL
, IKOT_NONE
);
840 if (iport
!= IP_NULL
) {
841 ipc_kobject_set(iport
, IKO_NULL
, IKOT_NONE
);
844 if (rdport
!= IP_NULL
) {
845 ipc_kobject_set(rdport
, IKO_NULL
, IKOT_NONE
);
848 if (pport
!= kport
&& pport
!= IP_NULL
) {
849 assert(immovable_control_port_enabled
);
850 assert(pport
->ip_immovable_send
);
851 ipc_kobject_set(pport
, IKO_NULL
, IKOT_NONE
);
854 /* unbind the thread special reply port */
855 if (IP_VALID(thread
->ith_special_reply_port
)) {
856 ipc_port_unbind_special_reply_port(thread
, TRUE
);
861 * Routine: ipc_thread_terminate
863 * Clean up and destroy a thread's IPC state.
869 ipc_thread_terminate(
872 ipc_port_t kport
= IP_NULL
;
873 ipc_port_t iport
= IP_NULL
;
874 ipc_port_t rdport
= IP_NULL
;
875 ipc_port_t ith_rpc_reply
= IP_NULL
;
876 ipc_port_t pport
= IP_NULL
;
878 thread_mtx_lock(thread
);
881 * If we ever failed to clear ipc_active before the last reference
882 * was dropped, lazy ports might be made and used after the last
883 * reference is dropped and cause use after free (see comment in
884 * ipc_thread_disable()).
886 assert(!thread
->ipc_active
);
888 kport
= thread
->ith_thread_ports
[THREAD_FLAVOR_CONTROL
];
889 iport
= thread
->ith_thread_ports
[THREAD_FLAVOR_INSPECT
];
890 rdport
= thread
->ith_thread_ports
[THREAD_FLAVOR_READ
];
891 pport
= thread
->ith_self
;
893 if (kport
!= IP_NULL
) {
894 if (IP_VALID(thread
->ith_settable_self
)) {
895 ipc_port_release_send(thread
->ith_settable_self
);
898 thread
->ith_thread_ports
[THREAD_FLAVOR_CONTROL
] = IP_NULL
;
899 thread
->ith_thread_ports
[THREAD_FLAVOR_READ
] = IP_NULL
;
900 thread
->ith_thread_ports
[THREAD_FLAVOR_INSPECT
] = IP_NULL
;
901 thread
->ith_settable_self
= IP_NULL
;
902 thread
->ith_self
= IP_NULL
;
904 if (thread
->exc_actions
!= NULL
) {
905 for (int i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
906 if (IP_VALID(thread
->exc_actions
[i
].port
)) {
907 ipc_port_release_send(thread
->exc_actions
[i
].port
);
910 ipc_thread_destroy_exc_actions(thread
);
914 #if IMPORTANCE_INHERITANCE
915 assert(thread
->ith_assertions
== 0);
918 assert(ipc_kmsg_queue_empty(&thread
->ith_messages
));
919 ith_rpc_reply
= thread
->ith_rpc_reply
;
920 thread
->ith_rpc_reply
= IP_NULL
;
922 thread_mtx_unlock(thread
);
924 if (pport
!= kport
&& pport
!= IP_NULL
) {
925 /* this thread has immovable contorl port */
927 kport
->ip_alt_port
= IP_NULL
;
928 ipc_kobject_set_atomically(kport
, IKO_NULL
, IKOT_NONE
);
930 ipc_port_dealloc_kernel(pport
);
932 if (kport
!= IP_NULL
) {
933 ipc_port_dealloc_kernel(kport
);
935 if (iport
!= IP_NULL
) {
936 ipc_port_dealloc_kernel(iport
);
938 if (rdport
!= IP_NULL
) {
939 ipc_port_dealloc_kernel(rdport
);
941 if (ith_rpc_reply
!= IP_NULL
) {
942 ipc_port_dealloc_reply(ith_rpc_reply
);
947 * Routine: ipc_thread_reset
949 * Reset the IPC state for a given Mach thread when
950 * its task enters an elevated security context.
951 * All flavors of thread port and its exception ports have
952 * to be reset. Its RPC reply port cannot have any
953 * rights outstanding, so it should be fine. The thread
954 * inspect and read port are set to NULL.
963 ipc_port_t old_kport
, new_kport
, old_pport
, new_pport
;
964 ipc_port_t old_sself
;
965 ipc_port_t old_rdport
;
966 ipc_port_t old_iport
;
967 ipc_port_t old_exc_actions
[EXC_TYPES_COUNT
];
968 boolean_t has_old_exc_actions
= FALSE
;
969 boolean_t thread_is_immovable
, thread_is_pinned
;
973 struct label
*new_label
= mac_exc_create_label();
976 thread_is_immovable
= thread
->ith_self
->ip_immovable_send
;
977 thread_is_pinned
= thread
->ith_self
->ip_pinned
;
979 if (thread_is_immovable
) {
980 ipc_kobject_alloc_options_t alloc_options
= IPC_KOBJECT_ALLOC_NONE
;
982 if (thread_is_pinned
) {
983 assert(pinned_control_port_enabled
);
984 alloc_options
|= IPC_KOBJECT_ALLOC_PINNED
;
986 if (thread_is_immovable
) {
987 alloc_options
|= IPC_KOBJECT_ALLOC_IMMOVABLE_SEND
;
989 new_pport
= ipc_kobject_alloc_port((ipc_kobject_t
)thread
,
990 IKOT_THREAD_CONTROL
, alloc_options
);
992 new_kport
= ipc_kobject_alloc_labeled_port((ipc_kobject_t
)thread
,
993 IKOT_THREAD_CONTROL
, IPC_LABEL_SUBST_THREAD
,
994 IPC_KOBJECT_ALLOC_NONE
);
995 new_kport
->ip_alt_port
= new_pport
;
997 new_kport
= ipc_kobject_alloc_port((ipc_kobject_t
)thread
,
998 IKOT_THREAD_CONTROL
, IPC_KOBJECT_ALLOC_NONE
);
1000 new_pport
= new_kport
;
1003 thread_mtx_lock(thread
);
1005 old_kport
= thread
->ith_thread_ports
[THREAD_FLAVOR_CONTROL
];
1006 old_rdport
= thread
->ith_thread_ports
[THREAD_FLAVOR_READ
];
1007 old_iport
= thread
->ith_thread_ports
[THREAD_FLAVOR_INSPECT
];
1009 old_sself
= thread
->ith_settable_self
;
1010 old_pport
= thread
->ith_self
;
1012 if (old_kport
== IP_NULL
&& thread
->inspection
== FALSE
) {
1013 /* thread is already terminated (can this happen?) */
1014 thread_mtx_unlock(thread
);
1015 ipc_port_dealloc_kernel(new_kport
);
1016 if (thread_is_immovable
) {
1017 ipc_port_dealloc_kernel(new_pport
);
1020 mac_exc_free_label(new_label
);
1025 thread
->ipc_active
= true;
1026 thread
->ith_thread_ports
[THREAD_FLAVOR_CONTROL
] = new_kport
;
1027 thread
->ith_self
= new_pport
;
1028 thread
->ith_settable_self
= ipc_port_make_send(new_kport
);
1029 thread
->ith_thread_ports
[THREAD_FLAVOR_INSPECT
] = IP_NULL
;
1030 thread
->ith_thread_ports
[THREAD_FLAVOR_READ
] = IP_NULL
;
1032 if (old_kport
!= IP_NULL
) {
1034 old_kport
->ip_alt_port
= IP_NULL
;
1035 ipc_kobject_set_atomically(old_kport
, IKO_NULL
, IKOT_NONE
);
1036 ip_unlock(old_kport
);
1038 if (old_rdport
!= IP_NULL
) {
1039 ipc_kobject_set(old_rdport
, IKO_NULL
, IKOT_NONE
);
1041 if (old_iport
!= IP_NULL
) {
1042 ipc_kobject_set(old_iport
, IKO_NULL
, IKOT_NONE
);
1044 if (thread_is_immovable
&& old_pport
!= IP_NULL
) {
1045 ipc_kobject_set(old_pport
, IKO_NULL
, IKOT_NONE
);
1049 * Only ports that were set by root-owned processes
1050 * (privileged ports) should survive
1052 if (thread
->exc_actions
!= NULL
) {
1053 has_old_exc_actions
= TRUE
;
1054 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1055 if (thread
->exc_actions
[i
].privileged
) {
1056 old_exc_actions
[i
] = IP_NULL
;
1059 mac_exc_update_action_label(thread
->exc_actions
+ i
, new_label
);
1061 old_exc_actions
[i
] = thread
->exc_actions
[i
].port
;
1062 thread
->exc_actions
[i
].port
= IP_NULL
;
1067 thread_mtx_unlock(thread
);
1070 mac_exc_free_label(new_label
);
1073 /* release the naked send rights */
1075 if (IP_VALID(old_sself
)) {
1076 ipc_port_release_send(old_sself
);
1079 if (has_old_exc_actions
) {
1080 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1081 ipc_port_release_send(old_exc_actions
[i
]);
1085 /* destroy the kernel port */
1086 if (old_kport
!= IP_NULL
) {
1087 ipc_port_dealloc_kernel(old_kport
);
1089 if (old_rdport
!= IP_NULL
) {
1090 ipc_port_dealloc_kernel(old_rdport
);
1092 if (old_iport
!= IP_NULL
) {
1093 ipc_port_dealloc_kernel(old_iport
);
1096 if (thread_is_immovable
&& old_pport
!= IP_NULL
) {
1097 ipc_port_dealloc_kernel(old_pport
);
1100 /* unbind the thread special reply port */
1101 if (IP_VALID(thread
->ith_special_reply_port
)) {
1102 ipc_port_unbind_special_reply_port(thread
, TRUE
);
1107 * Routine: retrieve_task_self_fast
1109 * Optimized version of retrieve_task_self,
1110 * that only works for the current task.
1112 * Return a send right (possibly null/dead)
1113 * for the task's user-visible self port.
1119 retrieve_task_self_fast(
1122 ipc_port_t port
= IP_NULL
;
1124 assert(task
== current_task());
1127 assert(task
->itk_self
!= IP_NULL
);
1129 if (task
->itk_settable_self
== task
->itk_task_ports
[TASK_FLAVOR_CONTROL
]) {
1130 /* no interposing, return the IMMOVABLE port */
1131 port
= ipc_port_make_send(task
->itk_self
);
1132 if (immovable_control_port_enabled
) {
1133 assert(port
->ip_immovable_send
== 1);
1134 if (pinned_control_port_enabled
) {
1135 /* pinned port is also immovable */
1136 assert(port
->ip_pinned
== 1);
1140 port
= ipc_port_copy_send(task
->itk_settable_self
);
1148 * Routine: mach_task_is_self
1150 * [MIG call] Checks if the task (control/read/inspect/name/movable)
1151 * port is pointing to current_task.
1158 if (task
== TASK_NULL
) {
1159 return KERN_INVALID_ARGUMENT
;
1162 *is_self
= (task
== current_task());
1164 return KERN_SUCCESS
;
1168 * Routine: retrieve_thread_self_fast
1170 * Return a send right (possibly null/dead)
1171 * for the thread's user-visible self port.
1173 * Only works for the current thread.
1180 retrieve_thread_self_fast(
1183 ipc_port_t port
= IP_NULL
;
1185 assert(thread
== current_thread());
1187 thread_mtx_lock(thread
);
1189 assert(thread
->ith_self
!= IP_NULL
);
1191 if (thread
->ith_settable_self
== thread
->ith_thread_ports
[THREAD_FLAVOR_CONTROL
]) {
1192 /* no interposing, return IMMOVABLE_PORT */
1193 port
= ipc_port_make_send(thread
->ith_self
);
1195 port
= ipc_port_copy_send(thread
->ith_settable_self
);
1198 thread_mtx_unlock(thread
);
1204 * Routine: task_self_trap [mach trap]
1206 * Give the caller send rights for his own task port.
1210 * MACH_PORT_NULL if there are any resource failures
1216 __unused
struct task_self_trap_args
*args
)
1218 task_t task
= current_task();
1220 mach_port_name_t name
;
1222 sright
= retrieve_task_self_fast(task
);
1223 name
= ipc_port_copyout_send(sright
, task
->itk_space
);
1228 * Routine: thread_self_trap [mach trap]
1230 * Give the caller send rights for his own thread port.
1234 * MACH_PORT_NULL if there are any resource failures
1240 __unused
struct thread_self_trap_args
*args
)
1242 thread_t thread
= current_thread();
1243 task_t task
= thread
->task
;
1245 mach_port_name_t name
;
1247 sright
= retrieve_thread_self_fast(thread
);
1248 name
= ipc_port_copyout_send(sright
, task
->itk_space
);
1253 * Routine: mach_reply_port [mach trap]
1255 * Allocate a port for the caller.
1259 * MACH_PORT_NULL if there are any resource failures
1265 __unused
struct mach_reply_port_args
*args
)
1268 mach_port_name_t name
;
1271 kr
= ipc_port_alloc(current_task()->itk_space
, IPC_PORT_INIT_MESSAGE_QUEUE
,
1273 if (kr
== KERN_SUCCESS
) {
1276 name
= MACH_PORT_NULL
;
1282 * Routine: thread_get_special_reply_port [mach trap]
1284 * Allocate a special reply port for the calling thread.
1288 * mach_port_name_t: send right & receive right for special reply port.
1289 * MACH_PORT_NULL if there are any resource failures
1294 thread_get_special_reply_port(
1295 __unused
struct thread_get_special_reply_port_args
*args
)
1298 mach_port_name_t name
;
1300 thread_t thread
= current_thread();
1301 ipc_port_init_flags_t flags
= IPC_PORT_INIT_MESSAGE_QUEUE
|
1302 IPC_PORT_INIT_MAKE_SEND_RIGHT
| IPC_PORT_INIT_SPECIAL_REPLY
;
1304 /* unbind the thread special reply port */
1305 if (IP_VALID(thread
->ith_special_reply_port
)) {
1306 kr
= ipc_port_unbind_special_reply_port(thread
, TRUE
);
1307 if (kr
!= KERN_SUCCESS
) {
1308 return MACH_PORT_NULL
;
1312 kr
= ipc_port_alloc(current_task()->itk_space
, flags
, &name
, &port
);
1313 if (kr
== KERN_SUCCESS
) {
1314 ipc_port_bind_special_reply_port_locked(port
);
1317 name
= MACH_PORT_NULL
;
1323 * Routine: ipc_port_bind_special_reply_port_locked
1325 * Bind the given port to current thread as a special reply port.
1333 ipc_port_bind_special_reply_port_locked(
1336 thread_t thread
= current_thread();
1337 assert(thread
->ith_special_reply_port
== NULL
);
1338 assert(port
->ip_specialreply
);
1339 assert(port
->ip_sync_link_state
== PORT_SYNC_LINK_ANY
);
1342 thread
->ith_special_reply_port
= port
;
1343 port
->ip_messages
.imq_srp_owner_thread
= thread
;
1345 ipc_special_reply_port_bits_reset(port
);
1349 * Routine: ipc_port_unbind_special_reply_port
1351 * Unbind the thread's special reply port.
1352 * If the special port has threads waiting on turnstile,
1353 * update it's inheritor.
1359 static kern_return_t
1360 ipc_port_unbind_special_reply_port(
1362 boolean_t unbind_active_port
)
1364 ipc_port_t special_reply_port
= thread
->ith_special_reply_port
;
1366 ip_lock(special_reply_port
);
1368 /* Return error if port active and unbind_active_port set to FALSE */
1369 if (unbind_active_port
== FALSE
&& ip_active(special_reply_port
)) {
1370 ip_unlock(special_reply_port
);
1371 return KERN_FAILURE
;
1374 thread
->ith_special_reply_port
= NULL
;
1375 ipc_port_adjust_special_reply_port_locked(special_reply_port
, NULL
,
1376 IPC_PORT_ADJUST_UNLINK_THREAD
, FALSE
);
1379 ip_release(special_reply_port
);
1380 return KERN_SUCCESS
;
1384 * Routine: thread_get_special_port [kernel call]
1386 * Clones a send right for one of the thread's
1391 * KERN_SUCCESS Extracted a send right.
1392 * KERN_INVALID_ARGUMENT The thread is null.
1393 * KERN_FAILURE The thread is dead.
1394 * KERN_INVALID_ARGUMENT Invalid special port.
1398 thread_get_special_port(
1399 thread_inspect_t thread
,
1403 static kern_return_t
1404 thread_get_special_port_internal(
1405 thread_inspect_t thread
,
1408 mach_thread_flavor_t flavor
)
1413 if (thread
== THREAD_NULL
) {
1414 return KERN_INVALID_ARGUMENT
;
1417 if ((kr
= port_allowed_with_thread_flavor(which
, flavor
)) != KERN_SUCCESS
) {
1421 thread_mtx_lock(thread
);
1422 if (!thread
->active
) {
1423 thread_mtx_unlock(thread
);
1424 return KERN_FAILURE
;
1428 case THREAD_KERNEL_PORT
:
1429 port
= ipc_port_copy_send(thread
->ith_settable_self
);
1430 thread_mtx_unlock(thread
);
1433 case THREAD_READ_PORT
:
1434 case THREAD_INSPECT_PORT
:
1435 thread_mtx_unlock(thread
);
1436 mach_thread_flavor_t current_flavor
= (which
== THREAD_READ_PORT
) ?
1437 THREAD_FLAVOR_READ
: THREAD_FLAVOR_INSPECT
;
1438 /* convert_thread_to_port_with_flavor consumes a thread reference */
1439 thread_reference(thread
);
1440 port
= convert_thread_to_port_with_flavor(thread
, current_flavor
);
1444 thread_mtx_unlock(thread
);
1445 return KERN_INVALID_ARGUMENT
;
1449 return KERN_SUCCESS
;
1453 thread_get_special_port(
1454 thread_inspect_t thread
,
1458 return thread_get_special_port_internal(thread
, which
, portp
, THREAD_FLAVOR_CONTROL
);
1462 thread_get_non_substituted_self(thread_t thread
)
1464 ipc_port_t port
= IP_NULL
;
1466 thread_mtx_lock(thread
);
1467 port
= thread
->ith_settable_self
;
1468 if (IP_VALID(port
)) {
1471 thread_mtx_unlock(thread
);
1473 if (IP_VALID(port
)) {
1474 /* consumes the port reference */
1475 return ipc_kobject_alloc_subst_once(port
);
1482 thread_get_special_port_from_user(
1487 ipc_kobject_type_t kotype
;
1488 mach_thread_flavor_t flavor
;
1489 kern_return_t kr
= KERN_SUCCESS
;
1491 thread_t thread
= convert_port_to_thread_check_type(port
, &kotype
,
1492 THREAD_FLAVOR_INSPECT
, FALSE
);
1494 if (thread
== THREAD_NULL
) {
1495 return KERN_INVALID_ARGUMENT
;
1498 if (which
== THREAD_KERNEL_PORT
&& thread
->task
== current_task()) {
1501 * only check for threads belong to current_task,
1502 * because foreign thread ports are always movable
1504 if (mac_task_check_get_movable_control_port()) {
1509 if (kotype
== IKOT_THREAD_CONTROL
) {
1510 *portp
= thread_get_non_substituted_self(thread
);
1516 case IKOT_THREAD_CONTROL
:
1517 flavor
= THREAD_FLAVOR_CONTROL
;
1519 case IKOT_THREAD_READ
:
1520 flavor
= THREAD_FLAVOR_READ
;
1522 case IKOT_THREAD_INSPECT
:
1523 flavor
= THREAD_FLAVOR_INSPECT
;
1526 panic("strange kobject type");
1529 kr
= thread_get_special_port_internal(thread
, which
, portp
, flavor
);
1531 thread_deallocate(thread
);
1535 static kern_return_t
1536 port_allowed_with_thread_flavor(
1538 mach_thread_flavor_t flavor
)
1541 case THREAD_FLAVOR_CONTROL
:
1542 return KERN_SUCCESS
;
1544 case THREAD_FLAVOR_READ
:
1547 case THREAD_READ_PORT
:
1548 case THREAD_INSPECT_PORT
:
1549 return KERN_SUCCESS
;
1551 return KERN_INVALID_CAPABILITY
;
1554 case THREAD_FLAVOR_INSPECT
:
1557 case THREAD_INSPECT_PORT
:
1558 return KERN_SUCCESS
;
1560 return KERN_INVALID_CAPABILITY
;
1564 return KERN_INVALID_CAPABILITY
;
1569 * Routine: thread_set_special_port [kernel call]
1571 * Changes one of the thread's special ports,
1572 * setting it to the supplied send right.
1574 * Nothing locked. If successful, consumes
1575 * the supplied send right.
1577 * KERN_SUCCESS Changed the special port.
1578 * KERN_INVALID_ARGUMENT The thread is null.
1579 * KERN_INVALID_RIGHT Port is marked as immovable.
1580 * KERN_FAILURE The thread is dead.
1581 * KERN_INVALID_ARGUMENT Invalid special port.
1582 * KERN_NO_ACCESS Restricted access to set port.
1586 thread_set_special_port(
1591 kern_return_t result
= KERN_SUCCESS
;
1592 ipc_port_t
*whichp
, old
= IP_NULL
;
1594 if (thread
== THREAD_NULL
) {
1595 return KERN_INVALID_ARGUMENT
;
1598 if (IP_VALID(port
) && (port
->ip_immovable_receive
|| port
->ip_immovable_send
)) {
1599 return KERN_INVALID_RIGHT
;
1603 case THREAD_KERNEL_PORT
:
1605 if (csr_check(CSR_ALLOW_KERNEL_DEBUGGER
) != 0) {
1607 * Only allow setting of thread-self
1608 * special port from user-space when SIP is
1609 * disabled (for Mach-on-Mach emulation).
1611 return KERN_NO_ACCESS
;
1614 whichp
= &thread
->ith_settable_self
;
1618 return KERN_INVALID_ARGUMENT
;
1621 thread_mtx_lock(thread
);
1623 if (thread
->active
) {
1627 result
= KERN_FAILURE
;
1630 thread_mtx_unlock(thread
);
1632 if (IP_VALID(old
)) {
1633 ipc_port_release_send(old
);
1640 * Routine: task_get_special_port [kernel call]
1642 * Clones a send right for one of the task's
1647 * KERN_SUCCESS Extracted a send right.
1648 * KERN_INVALID_ARGUMENT The task is null.
1649 * KERN_FAILURE The task/space is dead.
1650 * KERN_INVALID_ARGUMENT Invalid special port.
1654 task_get_special_port(
1659 static kern_return_t
1660 task_get_special_port_internal(
1664 mach_task_flavor_t flavor
)
1669 if (task
== TASK_NULL
) {
1670 return KERN_INVALID_ARGUMENT
;
1673 if ((kr
= port_allowed_with_task_flavor(which
, flavor
)) != KERN_SUCCESS
) {
1678 if (!task
->ipc_active
) {
1680 return KERN_FAILURE
;
1684 case TASK_KERNEL_PORT
:
1685 port
= ipc_port_copy_send(task
->itk_settable_self
);
1689 case TASK_READ_PORT
:
1690 case TASK_INSPECT_PORT
:
1692 mach_task_flavor_t current_flavor
= (which
== TASK_READ_PORT
) ?
1693 TASK_FLAVOR_READ
: TASK_FLAVOR_INSPECT
;
1694 /* convert_task_to_port_with_flavor consumes a task reference */
1695 task_reference(task
);
1696 port
= convert_task_to_port_with_flavor(task
, current_flavor
);
1699 case TASK_NAME_PORT
:
1700 port
= ipc_port_make_send(task
->itk_task_ports
[TASK_FLAVOR_NAME
]);
1704 case TASK_HOST_PORT
:
1705 port
= ipc_port_copy_send(task
->itk_host
);
1709 case TASK_BOOTSTRAP_PORT
:
1710 port
= ipc_port_copy_send(task
->itk_bootstrap
);
1714 case TASK_SEATBELT_PORT
:
1715 port
= ipc_port_copy_send(task
->itk_seatbelt
);
1719 case TASK_ACCESS_PORT
:
1720 port
= ipc_port_copy_send(task
->itk_task_access
);
1724 case TASK_DEBUG_CONTROL_PORT
:
1725 port
= ipc_port_copy_send(task
->itk_debug_control
);
1731 return KERN_INVALID_ARGUMENT
;
1735 return KERN_SUCCESS
;
1739 task_get_special_port(
1744 return task_get_special_port_internal(task
, which
, portp
, TASK_FLAVOR_CONTROL
);
1748 task_get_non_substituted_self(task_t task
)
1750 ipc_port_t port
= IP_NULL
;
1753 port
= task
->itk_settable_self
;
1754 if (IP_VALID(port
)) {
1759 if (IP_VALID(port
)) {
1760 /* consumes the port reference */
1761 return ipc_kobject_alloc_subst_once(port
);
1767 task_get_special_port_from_user(
1772 ipc_kobject_type_t kotype
;
1773 mach_task_flavor_t flavor
;
1774 kern_return_t kr
= KERN_SUCCESS
;
1776 task_t task
= convert_port_to_task_check_type(port
, &kotype
,
1777 TASK_FLAVOR_INSPECT
, FALSE
);
1779 if (task
== TASK_NULL
) {
1780 return KERN_INVALID_ARGUMENT
;
1783 if (which
== TASK_KERNEL_PORT
&& task
== current_task()) {
1786 * only check for current_task,
1787 * because foreign task ports are always movable
1789 if (mac_task_check_get_movable_control_port()) {
1794 if (kotype
== IKOT_TASK_CONTROL
) {
1795 *portp
= task_get_non_substituted_self(task
);
1801 case IKOT_TASK_CONTROL
:
1802 flavor
= TASK_FLAVOR_CONTROL
;
1804 case IKOT_TASK_READ
:
1805 flavor
= TASK_FLAVOR_READ
;
1807 case IKOT_TASK_INSPECT
:
1808 flavor
= TASK_FLAVOR_INSPECT
;
1811 panic("strange kobject type");
1814 kr
= task_get_special_port_internal(task
, which
, portp
, flavor
);
1816 task_deallocate(task
);
1820 static kern_return_t
1821 port_allowed_with_task_flavor(
1823 mach_task_flavor_t flavor
)
1826 case TASK_FLAVOR_CONTROL
:
1827 return KERN_SUCCESS
;
1829 case TASK_FLAVOR_READ
:
1832 case TASK_READ_PORT
:
1833 case TASK_INSPECT_PORT
:
1834 case TASK_NAME_PORT
:
1835 return KERN_SUCCESS
;
1837 return KERN_INVALID_CAPABILITY
;
1840 case TASK_FLAVOR_INSPECT
:
1843 case TASK_INSPECT_PORT
:
1844 case TASK_NAME_PORT
:
1845 return KERN_SUCCESS
;
1847 return KERN_INVALID_CAPABILITY
;
1851 return KERN_INVALID_CAPABILITY
;
1856 * Routine: task_set_special_port [kernel call]
1858 * Changes one of the task's special ports,
1859 * setting it to the supplied send right.
1861 * Nothing locked. If successful, consumes
1862 * the supplied send right.
1864 * KERN_SUCCESS Changed the special port.
1865 * KERN_INVALID_ARGUMENT The task is null.
1866 * KERN_INVALID_RIGHT Port is marked as immovable.
1867 * KERN_FAILURE The task/space is dead.
1868 * KERN_INVALID_ARGUMENT Invalid special port.
1869 * KERN_NO_ACCESS Restricted access to set port.
1873 task_set_special_port(
1878 if (task
== TASK_NULL
) {
1879 return KERN_INVALID_ARGUMENT
;
1882 if (task_is_driver(current_task())) {
1883 return KERN_NO_ACCESS
;
1886 if (IP_VALID(port
) && (port
->ip_immovable_receive
|| port
->ip_immovable_send
)) {
1887 return KERN_INVALID_RIGHT
;
1891 case TASK_KERNEL_PORT
:
1892 case TASK_HOST_PORT
:
1894 if (csr_check(CSR_ALLOW_KERNEL_DEBUGGER
) == 0) {
1896 * Only allow setting of task-self / task-host
1897 * special ports from user-space when SIP is
1898 * disabled (for Mach-on-Mach emulation).
1903 return KERN_NO_ACCESS
;
1908 return task_set_special_port_internal(task
, which
, port
);
1912 * Routine: task_set_special_port_internal
1914 * Changes one of the task's special ports,
1915 * setting it to the supplied send right.
1917 * Nothing locked. If successful, consumes
1918 * the supplied send right.
1920 * KERN_SUCCESS Changed the special port.
1921 * KERN_INVALID_ARGUMENT The task is null.
1922 * KERN_FAILURE The task/space is dead.
1923 * KERN_INVALID_ARGUMENT Invalid special port.
1924 * KERN_NO_ACCESS Restricted access to overwrite port.
1928 task_set_special_port_internal(
1933 ipc_port_t old
= IP_NULL
;
1934 kern_return_t rc
= KERN_INVALID_ARGUMENT
;
1936 if (task
== TASK_NULL
) {
1941 if (!task
->ipc_active
) {
1947 case TASK_KERNEL_PORT
:
1948 old
= task
->itk_settable_self
;
1949 task
->itk_settable_self
= port
;
1952 case TASK_HOST_PORT
:
1953 old
= task
->itk_host
;
1954 task
->itk_host
= port
;
1957 case TASK_BOOTSTRAP_PORT
:
1958 old
= task
->itk_bootstrap
;
1959 task
->itk_bootstrap
= port
;
1962 /* Never allow overwrite of seatbelt port */
1963 case TASK_SEATBELT_PORT
:
1964 if (IP_VALID(task
->itk_seatbelt
)) {
1965 rc
= KERN_NO_ACCESS
;
1968 task
->itk_seatbelt
= port
;
1971 /* Never allow overwrite of the task access port */
1972 case TASK_ACCESS_PORT
:
1973 if (IP_VALID(task
->itk_task_access
)) {
1974 rc
= KERN_NO_ACCESS
;
1977 task
->itk_task_access
= port
;
1980 case TASK_DEBUG_CONTROL_PORT
:
1981 old
= task
->itk_debug_control
;
1982 task
->itk_debug_control
= port
;
1986 rc
= KERN_INVALID_ARGUMENT
;
1995 if (IP_VALID(old
)) {
1996 ipc_port_release_send(old
);
2002 * Routine: mach_ports_register [kernel call]
2004 * Stash a handful of port send rights in the task.
2005 * Child tasks will inherit these rights, but they
2006 * must use mach_ports_lookup to acquire them.
2008 * The rights are supplied in a (wired) kalloc'd segment.
2009 * Rights which aren't supplied are assumed to be null.
2011 * Nothing locked. If successful, consumes
2012 * the supplied rights and memory.
2014 * KERN_SUCCESS Stashed the port rights.
2015 * KERN_INVALID_RIGHT Port in array is marked immovable.
2016 * KERN_INVALID_ARGUMENT The task is null.
2017 * KERN_INVALID_ARGUMENT The task is dead.
2018 * KERN_INVALID_ARGUMENT The memory param is null.
2019 * KERN_INVALID_ARGUMENT Too many port rights supplied.
2023 mach_ports_register(
2025 mach_port_array_t memory
,
2026 mach_msg_type_number_t portsCnt
)
2028 ipc_port_t ports
[TASK_PORT_REGISTER_MAX
];
2031 if ((task
== TASK_NULL
) ||
2032 (portsCnt
> TASK_PORT_REGISTER_MAX
) ||
2033 (portsCnt
&& memory
== NULL
)) {
2034 return KERN_INVALID_ARGUMENT
;
2038 * Pad the port rights with nulls.
2041 for (i
= 0; i
< portsCnt
; i
++) {
2042 ports
[i
] = memory
[i
];
2043 if (IP_VALID(ports
[i
]) && (ports
[i
]->ip_immovable_receive
|| ports
[i
]->ip_immovable_send
)) {
2044 return KERN_INVALID_RIGHT
;
2047 for (; i
< TASK_PORT_REGISTER_MAX
; i
++) {
2052 if (!task
->ipc_active
) {
2054 return KERN_INVALID_ARGUMENT
;
2058 * Replace the old send rights with the new.
2059 * Release the old rights after unlocking.
2062 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++) {
2065 old
= task
->itk_registered
[i
];
2066 task
->itk_registered
[i
] = ports
[i
];
2072 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++) {
2073 if (IP_VALID(ports
[i
])) {
2074 ipc_port_release_send(ports
[i
]);
2079 * Now that the operation is known to be successful,
2080 * we can free the memory.
2083 if (portsCnt
!= 0) {
2085 (vm_size_t
) (portsCnt
* sizeof(mach_port_t
)));
2088 return KERN_SUCCESS
;
2092 * Routine: mach_ports_lookup [kernel call]
2094 * Retrieves (clones) the stashed port send rights.
2096 * Nothing locked. If successful, the caller gets
2097 * rights and memory.
2099 * KERN_SUCCESS Retrieved the send rights.
2100 * KERN_INVALID_ARGUMENT The task is null.
2101 * KERN_INVALID_ARGUMENT The task is dead.
2102 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
2108 mach_port_array_t
*portsp
,
2109 mach_msg_type_number_t
*portsCnt
)
2116 if (task
== TASK_NULL
) {
2117 return KERN_INVALID_ARGUMENT
;
2120 size
= (vm_size_t
) (TASK_PORT_REGISTER_MAX
* sizeof(ipc_port_t
));
2122 memory
= kalloc(size
);
2124 return KERN_RESOURCE_SHORTAGE
;
2128 if (!task
->ipc_active
) {
2131 kfree(memory
, size
);
2132 return KERN_INVALID_ARGUMENT
;
2135 ports
= (ipc_port_t
*) memory
;
2138 * Clone port rights. Because kalloc'd memory
2139 * is wired, we won't fault while holding the task lock.
2142 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++) {
2143 ports
[i
] = ipc_port_copy_send(task
->itk_registered
[i
]);
2148 *portsp
= (mach_port_array_t
) ports
;
2149 *portsCnt
= TASK_PORT_REGISTER_MAX
;
2150 return KERN_SUCCESS
;
2154 task_conversion_eval(task_t caller
, task_t victim
)
2157 * Tasks are allowed to resolve their own task ports, and the kernel is
2158 * allowed to resolve anyone's task port.
2160 if (caller
== kernel_task
) {
2161 return KERN_SUCCESS
;
2164 if (caller
== victim
) {
2165 return KERN_SUCCESS
;
2169 * Only the kernel can can resolve the kernel's task port. We've established
2170 * by this point that the caller is not kernel_task.
2172 if (victim
== TASK_NULL
|| victim
== kernel_task
) {
2173 return KERN_INVALID_SECURITY
;
2176 task_require(victim
);
2178 #if !defined(XNU_TARGET_OS_OSX)
2180 * On platforms other than macOS, only a platform binary can resolve the task port
2181 * of another platform binary.
2183 if ((victim
->t_flags
& TF_PLATFORM
) && !(caller
->t_flags
& TF_PLATFORM
)) {
2185 return KERN_INVALID_SECURITY
;
2187 if (cs_relax_platform_task_ports
) {
2188 return KERN_SUCCESS
;
2190 return KERN_INVALID_SECURITY
;
2192 #endif /* SECURE_KERNEL */
2194 #endif /* !defined(XNU_TARGET_OS_OSX) */
2196 return KERN_SUCCESS
;
2200 * Routine: convert_port_to_locked_task
2202 * Internal helper routine to convert from a port to a locked
2203 * task. Used by several routines that try to convert from a
2204 * task port to a reference on some task related object.
2206 * Nothing locked, blocking OK.
2209 convert_port_to_locked_task(ipc_port_t port
, boolean_t eval
)
2211 int try_failed_count
= 0;
2213 while (IP_VALID(port
)) {
2214 task_t ct
= current_task();
2218 if (!ip_active(port
) || (ip_kotype(port
) != IKOT_TASK_CONTROL
)) {
2222 task
= (task_t
) ip_get_kobject(port
);
2223 assert(task
!= TASK_NULL
);
2225 if (eval
&& task_conversion_eval(ct
, task
)) {
2231 * Normal lock ordering puts task_lock() before ip_lock().
2232 * Attempt out-of-order locking here.
2234 if (task_lock_try(task
)) {
2241 mutex_pause(try_failed_count
);
2247 * Routine: convert_port_to_locked_task_inspect
2249 * Internal helper routine to convert from a port to a locked
2250 * task inspect right. Used by internal routines that try to convert from a
2251 * task inspect port to a reference on some task related object.
2253 * Nothing locked, blocking OK.
2255 static task_inspect_t
2256 convert_port_to_locked_task_inspect(ipc_port_t port
)
2258 int try_failed_count
= 0;
2260 while (IP_VALID(port
)) {
2261 task_inspect_t task
;
2264 if (!ip_active(port
) || (ip_kotype(port
) != IKOT_TASK_CONTROL
&&
2265 ip_kotype(port
) != IKOT_TASK_READ
&&
2266 ip_kotype(port
) != IKOT_TASK_INSPECT
)) {
2268 return TASK_INSPECT_NULL
;
2270 task
= (task_inspect_t
) ip_get_kobject(port
);
2271 assert(task
!= TASK_INSPECT_NULL
);
2273 * Normal lock ordering puts task_lock() before ip_lock().
2274 * Attempt out-of-order locking here.
2276 if (task_lock_try((task_t
)task
)) {
2283 mutex_pause(try_failed_count
);
2285 return TASK_INSPECT_NULL
;
2289 * Routine: convert_port_to_locked_task_read
2291 * Internal helper routine to convert from a port to a locked
2292 * task read right. Used by internal routines that try to convert from a
2293 * task read port to a reference on some task related object.
2295 * Nothing locked, blocking OK.
2298 convert_port_to_locked_task_read(
2302 int try_failed_count
= 0;
2304 while (IP_VALID(port
)) {
2305 task_t ct
= current_task();
2309 if (!ip_active(port
) || (ip_kotype(port
) != IKOT_TASK_CONTROL
&&
2310 ip_kotype(port
) != IKOT_TASK_READ
)) {
2312 return TASK_READ_NULL
;
2314 task
= (task_read_t
)ipc_kobject_get(port
);
2315 assert(task
!= TASK_READ_NULL
);
2317 if (eval
&& task_conversion_eval(ct
, task
)) {
2319 return TASK_READ_NULL
;
2323 * Normal lock ordering puts task_lock() before ip_lock().
2324 * Attempt out-of-order locking here.
2326 if (task_lock_try((task_t
)task
)) {
2333 mutex_pause(try_failed_count
);
2335 return TASK_READ_NULL
;
2339 convert_port_to_task_locked(
2341 uint32_t *exec_token
,
2344 task_t task
= TASK_NULL
;
2347 require_ip_active(port
);
2349 if (ip_kotype(port
) == IKOT_TASK_CONTROL
) {
2350 task
= (task_t
) ip_get_kobject(port
);
2351 assert(task
!= TASK_NULL
);
2353 if (eval
&& task_conversion_eval(current_task(), task
)) {
2358 *exec_token
= task
->exec_token
;
2361 task_reference_internal(task
);
2368 * Routine: convert_port_to_task_with_exec_token
2370 * Convert from a port to a task and return
2371 * the exec token stored in the task.
2372 * Doesn't consume the port ref; produces a task ref,
2373 * which may be null.
2378 convert_port_to_task_with_exec_token(
2380 uint32_t *exec_token
,
2383 task_t task
= TASK_NULL
;
2385 if (IP_VALID(port
)) {
2387 if (ip_active(port
)) {
2388 task
= convert_port_to_task_locked(port
, exec_token
, eval
);
2397 * Routine: convert_port_to_task
2399 * Convert from a port to a task.
2400 * Doesn't consume the port ref; produces a task ref,
2401 * which may be null.
2406 convert_port_to_task(
2409 return convert_port_to_task_with_exec_token(port
, NULL
, TRUE
);
2413 * Routine: convert_port_to_task_no_eval
2415 * Convert from a port to a task, skips task_conversion_eval.
2416 * Doesn't consume the port ref; produces a task ref,
2417 * which may be null.
2422 convert_port_to_task_no_eval(
2425 return convert_port_to_task_with_exec_token(port
, NULL
, FALSE
);
2429 * Routine: convert_port_to_task_name
2431 * Convert from a port to a task name.
2432 * Doesn't consume the port ref; produces a task name ref,
2433 * which may be null.
2439 convert_port_to_task_name_locked(
2442 task_name_t task
= TASK_NAME_NULL
;
2445 require_ip_active(port
);
2447 if (ip_kotype(port
) == IKOT_TASK_CONTROL
||
2448 ip_kotype(port
) == IKOT_TASK_READ
||
2449 ip_kotype(port
) == IKOT_TASK_INSPECT
||
2450 ip_kotype(port
) == IKOT_TASK_NAME
) {
2451 task
= (task_name_t
) ip_get_kobject(port
);
2452 assert(task
!= TASK_NAME_NULL
);
2454 task_reference_internal(task
);
2461 convert_port_to_task_name(
2464 task_name_t task
= TASK_NULL
;
2466 if (IP_VALID(port
)) {
2468 if (ip_active(port
)) {
2469 task
= convert_port_to_task_name_locked(port
);
2478 * Routine: convert_port_to_task_policy
2480 * Convert from a port to a task.
2481 * Doesn't consume the port ref; produces a task ref,
2482 * which may be null.
2483 * If the port is being used with task_port_set(), any task port
2484 * type other than TASK_CONTROL requires an entitlement. If the
2485 * port is being used with task_port_get(), TASK_NAME requires an
2491 convert_port_to_task_policy(ipc_port_t port
, boolean_t set
)
2493 task_t task
= TASK_NULL
;
2494 task_t ctask
= current_task();
2496 if (!IP_VALID(port
)) {
2501 convert_port_to_task(port
) :
2502 convert_port_to_task_inspect(port
);
2504 if (task
== TASK_NULL
&&
2505 IOTaskHasEntitlement(ctask
, "com.apple.private.task_policy")) {
2506 task
= convert_port_to_task_name(port
);
2509 if (task_conversion_eval(ctask
, task
) != KERN_SUCCESS
) {
2510 task_deallocate(task
);
2518 convert_port_to_task_policy_set(ipc_port_t port
)
2520 return convert_port_to_task_policy(port
, true);
2524 convert_port_to_task_policy_get(ipc_port_t port
)
2526 return convert_port_to_task_policy(port
, false);
2529 static task_inspect_t
2530 convert_port_to_task_inspect_locked(
2533 task_inspect_t task
= TASK_INSPECT_NULL
;
2536 require_ip_active(port
);
2538 if (ip_kotype(port
) == IKOT_TASK_CONTROL
||
2539 ip_kotype(port
) == IKOT_TASK_READ
||
2540 ip_kotype(port
) == IKOT_TASK_INSPECT
) {
2541 task
= (task_inspect_t
) ip_get_kobject(port
);
2542 assert(task
!= TASK_INSPECT_NULL
);
2544 task_reference_internal(task
);
2551 convert_port_to_task_read_locked(
2555 task_read_t task
= TASK_READ_NULL
;
2558 require_ip_active(port
);
2560 if (ip_kotype(port
) == IKOT_TASK_CONTROL
||
2561 ip_kotype(port
) == IKOT_TASK_READ
) {
2562 task_t ct
= current_task();
2563 task
= (task_read_t
)ipc_kobject_get(port
);
2565 assert(task
!= TASK_READ_NULL
);
2567 if (eval
&& task_conversion_eval(ct
, task
)) {
2568 return TASK_READ_NULL
;
2571 task_reference_internal(task
);
2578 * Routine: convert_port_to_task_check_type
2580 * Convert from a port to a task based on port's type.
2581 * Doesn't consume the port ref; produces a task ref,
2582 * which may be null.
2584 * port: The port that we do conversion on
2585 * kotype: Returns the IKOT_TYPE of the port, if translation succeeded
2586 * at_most: The lowest capability flavor allowed. In mach_task_flavor_t,
2587 * the higher the flavor number, the lesser the capability, hence the name.
2588 * eval_check: Whether to run task_conversion_eval check during the conversion.
2589 * For backward compatibility, some interfaces does not run conversion
2590 * eval on IKOT_TASK_CONTROL.
2594 * task_t and port's type, if translation succeeded;
2595 * TASK_NULL and IKOT_NONE, if translation failed
2598 convert_port_to_task_check_type(
2600 ipc_kobject_type_t
*kotype
,
2601 mach_task_flavor_t at_most
,
2602 boolean_t eval_check
)
2604 task_t task
= TASK_NULL
;
2605 ipc_kobject_type_t type
= IKOT_NONE
;
2607 if (!IP_VALID(port
) || !ip_active(port
)) {
2611 switch (ip_kotype(port
)) {
2612 case IKOT_TASK_CONTROL
:
2613 task
= eval_check
? convert_port_to_task(port
) : convert_port_to_task_no_eval(port
);
2614 if (task
!= TASK_NULL
) {
2615 type
= IKOT_TASK_CONTROL
;
2618 case IKOT_TASK_READ
:
2619 if (at_most
>= TASK_FLAVOR_READ
) {
2620 task
= eval_check
? convert_port_to_task_read(port
) : convert_port_to_task_read_no_eval(port
);
2621 if (task
!= TASK_READ_NULL
) {
2622 type
= IKOT_TASK_READ
;
2626 case IKOT_TASK_INSPECT
:
2627 if (at_most
>= TASK_FLAVOR_INSPECT
) {
2628 task
= convert_port_to_task_inspect(port
);
2629 if (task
!= TASK_INSPECT_NULL
) {
2630 type
= IKOT_TASK_INSPECT
;
2634 case IKOT_TASK_NAME
:
2635 if (at_most
>= TASK_FLAVOR_NAME
) {
2636 task
= convert_port_to_task_name(port
);
2637 if (task
!= TASK_NAME_NULL
) {
2638 type
= IKOT_TASK_NAME
;
2654 * Routine: convert_port_to_thread_check_type
2656 * Convert from a port to a thread based on port's type.
2657 * Doesn't consume the port ref; produces a thread ref,
2658 * which may be null.
2659 * This conversion routine is _ONLY_ supposed to be used
2660 * by thread_get_special_port.
2662 * port: The port that we do conversion on
2663 * kotype: Returns the IKOT_TYPE of the port, if translation succeeded
2664 * at_most: The lowest capability flavor allowed. In mach_thread_flavor_t,
2665 * the higher the flavor number, the lesser the capability, hence the name.
2666 * eval_check: Whether to run task_conversion_eval check during the conversion.
2667 * For backward compatibility, some interfaces do not run
2668 * conversion eval on IKOT_THREAD_CONTROL.
2672 * thread_t and port's type, if translation succeeded;
2673 * THREAD_NULL and IKOT_NONE, if translation failed
2676 convert_port_to_thread_check_type(
2678 ipc_kobject_type_t
*kotype
,
2679 mach_thread_flavor_t at_most
,
2680 boolean_t eval_check
)
2682 thread_t thread
= THREAD_NULL
;
2683 ipc_kobject_type_t type
= IKOT_NONE
;
2685 if (!IP_VALID(port
) || !ip_active(port
)) {
2689 switch (ip_kotype(port
)) {
2690 case IKOT_THREAD_CONTROL
:
2691 thread
= eval_check
? convert_port_to_thread(port
) : convert_port_to_thread_no_eval(port
);
2692 if (thread
!= THREAD_NULL
) {
2693 type
= IKOT_THREAD_CONTROL
;
2696 case IKOT_THREAD_READ
:
2697 if (at_most
>= THREAD_FLAVOR_READ
) {
2698 thread
= eval_check
? convert_port_to_thread_read(port
) : convert_port_to_thread_read_no_eval(port
);
2699 if (thread
!= THREAD_READ_NULL
) {
2700 type
= IKOT_THREAD_READ
;
2704 case IKOT_THREAD_INSPECT
:
2705 if (at_most
>= THREAD_FLAVOR_INSPECT
) {
2706 thread
= convert_port_to_thread_inspect(port
);
2707 if (thread
!= THREAD_INSPECT_NULL
) {
2708 type
= IKOT_THREAD_INSPECT
;
2724 * Routine: convert_port_to_space_check_type
2726 * Convert from a port to a space based on port's type.
2727 * Doesn't consume the port ref; produces a space ref,
2728 * which may be null.
2730 * port: The port that we do conversion on
2731 * kotype: Returns the IKOT_TYPE of the port, if translation succeeded
2732 * at_most: The lowest capability flavor allowed. In mach_task_flavor_t,
2733 * the higher the flavor number, the lesser the capability, hence the name.
2734 * eval_check: Whether to run task_conversion_eval check during the conversion.
2735 * For backward compatibility, some interfaces do not run
2736 * conversion eval on IKOT_TASK_CONTROL.
2740 * ipc_space_t and port's type, if translation succeeded;
2741 * IPC_SPACE_NULL and IKOT_NONE, if translation failed
2744 convert_port_to_space_check_type(
2746 ipc_kobject_type_t
*kotype
,
2747 mach_task_flavor_t at_most
,
2748 boolean_t eval_check
)
2750 ipc_space_t space
= IPC_SPACE_NULL
;
2751 ipc_kobject_type_t type
= IKOT_NONE
;
2753 if (!IP_VALID(port
) || !ip_active(port
)) {
2757 switch (ip_kotype(port
)) {
2758 case IKOT_TASK_CONTROL
:
2759 space
= eval_check
? convert_port_to_space(port
) : convert_port_to_space_no_eval(port
);
2760 if (space
!= IPC_SPACE_NULL
) {
2761 type
= IKOT_TASK_CONTROL
;
2764 case IKOT_TASK_READ
:
2765 if (at_most
>= TASK_FLAVOR_READ
) {
2766 space
= eval_check
? convert_port_to_space_read(port
) : convert_port_to_space_read_no_eval(port
);
2767 if (space
!= IPC_SPACE_READ_NULL
) {
2768 type
= IKOT_TASK_READ
;
2772 case IKOT_TASK_INSPECT
:
2773 if (at_most
>= TASK_FLAVOR_INSPECT
) {
2774 space
= convert_port_to_space_inspect(port
);
2775 if (space
!= IPC_SPACE_INSPECT_NULL
) {
2776 type
= IKOT_TASK_INSPECT
;
2792 * Routine: convert_port_to_task_inspect
2794 * Convert from a port to a task inspection right
2795 * Doesn't consume the port ref; produces a task ref,
2796 * which may be null.
2801 convert_port_to_task_inspect(
2804 task_inspect_t task
= TASK_INSPECT_NULL
;
2806 if (IP_VALID(port
)) {
2808 if (ip_active(port
)) {
2809 task
= convert_port_to_task_inspect_locked(port
);
2818 * Routine: convert_port_to_task_read
2820 * Convert from a port to a task read right
2821 * Doesn't consume the port ref; produces a task ref,
2822 * which may be null.
2827 convert_port_to_task_read(
2830 task_read_t task
= TASK_READ_NULL
;
2832 if (IP_VALID(port
)) {
2834 if (ip_active(port
)) {
2835 task
= convert_port_to_task_read_locked(port
, TRUE
);
2844 convert_port_to_task_read_no_eval(
2847 task_read_t task
= TASK_READ_NULL
;
2849 if (IP_VALID(port
)) {
2851 if (ip_active(port
)) {
2852 task
= convert_port_to_task_read_locked(port
, FALSE
);
2861 * Routine: convert_port_to_task_suspension_token
2863 * Convert from a port to a task suspension token.
2864 * Doesn't consume the port ref; produces a suspension token ref,
2865 * which may be null.
2869 task_suspension_token_t
2870 convert_port_to_task_suspension_token(
2873 task_suspension_token_t task
= TASK_NULL
;
2875 if (IP_VALID(port
)) {
2878 if (ip_active(port
) &&
2879 ip_kotype(port
) == IKOT_TASK_RESUME
) {
2880 task
= (task_suspension_token_t
) ip_get_kobject(port
);
2881 assert(task
!= TASK_NULL
);
2883 task_reference_internal(task
);
2893 * Routine: convert_port_to_space_with_flavor
2895 * Convert from a port to a space.
2896 * Doesn't consume the port ref; produces a space ref,
2897 * which may be null.
2902 convert_port_to_space_with_flavor(
2904 mach_task_flavor_t flavor
,
2911 case TASK_FLAVOR_CONTROL
:
2912 task
= convert_port_to_locked_task(port
, eval
);
2914 case TASK_FLAVOR_READ
:
2915 task
= convert_port_to_locked_task_read(port
, eval
);
2917 case TASK_FLAVOR_INSPECT
:
2918 task
= convert_port_to_locked_task_inspect(port
);
2925 if (task
== TASK_NULL
) {
2926 return IPC_SPACE_NULL
;
2929 if (!task
->active
) {
2931 return IPC_SPACE_NULL
;
2934 space
= task
->itk_space
;
2935 is_reference(space
);
2941 convert_port_to_space(
2944 return convert_port_to_space_with_flavor(port
, TASK_FLAVOR_CONTROL
, TRUE
);
2948 convert_port_to_space_no_eval(
2951 return convert_port_to_space_with_flavor(port
, TASK_FLAVOR_CONTROL
, FALSE
);
2955 convert_port_to_space_read(
2958 return convert_port_to_space_with_flavor(port
, TASK_FLAVOR_READ
, TRUE
);
2961 static ipc_space_read_t
2962 convert_port_to_space_read_no_eval(
2965 return convert_port_to_space_with_flavor(port
, TASK_FLAVOR_READ
, FALSE
);
2969 convert_port_to_space_inspect(
2972 return convert_port_to_space_with_flavor(port
, TASK_FLAVOR_INSPECT
, TRUE
);
2976 * Routine: convert_port_to_map_with_flavor
2978 * Convert from a port to a map.
2979 * Doesn't consume the port ref; produces a map ref,
2980 * which may be null.
2986 convert_port_to_map_with_flavor(
2988 mach_task_flavor_t flavor
)
2994 case TASK_FLAVOR_CONTROL
:
2995 task
= convert_port_to_locked_task(port
, TRUE
); /* always eval */
2997 case TASK_FLAVOR_READ
:
2998 task
= convert_port_to_locked_task_read(port
, TRUE
); /* always eval */
3000 case TASK_FLAVOR_INSPECT
:
3001 task
= convert_port_to_locked_task_inspect(port
); /* always no eval */
3008 if (task
== TASK_NULL
) {
3012 if (!task
->active
) {
3018 if (map
->pmap
== kernel_pmap
) {
3019 if (flavor
== TASK_FLAVOR_CONTROL
) {
3020 panic("userspace has control access to a "
3021 "kernel map %p through task %p", map
, task
);
3023 if (task
!= kernel_task
) {
3024 panic("userspace has access to a "
3025 "kernel map %p through task %p", map
, task
);
3028 pmap_require(map
->pmap
);
3031 vm_map_reference(map
);
3037 convert_port_to_map(
3040 return convert_port_to_map_with_flavor(port
, TASK_FLAVOR_CONTROL
);
3044 convert_port_to_map_read(
3047 return convert_port_to_map_with_flavor(port
, TASK_FLAVOR_READ
);
3051 convert_port_to_map_inspect(
3054 return convert_port_to_map_with_flavor(port
, TASK_FLAVOR_INSPECT
);
3059 * Routine: convert_port_to_thread
3061 * Convert from a port to a thread.
3062 * Doesn't consume the port ref; produces an thread ref,
3063 * which may be null.
3069 convert_port_to_thread_locked(
3071 port_to_thread_options_t options
,
3074 thread_t thread
= THREAD_NULL
;
3077 require_ip_active(port
);
3079 if (ip_kotype(port
) == IKOT_THREAD_CONTROL
) {
3080 thread
= (thread_t
) ip_get_kobject(port
);
3081 assert(thread
!= THREAD_NULL
);
3083 if (options
& PORT_TO_THREAD_NOT_CURRENT_THREAD
) {
3084 if (thread
== current_thread()) {
3089 if (options
& PORT_TO_THREAD_IN_CURRENT_TASK
) {
3090 if (thread
->task
!= current_task()) {
3094 /* Use task conversion rules for thread control conversions */
3095 if (eval
&& task_conversion_eval(current_task(), thread
->task
) != KERN_SUCCESS
) {
3100 thread_reference_internal(thread
);
3107 convert_port_to_thread(
3110 thread_t thread
= THREAD_NULL
;
3112 if (IP_VALID(port
)) {
3114 if (ip_active(port
)) {
3115 thread
= convert_port_to_thread_locked(port
, PORT_TO_THREAD_NONE
, TRUE
);
3124 convert_port_to_thread_no_eval(
3127 thread_t thread
= THREAD_NULL
;
3129 if (IP_VALID(port
)) {
3131 if (ip_active(port
)) {
3132 thread
= convert_port_to_thread_locked(port
, PORT_TO_THREAD_NONE
, FALSE
);
3141 * Routine: convert_port_to_thread_inspect
3143 * Convert from a port to a thread inspect right
3144 * Doesn't consume the port ref; produces a thread ref,
3145 * which may be null.
3149 static thread_inspect_t
3150 convert_port_to_thread_inspect_locked(
3153 thread_inspect_t thread
= THREAD_INSPECT_NULL
;
3156 require_ip_active(port
);
3158 if (ip_kotype(port
) == IKOT_THREAD_CONTROL
||
3159 ip_kotype(port
) == IKOT_THREAD_READ
||
3160 ip_kotype(port
) == IKOT_THREAD_INSPECT
) {
3161 thread
= (thread_inspect_t
)ipc_kobject_get(port
);
3162 assert(thread
!= THREAD_INSPECT_NULL
);
3163 thread_reference_internal((thread_t
)thread
);
3170 convert_port_to_thread_inspect(
3173 thread_inspect_t thread
= THREAD_INSPECT_NULL
;
3175 if (IP_VALID(port
)) {
3177 if (ip_active(port
)) {
3178 thread
= convert_port_to_thread_inspect_locked(port
);
3187 * Routine: convert_port_to_thread_read
3189 * Convert from a port to a thread read right
3190 * Doesn't consume the port ref; produces a thread ref,
3191 * which may be null.
3195 static thread_read_t
3196 convert_port_to_thread_read_locked(
3200 thread_read_t thread
= THREAD_READ_NULL
;
3203 require_ip_active(port
);
3205 if (ip_kotype(port
) == IKOT_THREAD_CONTROL
||
3206 ip_kotype(port
) == IKOT_THREAD_READ
) {
3207 thread
= (thread_read_t
) ip_get_kobject(port
);
3208 assert(thread
!= THREAD_READ_NULL
);
3210 /* Use task conversion rules for thread control conversions */
3211 if (eval
&& task_conversion_eval(current_task(), thread
->task
) != KERN_SUCCESS
) {
3212 return THREAD_READ_NULL
;
3215 thread_reference_internal((thread_t
)thread
);
3222 convert_port_to_thread_read(
3225 thread_read_t thread
= THREAD_READ_NULL
;
3227 if (IP_VALID(port
)) {
3229 if (ip_active(port
)) {
3230 thread
= convert_port_to_thread_read_locked(port
, TRUE
);
3238 static thread_read_t
3239 convert_port_to_thread_read_no_eval(
3242 thread_read_t thread
= THREAD_READ_NULL
;
3244 if (IP_VALID(port
)) {
3246 if (ip_active(port
)) {
3247 thread
= convert_port_to_thread_read_locked(port
, FALSE
);
3257 * Routine: convert_thread_to_port_with_flavor
3259 * Convert from a thread to a port of given flavor.
3260 * Consumes a thread ref; produces a naked send right
3261 * which may be invalid.
3266 convert_thread_to_port_with_flavor(
3268 mach_thread_flavor_t flavor
)
3270 ipc_port_t port
= IP_NULL
;
3272 thread_mtx_lock(thread
);
3274 if (!thread
->ipc_active
) {
3278 if (flavor
== THREAD_FLAVOR_CONTROL
) {
3279 port
= ipc_port_make_send(thread
->ith_thread_ports
[flavor
]);
3281 ipc_kobject_type_t kotype
= (flavor
== THREAD_FLAVOR_READ
) ? IKOT_THREAD_READ
: IKOT_THREAD_INSPECT
;
3283 * Claim a send right on the thread read/inspect port, and request a no-senders
3284 * notification on that port (if none outstanding). A thread reference is not
3285 * donated here even though the ports are created lazily because it doesn't own the
3286 * kobject that it points to. Threads manage their lifetime explicitly and
3287 * have to synchronize with each other, between the task/thread terminating and the
3288 * send-once notification firing, and this is done under the thread mutex
3289 * rather than with atomics.
3291 (void)ipc_kobject_make_send_lazy_alloc_port(&thread
->ith_thread_ports
[flavor
], (ipc_kobject_t
)thread
,
3292 kotype
, IPC_KOBJECT_ALLOC_IMMOVABLE_SEND
, false, 0);
3293 port
= thread
->ith_thread_ports
[flavor
];
3297 thread_mtx_unlock(thread
);
3298 thread_deallocate(thread
);
3303 convert_thread_to_port(
3306 return convert_thread_to_port_with_flavor(thread
, THREAD_FLAVOR_CONTROL
);
3310 convert_thread_read_to_port(thread_read_t thread
)
3312 return convert_thread_to_port_with_flavor(thread
, THREAD_FLAVOR_READ
);
3316 convert_thread_inspect_to_port(thread_inspect_t thread
)
3318 return convert_thread_to_port_with_flavor(thread
, THREAD_FLAVOR_INSPECT
);
3323 * Routine: port_name_to_thread
3325 * Convert from a port name to a thread reference
3326 * A name of MACH_PORT_NULL is valid for the null thread.
3331 port_name_to_thread(
3332 mach_port_name_t name
,
3333 port_to_thread_options_t options
)
3335 thread_t thread
= THREAD_NULL
;
3339 if (MACH_PORT_VALID(name
)) {
3340 kr
= ipc_port_translate_send(current_space(), name
, &kport
);
3341 if (kr
== KERN_SUCCESS
) {
3342 thread
= convert_port_to_thread_locked(kport
, options
, TRUE
);
3351 * Routine: port_name_to_task
3353 * Convert from a port name to a task reference
3354 * A name of MACH_PORT_NULL is valid for the null task.
3360 mach_port_name_t name
)
3364 task_t task
= TASK_NULL
;
3366 if (MACH_PORT_VALID(name
)) {
3367 kr
= ipc_port_translate_send(current_space(), name
, &kport
);
3368 if (kr
== KERN_SUCCESS
) {
3369 task
= convert_port_to_task_locked(kport
, NULL
, TRUE
);
3377 * Routine: port_name_to_task_read
3379 * Convert from a port name to a task reference
3380 * A name of MACH_PORT_NULL is valid for the null task.
3385 port_name_to_task_read(
3386 mach_port_name_t name
)
3390 task_read_t tr
= TASK_READ_NULL
;
3392 if (MACH_PORT_VALID(name
)) {
3393 kr
= ipc_port_translate_send(current_space(), name
, &kport
);
3394 if (kr
== KERN_SUCCESS
) {
3395 tr
= convert_port_to_task_read_locked(kport
, TRUE
);
3403 * Routine: port_name_to_task_read_no_eval
3405 * Convert from a port name to a task reference
3406 * A name of MACH_PORT_NULL is valid for the null task.
3407 * Skips task_conversion_eval() during conversion.
3412 port_name_to_task_read_no_eval(
3413 mach_port_name_t name
)
3417 task_read_t tr
= TASK_READ_NULL
;
3419 if (MACH_PORT_VALID(name
)) {
3420 kr
= ipc_port_translate_send(current_space(), name
, &kport
);
3421 if (kr
== KERN_SUCCESS
) {
3422 tr
= convert_port_to_task_read_locked(kport
, FALSE
);
3430 * Routine: port_name_to_task_name
3432 * Convert from a port name to a task reference
3433 * A name of MACH_PORT_NULL is valid for the null task.
3438 port_name_to_task_name(
3439 mach_port_name_t name
)
3443 task_name_t tn
= TASK_NAME_NULL
;
3445 if (MACH_PORT_VALID(name
)) {
3446 kr
= ipc_port_translate_send(current_space(), name
, &kport
);
3447 if (kr
== KERN_SUCCESS
) {
3448 tn
= convert_port_to_task_name_locked(kport
);
3456 * Routine: port_name_to_host
3458 * Convert from a port name to a host pointer.
3459 * NOTE: This does _not_ return a +1 reference to the host_t
3465 mach_port_name_t name
)
3467 host_t host
= HOST_NULL
;
3471 if (MACH_PORT_VALID(name
)) {
3472 kr
= ipc_port_translate_send(current_space(), name
, &port
);
3473 if (kr
== KERN_SUCCESS
) {
3474 host
= convert_port_to_host(port
);
3482 * Routine: convert_task_to_port_with_flavor
3484 * Convert from a task to a port of given flavor.
3485 * Consumes a task ref; produces a naked send right
3486 * which may be invalid.
3491 convert_task_to_port_with_flavor(
3493 mach_task_flavor_t flavor
)
3495 ipc_port_t port
= IP_NULL
;
3496 ipc_kobject_type_t kotype
= IKOT_NONE
;
3500 if (!task
->ipc_active
) {
3505 case TASK_FLAVOR_CONTROL
:
3506 case TASK_FLAVOR_NAME
:
3507 port
= ipc_port_make_send(task
->itk_task_ports
[flavor
]);
3510 * Claim a send right on the task read/inspect port, and request a no-senders
3511 * notification on that port (if none outstanding). A task reference is
3512 * deliberately not donated here because ipc_kobject_make_send_lazy_alloc_port
3513 * is used only for convenience and these ports don't control the lifecycle of
3514 * the task kobject. Instead, the task's itk_lock is used to synchronize the
3515 * handling of the no-senders notification with the task termination.
3517 case TASK_FLAVOR_READ
:
3518 case TASK_FLAVOR_INSPECT
:
3519 kotype
= (flavor
== TASK_FLAVOR_READ
) ? IKOT_TASK_READ
: IKOT_TASK_INSPECT
;
3520 (void)ipc_kobject_make_send_lazy_alloc_port((ipc_port_t
*) &task
->itk_task_ports
[flavor
],
3521 (ipc_kobject_t
)task
, kotype
, IPC_KOBJECT_ALLOC_IMMOVABLE_SEND
, true,
3522 OS_PTRAUTH_DISCRIMINATOR("task.itk_task_ports"));
3523 port
= task
->itk_task_ports
[flavor
];
3530 task_deallocate(task
);
3535 convert_task_to_port(
3538 return convert_task_to_port_with_flavor(task
, TASK_FLAVOR_CONTROL
);
3542 convert_task_read_to_port(
3545 return convert_task_to_port_with_flavor(task
, TASK_FLAVOR_READ
);
3549 convert_task_inspect_to_port(
3550 task_inspect_t task
)
3552 return convert_task_to_port_with_flavor(task
, TASK_FLAVOR_INSPECT
);
3556 convert_task_name_to_port(
3559 return convert_task_to_port_with_flavor(task
, TASK_FLAVOR_NAME
);
3563 convert_task_to_port_pinned(
3566 ipc_port_t port
= IP_NULL
;
3570 if (task
->ipc_active
&& task
->itk_self
!= IP_NULL
) {
3571 port
= ipc_port_make_send(task
->itk_self
);
3575 task_deallocate(task
);
3579 * Routine: convert_task_suspend_token_to_port
3581 * Convert from a task suspension token to a port.
3582 * Consumes a task suspension token ref; produces a naked send-once right
3583 * which may be invalid.
3588 convert_task_suspension_token_to_port(
3589 task_suspension_token_t task
)
3595 if (task
->itk_resume
== IP_NULL
) {
3596 task
->itk_resume
= ipc_kobject_alloc_port((ipc_kobject_t
) task
,
3597 IKOT_TASK_RESUME
, IPC_KOBJECT_ALLOC_NONE
);
3601 * Create a send-once right for each instance of a direct user-called
3602 * task_suspend2 call. Each time one of these send-once rights is abandoned,
3603 * the notification handler will resume the target task.
3605 port
= ipc_port_make_sonce(task
->itk_resume
);
3606 assert(IP_VALID(port
));
3612 task_suspension_token_deallocate(task
);
3618 convert_thread_to_port_pinned(
3621 ipc_port_t port
= IP_NULL
;
3623 thread_mtx_lock(thread
);
3625 if (thread
->ipc_active
&& thread
->ith_self
!= IP_NULL
) {
3626 port
= ipc_port_make_send(thread
->ith_self
);
3629 thread_mtx_unlock(thread
);
3630 thread_deallocate(thread
);
3634 * Routine: space_deallocate
3636 * Deallocate a space ref produced by convert_port_to_space.
3645 if (space
!= IS_NULL
) {
3651 * Routine: space_read_deallocate
3653 * Deallocate a space read ref produced by convert_port_to_space_read.
3659 space_read_deallocate(
3660 ipc_space_read_t space
)
3662 if (space
!= IS_INSPECT_NULL
) {
3663 is_release((ipc_space_t
)space
);
3668 * Routine: space_inspect_deallocate
3670 * Deallocate a space inspect ref produced by convert_port_to_space_inspect.
3676 space_inspect_deallocate(
3677 ipc_space_inspect_t space
)
3679 if (space
!= IS_INSPECT_NULL
) {
3680 is_release((ipc_space_t
)space
);
3686 * Routine: thread/task_set_exception_ports [kernel call]
3688 * Sets the thread/task exception port, flavor and
3689 * behavior for the exception types specified by the mask.
3690 * There will be one send right per exception per valid
3693 * Nothing locked. If successful, consumes
3694 * the supplied send right.
3696 * KERN_SUCCESS Changed the special port.
3697 * KERN_INVALID_ARGUMENT The thread is null,
3698 * Illegal mask bit set.
3699 * Illegal exception behavior
3700 * KERN_FAILURE The thread is dead.
3704 thread_set_exception_ports(
3706 exception_mask_t exception_mask
,
3707 ipc_port_t new_port
,
3708 exception_behavior_t new_behavior
,
3709 thread_state_flavor_t new_flavor
)
3711 ipc_port_t old_port
[EXC_TYPES_COUNT
];
3712 boolean_t privileged
= current_task()->sec_token
.val
[0] == 0;
3716 struct label
*new_label
;
3719 if (thread
== THREAD_NULL
) {
3720 return KERN_INVALID_ARGUMENT
;
3723 if (exception_mask
& ~EXC_MASK_VALID
) {
3724 return KERN_INVALID_ARGUMENT
;
3727 if (IP_VALID(new_port
)) {
3728 switch (new_behavior
& ~MACH_EXCEPTION_MASK
) {
3729 case EXCEPTION_DEFAULT
:
3730 case EXCEPTION_STATE
:
3731 case EXCEPTION_STATE_IDENTITY
:
3735 return KERN_INVALID_ARGUMENT
;
3741 * Check the validity of the thread_state_flavor by calling the
3742 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in
3743 * osfmk/mach/ARCHITECTURE/thread_status.h
3745 if (new_flavor
!= 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor
)) {
3746 return KERN_INVALID_ARGUMENT
;
3750 new_label
= mac_exc_create_label_for_current_proc();
3753 thread_mtx_lock(thread
);
3755 if (!thread
->active
) {
3756 thread_mtx_unlock(thread
);
3758 return KERN_FAILURE
;
3761 if (thread
->exc_actions
== NULL
) {
3762 ipc_thread_init_exc_actions(thread
);
3764 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
3765 if ((exception_mask
& (1 << i
))
3767 && mac_exc_update_action_label(&thread
->exc_actions
[i
], new_label
) == 0
3770 old_port
[i
] = thread
->exc_actions
[i
].port
;
3771 thread
->exc_actions
[i
].port
= ipc_port_copy_send(new_port
);
3772 thread
->exc_actions
[i
].behavior
= new_behavior
;
3773 thread
->exc_actions
[i
].flavor
= new_flavor
;
3774 thread
->exc_actions
[i
].privileged
= privileged
;
3776 old_port
[i
] = IP_NULL
;
3780 thread_mtx_unlock(thread
);
3783 mac_exc_free_label(new_label
);
3786 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
3787 if (IP_VALID(old_port
[i
])) {
3788 ipc_port_release_send(old_port
[i
]);
3792 if (IP_VALID(new_port
)) { /* consume send right */
3793 ipc_port_release_send(new_port
);
3796 return KERN_SUCCESS
;
3800 task_set_exception_ports(
3802 exception_mask_t exception_mask
,
3803 ipc_port_t new_port
,
3804 exception_behavior_t new_behavior
,
3805 thread_state_flavor_t new_flavor
)
3807 ipc_port_t old_port
[EXC_TYPES_COUNT
];
3808 boolean_t privileged
= current_task()->sec_token
.val
[0] == 0;
3812 struct label
*new_label
;
3815 if (task
== TASK_NULL
) {
3816 return KERN_INVALID_ARGUMENT
;
3819 if (exception_mask
& ~EXC_MASK_VALID
) {
3820 return KERN_INVALID_ARGUMENT
;
3823 if (IP_VALID(new_port
)) {
3824 switch (new_behavior
& ~MACH_EXCEPTION_MASK
) {
3825 case EXCEPTION_DEFAULT
:
3826 case EXCEPTION_STATE
:
3827 case EXCEPTION_STATE_IDENTITY
:
3831 return KERN_INVALID_ARGUMENT
;
3837 * Check the validity of the thread_state_flavor by calling the
3838 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in
3839 * osfmk/mach/ARCHITECTURE/thread_status.h
3841 if (new_flavor
!= 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor
)) {
3842 return KERN_INVALID_ARGUMENT
;
3846 new_label
= mac_exc_create_label_for_current_proc();
3851 if (!task
->ipc_active
) {
3853 return KERN_FAILURE
;
3856 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
3857 if ((exception_mask
& (1 << i
))
3859 && mac_exc_update_action_label(&task
->exc_actions
[i
], new_label
) == 0
3862 old_port
[i
] = task
->exc_actions
[i
].port
;
3863 task
->exc_actions
[i
].port
=
3864 ipc_port_copy_send(new_port
);
3865 task
->exc_actions
[i
].behavior
= new_behavior
;
3866 task
->exc_actions
[i
].flavor
= new_flavor
;
3867 task
->exc_actions
[i
].privileged
= privileged
;
3869 old_port
[i
] = IP_NULL
;
3876 mac_exc_free_label(new_label
);
3879 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
3880 if (IP_VALID(old_port
[i
])) {
3881 ipc_port_release_send(old_port
[i
]);
3885 if (IP_VALID(new_port
)) { /* consume send right */
3886 ipc_port_release_send(new_port
);
3889 return KERN_SUCCESS
;
3893 * Routine: thread/task_swap_exception_ports [kernel call]
3895 * Sets the thread/task exception port, flavor and
3896 * behavior for the exception types specified by the
3899 * The old ports, behavior and flavors are returned
3900 * Count specifies the array sizes on input and
3901 * the number of returned ports etc. on output. The
3902 * arrays must be large enough to hold all the returned
3903 * data, MIG returnes an error otherwise. The masks
3904 * array specifies the corresponding exception type(s).
3907 * Nothing locked. If successful, consumes
3908 * the supplied send right.
3910 * Returns upto [in} CountCnt elements.
3912 * KERN_SUCCESS Changed the special port.
3913 * KERN_INVALID_ARGUMENT The thread is null,
3914 * Illegal mask bit set.
3915 * Illegal exception behavior
3916 * KERN_FAILURE The thread is dead.
3920 thread_swap_exception_ports(
3922 exception_mask_t exception_mask
,
3923 ipc_port_t new_port
,
3924 exception_behavior_t new_behavior
,
3925 thread_state_flavor_t new_flavor
,
3926 exception_mask_array_t masks
,
3927 mach_msg_type_number_t
*CountCnt
,
3928 exception_port_array_t ports
,
3929 exception_behavior_array_t behaviors
,
3930 thread_state_flavor_array_t flavors
)
3932 ipc_port_t old_port
[EXC_TYPES_COUNT
];
3933 boolean_t privileged
= current_task()->sec_token
.val
[0] == 0;
3934 unsigned int i
, j
, count
;
3937 struct label
*new_label
;
3940 if (thread
== THREAD_NULL
) {
3941 return KERN_INVALID_ARGUMENT
;
3944 if (exception_mask
& ~EXC_MASK_VALID
) {
3945 return KERN_INVALID_ARGUMENT
;
3948 if (IP_VALID(new_port
)) {
3949 switch (new_behavior
& ~MACH_EXCEPTION_MASK
) {
3950 case EXCEPTION_DEFAULT
:
3951 case EXCEPTION_STATE
:
3952 case EXCEPTION_STATE_IDENTITY
:
3956 return KERN_INVALID_ARGUMENT
;
3961 if (new_flavor
!= 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor
)) {
3962 return KERN_INVALID_ARGUMENT
;
3966 new_label
= mac_exc_create_label_for_current_proc();
3969 thread_mtx_lock(thread
);
3971 if (!thread
->active
) {
3972 thread_mtx_unlock(thread
);
3974 mac_exc_free_label(new_label
);
3976 return KERN_FAILURE
;
3979 if (thread
->exc_actions
== NULL
) {
3980 ipc_thread_init_exc_actions(thread
);
3983 assert(EXC_TYPES_COUNT
> FIRST_EXCEPTION
);
3984 for (count
= 0, i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
&& count
< *CountCnt
; ++i
) {
3985 if ((exception_mask
& (1 << i
))
3987 && mac_exc_update_action_label(&thread
->exc_actions
[i
], new_label
) == 0
3990 for (j
= 0; j
< count
; ++j
) {
3992 * search for an identical entry, if found
3993 * set corresponding mask for this exception.
3995 if (thread
->exc_actions
[i
].port
== ports
[j
] &&
3996 thread
->exc_actions
[i
].behavior
== behaviors
[j
] &&
3997 thread
->exc_actions
[i
].flavor
== flavors
[j
]) {
3998 masks
[j
] |= (1 << i
);
4004 masks
[j
] = (1 << i
);
4005 ports
[j
] = ipc_port_copy_send(thread
->exc_actions
[i
].port
);
4007 behaviors
[j
] = thread
->exc_actions
[i
].behavior
;
4008 flavors
[j
] = thread
->exc_actions
[i
].flavor
;
4012 old_port
[i
] = thread
->exc_actions
[i
].port
;
4013 thread
->exc_actions
[i
].port
= ipc_port_copy_send(new_port
);
4014 thread
->exc_actions
[i
].behavior
= new_behavior
;
4015 thread
->exc_actions
[i
].flavor
= new_flavor
;
4016 thread
->exc_actions
[i
].privileged
= privileged
;
4018 old_port
[i
] = IP_NULL
;
4022 thread_mtx_unlock(thread
);
4025 mac_exc_free_label(new_label
);
4028 while (--i
>= FIRST_EXCEPTION
) {
4029 if (IP_VALID(old_port
[i
])) {
4030 ipc_port_release_send(old_port
[i
]);
4034 if (IP_VALID(new_port
)) { /* consume send right */
4035 ipc_port_release_send(new_port
);
4040 return KERN_SUCCESS
;
4044 task_swap_exception_ports(
4046 exception_mask_t exception_mask
,
4047 ipc_port_t new_port
,
4048 exception_behavior_t new_behavior
,
4049 thread_state_flavor_t new_flavor
,
4050 exception_mask_array_t masks
,
4051 mach_msg_type_number_t
*CountCnt
,
4052 exception_port_array_t ports
,
4053 exception_behavior_array_t behaviors
,
4054 thread_state_flavor_array_t flavors
)
4056 ipc_port_t old_port
[EXC_TYPES_COUNT
];
4057 boolean_t privileged
= current_task()->sec_token
.val
[0] == 0;
4058 unsigned int i
, j
, count
;
4061 struct label
*new_label
;
4064 if (task
== TASK_NULL
) {
4065 return KERN_INVALID_ARGUMENT
;
4068 if (exception_mask
& ~EXC_MASK_VALID
) {
4069 return KERN_INVALID_ARGUMENT
;
4072 if (IP_VALID(new_port
)) {
4073 switch (new_behavior
& ~MACH_EXCEPTION_MASK
) {
4074 case EXCEPTION_DEFAULT
:
4075 case EXCEPTION_STATE
:
4076 case EXCEPTION_STATE_IDENTITY
:
4080 return KERN_INVALID_ARGUMENT
;
4085 if (new_flavor
!= 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor
)) {
4086 return KERN_INVALID_ARGUMENT
;
4090 new_label
= mac_exc_create_label_for_current_proc();
4095 if (!task
->ipc_active
) {
4098 mac_exc_free_label(new_label
);
4100 return KERN_FAILURE
;
4103 assert(EXC_TYPES_COUNT
> FIRST_EXCEPTION
);
4104 for (count
= 0, i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
&& count
< *CountCnt
; ++i
) {
4105 if ((exception_mask
& (1 << i
))
4107 && mac_exc_update_action_label(&task
->exc_actions
[i
], new_label
) == 0
4110 for (j
= 0; j
< count
; j
++) {
4112 * search for an identical entry, if found
4113 * set corresponding mask for this exception.
4115 if (task
->exc_actions
[i
].port
== ports
[j
] &&
4116 task
->exc_actions
[i
].behavior
== behaviors
[j
] &&
4117 task
->exc_actions
[i
].flavor
== flavors
[j
]) {
4118 masks
[j
] |= (1 << i
);
4124 masks
[j
] = (1 << i
);
4125 ports
[j
] = ipc_port_copy_send(task
->exc_actions
[i
].port
);
4126 behaviors
[j
] = task
->exc_actions
[i
].behavior
;
4127 flavors
[j
] = task
->exc_actions
[i
].flavor
;
4131 old_port
[i
] = task
->exc_actions
[i
].port
;
4133 task
->exc_actions
[i
].port
= ipc_port_copy_send(new_port
);
4134 task
->exc_actions
[i
].behavior
= new_behavior
;
4135 task
->exc_actions
[i
].flavor
= new_flavor
;
4136 task
->exc_actions
[i
].privileged
= privileged
;
4138 old_port
[i
] = IP_NULL
;
4145 mac_exc_free_label(new_label
);
4148 while (--i
>= FIRST_EXCEPTION
) {
4149 if (IP_VALID(old_port
[i
])) {
4150 ipc_port_release_send(old_port
[i
]);
4154 if (IP_VALID(new_port
)) { /* consume send right */
4155 ipc_port_release_send(new_port
);
4160 return KERN_SUCCESS
;
4164 * Routine: thread/task_get_exception_ports [kernel call]
4166 * Clones a send right for each of the thread/task's exception
4167 * ports specified in the mask and returns the behaviour
4168 * and flavor of said port.
4170 * Returns upto [in} CountCnt elements.
4175 * KERN_SUCCESS Extracted a send right.
4176 * KERN_INVALID_ARGUMENT The thread is null,
4177 * Invalid special port,
4178 * Illegal mask bit set.
4179 * KERN_FAILURE The thread is dead.
4181 static kern_return_t
4182 thread_get_exception_ports_internal(
4184 exception_mask_t exception_mask
,
4185 exception_mask_array_t masks
,
4186 mach_msg_type_number_t
*CountCnt
,
4187 exception_port_info_array_t ports_info
,
4188 exception_port_array_t ports
,
4189 exception_behavior_array_t behaviors
,
4190 thread_state_flavor_array_t flavors
)
4193 boolean_t info_only
= (ports_info
!= NULL
);
4194 boolean_t dbg_ok
= TRUE
;
4195 ipc_port_t port_ptrs
[EXC_TYPES_COUNT
]; /* pointers only, does not hold right */
4197 if (thread
== THREAD_NULL
) {
4198 return KERN_INVALID_ARGUMENT
;
4201 if (exception_mask
& ~EXC_MASK_VALID
) {
4202 return KERN_INVALID_ARGUMENT
;
4205 if (!info_only
&& !ports
) {
4206 return KERN_INVALID_ARGUMENT
;
4209 #if !(DEVELOPMENT || DEBUG) && CONFIG_MACF
4210 if (info_only
&& mac_task_check_expose_task(kernel_task
, TASK_FLAVOR_CONTROL
) == 0) {
4217 thread_mtx_lock(thread
);
4219 if (!thread
->active
) {
4220 thread_mtx_unlock(thread
);
4222 return KERN_FAILURE
;
4227 if (thread
->exc_actions
== NULL
) {
4231 for (int i
= FIRST_EXCEPTION
, j
= 0; i
< EXC_TYPES_COUNT
; ++i
) {
4232 if (exception_mask
& (1 << i
)) {
4233 ipc_port_t exc_port
= thread
->exc_actions
[i
].port
;
4234 exception_behavior_t exc_behavior
= thread
->exc_actions
[i
].behavior
;
4235 thread_state_flavor_t exc_flavor
= thread
->exc_actions
[i
].flavor
;
4237 for (j
= 0; j
< count
; ++j
) {
4239 * search for an identical entry, if found
4240 * set corresponding mask for this exception.
4242 if (exc_port
== port_ptrs
[j
] &&
4243 exc_behavior
== behaviors
[j
] &&
4244 exc_flavor
== flavors
[j
]) {
4245 masks
[j
] |= (1 << i
);
4250 if (j
== count
&& count
< *CountCnt
) {
4251 masks
[j
] = (1 << i
);
4252 port_ptrs
[j
] = exc_port
;
4255 if (!dbg_ok
|| !IP_VALID(exc_port
)) {
4256 /* avoid taking port lock if !dbg_ok */
4257 ports_info
[j
] = (ipc_info_port_t
){ .iip_port_object
= 0, .iip_receiver_object
= 0 };
4260 (void)ipc_port_get_receiver_task(exc_port
, &receiver
);
4261 ports_info
[j
].iip_port_object
= (natural_t
)VM_KERNEL_ADDRPERM(exc_port
);
4262 ports_info
[j
].iip_receiver_object
= receiver
? (natural_t
)VM_KERNEL_ADDRPERM(receiver
) : 0;
4265 ports
[j
] = ipc_port_copy_send(exc_port
);
4267 behaviors
[j
] = exc_behavior
;
4268 flavors
[j
] = exc_flavor
;
4275 thread_mtx_unlock(thread
);
4279 return KERN_SUCCESS
;
4282 static kern_return_t
4283 thread_get_exception_ports(
4285 exception_mask_t exception_mask
,
4286 exception_mask_array_t masks
,
4287 mach_msg_type_number_t
*CountCnt
,
4288 exception_port_array_t ports
,
4289 exception_behavior_array_t behaviors
,
4290 thread_state_flavor_array_t flavors
)
4292 return thread_get_exception_ports_internal(thread
, exception_mask
, masks
, CountCnt
,
4293 NULL
, ports
, behaviors
, flavors
);
4297 thread_get_exception_ports_info(
4299 exception_mask_t exception_mask
,
4300 exception_mask_array_t masks
,
4301 mach_msg_type_number_t
*CountCnt
,
4302 exception_port_info_array_t ports_info
,
4303 exception_behavior_array_t behaviors
,
4304 thread_state_flavor_array_t flavors
)
4308 thread_t thread
= convert_port_to_thread_read_no_eval(port
);
4310 if (thread
== THREAD_NULL
) {
4311 return KERN_INVALID_ARGUMENT
;
4314 kr
= thread_get_exception_ports_internal(thread
, exception_mask
, masks
, CountCnt
,
4315 ports_info
, NULL
, behaviors
, flavors
);
4317 thread_deallocate(thread
);
4322 thread_get_exception_ports_from_user(
4324 exception_mask_t exception_mask
,
4325 exception_mask_array_t masks
,
4326 mach_msg_type_number_t
*CountCnt
,
4327 exception_port_array_t ports
,
4328 exception_behavior_array_t behaviors
,
4329 thread_state_flavor_array_t flavors
)
4333 thread_t thread
= convert_port_to_thread_no_eval(port
);
4335 if (thread
== THREAD_NULL
) {
4336 return KERN_INVALID_ARGUMENT
;
4339 kr
= thread_get_exception_ports(thread
, exception_mask
, masks
, CountCnt
, ports
, behaviors
, flavors
);
4341 thread_deallocate(thread
);
4345 static kern_return_t
4346 task_get_exception_ports_internal(
4348 exception_mask_t exception_mask
,
4349 exception_mask_array_t masks
,
4350 mach_msg_type_number_t
*CountCnt
,
4351 exception_port_info_array_t ports_info
,
4352 exception_port_array_t ports
,
4353 exception_behavior_array_t behaviors
,
4354 thread_state_flavor_array_t flavors
)
4357 boolean_t info_only
= (ports_info
!= NULL
);
4358 boolean_t dbg_ok
= TRUE
;
4359 ipc_port_t port_ptrs
[EXC_TYPES_COUNT
]; /* pointers only, does not hold right */
4361 if (task
== TASK_NULL
) {
4362 return KERN_INVALID_ARGUMENT
;
4365 if (exception_mask
& ~EXC_MASK_VALID
) {
4366 return KERN_INVALID_ARGUMENT
;
4369 if (!info_only
&& !ports
) {
4370 return KERN_INVALID_ARGUMENT
;
4373 #if !(DEVELOPMENT || DEBUG) && CONFIG_MACF
4374 if (info_only
&& mac_task_check_expose_task(kernel_task
, TASK_FLAVOR_CONTROL
) == 0) {
4383 if (!task
->ipc_active
) {
4385 return KERN_FAILURE
;
4390 for (int i
= FIRST_EXCEPTION
, j
= 0; i
< EXC_TYPES_COUNT
; ++i
) {
4391 if (exception_mask
& (1 << i
)) {
4392 ipc_port_t exc_port
= task
->exc_actions
[i
].port
;
4393 exception_behavior_t exc_behavior
= task
->exc_actions
[i
].behavior
;
4394 thread_state_flavor_t exc_flavor
= task
->exc_actions
[i
].flavor
;
4396 for (j
= 0; j
< count
; ++j
) {
4398 * search for an identical entry, if found
4399 * set corresponding mask for this exception.
4401 if (exc_port
== port_ptrs
[j
] &&
4402 exc_behavior
== behaviors
[j
] &&
4403 exc_flavor
== flavors
[j
]) {
4404 masks
[j
] |= (1 << i
);
4409 if (j
== count
&& count
< *CountCnt
) {
4410 masks
[j
] = (1 << i
);
4411 port_ptrs
[j
] = exc_port
;
4414 if (!dbg_ok
|| !IP_VALID(exc_port
)) {
4415 /* avoid taking port lock if !dbg_ok */
4416 ports_info
[j
] = (ipc_info_port_t
){ .iip_port_object
= 0, .iip_receiver_object
= 0 };
4419 (void)ipc_port_get_receiver_task(exc_port
, &receiver
);
4420 ports_info
[j
].iip_port_object
= (natural_t
)VM_KERNEL_ADDRPERM(exc_port
);
4421 ports_info
[j
].iip_receiver_object
= receiver
? (natural_t
)VM_KERNEL_ADDRPERM(receiver
) : 0;
4424 ports
[j
] = ipc_port_copy_send(exc_port
);
4426 behaviors
[j
] = exc_behavior
;
4427 flavors
[j
] = exc_flavor
;
4437 return KERN_SUCCESS
;
4440 static kern_return_t
4441 task_get_exception_ports(
4443 exception_mask_t exception_mask
,
4444 exception_mask_array_t masks
,
4445 mach_msg_type_number_t
*CountCnt
,
4446 exception_port_array_t ports
,
4447 exception_behavior_array_t behaviors
,
4448 thread_state_flavor_array_t flavors
)
4450 return task_get_exception_ports_internal(task
, exception_mask
, masks
, CountCnt
,
4451 NULL
, ports
, behaviors
, flavors
);
4455 task_get_exception_ports_info(
4457 exception_mask_t exception_mask
,
4458 exception_mask_array_t masks
,
4459 mach_msg_type_number_t
*CountCnt
,
4460 exception_port_info_array_t ports_info
,
4461 exception_behavior_array_t behaviors
,
4462 thread_state_flavor_array_t flavors
)
4466 task_t task
= convert_port_to_task_read_no_eval(port
);
4468 if (task
== TASK_NULL
) {
4469 return KERN_INVALID_ARGUMENT
;
4472 kr
= task_get_exception_ports_internal(task
, exception_mask
, masks
, CountCnt
,
4473 ports_info
, NULL
, behaviors
, flavors
);
4475 task_deallocate(task
);
4480 task_get_exception_ports_from_user(
4482 exception_mask_t exception_mask
,
4483 exception_mask_array_t masks
,
4484 mach_msg_type_number_t
*CountCnt
,
4485 exception_port_array_t ports
,
4486 exception_behavior_array_t behaviors
,
4487 thread_state_flavor_array_t flavors
)
4491 task_t task
= convert_port_to_task_no_eval(port
);
4493 if (task
== TASK_NULL
) {
4494 return KERN_INVALID_ARGUMENT
;
4497 kr
= task_get_exception_ports(task
, exception_mask
, masks
, CountCnt
, ports
, behaviors
, flavors
);
4499 task_deallocate(task
);
4504 * Routine: ipc_thread_port_unpin
4506 * Called on the thread port when the thread is
4507 * terminating so that the last ref can be deallocated
4508 * without a guard exception.
4510 * Thread mutex lock is held.
4511 * check_bit should be set to true only when port is expected
4512 * to have ip_pinned bit set.
4515 ipc_thread_port_unpin(
4517 __unused
bool check_bit
)
4519 if (port
== IP_NULL
) {
4523 imq_lock(&port
->ip_messages
);
4524 #if DEVELOPMENT || DEBUG
4525 if (pinned_control_port_enabled
&& check_bit
) {
4526 assert(ip_is_control(port
)); /*remove once we get rid of boot-arg */
4527 assert(port
->ip_pinned
== 1);
4530 port
->ip_pinned
= 0;
4531 imq_unlock(&port
->ip_messages
);