]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kern/ipc_tt.c
xnu-7195.81.3.tar.gz
[apple/xnu.git] / osfmk / kern / ipc_tt.c
CommitLineData
1c79356b 1/*
316670eb 2 * Copyright (c) 2000-2010 Apple Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
2d21ac55
A
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.
0a7de745 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
0a7de745 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/*
29 * @OSF_COPYRIGHT@
30 */
0a7de745 31/*
1c79356b
A
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
34 * All Rights Reserved.
0a7de745 35 *
1c79356b
A
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.
0a7de745 41 *
1c79356b
A
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.
0a7de745 45 *
1c79356b 46 * Carnegie Mellon requests users of this software to return to
0a7de745 47 *
1c79356b
A
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
0a7de745 52 *
1c79356b
A
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
2d21ac55
A
56/*
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,
60 * Version 2.0.
61 */
1c79356b
A
62/*
63 */
64
65/*
66 * File: ipc_tt.c
67 * Purpose:
68 * Task and thread related IPC functions.
69 */
70
55e303ae 71#include <mach/mach_types.h>
1c79356b 72#include <mach/boolean.h>
1c79356b
A
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>
91447636 79#include <mach/memory_object_types.h>
1c79356b
A
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>
91447636 84#include <mach/host_priv_server.h>
1c79356b 85#include <mach/vm_map_server.h>
91447636
A
86
87#include <kern/kern_types.h>
1c79356b 88#include <kern/host.h>
91447636 89#include <kern/ipc_kobject.h>
1c79356b 90#include <kern/ipc_tt.h>
91447636
A
91#include <kern/kalloc.h>
92#include <kern/thread.h>
1c79356b 93#include <kern/misc_protos.h>
91447636
A
94
95#include <vm/vm_map.h>
1c79356b 96#include <vm/vm_pageout.h>
91447636
A
97#include <vm/vm_protos.h>
98
2d21ac55
A
99#include <security/mac_mach_internal.h>
100
4ba76501
A
101#if CONFIG_CSR
102#include <sys/csr.h>
103#endif
104
f427ee49 105#if !defined(XNU_TARGET_OS_OSX) && !SECURE_KERNEL
5ba3f43e
A
106extern int cs_relax_platform_task_ports;
107#endif
108
f427ee49
A
109extern boolean_t IOTaskHasEntitlement(task_t, const char *);
110
91447636 111/* forward declarations */
f427ee49 112task_t convert_port_to_locked_task(ipc_port_t port, boolean_t eval);
813fb2f6 113task_inspect_t convert_port_to_locked_task_inspect(ipc_port_t port);
f427ee49
A
114task_read_t convert_port_to_locked_task_read(ipc_port_t port);
115static task_read_t convert_port_to_task_read_locked(ipc_port_t port);
116static kern_return_t port_allowed_with_task_flavor(int which, mach_task_flavor_t flavor);
117static kern_return_t port_allowed_with_thread_flavor(int which, mach_thread_flavor_t flavor);
118static task_inspect_t convert_port_to_task_inspect_locked(ipc_port_t port);
5ba3f43e
A
119static void ipc_port_bind_special_reply_port_locked(ipc_port_t port);
120static kern_return_t ipc_port_unbind_special_reply_port(thread_t thread, boolean_t unbind_active_port);
121kern_return_t task_conversion_eval(task_t caller, task_t victim);
f427ee49
A
122static ipc_space_t convert_port_to_space_no_eval(ipc_port_t port);
123static task_t convert_port_to_task_no_eval(ipc_port_t port);
124static thread_t convert_port_to_thread_no_eval(ipc_port_t port);
125static ipc_port_t convert_task_to_port_with_flavor(task_t task, mach_task_flavor_t flavor);
126static ipc_port_t convert_thread_to_port_with_flavor(thread_t thread, mach_thread_flavor_t flavor);
1c79356b
A
127
128/*
129 * Routine: ipc_task_init
130 * Purpose:
131 * Initialize a task's IPC state.
132 *
133 * If non-null, some state will be inherited from the parent.
134 * The parent must be appropriately initialized.
135 * Conditions:
136 * Nothing locked.
137 */
138
139void
140ipc_task_init(
0a7de745
A
141 task_t task,
142 task_t parent)
1c79356b
A
143{
144 ipc_space_t space;
145 ipc_port_t kport;
0c530ab8 146 ipc_port_t nport;
f427ee49 147
1c79356b
A
148 kern_return_t kr;
149 int i;
150
151
ea3f0419 152 kr = ipc_space_create(&ipc_table_entries[0], IPC_LABEL_NONE, &space);
0a7de745 153 if (kr != KERN_SUCCESS) {
1c79356b 154 panic("ipc_task_init");
0a7de745 155 }
1c79356b 156
2d21ac55 157 space->is_task = task;
1c79356b
A
158
159 kport = ipc_port_alloc_kernel();
f427ee49 160
0a7de745 161 if (kport == IP_NULL) {
1c79356b 162 panic("ipc_task_init");
0a7de745 163 }
1c79356b 164
0c530ab8 165 nport = ipc_port_alloc_kernel();
0a7de745 166 if (nport == IP_NULL) {
0c530ab8 167 panic("ipc_task_init");
0a7de745 168 }
0c530ab8 169
1c79356b 170 itk_lock_init(task);
f427ee49
A
171 task->itk_self[TASK_FLAVOR_CONTROL] = kport;
172 task->itk_self[TASK_FLAVOR_NAME] = nport;
173
174 /* Lazily allocated on-demand */
175 task->itk_self[TASK_FLAVOR_INSPECT] = IP_NULL;
176 task->itk_self[TASK_FLAVOR_READ] = IP_NULL;
177 task->itk_resume = IP_NULL;
178
39037602
A
179 if (task_is_a_corpse_fork(task)) {
180 /*
181 * No sender's notification for corpse would not
182 * work with a naked send right in kernel.
183 */
f427ee49 184 task->itk_settable_self = IP_NULL;
39037602 185 } else {
f427ee49 186 task->itk_settable_self = ipc_port_make_send(kport);
39037602 187 }
fe8ab488 188 task->itk_debug_control = IP_NULL;
1c79356b 189 task->itk_space = space;
1c79356b 190
5ba3f43e 191#if CONFIG_MACF
b226f5e5 192 task->exc_actions[0].label = NULL;
5ba3f43e
A
193 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
194 mac_exc_associate_action_label(&task->exc_actions[i], mac_exc_create_label());
195 }
196#endif
b226f5e5
A
197
198 /* always zero-out the first (unused) array element */
b226f5e5 199 bzero(&task->exc_actions[0], sizeof(task->exc_actions[0]));
0a7de745 200
1c79356b 201 if (parent == TASK_NULL) {
55e303ae 202 ipc_port_t port;
1c79356b
A
203 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
204 task->exc_actions[i].port = IP_NULL;
b226f5e5
A
205 task->exc_actions[i].flavor = 0;
206 task->exc_actions[i].behavior = 0;
207 task->exc_actions[i].privileged = FALSE;
1c79356b 208 }/* for */
0a7de745 209
55e303ae
A
210 kr = host_get_host_port(host_priv_self(), &port);
211 assert(kr == KERN_SUCCESS);
212 task->itk_host = port;
213
1c79356b 214 task->itk_bootstrap = IP_NULL;
2d21ac55
A
215 task->itk_seatbelt = IP_NULL;
216 task->itk_gssd = IP_NULL;
2d21ac55 217 task->itk_task_access = IP_NULL;
55e303ae 218
0a7de745 219 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) {
1c79356b 220 task->itk_registered[i] = IP_NULL;
0a7de745 221 }
1c79356b
A
222 } else {
223 itk_lock(parent);
f427ee49 224 assert(parent->itk_self[TASK_FLAVOR_CONTROL] != IP_NULL);
1c79356b
A
225
226 /* inherit registered ports */
227
0a7de745 228 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) {
1c79356b 229 task->itk_registered[i] =
0a7de745
A
230 ipc_port_copy_send(parent->itk_registered[i]);
231 }
1c79356b
A
232
233 /* inherit exception and bootstrap ports */
234
235 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
0a7de745
A
236 task->exc_actions[i].port =
237 ipc_port_copy_send(parent->exc_actions[i].port);
238 task->exc_actions[i].flavor =
239 parent->exc_actions[i].flavor;
240 task->exc_actions[i].behavior =
241 parent->exc_actions[i].behavior;
242 task->exc_actions[i].privileged =
243 parent->exc_actions[i].privileged;
39037602 244#if CONFIG_MACF
0a7de745 245 mac_exc_inherit_action_label(parent->exc_actions + i, task->exc_actions + i);
39037602 246#endif
1c79356b
A
247 }/* for */
248 task->itk_host =
0a7de745 249 ipc_port_copy_send(parent->itk_host);
1c79356b
A
250
251 task->itk_bootstrap =
0a7de745 252 ipc_port_copy_send(parent->itk_bootstrap);
1c79356b 253
2d21ac55 254 task->itk_seatbelt =
0a7de745 255 ipc_port_copy_send(parent->itk_seatbelt);
2d21ac55
A
256
257 task->itk_gssd =
0a7de745 258 ipc_port_copy_send(parent->itk_gssd);
2d21ac55 259
2d21ac55 260 task->itk_task_access =
0a7de745 261 ipc_port_copy_send(parent->itk_task_access);
2d21ac55 262
1c79356b
A
263 itk_unlock(parent);
264 }
265}
266
267/*
268 * Routine: ipc_task_enable
269 * Purpose:
270 * Enable a task for IPC access.
271 * Conditions:
272 * Nothing locked.
273 */
274
275void
276ipc_task_enable(
0a7de745 277 task_t task)
1c79356b
A
278{
279 ipc_port_t kport;
0c530ab8 280 ipc_port_t nport;
f427ee49
A
281 ipc_port_t iport;
282 ipc_port_t rdport;
1c79356b
A
283
284 itk_lock(task);
f427ee49 285 kport = task->itk_self[TASK_FLAVOR_CONTROL];
0a7de745 286 if (kport != IP_NULL) {
f427ee49 287 ipc_kobject_set(kport, (ipc_kobject_t) task, IKOT_TASK_CONTROL);
0a7de745 288 }
f427ee49 289 nport = task->itk_self[TASK_FLAVOR_NAME];
0a7de745 290 if (nport != IP_NULL) {
0c530ab8 291 ipc_kobject_set(nport, (ipc_kobject_t) task, IKOT_TASK_NAME);
0a7de745 292 }
f427ee49
A
293 iport = task->itk_self[TASK_FLAVOR_INSPECT];
294 if (iport != IP_NULL) {
295 ipc_kobject_set(iport, (ipc_kobject_t) task, IKOT_TASK_INSPECT);
296 }
297 rdport = task->itk_self[TASK_FLAVOR_READ];
298 if (rdport != IP_NULL) {
299 ipc_kobject_set(rdport, (ipc_kobject_t) task, IKOT_TASK_READ);
300 }
301
1c79356b
A
302 itk_unlock(task);
303}
304
305/*
306 * Routine: ipc_task_disable
307 * Purpose:
308 * Disable IPC access to a task.
309 * Conditions:
310 * Nothing locked.
311 */
312
313void
314ipc_task_disable(
0a7de745 315 task_t task)
1c79356b
A
316{
317 ipc_port_t kport;
0c530ab8 318 ipc_port_t nport;
f427ee49
A
319 ipc_port_t iport;
320 ipc_port_t rdport;
39236c6e 321 ipc_port_t rport;
1c79356b
A
322
323 itk_lock(task);
f427ee49 324 kport = task->itk_self[TASK_FLAVOR_CONTROL];
0a7de745 325 if (kport != IP_NULL) {
1c79356b 326 ipc_kobject_set(kport, IKO_NULL, IKOT_NONE);
0a7de745 327 }
f427ee49 328 nport = task->itk_self[TASK_FLAVOR_NAME];
0a7de745 329 if (nport != IP_NULL) {
0c530ab8 330 ipc_kobject_set(nport, IKO_NULL, IKOT_NONE);
0a7de745 331 }
f427ee49
A
332 iport = task->itk_self[TASK_FLAVOR_INSPECT];
333 if (iport != IP_NULL) {
334 ipc_kobject_set(iport, IKO_NULL, IKOT_NONE);
335 }
336 rdport = task->itk_self[TASK_FLAVOR_READ];
337 if (rdport != IP_NULL) {
338 ipc_kobject_set(rdport, IKO_NULL, IKOT_NONE);
339 }
39236c6e
A
340
341 rport = task->itk_resume;
342 if (rport != IP_NULL) {
343 /*
344 * From this point onwards this task is no longer accepting
345 * resumptions.
346 *
347 * There are still outstanding suspensions on this task,
348 * even as it is being torn down. Disconnect the task
0a7de745 349 * from the rport, thereby "orphaning" the rport. The rport
39236c6e
A
350 * itself will go away only when the last suspension holder
351 * destroys his SO right to it -- when he either
352 * exits, or tries to actually use that last SO right to
353 * resume this (now non-existent) task.
354 */
355 ipc_kobject_set(rport, IKO_NULL, IKOT_NONE);
356 }
1c79356b
A
357 itk_unlock(task);
358}
359
360/*
361 * Routine: ipc_task_terminate
362 * Purpose:
363 * Clean up and destroy a task's IPC state.
364 * Conditions:
365 * Nothing locked. The task must be suspended.
366 * (Or the current thread must be in the task.)
367 */
368
369void
370ipc_task_terminate(
0a7de745 371 task_t task)
1c79356b
A
372{
373 ipc_port_t kport;
0c530ab8 374 ipc_port_t nport;
f427ee49
A
375 ipc_port_t iport;
376 ipc_port_t rdport;
0a7de745 377 ipc_port_t rport;
1c79356b
A
378 int i;
379
380 itk_lock(task);
f427ee49 381 kport = task->itk_self[TASK_FLAVOR_CONTROL];
1c79356b
A
382
383 if (kport == IP_NULL) {
384 /* the task is already terminated (can this happen?) */
385 itk_unlock(task);
386 return;
387 }
f427ee49
A
388 task->itk_self[TASK_FLAVOR_CONTROL] = IP_NULL;
389
390 rdport = task->itk_self[TASK_FLAVOR_READ];
391 task->itk_self[TASK_FLAVOR_READ] = IP_NULL;
0c530ab8 392
f427ee49
A
393 iport = task->itk_self[TASK_FLAVOR_INSPECT];
394 task->itk_self[TASK_FLAVOR_INSPECT] = IP_NULL;
395
396 nport = task->itk_self[TASK_FLAVOR_NAME];
0c530ab8 397 assert(nport != IP_NULL);
f427ee49 398 task->itk_self[TASK_FLAVOR_NAME] = IP_NULL;
0c530ab8 399
39236c6e
A
400 rport = task->itk_resume;
401 task->itk_resume = IP_NULL;
402
1c79356b
A
403 itk_unlock(task);
404
405 /* release the naked send rights */
406
f427ee49
A
407 if (IP_VALID(task->itk_settable_self)) {
408 ipc_port_release_send(task->itk_settable_self);
0a7de745 409 }
1c79356b
A
410
411 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
412 if (IP_VALID(task->exc_actions[i].port)) {
413 ipc_port_release_send(task->exc_actions[i].port);
414 }
39037602 415#if CONFIG_MACF
5ba3f43e 416 mac_exc_free_action_label(task->exc_actions + i);
39037602 417#endif
91447636
A
418 }
419
0a7de745 420 if (IP_VALID(task->itk_host)) {
1c79356b 421 ipc_port_release_send(task->itk_host);
0a7de745 422 }
1c79356b 423
0a7de745 424 if (IP_VALID(task->itk_bootstrap)) {
1c79356b 425 ipc_port_release_send(task->itk_bootstrap);
0a7de745 426 }
1c79356b 427
0a7de745 428 if (IP_VALID(task->itk_seatbelt)) {
2d21ac55 429 ipc_port_release_send(task->itk_seatbelt);
0a7de745
A
430 }
431
432 if (IP_VALID(task->itk_gssd)) {
2d21ac55 433 ipc_port_release_send(task->itk_gssd);
0a7de745 434 }
2d21ac55 435
0a7de745 436 if (IP_VALID(task->itk_task_access)) {
2d21ac55 437 ipc_port_release_send(task->itk_task_access);
0a7de745 438 }
2d21ac55 439
0a7de745 440 if (IP_VALID(task->itk_debug_control)) {
fe8ab488 441 ipc_port_release_send(task->itk_debug_control);
0a7de745 442 }
fe8ab488 443
0a7de745
A
444 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) {
445 if (IP_VALID(task->itk_registered[i])) {
1c79356b 446 ipc_port_release_send(task->itk_registered[i]);
0a7de745
A
447 }
448 }
1c79356b 449
0c530ab8 450 /* destroy the kernel ports */
1c79356b 451 ipc_port_dealloc_kernel(kport);
0c530ab8 452 ipc_port_dealloc_kernel(nport);
f427ee49
A
453 if (iport != IP_NULL) {
454 ipc_port_dealloc_kernel(iport);
455 }
456 if (rdport != IP_NULL) {
457 ipc_port_dealloc_kernel(rdport);
458 }
0a7de745
A
459 if (rport != IP_NULL) {
460 ipc_port_dealloc_kernel(rport);
461 }
b0d623f7
A
462
463 itk_lock_destroy(task);
1c79356b
A
464}
465
55e303ae
A
466/*
467 * Routine: ipc_task_reset
468 * Purpose:
469 * Reset a task's IPC state to protect it when
0c530ab8 470 * it enters an elevated security context. The
f427ee49
A
471 * task name port can remain the same - since it
472 * represents no specific privilege.
55e303ae
A
473 * Conditions:
474 * Nothing locked. The task must be suspended.
475 * (Or the current thread must be in the task.)
476 */
477
478void
479ipc_task_reset(
0a7de745 480 task_t task)
55e303ae
A
481{
482 ipc_port_t old_kport, new_kport;
483 ipc_port_t old_sself;
f427ee49
A
484 ipc_port_t old_rdport;
485 ipc_port_t old_iport;
55e303ae
A
486 ipc_port_t old_exc_actions[EXC_TYPES_COUNT];
487 int i;
55e303ae 488
5ba3f43e
A
489#if CONFIG_MACF
490 /* Fresh label to unset credentials in existing labels. */
491 struct label *unset_label = mac_exc_create_label();
492#endif
0a7de745 493
f427ee49 494 new_kport = ipc_kobject_alloc_port((ipc_kobject_t)task, IKOT_TASK_CONTROL,
cb323159 495 IPC_KOBJECT_ALLOC_MAKE_SEND);
55e303ae
A
496
497 itk_lock(task);
498
f427ee49
A
499 old_kport = task->itk_self[TASK_FLAVOR_CONTROL];
500 old_rdport = task->itk_self[TASK_FLAVOR_READ];
501 old_iport = task->itk_self[TASK_FLAVOR_INSPECT];
55e303ae
A
502
503 if (old_kport == IP_NULL) {
504 /* the task is already terminated (can this happen?) */
505 itk_unlock(task);
cb323159 506 ipc_port_release_send(new_kport);
55e303ae 507 ipc_port_dealloc_kernel(new_kport);
5ba3f43e
A
508#if CONFIG_MACF
509 mac_exc_free_label(unset_label);
510#endif
55e303ae
A
511 return;
512 }
513
f427ee49
A
514 old_sself = task->itk_settable_self;
515 task->itk_settable_self = task->itk_self[TASK_FLAVOR_CONTROL] = new_kport;
39037602
A
516
517 /* Set the old kport to IKOT_NONE and update the exec token while under the port lock */
518 ip_lock(old_kport);
519 ipc_kobject_set_atomically(old_kport, IKO_NULL, IKOT_NONE);
520 task->exec_token += 1;
521 ip_unlock(old_kport);
522
f427ee49
A
523 /* Reset the read and inspect flavors of task port */
524 task->itk_self[TASK_FLAVOR_READ] = IP_NULL;
525 task->itk_self[TASK_FLAVOR_INSPECT] = IP_NULL;
526
55e303ae 527 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
3e170ce0
A
528 old_exc_actions[i] = IP_NULL;
529
530 if (i == EXC_CORPSE_NOTIFY && task_corpse_pending_report(task)) {
531 continue;
532 }
533
8ad349bb 534 if (!task->exc_actions[i].privileged) {
39037602 535#if CONFIG_MACF
5ba3f43e 536 mac_exc_update_action_label(task->exc_actions + i, unset_label);
39037602 537#endif
8ad349bb
A
538 old_exc_actions[i] = task->exc_actions[i].port;
539 task->exc_actions[i].port = IP_NULL;
8ad349bb 540 }
55e303ae 541 }/* for */
0a7de745 542
fe8ab488
A
543 if (IP_VALID(task->itk_debug_control)) {
544 ipc_port_release_send(task->itk_debug_control);
545 }
546 task->itk_debug_control = IP_NULL;
0a7de745 547
55e303ae
A
548 itk_unlock(task);
549
5ba3f43e
A
550#if CONFIG_MACF
551 mac_exc_free_label(unset_label);
552#endif
553
55e303ae
A
554 /* release the naked send rights */
555
0a7de745 556 if (IP_VALID(old_sself)) {
55e303ae 557 ipc_port_release_send(old_sself);
0a7de745 558 }
55e303ae 559
55e303ae
A
560 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
561 if (IP_VALID(old_exc_actions[i])) {
562 ipc_port_release_send(old_exc_actions[i]);
563 }
564 }/* for */
55e303ae 565
f427ee49 566 /* destroy all task port flavors */
55e303ae 567 ipc_port_dealloc_kernel(old_kport);
f427ee49
A
568 if (old_rdport != IP_NULL) {
569 ipc_port_dealloc_kernel(old_rdport);
570 }
571 if (old_iport != IP_NULL) {
572 ipc_port_dealloc_kernel(old_iport);
573 }
55e303ae
A
574}
575
1c79356b
A
576/*
577 * Routine: ipc_thread_init
578 * Purpose:
579 * Initialize a thread's IPC state.
580 * Conditions:
581 * Nothing locked.
582 */
583
584void
585ipc_thread_init(
0a7de745 586 thread_t thread)
1c79356b 587{
0a7de745 588 ipc_port_t kport;
91447636 589
f427ee49 590 kport = ipc_kobject_alloc_port((ipc_kobject_t)thread, IKOT_THREAD_CONTROL,
cb323159 591 IPC_KOBJECT_ALLOC_MAKE_SEND);
91447636 592
f427ee49
A
593 thread->ith_settable_self = thread->ith_self[THREAD_FLAVOR_CONTROL] = kport;
594 thread->ith_self[THREAD_FLAVOR_INSPECT] = IP_NULL;
595 thread->ith_self[THREAD_FLAVOR_READ] = IP_NULL;
5ba3f43e 596 thread->ith_special_reply_port = NULL;
39236c6e 597 thread->exc_actions = NULL;
91447636 598
39236c6e
A
599#if IMPORTANCE_INHERITANCE
600 thread->ith_assertions = 0;
601#endif
602
1c79356b 603 ipc_kmsg_queue_init(&thread->ith_messages);
91447636 604
1c79356b
A
605 thread->ith_rpc_reply = IP_NULL;
606}
607
39236c6e
A
608void
609ipc_thread_init_exc_actions(
0a7de745 610 thread_t thread)
39236c6e
A
611{
612 assert(thread->exc_actions == NULL);
613
614 thread->exc_actions = kalloc(sizeof(struct exception_action) * EXC_TYPES_COUNT);
615 bzero(thread->exc_actions, sizeof(struct exception_action) * EXC_TYPES_COUNT);
39037602
A
616
617#if CONFIG_MACF
618 for (size_t i = 0; i < EXC_TYPES_COUNT; ++i) {
5ba3f43e 619 mac_exc_associate_action_label(thread->exc_actions + i, mac_exc_create_label());
39037602
A
620 }
621#endif
39236c6e
A
622}
623
624void
625ipc_thread_destroy_exc_actions(
0a7de745 626 thread_t thread)
39236c6e
A
627{
628 if (thread->exc_actions != NULL) {
39037602
A
629#if CONFIG_MACF
630 for (size_t i = 0; i < EXC_TYPES_COUNT; ++i) {
5ba3f43e 631 mac_exc_free_action_label(thread->exc_actions + i);
39037602
A
632 }
633#endif
634
0a7de745
A
635 kfree(thread->exc_actions,
636 sizeof(struct exception_action) * EXC_TYPES_COUNT);
39236c6e
A
637 thread->exc_actions = NULL;
638 }
639}
640
f427ee49
A
641/*
642 * Routine: ipc_thread_disable
643 * Purpose:
644 * Clean up and destroy a thread's IPC state.
645 * Conditions:
646 * Thread locked.
647 */
1c79356b 648void
91447636 649ipc_thread_disable(
0a7de745 650 thread_t thread)
1c79356b 651{
f427ee49
A
652 ipc_port_t kport = thread->ith_self[THREAD_FLAVOR_CONTROL];
653 ipc_port_t iport = thread->ith_self[THREAD_FLAVOR_INSPECT];
654 ipc_port_t rdport = thread->ith_self[THREAD_FLAVOR_READ];
1c79356b 655
0a7de745 656 if (kport != IP_NULL) {
91447636 657 ipc_kobject_set(kport, IKO_NULL, IKOT_NONE);
0a7de745 658 }
cb323159 659
f427ee49
A
660 if (iport != IP_NULL) {
661 ipc_kobject_set(iport, IKO_NULL, IKOT_NONE);
662 }
663
664 if (rdport != IP_NULL) {
665 ipc_kobject_set(rdport, IKO_NULL, IKOT_NONE);
666 }
667
cb323159
A
668 /* unbind the thread special reply port */
669 if (IP_VALID(thread->ith_special_reply_port)) {
670 ipc_port_unbind_special_reply_port(thread, TRUE);
671 }
1c79356b
A
672}
673
674/*
91447636 675 * Routine: ipc_thread_terminate
1c79356b 676 * Purpose:
91447636 677 * Clean up and destroy a thread's IPC state.
1c79356b
A
678 * Conditions:
679 * Nothing locked.
680 */
681
682void
91447636 683ipc_thread_terminate(
0a7de745 684 thread_t thread)
1c79356b 685{
f427ee49
A
686 ipc_port_t kport = IP_NULL;
687 ipc_port_t iport = IP_NULL;
688 ipc_port_t rdport = IP_NULL;
689 ipc_port_t ith_rpc_reply = IP_NULL;
1c79356b 690
f427ee49 691 thread_mtx_lock(thread);
1c79356b 692
f427ee49
A
693 kport = thread->ith_self[THREAD_FLAVOR_CONTROL];
694 iport = thread->ith_self[THREAD_FLAVOR_INSPECT];
695 rdport = thread->ith_self[THREAD_FLAVOR_READ];
696
697 if (kport != IP_NULL) {
698 if (IP_VALID(thread->ith_settable_self)) {
699 ipc_port_release_send(thread->ith_settable_self);
0a7de745 700 }
1c79356b 701
f427ee49
A
702 thread->ith_settable_self = thread->ith_self[THREAD_FLAVOR_CONTROL] = IP_NULL;
703 thread->ith_self[THREAD_FLAVOR_INSPECT] = IP_NULL;
704 thread->ith_self[THREAD_FLAVOR_READ] = IP_NULL;
1c79356b 705
39236c6e 706 if (thread->exc_actions != NULL) {
f427ee49 707 for (int i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
0a7de745 708 if (IP_VALID(thread->exc_actions[i].port)) {
39236c6e 709 ipc_port_release_send(thread->exc_actions[i].port);
0a7de745 710 }
39236c6e
A
711 }
712 ipc_thread_destroy_exc_actions(thread);
713 }
1c79356b
A
714 }
715
39236c6e
A
716#if IMPORTANCE_INHERITANCE
717 assert(thread->ith_assertions == 0);
718#endif
719
91447636 720 assert(ipc_kmsg_queue_empty(&thread->ith_messages));
f427ee49
A
721 ith_rpc_reply = thread->ith_rpc_reply;
722 thread->ith_rpc_reply = IP_NULL;
1c79356b 723
f427ee49 724 thread_mtx_unlock(thread);
1c79356b 725
f427ee49
A
726 if (kport != IP_NULL) {
727 ipc_port_dealloc_kernel(kport);
728 }
729 if (iport != IP_NULL) {
730 ipc_port_dealloc_kernel(iport);
731 }
732 if (rdport != IP_NULL) {
733 ipc_port_dealloc_kernel(rdport);
734 }
735 if (ith_rpc_reply != IP_NULL) {
736 ipc_port_dealloc_reply(ith_rpc_reply);
737 }
1c79356b
A
738}
739
6601e61a
A
740/*
741 * Routine: ipc_thread_reset
742 * Purpose:
743 * Reset the IPC state for a given Mach thread when
744 * its task enters an elevated security context.
f427ee49 745 * All flavors of thread port and its exception ports have
6601e61a 746 * to be reset. Its RPC reply port cannot have any
f427ee49
A
747 * rights outstanding, so it should be fine. The thread
748 * inspect and read port are set to NULL.
6601e61a
A
749 * Conditions:
750 * Nothing locked.
751 */
752
753void
754ipc_thread_reset(
0a7de745 755 thread_t thread)
6601e61a
A
756{
757 ipc_port_t old_kport, new_kport;
758 ipc_port_t old_sself;
f427ee49
A
759 ipc_port_t old_rdport;
760 ipc_port_t old_iport;
6601e61a 761 ipc_port_t old_exc_actions[EXC_TYPES_COUNT];
0a7de745 762 boolean_t has_old_exc_actions = FALSE;
f427ee49 763 int i;
6601e61a 764
5ba3f43e
A
765#if CONFIG_MACF
766 struct label *new_label = mac_exc_create_label();
767#endif
0a7de745 768
f427ee49 769 new_kport = ipc_kobject_alloc_port((ipc_kobject_t)thread, IKOT_THREAD_CONTROL,
cb323159 770 IPC_KOBJECT_ALLOC_MAKE_SEND);
6601e61a
A
771
772 thread_mtx_lock(thread);
773
f427ee49
A
774 old_kport = thread->ith_self[THREAD_FLAVOR_CONTROL];
775 old_rdport = thread->ith_self[THREAD_FLAVOR_READ];
776 old_iport = thread->ith_self[THREAD_FLAVOR_INSPECT];
777 old_sself = thread->ith_settable_self;
6601e61a 778
3e170ce0 779 if (old_kport == IP_NULL && thread->inspection == FALSE) {
6601e61a
A
780 /* the is already terminated (can this happen?) */
781 thread_mtx_unlock(thread);
cb323159 782 ipc_port_release_send(new_kport);
6601e61a 783 ipc_port_dealloc_kernel(new_kport);
5ba3f43e
A
784#if CONFIG_MACF
785 mac_exc_free_label(new_label);
786#endif
6601e61a
A
787 return;
788 }
789
f427ee49
A
790 thread->ith_settable_self = thread->ith_self[THREAD_FLAVOR_CONTROL] = new_kport;
791 thread->ith_self[THREAD_FLAVOR_READ] = IP_NULL;
792 thread->ith_self[THREAD_FLAVOR_INSPECT] = IP_NULL;
793
3e170ce0
A
794 if (old_kport != IP_NULL) {
795 ipc_kobject_set(old_kport, IKO_NULL, IKOT_NONE);
796 }
f427ee49
A
797 if (old_rdport != IP_NULL) {
798 ipc_kobject_set(old_rdport, IKO_NULL, IKOT_NONE);
799 }
800 if (old_iport != IP_NULL) {
801 ipc_kobject_set(old_iport, IKO_NULL, IKOT_NONE);
802 }
6601e61a 803
39236c6e
A
804 /*
805 * Only ports that were set by root-owned processes
0a7de745 806 * (privileged ports) should survive
39236c6e
A
807 */
808 if (thread->exc_actions != NULL) {
809 has_old_exc_actions = TRUE;
810 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
811 if (thread->exc_actions[i].privileged) {
812 old_exc_actions[i] = IP_NULL;
813 } else {
39037602 814#if CONFIG_MACF
5ba3f43e 815 mac_exc_update_action_label(thread->exc_actions + i, new_label);
39037602 816#endif
39236c6e 817 old_exc_actions[i] = thread->exc_actions[i].port;
0a7de745 818 thread->exc_actions[i].port = IP_NULL;
39236c6e 819 }
6601e61a 820 }
39236c6e 821 }
6601e61a
A
822
823 thread_mtx_unlock(thread);
824
5ba3f43e
A
825#if CONFIG_MACF
826 mac_exc_free_label(new_label);
827#endif
0a7de745 828
6601e61a
A
829 /* release the naked send rights */
830
0a7de745 831 if (IP_VALID(old_sself)) {
6601e61a 832 ipc_port_release_send(old_sself);
0a7de745 833 }
6601e61a 834
39236c6e
A
835 if (has_old_exc_actions) {
836 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
6601e61a
A
837 ipc_port_release_send(old_exc_actions[i]);
838 }
39236c6e 839 }
6601e61a
A
840
841 /* destroy the kernel port */
3e170ce0
A
842 if (old_kport != IP_NULL) {
843 ipc_port_dealloc_kernel(old_kport);
844 }
f427ee49
A
845 if (old_rdport != IP_NULL) {
846 ipc_port_dealloc_kernel(old_rdport);
847 }
848 if (old_iport != IP_NULL) {
849 ipc_port_dealloc_kernel(old_iport);
850 }
5ba3f43e
A
851
852 /* unbind the thread special reply port */
853 if (IP_VALID(thread->ith_special_reply_port)) {
854 ipc_port_unbind_special_reply_port(thread, TRUE);
855 }
6601e61a
A
856}
857
1c79356b
A
858/*
859 * Routine: retrieve_task_self_fast
860 * Purpose:
861 * Optimized version of retrieve_task_self,
862 * that only works for the current task.
863 *
864 * Return a send right (possibly null/dead)
865 * for the task's user-visible self port.
866 * Conditions:
867 * Nothing locked.
868 */
869
870ipc_port_t
871retrieve_task_self_fast(
0a7de745 872 task_t task)
1c79356b 873{
cb323159 874 __assert_only ipc_port_t sright;
39037602 875 ipc_port_t port;
1c79356b
A
876
877 assert(task == current_task());
878
879 itk_lock(task);
f427ee49 880 assert(task->itk_self[TASK_FLAVOR_CONTROL] != IP_NULL);
1c79356b 881
f427ee49 882 if ((port = task->itk_settable_self) == task->itk_self[TASK_FLAVOR_CONTROL]) {
1c79356b 883 /* no interposing */
cb323159
A
884 sright = ipc_port_copy_send(port);
885 assert(sright == port);
0a7de745 886 } else {
1c79356b 887 port = ipc_port_copy_send(port);
0a7de745 888 }
1c79356b
A
889 itk_unlock(task);
890
891 return port;
892}
893
894/*
91447636 895 * Routine: retrieve_thread_self_fast
1c79356b 896 * Purpose:
1c79356b
A
897 * Return a send right (possibly null/dead)
898 * for the thread's user-visible self port.
91447636
A
899 *
900 * Only works for the current thread.
901 *
1c79356b
A
902 * Conditions:
903 * Nothing locked.
904 */
905
906ipc_port_t
91447636 907retrieve_thread_self_fast(
0a7de745 908 thread_t thread)
1c79356b 909{
cb323159 910 __assert_only ipc_port_t sright;
39037602 911 ipc_port_t port;
1c79356b 912
91447636
A
913 assert(thread == current_thread());
914
915 thread_mtx_lock(thread);
1c79356b 916
f427ee49 917 assert(thread->ith_self[THREAD_FLAVOR_CONTROL] != IP_NULL);
91447636 918
f427ee49 919 if ((port = thread->ith_settable_self) == thread->ith_self[THREAD_FLAVOR_CONTROL]) {
1c79356b 920 /* no interposing */
cb323159
A
921 sright = ipc_port_copy_send(port);
922 assert(sright == port);
0a7de745 923 } else {
1c79356b 924 port = ipc_port_copy_send(port);
0a7de745 925 }
91447636
A
926
927 thread_mtx_unlock(thread);
1c79356b
A
928
929 return port;
930}
931
932/*
933 * Routine: task_self_trap [mach trap]
934 * Purpose:
935 * Give the caller send rights for his own task port.
936 * Conditions:
937 * Nothing locked.
938 * Returns:
939 * MACH_PORT_NULL if there are any resource failures
940 * or other errors.
941 */
942
943mach_port_name_t
91447636
A
944task_self_trap(
945 __unused struct task_self_trap_args *args)
1c79356b
A
946{
947 task_t task = current_task();
948 ipc_port_t sright;
91447636 949 mach_port_name_t name;
1c79356b
A
950
951 sright = retrieve_task_self_fast(task);
91447636
A
952 name = ipc_port_copyout_send(sright, task->itk_space);
953 return name;
1c79356b
A
954}
955
956/*
957 * Routine: thread_self_trap [mach trap]
958 * Purpose:
959 * Give the caller send rights for his own thread port.
960 * Conditions:
961 * Nothing locked.
962 * Returns:
963 * MACH_PORT_NULL if there are any resource failures
964 * or other errors.
965 */
966
967mach_port_name_t
91447636
A
968thread_self_trap(
969 __unused struct thread_self_trap_args *args)
1c79356b 970{
91447636
A
971 thread_t thread = current_thread();
972 task_t task = thread->task;
1c79356b 973 ipc_port_t sright;
91447636
A
974 mach_port_name_t name;
975
976 sright = retrieve_thread_self_fast(thread);
977 name = ipc_port_copyout_send(sright, task->itk_space);
978 return name;
1c79356b
A
979}
980
981/*
982 * Routine: mach_reply_port [mach trap]
983 * Purpose:
984 * Allocate a port for the caller.
985 * Conditions:
986 * Nothing locked.
987 * Returns:
988 * MACH_PORT_NULL if there are any resource failures
989 * or other errors.
990 */
991
992mach_port_name_t
91447636
A
993mach_reply_port(
994 __unused struct mach_reply_port_args *args)
1c79356b
A
995{
996 ipc_port_t port;
997 mach_port_name_t name;
998 kern_return_t kr;
999
94ff46dc
A
1000 kr = ipc_port_alloc(current_task()->itk_space, IPC_PORT_INIT_MESSAGE_QUEUE,
1001 &name, &port);
0a7de745 1002 if (kr == KERN_SUCCESS) {
1c79356b 1003 ip_unlock(port);
0a7de745 1004 } else {
1c79356b 1005 name = MACH_PORT_NULL;
0a7de745 1006 }
1c79356b
A
1007 return name;
1008}
1009
5ba3f43e
A
1010/*
1011 * Routine: thread_get_special_reply_port [mach trap]
1012 * Purpose:
1013 * Allocate a special reply port for the calling thread.
1014 * Conditions:
1015 * Nothing locked.
1016 * Returns:
d9a64523 1017 * mach_port_name_t: send right & receive right for special reply port.
5ba3f43e
A
1018 * MACH_PORT_NULL if there are any resource failures
1019 * or other errors.
1020 */
1021
1022mach_port_name_t
1023thread_get_special_reply_port(
1024 __unused struct thread_get_special_reply_port_args *args)
1025{
1026 ipc_port_t port;
1027 mach_port_name_t name;
1028 kern_return_t kr;
1029 thread_t thread = current_thread();
94ff46dc
A
1030 ipc_port_init_flags_t flags = IPC_PORT_INIT_MESSAGE_QUEUE |
1031 IPC_PORT_INIT_MAKE_SEND_RIGHT | IPC_PORT_INIT_SPECIAL_REPLY;
5ba3f43e
A
1032
1033 /* unbind the thread special reply port */
1034 if (IP_VALID(thread->ith_special_reply_port)) {
1035 kr = ipc_port_unbind_special_reply_port(thread, TRUE);
1036 if (kr != KERN_SUCCESS) {
1037 return MACH_PORT_NULL;
1038 }
1039 }
1040
94ff46dc 1041 kr = ipc_port_alloc(current_task()->itk_space, flags, &name, &port);
5ba3f43e
A
1042 if (kr == KERN_SUCCESS) {
1043 ipc_port_bind_special_reply_port_locked(port);
1044 ip_unlock(port);
1045 } else {
1046 name = MACH_PORT_NULL;
1047 }
1048 return name;
1049}
1050
1051/*
1052 * Routine: ipc_port_bind_special_reply_port_locked
1053 * Purpose:
1054 * Bind the given port to current thread as a special reply port.
1055 * Conditions:
1056 * Port locked.
1057 * Returns:
1058 * None.
1059 */
1060
1061static void
1062ipc_port_bind_special_reply_port_locked(
1063 ipc_port_t port)
1064{
1065 thread_t thread = current_thread();
1066 assert(thread->ith_special_reply_port == NULL);
94ff46dc
A
1067 assert(port->ip_specialreply);
1068 assert(port->ip_sync_link_state == PORT_SYNC_LINK_ANY);
5ba3f43e
A
1069
1070 ip_reference(port);
1071 thread->ith_special_reply_port = port;
cb323159 1072 port->ip_messages.imq_srp_owner_thread = thread;
d9a64523 1073
cb323159 1074 ipc_special_reply_port_bits_reset(port);
5ba3f43e
A
1075}
1076
1077/*
1078 * Routine: ipc_port_unbind_special_reply_port
1079 * Purpose:
1080 * Unbind the thread's special reply port.
d9a64523
A
1081 * If the special port has threads waiting on turnstile,
1082 * update it's inheritor.
5ba3f43e
A
1083 * Condition:
1084 * Nothing locked.
1085 * Returns:
1086 * None.
1087 */
1088static kern_return_t
1089ipc_port_unbind_special_reply_port(
1090 thread_t thread,
1091 boolean_t unbind_active_port)
1092{
1093 ipc_port_t special_reply_port = thread->ith_special_reply_port;
1094
1095 ip_lock(special_reply_port);
1096
1097 /* Return error if port active and unbind_active_port set to FALSE */
1098 if (unbind_active_port == FALSE && ip_active(special_reply_port)) {
1099 ip_unlock(special_reply_port);
1100 return KERN_FAILURE;
1101 }
1102
1103 thread->ith_special_reply_port = NULL;
d9a64523 1104 ipc_port_adjust_special_reply_port_locked(special_reply_port, NULL,
cb323159 1105 IPC_PORT_ADJUST_UNLINK_THREAD, FALSE);
5ba3f43e
A
1106 /* port unlocked */
1107
1108 ip_release(special_reply_port);
1109 return KERN_SUCCESS;
1110}
1111
91447636
A
1112/*
1113 * Routine: thread_get_special_port [kernel call]
1114 * Purpose:
1115 * Clones a send right for one of the thread's
1116 * special ports.
1117 * Conditions:
1118 * Nothing locked.
1119 * Returns:
1120 * KERN_SUCCESS Extracted a send right.
1121 * KERN_INVALID_ARGUMENT The thread is null.
1122 * KERN_FAILURE The thread is dead.
1123 * KERN_INVALID_ARGUMENT Invalid special port.
1124 */
1125
1126kern_return_t
1127thread_get_special_port(
f427ee49
A
1128 thread_inspect_t thread,
1129 int which,
1130 ipc_port_t *portp);
1131
1132kern_return_t
1133static
1134thread_get_special_port_internal(
1135 thread_inspect_t thread,
1136 int which,
1137 ipc_port_t *portp,
1138 mach_thread_flavor_t flavor)
91447636 1139{
f427ee49
A
1140 kern_return_t kr;
1141 ipc_port_t port;
91447636 1142
0a7de745
A
1143 if (thread == THREAD_NULL) {
1144 return KERN_INVALID_ARGUMENT;
1145 }
91447636 1146
f427ee49
A
1147 if ((kr = port_allowed_with_thread_flavor(which, flavor)) != KERN_SUCCESS) {
1148 return kr;
1149 }
1150
1151 thread_mtx_lock(thread);
1152 if (!thread->active) {
1153 thread_mtx_unlock(thread);
1154 return KERN_FAILURE;
1155 }
1156
91447636 1157 switch (which) {
91447636 1158 case THREAD_KERNEL_PORT:
f427ee49
A
1159 port = ipc_port_copy_send(thread->ith_settable_self);
1160 thread_mtx_unlock(thread);
1161 break;
1162
1163 case THREAD_READ_PORT:
1164 case THREAD_INSPECT_PORT:
1165 thread_mtx_unlock(thread);
1166 mach_thread_flavor_t current_flavor = (which == THREAD_READ_PORT) ?
1167 THREAD_FLAVOR_READ : THREAD_FLAVOR_INSPECT;
1168 /* convert_thread_to_port_with_flavor consumes a thread reference */
1169 thread_reference(thread);
1170 port = convert_thread_to_port_with_flavor(thread, current_flavor);
91447636
A
1171 break;
1172
1173 default:
f427ee49 1174 thread_mtx_unlock(thread);
0a7de745 1175 return KERN_INVALID_ARGUMENT;
91447636
A
1176 }
1177
f427ee49 1178 *portp = port;
91447636 1179
f427ee49
A
1180 return KERN_SUCCESS;
1181}
1182
1183kern_return_t
1184thread_get_special_port(
1185 thread_inspect_t thread,
1186 int which,
1187 ipc_port_t *portp)
1188{
1189 return thread_get_special_port_internal(thread, which, portp, THREAD_FLAVOR_CONTROL);
1190}
1191
1192kern_return_t
1193thread_get_special_port_from_user(
1194 mach_port_t port,
1195 int which,
1196 ipc_port_t *portp)
1197{
1198 ipc_kobject_type_t kotype;
1199 kern_return_t kr;
1200
1201 thread_t thread = convert_port_to_thread_check_type(port, &kotype, THREAD_FLAVOR_INSPECT, FALSE);
1202
1203 if (thread == THREAD_NULL) {
1204 return KERN_INVALID_ARGUMENT;
0a7de745 1205 }
91447636 1206
f427ee49
A
1207 switch (kotype) {
1208 case IKOT_THREAD_CONTROL:
1209 kr = thread_get_special_port_internal(thread, which, portp, THREAD_FLAVOR_CONTROL);
1210 break;
1211 case IKOT_THREAD_READ:
1212 kr = thread_get_special_port_internal(thread, which, portp, THREAD_FLAVOR_READ);
1213 break;
1214 case IKOT_THREAD_INSPECT:
1215 kr = thread_get_special_port_internal(thread, which, portp, THREAD_FLAVOR_INSPECT);
1216 break;
1217 default:
1218 panic("strange kobject type");
1219 break;
1220 }
91447636 1221
f427ee49
A
1222 thread_deallocate(thread);
1223 return kr;
1224}
1225
1226static kern_return_t
1227port_allowed_with_thread_flavor(
1228 int which,
1229 mach_thread_flavor_t flavor)
1230{
1231 switch (flavor) {
1232 case THREAD_FLAVOR_CONTROL:
1233 return KERN_SUCCESS;
1234
1235 case THREAD_FLAVOR_READ:
1236
1237 switch (which) {
1238 case THREAD_READ_PORT:
1239 case THREAD_INSPECT_PORT:
1240 return KERN_SUCCESS;
1241 default:
1242 return KERN_INVALID_CAPABILITY;
1243 }
1244
1245 case THREAD_FLAVOR_INSPECT:
1246
1247 switch (which) {
1248 case THREAD_INSPECT_PORT:
1249 return KERN_SUCCESS;
1250 default:
1251 return KERN_INVALID_CAPABILITY;
1252 }
1253
1254 default:
1255 return KERN_INVALID_CAPABILITY;
1256 }
91447636
A
1257}
1258
1259/*
1260 * Routine: thread_set_special_port [kernel call]
1261 * Purpose:
1262 * Changes one of the thread's special ports,
1263 * setting it to the supplied send right.
1264 * Conditions:
1265 * Nothing locked. If successful, consumes
1266 * the supplied send right.
1267 * Returns:
f427ee49
A
1268 * KERN_SUCCESS Changed the special port.
1269 * KERN_INVALID_ARGUMENT The thread is null.
1270 * KERN_FAILURE The thread is dead.
1271 * KERN_INVALID_ARGUMENT Invalid special port.
1272 * KERN_NO_ACCESS Restricted access to set port.
91447636
A
1273 */
1274
1275kern_return_t
1276thread_set_special_port(
0a7de745
A
1277 thread_t thread,
1278 int which,
1279 ipc_port_t port)
91447636 1280{
0a7de745
A
1281 kern_return_t result = KERN_SUCCESS;
1282 ipc_port_t *whichp, old = IP_NULL;
91447636 1283
0a7de745
A
1284 if (thread == THREAD_NULL) {
1285 return KERN_INVALID_ARGUMENT;
1286 }
91447636
A
1287
1288 switch (which) {
91447636 1289 case THREAD_KERNEL_PORT:
f427ee49
A
1290#if CONFIG_CSR
1291 if (csr_check(CSR_ALLOW_KERNEL_DEBUGGER) != 0) {
1292 /*
1293 * Only allow setting of thread-self
1294 * special port from user-space when SIP is
1295 * disabled (for Mach-on-Mach emulation).
1296 */
1297 return KERN_NO_ACCESS;
1298 }
1299#endif
1300 whichp = &thread->ith_settable_self;
91447636
A
1301 break;
1302
1303 default:
0a7de745 1304 return KERN_INVALID_ARGUMENT;
91447636
A
1305 }
1306
1307 thread_mtx_lock(thread);
1308
1309 if (thread->active) {
1310 old = *whichp;
1311 *whichp = port;
0a7de745 1312 } else {
91447636 1313 result = KERN_FAILURE;
0a7de745 1314 }
91447636
A
1315
1316 thread_mtx_unlock(thread);
1317
0a7de745 1318 if (IP_VALID(old)) {
91447636 1319 ipc_port_release_send(old);
0a7de745 1320 }
91447636 1321
0a7de745 1322 return result;
91447636
A
1323}
1324
1c79356b
A
1325/*
1326 * Routine: task_get_special_port [kernel call]
1327 * Purpose:
1328 * Clones a send right for one of the task's
1329 * special ports.
1330 * Conditions:
1331 * Nothing locked.
1332 * Returns:
1333 * KERN_SUCCESS Extracted a send right.
1334 * KERN_INVALID_ARGUMENT The task is null.
1335 * KERN_FAILURE The task/space is dead.
1336 * KERN_INVALID_ARGUMENT Invalid special port.
1337 */
1338
1339kern_return_t
1340task_get_special_port(
0a7de745
A
1341 task_t task,
1342 int which,
f427ee49
A
1343 ipc_port_t *portp);
1344
1345static kern_return_t
1346task_get_special_port_internal(
1347 task_t task,
1348 int which,
1349 ipc_port_t *portp,
1350 mach_task_flavor_t flavor)
1c79356b 1351{
f427ee49 1352 kern_return_t kr;
1c79356b
A
1353 ipc_port_t port;
1354
0a7de745 1355 if (task == TASK_NULL) {
1c79356b 1356 return KERN_INVALID_ARGUMENT;
0a7de745 1357 }
1c79356b 1358
f427ee49
A
1359 if ((kr = port_allowed_with_task_flavor(which, flavor)) != KERN_SUCCESS) {
1360 return kr;
1361 }
1362
0c530ab8 1363 itk_lock(task);
f427ee49 1364 if (task->itk_self[TASK_FLAVOR_CONTROL] == IP_NULL) {
0c530ab8
A
1365 itk_unlock(task);
1366 return KERN_FAILURE;
1367 }
1368
1c79356b 1369 switch (which) {
39037602 1370 case TASK_KERNEL_PORT:
f427ee49 1371 port = ipc_port_copy_send(task->itk_settable_self);
0c530ab8
A
1372 break;
1373
f427ee49
A
1374 case TASK_READ_PORT:
1375 case TASK_INSPECT_PORT:
1376 itk_unlock(task);
1377 mach_task_flavor_t current_flavor = (which == TASK_READ_PORT) ?
1378 TASK_FLAVOR_READ : TASK_FLAVOR_INSPECT;
1379 /* convert_task_to_port_with_flavor consumes a task reference */
1380 task_reference(task);
1381 port = convert_task_to_port_with_flavor(task, current_flavor);
1382 goto copyout;
1383
39037602 1384 case TASK_NAME_PORT:
f427ee49 1385 port = ipc_port_make_send(task->itk_self[TASK_FLAVOR_NAME]);
1c79356b
A
1386 break;
1387
39037602 1388 case TASK_HOST_PORT:
0c530ab8 1389 port = ipc_port_copy_send(task->itk_host);
1c79356b
A
1390 break;
1391
39037602 1392 case TASK_BOOTSTRAP_PORT:
0c530ab8 1393 port = ipc_port_copy_send(task->itk_bootstrap);
1c79356b
A
1394 break;
1395
39037602 1396 case TASK_SEATBELT_PORT:
2d21ac55
A
1397 port = ipc_port_copy_send(task->itk_seatbelt);
1398 break;
1399
39037602 1400 case TASK_ACCESS_PORT:
2d21ac55
A
1401 port = ipc_port_copy_send(task->itk_task_access);
1402 break;
39236c6e 1403
39037602 1404 case TASK_DEBUG_CONTROL_PORT:
fe8ab488
A
1405 port = ipc_port_copy_send(task->itk_debug_control);
1406 break;
1407
39037602 1408 default:
0a7de745 1409 itk_unlock(task);
1c79356b
A
1410 return KERN_INVALID_ARGUMENT;
1411 }
f427ee49 1412
1c79356b
A
1413 itk_unlock(task);
1414
f427ee49 1415copyout:
1c79356b
A
1416 *portp = port;
1417 return KERN_SUCCESS;
1418}
1419
f427ee49
A
1420kern_return_t
1421task_get_special_port(
1422 task_t task,
1423 int which,
1424 ipc_port_t *portp)
1425{
1426 return task_get_special_port_internal(task, which, portp, TASK_FLAVOR_CONTROL);
1427}
1428
1429kern_return_t
1430task_get_special_port_from_user(
1431 mach_port_t port,
1432 int which,
1433 ipc_port_t *portp)
1434{
1435 ipc_kobject_type_t kotype;
1436 kern_return_t kr;
1437
1438 task_t task = convert_port_to_task_check_type(port, &kotype, TASK_FLAVOR_INSPECT, FALSE);
1439
1440 if (task == TASK_NULL) {
1441 return KERN_INVALID_ARGUMENT;
1442 }
1443
1444 switch (kotype) {
1445 case IKOT_TASK_CONTROL:
1446 kr = task_get_special_port_internal(task, which, portp, TASK_FLAVOR_CONTROL);
1447 break;
1448 case IKOT_TASK_READ:
1449 kr = task_get_special_port_internal(task, which, portp, TASK_FLAVOR_READ);
1450 break;
1451 case IKOT_TASK_INSPECT:
1452 kr = task_get_special_port_internal(task, which, portp, TASK_FLAVOR_INSPECT);
1453 break;
1454 default:
1455 panic("strange kobject type");
1456 break;
1457 }
1458
1459 task_deallocate(task);
1460 return kr;
1461}
1462
1463static kern_return_t
1464port_allowed_with_task_flavor(
1465 int which,
1466 mach_task_flavor_t flavor)
1467{
1468 switch (flavor) {
1469 case TASK_FLAVOR_CONTROL:
1470 return KERN_SUCCESS;
1471
1472 case TASK_FLAVOR_READ:
1473
1474 switch (which) {
1475 case TASK_READ_PORT:
1476 case TASK_INSPECT_PORT:
1477 case TASK_NAME_PORT:
1478 return KERN_SUCCESS;
1479 default:
1480 return KERN_INVALID_CAPABILITY;
1481 }
1482
1483 case TASK_FLAVOR_INSPECT:
1484
1485 switch (which) {
1486 case TASK_INSPECT_PORT:
1487 case TASK_NAME_PORT:
1488 return KERN_SUCCESS;
1489 default:
1490 return KERN_INVALID_CAPABILITY;
1491 }
1492
1493 default:
1494 return KERN_INVALID_CAPABILITY;
1495 }
1496}
1497
1c79356b
A
1498/*
1499 * Routine: task_set_special_port [kernel call]
1500 * Purpose:
1501 * Changes one of the task's special ports,
1502 * setting it to the supplied send right.
1503 * Conditions:
1504 * Nothing locked. If successful, consumes
1505 * the supplied send right.
1506 * Returns:
1507 * KERN_SUCCESS Changed the special port.
1508 * KERN_INVALID_ARGUMENT The task is null.
1509 * KERN_FAILURE The task/space is dead.
1510 * KERN_INVALID_ARGUMENT Invalid special port.
4ba76501 1511 * KERN_NO_ACCESS Restricted access to set port.
1c79356b
A
1512 */
1513
1514kern_return_t
1515task_set_special_port(
0a7de745
A
1516 task_t task,
1517 int which,
1518 ipc_port_t port)
1c79356b 1519{
0a7de745 1520 if (task == TASK_NULL) {
1c79356b 1521 return KERN_INVALID_ARGUMENT;
0a7de745 1522 }
1c79356b 1523
cb323159
A
1524 if (task_is_driver(current_task())) {
1525 return KERN_NO_ACCESS;
1526 }
1527
4ba76501
A
1528 switch (which) {
1529 case TASK_KERNEL_PORT:
1530 case TASK_HOST_PORT:
1531#if CONFIG_CSR
1532 if (csr_check(CSR_ALLOW_KERNEL_DEBUGGER) == 0) {
1533 /*
1534 * Only allow setting of task-self / task-host
1535 * special ports from user-space when SIP is
1536 * disabled (for Mach-on-Mach emulation).
1537 */
1538 break;
1539 }
1540#endif
1541 return KERN_NO_ACCESS;
1542 default:
1543 break;
1544 }
1545
1546 return task_set_special_port_internal(task, which, port);
1547}
1548
1549/*
1550 * Routine: task_set_special_port_internal
1551 * Purpose:
1552 * Changes one of the task's special ports,
1553 * setting it to the supplied send right.
1554 * Conditions:
1555 * Nothing locked. If successful, consumes
1556 * the supplied send right.
1557 * Returns:
1558 * KERN_SUCCESS Changed the special port.
1559 * KERN_INVALID_ARGUMENT The task is null.
1560 * KERN_FAILURE The task/space is dead.
1561 * KERN_INVALID_ARGUMENT Invalid special port.
1562 * KERN_NO_ACCESS Restricted access to overwrite port.
1563 */
1564
1565kern_return_t
1566task_set_special_port_internal(
1567 task_t task,
1568 int which,
1569 ipc_port_t port)
1570{
f427ee49
A
1571 ipc_port_t old = IP_NULL;
1572 kern_return_t rc = KERN_INVALID_ARGUMENT;
4ba76501
A
1573
1574 if (task == TASK_NULL) {
f427ee49
A
1575 goto out;
1576 }
1577
1578 itk_lock(task);
1579 if (task->itk_self[TASK_FLAVOR_CONTROL] == IP_NULL) {
1580 rc = KERN_FAILURE;
1581 goto out_unlock;
4ba76501
A
1582 }
1583
1c79356b 1584 switch (which) {
39037602 1585 case TASK_KERNEL_PORT:
f427ee49
A
1586 old = task->itk_settable_self;
1587 task->itk_settable_self = port;
0a7de745 1588 break;
1c79356b 1589
39037602 1590 case TASK_HOST_PORT:
f427ee49
A
1591 old = task->itk_host;
1592 task->itk_host = port;
0a7de745 1593 break;
1c79356b 1594
39037602 1595 case TASK_BOOTSTRAP_PORT:
f427ee49
A
1596 old = task->itk_bootstrap;
1597 task->itk_bootstrap = port;
0a7de745 1598 break;
1c79356b 1599
f427ee49 1600 /* Never allow overwrite of seatbelt port */
39037602 1601 case TASK_SEATBELT_PORT:
f427ee49
A
1602 if (IP_VALID(task->itk_seatbelt)) {
1603 rc = KERN_NO_ACCESS;
1604 goto out_unlock;
1605 }
1606 task->itk_seatbelt = port;
0a7de745 1607 break;
2d21ac55 1608
f427ee49 1609 /* Never allow overwrite of the task access port */
39037602 1610 case TASK_ACCESS_PORT:
f427ee49
A
1611 if (IP_VALID(task->itk_task_access)) {
1612 rc = KERN_NO_ACCESS;
1613 goto out_unlock;
1614 }
1615 task->itk_task_access = port;
0a7de745 1616 break;
fe8ab488 1617
39037602 1618 case TASK_DEBUG_CONTROL_PORT:
f427ee49
A
1619 old = task->itk_debug_control;
1620 task->itk_debug_control = port;
0a7de745 1621 break;
fe8ab488 1622
39037602 1623 default:
f427ee49
A
1624 rc = KERN_INVALID_ARGUMENT;
1625 goto out_unlock;
1c79356b
A
1626 }/* switch */
1627
f427ee49 1628 rc = KERN_SUCCESS;
2d21ac55 1629
f427ee49 1630out_unlock:
1c79356b
A
1631 itk_unlock(task);
1632
0a7de745 1633 if (IP_VALID(old)) {
1c79356b 1634 ipc_port_release_send(old);
0a7de745 1635 }
f427ee49
A
1636out:
1637 return rc;
1c79356b 1638}
1c79356b
A
1639/*
1640 * Routine: mach_ports_register [kernel call]
1641 * Purpose:
1642 * Stash a handful of port send rights in the task.
1643 * Child tasks will inherit these rights, but they
1644 * must use mach_ports_lookup to acquire them.
1645 *
1646 * The rights are supplied in a (wired) kalloc'd segment.
1647 * Rights which aren't supplied are assumed to be null.
1648 * Conditions:
1649 * Nothing locked. If successful, consumes
1650 * the supplied rights and memory.
1651 * Returns:
1652 * KERN_SUCCESS Stashed the port rights.
1653 * KERN_INVALID_ARGUMENT The task is null.
1654 * KERN_INVALID_ARGUMENT The task is dead.
39236c6e 1655 * KERN_INVALID_ARGUMENT The memory param is null.
1c79356b
A
1656 * KERN_INVALID_ARGUMENT Too many port rights supplied.
1657 */
1658
1659kern_return_t
1660mach_ports_register(
0a7de745
A
1661 task_t task,
1662 mach_port_array_t memory,
1663 mach_msg_type_number_t portsCnt)
1c79356b
A
1664{
1665 ipc_port_t ports[TASK_PORT_REGISTER_MAX];
91447636 1666 unsigned int i;
1c79356b
A
1667
1668 if ((task == TASK_NULL) ||
39236c6e 1669 (portsCnt > TASK_PORT_REGISTER_MAX) ||
0a7de745 1670 (portsCnt && memory == NULL)) {
1c79356b 1671 return KERN_INVALID_ARGUMENT;
0a7de745 1672 }
1c79356b
A
1673
1674 /*
1675 * Pad the port rights with nulls.
1676 */
1677
0a7de745 1678 for (i = 0; i < portsCnt; i++) {
1c79356b 1679 ports[i] = memory[i];
0a7de745
A
1680 }
1681 for (; i < TASK_PORT_REGISTER_MAX; i++) {
1c79356b 1682 ports[i] = IP_NULL;
0a7de745 1683 }
1c79356b
A
1684
1685 itk_lock(task);
f427ee49 1686 if (task->itk_self[TASK_FLAVOR_CONTROL] == IP_NULL) {
1c79356b
A
1687 itk_unlock(task);
1688 return KERN_INVALID_ARGUMENT;
1689 }
1690
1691 /*
1692 * Replace the old send rights with the new.
1693 * Release the old rights after unlocking.
1694 */
1695
1696 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) {
1697 ipc_port_t old;
1698
1699 old = task->itk_registered[i];
1700 task->itk_registered[i] = ports[i];
1701 ports[i] = old;
1702 }
1703
1704 itk_unlock(task);
1705
0a7de745
A
1706 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) {
1707 if (IP_VALID(ports[i])) {
1c79356b 1708 ipc_port_release_send(ports[i]);
0a7de745
A
1709 }
1710 }
1c79356b
A
1711
1712 /*
1713 * Now that the operation is known to be successful,
1714 * we can free the memory.
1715 */
1716
0a7de745 1717 if (portsCnt != 0) {
91447636 1718 kfree(memory,
0a7de745
A
1719 (vm_size_t) (portsCnt * sizeof(mach_port_t)));
1720 }
1c79356b
A
1721
1722 return KERN_SUCCESS;
1723}
1724
1725/*
1726 * Routine: mach_ports_lookup [kernel call]
1727 * Purpose:
1728 * Retrieves (clones) the stashed port send rights.
1729 * Conditions:
1730 * Nothing locked. If successful, the caller gets
1731 * rights and memory.
1732 * Returns:
1733 * KERN_SUCCESS Retrieved the send rights.
1734 * KERN_INVALID_ARGUMENT The task is null.
1735 * KERN_INVALID_ARGUMENT The task is dead.
1736 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1737 */
1738
1739kern_return_t
1740mach_ports_lookup(
0a7de745
A
1741 task_t task,
1742 mach_port_array_t *portsp,
1743 mach_msg_type_number_t *portsCnt)
1c79356b 1744{
91447636 1745 void *memory;
1c79356b
A
1746 vm_size_t size;
1747 ipc_port_t *ports;
1748 int i;
1749
0a7de745 1750 if (task == TASK_NULL) {
1c79356b 1751 return KERN_INVALID_ARGUMENT;
0a7de745 1752 }
1c79356b
A
1753
1754 size = (vm_size_t) (TASK_PORT_REGISTER_MAX * sizeof(ipc_port_t));
1755
1756 memory = kalloc(size);
0a7de745 1757 if (memory == 0) {
1c79356b 1758 return KERN_RESOURCE_SHORTAGE;
0a7de745 1759 }
1c79356b
A
1760
1761 itk_lock(task);
f427ee49 1762 if (task->itk_self[TASK_FLAVOR_CONTROL] == IP_NULL) {
1c79356b
A
1763 itk_unlock(task);
1764
1765 kfree(memory, size);
1766 return KERN_INVALID_ARGUMENT;
1767 }
1768
1769 ports = (ipc_port_t *) memory;
1770
1771 /*
1772 * Clone port rights. Because kalloc'd memory
1773 * is wired, we won't fault while holding the task lock.
1774 */
1775
0a7de745 1776 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) {
1c79356b 1777 ports[i] = ipc_port_copy_send(task->itk_registered[i]);
0a7de745 1778 }
1c79356b
A
1779
1780 itk_unlock(task);
1781
1782 *portsp = (mach_port_array_t) ports;
1783 *portsCnt = TASK_PORT_REGISTER_MAX;
1784 return KERN_SUCCESS;
1785}
1786
5ba3f43e
A
1787kern_return_t
1788task_conversion_eval(task_t caller, task_t victim)
1789{
1790 /*
1791 * Tasks are allowed to resolve their own task ports, and the kernel is
1792 * allowed to resolve anyone's task port.
1793 */
1794 if (caller == kernel_task) {
1795 return KERN_SUCCESS;
1796 }
1797
1798 if (caller == victim) {
1799 return KERN_SUCCESS;
1800 }
1801
1802 /*
1803 * Only the kernel can can resolve the kernel's task port. We've established
1804 * by this point that the caller is not kernel_task.
1805 */
d9a64523 1806 if (victim == TASK_NULL || victim == kernel_task) {
5ba3f43e
A
1807 return KERN_INVALID_SECURITY;
1808 }
1809
f427ee49 1810 task_require(victim);
94ff46dc 1811
f427ee49 1812#if !defined(XNU_TARGET_OS_OSX)
5ba3f43e 1813 /*
f427ee49 1814 * On platforms other than macOS, only a platform binary can resolve the task port
5ba3f43e
A
1815 * of another platform binary.
1816 */
1817 if ((victim->t_flags & TF_PLATFORM) && !(caller->t_flags & TF_PLATFORM)) {
1818#if SECURE_KERNEL
1819 return KERN_INVALID_SECURITY;
1820#else
1821 if (cs_relax_platform_task_ports) {
1822 return KERN_SUCCESS;
1823 } else {
1824 return KERN_INVALID_SECURITY;
1825 }
1826#endif /* SECURE_KERNEL */
1827 }
f427ee49 1828#endif /* !defined(XNU_TARGET_OS_OSX) */
5ba3f43e
A
1829
1830 return KERN_SUCCESS;
1831}
1832
1c79356b
A
1833/*
1834 * Routine: convert_port_to_locked_task
1835 * Purpose:
1836 * Internal helper routine to convert from a port to a locked
1837 * task. Used by several routines that try to convert from a
1838 * task port to a reference on some task related object.
1839 * Conditions:
1840 * Nothing locked, blocking OK.
1841 */
1842task_t
f427ee49 1843convert_port_to_locked_task(ipc_port_t port, boolean_t eval)
1c79356b 1844{
5ba3f43e 1845 int try_failed_count = 0;
2d21ac55 1846
1c79356b 1847 while (IP_VALID(port)) {
5ba3f43e 1848 task_t ct = current_task();
1c79356b
A
1849 task_t task;
1850
1851 ip_lock(port);
f427ee49 1852 if (!ip_active(port) || (ip_kotype(port) != IKOT_TASK_CONTROL)) {
1c79356b
A
1853 ip_unlock(port);
1854 return TASK_NULL;
1855 }
ea3f0419 1856 task = (task_t) ip_get_kobject(port);
1c79356b
A
1857 assert(task != TASK_NULL);
1858
f427ee49 1859 if (eval && task_conversion_eval(ct, task)) {
813fb2f6
A
1860 ip_unlock(port);
1861 return TASK_NULL;
1862 }
1863
1c79356b
A
1864 /*
1865 * Normal lock ordering puts task_lock() before ip_lock().
1866 * Attempt out-of-order locking here.
1867 */
1868 if (task_lock_try(task)) {
1869 ip_unlock(port);
0a7de745 1870 return task;
1c79356b 1871 }
2d21ac55 1872 try_failed_count++;
1c79356b
A
1873
1874 ip_unlock(port);
2d21ac55 1875 mutex_pause(try_failed_count);
1c79356b
A
1876 }
1877 return TASK_NULL;
1878}
1879
813fb2f6
A
1880/*
1881 * Routine: convert_port_to_locked_task_inspect
1882 * Purpose:
1883 * Internal helper routine to convert from a port to a locked
1884 * task inspect right. Used by internal routines that try to convert from a
1885 * task inspect port to a reference on some task related object.
1886 * Conditions:
1887 * Nothing locked, blocking OK.
1888 */
1889task_inspect_t
1890convert_port_to_locked_task_inspect(ipc_port_t port)
1891{
0a7de745 1892 int try_failed_count = 0;
813fb2f6
A
1893
1894 while (IP_VALID(port)) {
1895 task_inspect_t task;
1896
1897 ip_lock(port);
f427ee49
A
1898 if (!ip_active(port) || (ip_kotype(port) != IKOT_TASK_CONTROL &&
1899 ip_kotype(port) != IKOT_TASK_READ &&
1900 ip_kotype(port) != IKOT_TASK_INSPECT)) {
813fb2f6
A
1901 ip_unlock(port);
1902 return TASK_INSPECT_NULL;
1903 }
ea3f0419 1904 task = (task_inspect_t) ip_get_kobject(port);
813fb2f6
A
1905 assert(task != TASK_INSPECT_NULL);
1906 /*
1907 * Normal lock ordering puts task_lock() before ip_lock().
1908 * Attempt out-of-order locking here.
1909 */
1910 if (task_lock_try((task_t)task)) {
1911 ip_unlock(port);
1912 return task;
1913 }
1914 try_failed_count++;
1915
1916 ip_unlock(port);
1917 mutex_pause(try_failed_count);
1918 }
1919 return TASK_INSPECT_NULL;
1920}
1921
f427ee49
A
1922/*
1923 * Routine: convert_port_to_locked_task_read
1924 * Purpose:
1925 * Internal helper routine to convert from a port to a locked
1926 * task read right. Used by internal routines that try to convert from a
1927 * task read port to a reference on some task related object.
1928 * Conditions:
1929 * Nothing locked, blocking OK.
1930 */
1931task_read_t
1932convert_port_to_locked_task_read(ipc_port_t port)
1933{
1934 int try_failed_count = 0;
1935
1936 while (IP_VALID(port)) {
1937 task_read_t task;
1938
1939 ip_lock(port);
1940 if (!ip_active(port) || (ip_kotype(port) != IKOT_TASK_CONTROL &&
1941 ip_kotype(port) != IKOT_TASK_READ)) {
1942 ip_unlock(port);
1943 return TASK_READ_NULL;
1944 }
1945 task = (task_read_t)port->ip_kobject;
1946 assert(task != TASK_READ_NULL);
1947 /*
1948 * Normal lock ordering puts task_lock() before ip_lock().
1949 * Attempt out-of-order locking here.
1950 */
1951 if (task_lock_try((task_t)task)) {
1952 ip_unlock(port);
1953 return task;
1954 }
1955 try_failed_count++;
1956
1957 ip_unlock(port);
1958 mutex_pause(try_failed_count);
1959 }
1960 return TASK_READ_NULL;
1961}
1962
cb323159
A
1963static task_t
1964convert_port_to_task_locked(
1965 ipc_port_t port,
f427ee49
A
1966 uint32_t *exec_token,
1967 boolean_t eval)
39037602 1968{
cb323159
A
1969 task_t task = TASK_NULL;
1970
1971 ip_lock_held(port);
1972 require_ip_active(port);
1973
f427ee49 1974 if (ip_kotype(port) == IKOT_TASK_CONTROL) {
ea3f0419 1975 task = (task_t) ip_get_kobject(port);
cb323159
A
1976 assert(task != TASK_NULL);
1977
f427ee49 1978 if (eval && task_conversion_eval(current_task(), task)) {
cb323159
A
1979 return TASK_NULL;
1980 }
1981
1982 if (exec_token) {
1983 *exec_token = task->exec_token;
1984 }
f427ee49 1985
cb323159
A
1986 task_reference_internal(task);
1987 }
1988
1989 return task;
39037602
A
1990}
1991
1992/*
1993 * Routine: convert_port_to_task_with_exec_token
1994 * Purpose:
1995 * Convert from a port to a task and return
1996 * the exec token stored in the task.
1997 * Doesn't consume the port ref; produces a task ref,
1998 * which may be null.
1999 * Conditions:
2000 * Nothing locked.
2001 */
2002task_t
2003convert_port_to_task_with_exec_token(
0a7de745 2004 ipc_port_t port,
f427ee49
A
2005 uint32_t *exec_token,
2006 boolean_t eval)
1c79356b 2007{
0a7de745 2008 task_t task = TASK_NULL;
1c79356b 2009
91447636
A
2010 if (IP_VALID(port)) {
2011 ip_lock(port);
cb323159 2012 if (ip_active(port)) {
f427ee49 2013 task = convert_port_to_task_locked(port, exec_token, eval);
91447636 2014 }
91447636 2015 ip_unlock(port);
1c79356b 2016 }
91447636 2017
0a7de745 2018 return task;
1c79356b
A
2019}
2020
cb323159
A
2021/*
2022 * Routine: convert_port_to_task
2023 * Purpose:
2024 * Convert from a port to a task.
2025 * Doesn't consume the port ref; produces a task ref,
2026 * which may be null.
2027 * Conditions:
2028 * Nothing locked.
2029 */
2030task_t
2031convert_port_to_task(
2032 ipc_port_t port)
2033{
f427ee49 2034 return convert_port_to_task_with_exec_token(port, NULL, TRUE);
cb323159
A
2035}
2036
0c530ab8 2037/*
f427ee49 2038 * Routine: convert_port_to_task_no_eval
0c530ab8 2039 * Purpose:
f427ee49
A
2040 * Convert from a port to a task, skips task_conversion_eval.
2041 * Doesn't consume the port ref; produces a task ref,
0c530ab8
A
2042 * which may be null.
2043 * Conditions:
2044 * Nothing locked.
2045 */
f427ee49
A
2046static task_t
2047convert_port_to_task_no_eval(
0a7de745 2048 ipc_port_t port)
0c530ab8 2049{
f427ee49
A
2050 return convert_port_to_task_with_exec_token(port, NULL, FALSE);
2051}
2052
2053/*
2054 * Routine: convert_port_to_task_name
2055 * Purpose:
2056 * Convert from a port to a task name.
2057 * Doesn't consume the port ref; produces a task name ref,
2058 * which may be null.
2059 * Conditions:
2060 * Nothing locked.
2061 */
2062
2063static task_name_t
2064convert_port_to_task_name_locked(
2065 ipc_port_t port)
2066{
2067 task_name_t task = TASK_NAME_NULL;
2068
2069 ip_lock_held(port);
2070 require_ip_active(port);
2071
2072 if (ip_kotype(port) == IKOT_TASK_CONTROL ||
2073 ip_kotype(port) == IKOT_TASK_READ ||
2074 ip_kotype(port) == IKOT_TASK_INSPECT ||
2075 ip_kotype(port) == IKOT_TASK_NAME) {
2076 task = (task_name_t) ip_get_kobject(port);
2077 assert(task != TASK_NAME_NULL);
2078
2079 task_reference_internal(task);
2080 }
2081
2082 return task;
2083}
2084
2085task_name_t
2086convert_port_to_task_name(
2087 ipc_port_t port)
2088{
2089 task_name_t task = TASK_NULL;
0c530ab8
A
2090
2091 if (IP_VALID(port)) {
2092 ip_lock(port);
f427ee49
A
2093 if (ip_active(port)) {
2094 task = convert_port_to_task_name_locked(port);
2095 }
2096 ip_unlock(port);
2097 }
0c530ab8 2098
f427ee49
A
2099 return task;
2100}
0c530ab8 2101
f427ee49
A
2102/*
2103 * Routine: convert_port_to_task_policy
2104 * Purpose:
2105 * Convert from a port to a task.
2106 * Doesn't consume the port ref; produces a task ref,
2107 * which may be null.
2108 * If the port is being used with task_port_set(), any task port
2109 * type other than TASK_CONTROL requires an entitlement. If the
2110 * port is being used with task_port_get(), TASK_NAME requires an
2111 * entitlement.
2112 * Conditions:
2113 * Nothing locked.
2114 */
2115static task_t
2116convert_port_to_task_policy(ipc_port_t port, boolean_t set)
2117{
2118 task_t task = TASK_NULL;
2119 task_t ctask = current_task();
0c530ab8 2120
f427ee49
A
2121 if (!IP_VALID(port)) {
2122 return TASK_NULL;
2123 }
2124
2125 task = set ?
2126 convert_port_to_task(port) :
2127 convert_port_to_task_inspect(port);
2128
2129 if (task == TASK_NULL &&
2130 IOTaskHasEntitlement(ctask, "com.apple.private.task_policy")) {
2131 task = convert_port_to_task_name(port);
2132 }
2133
2134 if (task_conversion_eval(ctask, task) != KERN_SUCCESS) {
2135 task_deallocate(task);
2136 return TASK_NULL;
0c530ab8
A
2137 }
2138
0a7de745 2139 return task;
0c530ab8
A
2140}
2141
f427ee49
A
2142task_policy_set_t
2143convert_port_to_task_policy_set(ipc_port_t port)
2144{
2145 return convert_port_to_task_policy(port, true);
2146}
2147
2148task_policy_get_t
2149convert_port_to_task_policy_get(ipc_port_t port)
2150{
2151 return convert_port_to_task_policy(port, false);
2152}
2153
cb323159
A
2154static task_inspect_t
2155convert_port_to_task_inspect_locked(
2156 ipc_port_t port)
2157{
2158 task_inspect_t task = TASK_INSPECT_NULL;
2159
2160 ip_lock_held(port);
2161 require_ip_active(port);
2162
f427ee49
A
2163 if (ip_kotype(port) == IKOT_TASK_CONTROL ||
2164 ip_kotype(port) == IKOT_TASK_READ ||
2165 ip_kotype(port) == IKOT_TASK_INSPECT) {
ea3f0419 2166 task = (task_inspect_t) ip_get_kobject(port);
cb323159
A
2167 assert(task != TASK_INSPECT_NULL);
2168
2169 task_reference_internal(task);
2170 }
2171
2172 return task;
2173}
2174
f427ee49
A
2175static task_read_t
2176convert_port_to_task_read_locked(
2177 ipc_port_t port)
2178{
2179 task_read_t task = TASK_READ_NULL;
2180
2181 ip_lock_held(port);
2182 require_ip_active(port);
2183
2184 if (ip_kotype(port) == IKOT_TASK_CONTROL ||
2185 ip_kotype(port) == IKOT_TASK_READ) {
2186 task_t ct = current_task();
2187 task = (task_t)port->ip_kobject;
2188
2189 assert(task != TASK_READ_NULL);
2190
2191 if (task_conversion_eval(ct, task)) {
2192 return TASK_READ_NULL;
2193 }
2194
2195 task_reference_internal(task);
2196 }
2197
2198 return task;
2199}
2200
2201/*
2202 * Routine: convert_port_to_task_check_type
2203 * Purpose:
2204 * Convert from a port to a task based on port's type.
2205 * Doesn't consume the port ref; produces a task ref,
2206 * which may be null.
2207 * Arguments:
2208 * port: The port that we do conversion on
2209 * kotype: Returns the IKOT_TYPE of the port, if translation succeeded
2210 * at_most: The lowest capability flavor allowed. In mach_task_flavor_t,
2211 * the higher the flavor number, the lesser the capability, hence the name.
2212 * eval_check: Whether to run task_conversion_eval check during the conversion.
2213 * For backward compatibility, some interfaces does not run conversion
2214 * eval on IKOT_TASK_CONTROL.
2215 * Conditions:
2216 * Nothing locked.
2217 * Returns:
2218 * task_t and port's type, if translation succeeded;
2219 * TASK_NULL and IKOT_NONE, if translation failed
2220 */
2221task_t
2222convert_port_to_task_check_type(
2223 ipc_port_t port,
2224 ipc_kobject_type_t *kotype,
2225 mach_task_flavor_t at_most,
2226 boolean_t eval_check)
2227{
2228 task_t task = TASK_NULL;
2229 ipc_kobject_type_t type = IKOT_NONE;
2230
2231 if (!IP_VALID(port) || !ip_active(port)) {
2232 goto out;
2233 }
2234
2235 switch (ip_kotype(port)) {
2236 case IKOT_TASK_CONTROL:
2237 task = eval_check ? convert_port_to_task(port) : convert_port_to_task_no_eval(port);
2238 if (task != TASK_NULL) {
2239 type = IKOT_TASK_CONTROL;
2240 }
2241 break;
2242 case IKOT_TASK_READ:
2243 if (at_most >= TASK_FLAVOR_READ) {
2244 task = convert_port_to_task_read(port);
2245 if (task != TASK_READ_NULL) {
2246 type = IKOT_TASK_READ;
2247 }
2248 }
2249 break;
2250 case IKOT_TASK_INSPECT:
2251 if (at_most >= TASK_FLAVOR_INSPECT) {
2252 task = convert_port_to_task_inspect(port);
2253 if (task != TASK_INSPECT_NULL) {
2254 type = IKOT_TASK_INSPECT;
2255 }
2256 }
2257 break;
2258 case IKOT_TASK_NAME:
2259 if (at_most >= TASK_FLAVOR_NAME) {
2260 task = convert_port_to_task_name(port);
2261 if (task != TASK_NAME_NULL) {
2262 type = IKOT_TASK_NAME;
2263 }
2264 }
2265 break;
2266 default:
2267 break;
2268 }
2269
2270out:
2271 if (kotype) {
2272 *kotype = type;
2273 }
2274 return task;
2275}
2276
2277/*
2278 * Routine: convert_port_to_thread_check_type
2279 * Purpose:
2280 * Convert from a port to a thread based on port's type.
2281 * Doesn't consume the port ref; produces a thread ref,
2282 * which may be null.
2283 * This conversion routine is _ONLY_ supposed to be used
2284 * by thread_get_special_port.
2285 * Arguments:
2286 * port: The port that we do conversion on
2287 * kotype: Returns the IKOT_TYPE of the port, if translation succeeded
2288 * at_most: The lowest capability flavor allowed. In mach_thread_flavor_t,
2289 * the higher the flavor number, the lesser the capability, hence the name.
2290 * eval_check: Whether to run task_conversion_eval check during the conversion.
2291 * For backward compatibility, some interfaces do not run
2292 * conversion eval on IKOT_THREAD_CONTROL.
2293 * Conditions:
2294 * Nothing locked.
2295 * Returns:
2296 * thread_t and port's type, if translation succeeded;
2297 * THREAD_NULL and IKOT_NONE, if translation failed
2298 */
2299thread_t
2300convert_port_to_thread_check_type(
2301 ipc_port_t port,
2302 ipc_kobject_type_t *kotype,
2303 mach_thread_flavor_t at_most,
2304 boolean_t eval_check)
2305{
2306 thread_t thread = THREAD_NULL;
2307 ipc_kobject_type_t type = IKOT_NONE;
2308
2309 if (!IP_VALID(port) || !ip_active(port)) {
2310 goto out;
2311 }
2312
2313 switch (ip_kotype(port)) {
2314 case IKOT_THREAD_CONTROL:
2315 thread = eval_check ? convert_port_to_thread(port) : convert_port_to_thread_no_eval(port);
2316 if (thread != THREAD_NULL) {
2317 type = IKOT_THREAD_CONTROL;
2318 }
2319 break;
2320 case IKOT_THREAD_READ:
2321 if (at_most >= THREAD_FLAVOR_READ) {
2322 thread = convert_port_to_thread_read(port);
2323 if (thread != THREAD_READ_NULL) {
2324 type = IKOT_THREAD_READ;
2325 }
2326 }
2327 break;
2328 case IKOT_THREAD_INSPECT:
2329 if (at_most >= THREAD_FLAVOR_INSPECT) {
2330 thread = convert_port_to_thread_inspect(port);
2331 if (thread != THREAD_INSPECT_NULL) {
2332 type = IKOT_THREAD_INSPECT;
2333 }
2334 }
2335 break;
2336 default:
2337 break;
2338 }
2339
2340out:
2341 if (kotype) {
2342 *kotype = type;
2343 }
2344 return thread;
2345}
2346
2347/*
2348 * Routine: convert_port_to_space_check_type
2349 * Purpose:
2350 * Convert from a port to a space based on port's type.
2351 * Doesn't consume the port ref; produces a space ref,
2352 * which may be null.
2353 * Arguments:
2354 * port: The port that we do conversion on
2355 * kotype: Returns the IKOT_TYPE of the port, if translation succeeded
2356 * at_most: The lowest capability flavor allowed. In mach_task_flavor_t,
2357 * the higher the flavor number, the lesser the capability, hence the name.
2358 * eval_check: Whether to run task_conversion_eval check during the conversion.
2359 * For backward compatibility, some interfaces do not run
2360 * conversion eval on IKOT_TASK_CONTROL.
2361 * Conditions:
2362 * Nothing locked.
2363 * Returns:
2364 * ipc_space_t and port's type, if translation succeeded;
2365 * IPC_SPACE_NULL and IKOT_NONE, if translation failed
2366 */
2367ipc_space_t
2368convert_port_to_space_check_type(
2369 ipc_port_t port,
2370 ipc_kobject_type_t *kotype,
2371 mach_task_flavor_t at_most,
2372 boolean_t eval_check)
2373{
2374 ipc_space_t space = IPC_SPACE_NULL;
2375 ipc_kobject_type_t type = IKOT_NONE;
2376
2377 if (!IP_VALID(port) || !ip_active(port)) {
2378 goto out;
2379 }
2380
2381 switch (ip_kotype(port)) {
2382 case IKOT_TASK_CONTROL:
2383 space = eval_check ? convert_port_to_space(port) : convert_port_to_space_no_eval(port);
2384 if (space != IPC_SPACE_NULL) {
2385 type = IKOT_TASK_CONTROL;
2386 }
2387 break;
2388 case IKOT_TASK_READ:
2389 if (at_most >= TASK_FLAVOR_READ) {
2390 space = convert_port_to_space_read(port);
2391 if (space != IPC_SPACE_READ_NULL) {
2392 type = IKOT_TASK_READ;
2393 }
2394 }
2395 break;
2396 case IKOT_TASK_INSPECT:
2397 if (at_most >= TASK_FLAVOR_INSPECT) {
2398 space = convert_port_to_space_inspect(port);
2399 if (space != IPC_SPACE_INSPECT_NULL) {
2400 type = IKOT_TASK_INSPECT;
2401 }
2402 }
2403 break;
2404 default:
2405 break;
2406 }
2407
2408out:
2409 if (kotype) {
2410 *kotype = type;
2411 }
2412 return space;
2413}
2414
813fb2f6
A
2415/*
2416 * Routine: convert_port_to_task_inspect
2417 * Purpose:
2418 * Convert from a port to a task inspection right
2419 * Doesn't consume the port ref; produces a task ref,
2420 * which may be null.
2421 * Conditions:
2422 * Nothing locked.
2423 */
2424task_inspect_t
2425convert_port_to_task_inspect(
0a7de745 2426 ipc_port_t port)
813fb2f6
A
2427{
2428 task_inspect_t task = TASK_INSPECT_NULL;
2429
2430 if (IP_VALID(port)) {
2431 ip_lock(port);
cb323159
A
2432 if (ip_active(port)) {
2433 task = convert_port_to_task_inspect_locked(port);
813fb2f6 2434 }
813fb2f6
A
2435 ip_unlock(port);
2436 }
2437
0a7de745 2438 return task;
813fb2f6
A
2439}
2440
f427ee49
A
2441/*
2442 * Routine: convert_port_to_task_read
2443 * Purpose:
2444 * Convert from a port to a task read right
2445 * Doesn't consume the port ref; produces a task ref,
2446 * which may be null.
2447 * Conditions:
2448 * Nothing locked.
2449 */
2450task_read_t
2451convert_port_to_task_read(
2452 ipc_port_t port)
2453{
2454 task_read_t task = TASK_READ_NULL;
2455
2456 if (IP_VALID(port)) {
2457 ip_lock(port);
2458 if (ip_active(port)) {
2459 task = convert_port_to_task_read_locked(port);
2460 }
2461 ip_unlock(port);
2462 }
2463
2464 return task;
2465}
2466
39236c6e
A
2467/*
2468 * Routine: convert_port_to_task_suspension_token
2469 * Purpose:
2470 * Convert from a port to a task suspension token.
2471 * Doesn't consume the port ref; produces a suspension token ref,
2472 * which may be null.
2473 * Conditions:
2474 * Nothing locked.
2475 */
2476task_suspension_token_t
2477convert_port_to_task_suspension_token(
0a7de745 2478 ipc_port_t port)
39236c6e 2479{
0a7de745 2480 task_suspension_token_t task = TASK_NULL;
39236c6e
A
2481
2482 if (IP_VALID(port)) {
2483 ip_lock(port);
2484
0a7de745
A
2485 if (ip_active(port) &&
2486 ip_kotype(port) == IKOT_TASK_RESUME) {
ea3f0419 2487 task = (task_suspension_token_t) ip_get_kobject(port);
39236c6e
A
2488 assert(task != TASK_NULL);
2489
2490 task_reference_internal(task);
2491 }
2492
2493 ip_unlock(port);
2494 }
2495
0a7de745 2496 return task;
39236c6e
A
2497}
2498
1c79356b 2499/*
f427ee49 2500 * Routine: convert_port_to_space_with_flavor
1c79356b
A
2501 * Purpose:
2502 * Convert from a port to a space.
2503 * Doesn't consume the port ref; produces a space ref,
2504 * which may be null.
2505 * Conditions:
2506 * Nothing locked.
2507 */
f427ee49
A
2508static ipc_space_t
2509convert_port_to_space_with_flavor(
2510 ipc_port_t port,
2511 mach_task_flavor_t flavor,
2512 boolean_t eval)
1c79356b
A
2513{
2514 ipc_space_t space;
2515 task_t task;
2516
f427ee49
A
2517 switch (flavor) {
2518 case TASK_FLAVOR_CONTROL:
2519 task = convert_port_to_locked_task(port, eval);
2520 break;
2521 case TASK_FLAVOR_READ:
2522 task = convert_port_to_locked_task_read(port);
2523 break;
2524 case TASK_FLAVOR_INSPECT:
2525 task = convert_port_to_locked_task_inspect(port);
2526 break;
2527 default:
2528 task = TASK_NULL;
2529 break;
2530 }
1c79356b 2531
0a7de745 2532 if (task == TASK_NULL) {
1c79356b 2533 return IPC_SPACE_NULL;
0a7de745 2534 }
1c79356b
A
2535
2536 if (!task->active) {
2537 task_unlock(task);
2538 return IPC_SPACE_NULL;
2539 }
0a7de745 2540
1c79356b
A
2541 space = task->itk_space;
2542 is_reference(space);
2543 task_unlock(task);
0a7de745 2544 return space;
1c79356b
A
2545}
2546
f427ee49
A
2547ipc_space_t
2548convert_port_to_space(
0a7de745 2549 ipc_port_t port)
813fb2f6 2550{
f427ee49
A
2551 return convert_port_to_space_with_flavor(port, TASK_FLAVOR_CONTROL, TRUE);
2552}
813fb2f6 2553
f427ee49
A
2554static ipc_space_t
2555convert_port_to_space_no_eval(
2556 ipc_port_t port)
2557{
2558 return convert_port_to_space_with_flavor(port, TASK_FLAVOR_CONTROL, FALSE);
2559}
813fb2f6 2560
f427ee49
A
2561ipc_space_read_t
2562convert_port_to_space_read(
2563 ipc_port_t port)
2564{
2565 return convert_port_to_space_with_flavor(port, TASK_FLAVOR_READ, TRUE);
2566}
813fb2f6 2567
f427ee49
A
2568ipc_space_inspect_t
2569convert_port_to_space_inspect(
2570 ipc_port_t port)
2571{
2572 return convert_port_to_space_with_flavor(port, TASK_FLAVOR_INSPECT, TRUE);
813fb2f6
A
2573}
2574
1c79356b 2575/*
f427ee49 2576 * Routine: convert_port_to_map_with_flavor
1c79356b
A
2577 * Purpose:
2578 * Convert from a port to a map.
2579 * Doesn't consume the port ref; produces a map ref,
2580 * which may be null.
2581 * Conditions:
2582 * Nothing locked.
2583 */
2584
f427ee49
A
2585static vm_map_t
2586convert_port_to_map_with_flavor(
2587 ipc_port_t port,
2588 mach_task_flavor_t flavor)
1c79356b
A
2589{
2590 task_t task;
2591 vm_map_t map;
2592
f427ee49
A
2593 switch (flavor) {
2594 case TASK_FLAVOR_CONTROL:
2595 task = convert_port_to_locked_task(port, TRUE);
2596 break;
2597 case TASK_FLAVOR_READ:
2598 task = convert_port_to_locked_task_read(port);
2599 break;
2600 case TASK_FLAVOR_INSPECT:
2601 task = convert_port_to_locked_task_inspect(port);
2602 break;
2603 default:
2604 task = TASK_NULL;
2605 break;
2606 }
0a7de745
A
2607
2608 if (task == TASK_NULL) {
1c79356b 2609 return VM_MAP_NULL;
0a7de745 2610 }
1c79356b
A
2611
2612 if (!task->active) {
2613 task_unlock(task);
2614 return VM_MAP_NULL;
2615 }
0a7de745 2616
1c79356b 2617 map = task->map;
f427ee49
A
2618 if (map->pmap == kernel_pmap) {
2619 if (flavor == TASK_FLAVOR_CONTROL) {
2620 panic("userspace has control access to a "
2621 "kernel map %p through task %p", map, task);
2622 }
2623 if (task != kernel_task) {
2624 panic("userspace has access to a "
2625 "kernel map %p through task %p", map, task);
2626 }
2627 } else {
2628 pmap_require(map->pmap);
2629 }
2630
1c79356b
A
2631 vm_map_reference_swap(map);
2632 task_unlock(task);
2633 return map;
2634}
2635
f427ee49
A
2636vm_map_read_t
2637convert_port_to_map(
2638 ipc_port_t port)
2639{
2640 return convert_port_to_map_with_flavor(port, TASK_FLAVOR_CONTROL);
2641}
2642
2643vm_map_read_t
2644convert_port_to_map_read(
2645 ipc_port_t port)
2646{
2647 return convert_port_to_map_with_flavor(port, TASK_FLAVOR_READ);
2648}
2649
2650vm_map_inspect_t
2651convert_port_to_map_inspect(
2652 ipc_port_t port)
2653{
2654 return convert_port_to_map_with_flavor(port, TASK_FLAVOR_INSPECT);
2655}
2656
1c79356b
A
2657
2658/*
91447636 2659 * Routine: convert_port_to_thread
1c79356b 2660 * Purpose:
91447636
A
2661 * Convert from a port to a thread.
2662 * Doesn't consume the port ref; produces an thread ref,
1c79356b
A
2663 * which may be null.
2664 * Conditions:
2665 * Nothing locked.
2666 */
2667
cb323159
A
2668static thread_t
2669convert_port_to_thread_locked(
2670 ipc_port_t port,
f427ee49
A
2671 port_to_thread_options_t options,
2672 boolean_t eval)
1c79356b 2673{
0a7de745 2674 thread_t thread = THREAD_NULL;
1c79356b 2675
cb323159
A
2676 ip_lock_held(port);
2677 require_ip_active(port);
1c79356b 2678
f427ee49 2679 if (ip_kotype(port) == IKOT_THREAD_CONTROL) {
ea3f0419 2680 thread = (thread_t) ip_get_kobject(port);
cb323159 2681 assert(thread != THREAD_NULL);
d9a64523 2682
cb323159
A
2683 if (options & PORT_TO_THREAD_NOT_CURRENT_THREAD) {
2684 if (thread == current_thread()) {
2685 return THREAD_NULL;
2686 }
2687 }
2688
2689 if (options & PORT_TO_THREAD_IN_CURRENT_TASK) {
2690 if (thread->task != current_task()) {
2691 return THREAD_NULL;
2692 }
2693 } else {
d9a64523 2694 /* Use task conversion rules for thread control conversions */
f427ee49 2695 if (eval && task_conversion_eval(current_task(), thread->task) != KERN_SUCCESS) {
813fb2f6
A
2696 return THREAD_NULL;
2697 }
1c79356b 2698 }
91447636 2699
cb323159
A
2700 thread_reference_internal(thread);
2701 }
2702
2703 return thread;
2704}
2705
2706thread_t
2707convert_port_to_thread(
2708 ipc_port_t port)
2709{
f427ee49
A
2710 thread_t thread = THREAD_NULL;
2711
2712 if (IP_VALID(port)) {
2713 ip_lock(port);
2714 if (ip_active(port)) {
2715 thread = convert_port_to_thread_locked(port, PORT_TO_THREAD_NONE, TRUE);
2716 }
2717 ip_unlock(port);
2718 }
2719
2720 return thread;
2721}
2722
2723static thread_t
2724convert_port_to_thread_no_eval(
2725 ipc_port_t port)
2726{
2727 thread_t thread = THREAD_NULL;
2728
2729 if (IP_VALID(port)) {
2730 ip_lock(port);
2731 if (ip_active(port)) {
2732 thread = convert_port_to_thread_locked(port, PORT_TO_THREAD_NONE, FALSE);
2733 }
2734 ip_unlock(port);
2735 }
2736
2737 return thread;
2738}
2739
2740/*
2741 * Routine: convert_port_to_thread_inspect
2742 * Purpose:
2743 * Convert from a port to a thread inspect right
2744 * Doesn't consume the port ref; produces a thread ref,
2745 * which may be null.
2746 * Conditions:
2747 * Nothing locked.
2748 */
2749static thread_inspect_t
2750convert_port_to_thread_inspect_locked(
2751 ipc_port_t port)
2752{
2753 thread_inspect_t thread = THREAD_INSPECT_NULL;
2754
2755 ip_lock_held(port);
2756 require_ip_active(port);
2757
2758 if (ip_kotype(port) == IKOT_THREAD_CONTROL ||
2759 ip_kotype(port) == IKOT_THREAD_READ ||
2760 ip_kotype(port) == IKOT_THREAD_INSPECT) {
2761 thread = (thread_inspect_t)port->ip_kobject;
2762 assert(thread != THREAD_INSPECT_NULL);
2763 thread_reference_internal((thread_t)thread);
2764 }
2765
2766 return thread;
2767}
2768
2769thread_inspect_t
2770convert_port_to_thread_inspect(
2771 ipc_port_t port)
2772{
2773 thread_inspect_t thread = THREAD_INSPECT_NULL;
2774
2775 if (IP_VALID(port)) {
2776 ip_lock(port);
2777 if (ip_active(port)) {
2778 thread = convert_port_to_thread_inspect_locked(port);
2779 }
2780 ip_unlock(port);
2781 }
2782
2783 return thread;
2784}
2785
2786/*
2787 * Routine: convert_port_to_thread_read
2788 * Purpose:
2789 * Convert from a port to a thread read right
2790 * Doesn't consume the port ref; produces a thread ref,
2791 * which may be null.
2792 * Conditions:
2793 * Nothing locked.
2794 */
2795static thread_read_t
2796convert_port_to_thread_read_locked(
2797 ipc_port_t port)
2798{
2799 thread_read_t thread = THREAD_READ_NULL;
2800
2801 ip_lock_held(port);
2802 require_ip_active(port);
2803
2804 if (ip_kotype(port) == IKOT_THREAD_CONTROL ||
2805 ip_kotype(port) == IKOT_THREAD_READ) {
2806 thread = (thread_read_t) ip_get_kobject(port);
2807 assert(thread != THREAD_READ_NULL);
2808
2809 /* Use task conversion rules for thread control conversions */
2810 if (task_conversion_eval(current_task(), thread->task) != KERN_SUCCESS) {
2811 return THREAD_READ_NULL;
2812 }
2813
2814 thread_reference_internal((thread_t)thread);
2815 }
2816
2817 return thread;
2818}
2819
2820thread_read_t
2821convert_port_to_thread_read(
2822 ipc_port_t port)
2823{
2824 thread_read_t thread = THREAD_READ_NULL;
cb323159
A
2825
2826 if (IP_VALID(port)) {
2827 ip_lock(port);
2828 if (ip_active(port)) {
f427ee49 2829 thread = convert_port_to_thread_read_locked(port);
cb323159 2830 }
91447636 2831 ip_unlock(port);
1c79356b 2832 }
91447636 2833
0a7de745 2834 return thread;
1c79356b
A
2835}
2836
f427ee49 2837
813fb2f6 2838/*
f427ee49 2839 * Routine: convert_thread_to_port_with_flavor
813fb2f6 2840 * Purpose:
f427ee49
A
2841 * Convert from a thread to a port of given flavor.
2842 * Consumes a thread ref; produces a naked send right
2843 * which may be invalid.
813fb2f6
A
2844 * Conditions:
2845 * Nothing locked.
2846 */
f427ee49
A
2847static ipc_port_t
2848convert_thread_to_port_with_flavor(
2849 thread_t thread,
2850 mach_thread_flavor_t flavor)
813fb2f6 2851{
f427ee49 2852 ipc_port_t port = IP_NULL;
813fb2f6 2853
f427ee49 2854 thread_mtx_lock(thread);
813fb2f6 2855
f427ee49
A
2856 if (thread->ith_self[THREAD_FLAVOR_CONTROL] == IP_NULL) {
2857 goto exit;
2858 }
2859
2860 if (flavor == THREAD_FLAVOR_CONTROL) {
2861 port = ipc_port_make_send(thread->ith_self[flavor]);
2862 } else {
2863 if (!thread->active) {
2864 goto exit;
813fb2f6 2865 }
f427ee49
A
2866 ipc_kobject_type_t kotype = (flavor == THREAD_FLAVOR_READ) ? IKOT_THREAD_READ : IKOT_THREAD_INSPECT;
2867 /*
2868 * Claim a send right on the thread read/inspect port, and request a no-senders
2869 * notification on that port (if none outstanding). A thread reference is not
2870 * donated here even though the ports are created lazily because it doesn't own the
2871 * kobject that it points to. Threads manage their lifetime explicitly and
2872 * have to synchronize with each other, between the task/thread terminating and the
2873 * send-once notification firing, and this is done under the thread mutex
2874 * rather than with atomics.
2875 */
2876 (void)ipc_kobject_make_send_lazy_alloc_port(&thread->ith_self[flavor], (ipc_kobject_t)thread,
2877 kotype, false, 0);
2878 port = thread->ith_self[flavor];
813fb2f6
A
2879 }
2880
f427ee49
A
2881exit:
2882 thread_mtx_unlock(thread);
2883 thread_deallocate(thread);
2884 return port;
813fb2f6
A
2885}
2886
f427ee49
A
2887ipc_port_t
2888convert_thread_to_port(
2889 thread_t thread)
2890{
2891 return convert_thread_to_port_with_flavor(thread, THREAD_FLAVOR_CONTROL);
2892}
2893
2894ipc_port_t
2895convert_thread_read_to_port(thread_read_t thread)
2896{
2897 return convert_thread_to_port_with_flavor(thread, THREAD_FLAVOR_READ);
2898}
813fb2f6
A
2899
2900ipc_port_t
2901convert_thread_inspect_to_port(thread_inspect_t thread)
2902{
f427ee49 2903 return convert_thread_to_port_with_flavor(thread, THREAD_FLAVOR_INSPECT);
813fb2f6
A
2904}
2905
2906
1c79356b 2907/*
91447636 2908 * Routine: port_name_to_thread
1c79356b 2909 * Purpose:
f427ee49 2910 * Convert from a port name to a thread reference
91447636 2911 * A name of MACH_PORT_NULL is valid for the null thread.
1c79356b
A
2912 * Conditions:
2913 * Nothing locked.
2914 */
91447636
A
2915thread_t
2916port_name_to_thread(
cb323159
A
2917 mach_port_name_t name,
2918 port_to_thread_options_t options)
1c79356b 2919{
0a7de745
A
2920 thread_t thread = THREAD_NULL;
2921 ipc_port_t kport;
cb323159 2922 kern_return_t kr;
1c79356b
A
2923
2924 if (MACH_PORT_VALID(name)) {
cb323159
A
2925 kr = ipc_port_translate_send(current_space(), name, &kport);
2926 if (kr == KERN_SUCCESS) {
f427ee49 2927 thread = convert_port_to_thread_locked(kport, options, TRUE);
cb323159 2928 ip_unlock(kport);
0a7de745 2929 }
1c79356b 2930 }
91447636 2931
0a7de745 2932 return thread;
1c79356b
A
2933}
2934
f427ee49
A
2935/*
2936 * Routine: port_name_to_task
2937 * Purpose:
2938 * Convert from a port name to a task reference
2939 * A name of MACH_PORT_NULL is valid for the null task.
2940 * Conditions:
2941 * Nothing locked.
2942 */
1c79356b
A
2943task_t
2944port_name_to_task(
2945 mach_port_name_t name)
2946{
cb323159 2947 ipc_port_t kport;
1c79356b
A
2948 kern_return_t kr;
2949 task_t task = TASK_NULL;
2950
2951 if (MACH_PORT_VALID(name)) {
cb323159
A
2952 kr = ipc_port_translate_send(current_space(), name, &kport);
2953 if (kr == KERN_SUCCESS) {
f427ee49 2954 task = convert_port_to_task_locked(kport, NULL, TRUE);
cb323159 2955 ip_unlock(kport);
0a7de745 2956 }
1c79356b
A
2957 }
2958 return task;
2959}
2960
f427ee49
A
2961/*
2962 * Routine: port_name_to_task_read
2963 * Purpose:
2964 * Convert from a port name to a task reference
2965 * A name of MACH_PORT_NULL is valid for the null task.
2966 * Conditions:
2967 * Nothing locked.
2968 */
2969task_read_t
2970port_name_to_task_read(
2971 mach_port_name_t name)
2972{
2973 ipc_port_t kport;
2974 kern_return_t kr;
2975 task_read_t tr = TASK_READ_NULL;
2976
2977 if (MACH_PORT_VALID(name)) {
2978 kr = ipc_port_translate_send(current_space(), name, &kport);
2979 if (kr == KERN_SUCCESS) {
2980 tr = convert_port_to_task_read_locked(kport);
2981 ip_unlock(kport);
2982 }
2983 }
2984 return tr;
2985}
2986
2987/*
2988 * Routine: port_name_to_task_read_no_eval
2989 * Purpose:
2990 * Convert from a port name to a task reference
2991 * A name of MACH_PORT_NULL is valid for the null task.
2992 * It doesnt run the task_conversion_eval check if the port
2993 * is of type IKOT_TASK_CONTROL.
2994 * Conditions:
2995 * Nothing locked.
2996 */
2997task_read_t
2998port_name_to_task_read_no_eval(
2999 mach_port_name_t name)
3000{
3001 ipc_port_t kport;
3002 kern_return_t kr;
3003 task_read_t tr = TASK_READ_NULL;
3004
3005 if (MACH_PORT_VALID(name)) {
3006 kr = ipc_port_translate_send(current_space(), name, &kport);
3007 if (kr == KERN_SUCCESS) {
3008 switch (ip_kotype(kport)) {
3009 case IKOT_TASK_CONTROL:
3010 tr = convert_port_to_task_locked(kport, NULL, FALSE);
3011 break;
3012 case IKOT_TASK_READ:
3013 tr = convert_port_to_task_read_locked(kport);
3014 break;
3015 default:
3016 break;
3017 }
3018 ip_unlock(kport);
3019 }
3020 }
3021 return tr;
3022}
3023
3024/*
3025 * Routine: port_name_to_task_inspect
3026 * Purpose:
3027 * Convert from a port name to a task reference
3028 * A name of MACH_PORT_NULL is valid for the null task.
3029 * Conditions:
3030 * Nothing locked.
3031 */
813fb2f6
A
3032task_inspect_t
3033port_name_to_task_inspect(
3034 mach_port_name_t name)
3035{
cb323159 3036 ipc_port_t kport;
813fb2f6
A
3037 kern_return_t kr;
3038 task_inspect_t ti = TASK_INSPECT_NULL;
3039
3040 if (MACH_PORT_VALID(name)) {
cb323159
A
3041 kr = ipc_port_translate_send(current_space(), name, &kport);
3042 if (kr == KERN_SUCCESS) {
3043 ti = convert_port_to_task_inspect_locked(kport);
3044 ip_unlock(kport);
0a7de745 3045 }
813fb2f6
A
3046 }
3047 return ti;
3048}
3049
f427ee49
A
3050/*
3051 * Routine: port_name_to_task_name
3052 * Purpose:
3053 * Convert from a port name to a task reference
3054 * A name of MACH_PORT_NULL is valid for the null task.
3055 * Conditions:
3056 * Nothing locked.
3057 */
3058task_name_t
3059port_name_to_task_name(
3060 mach_port_name_t name)
3061{
3062 ipc_port_t kport;
3063 kern_return_t kr;
3064 task_name_t tn = TASK_NAME_NULL;
3065
3066 if (MACH_PORT_VALID(name)) {
3067 kr = ipc_port_translate_send(current_space(), name, &kport);
3068 if (kr == KERN_SUCCESS) {
3069 tn = convert_port_to_task_name_locked(kport);
3070 ip_unlock(kport);
3071 }
3072 }
3073 return tn;
3074}
3075
39037602
A
3076/*
3077 * Routine: port_name_to_host
3078 * Purpose:
3079 * Convert from a port name to a host pointer.
3080 * NOTE: This does _not_ return a +1 reference to the host_t
3081 * Conditions:
3082 * Nothing locked.
3083 */
3084host_t
3085port_name_to_host(
3086 mach_port_name_t name)
3087{
39037602
A
3088 host_t host = HOST_NULL;
3089 kern_return_t kr;
3090 ipc_port_t port;
3091
3092 if (MACH_PORT_VALID(name)) {
3093 kr = ipc_port_translate_send(current_space(), name, &port);
3094 if (kr == KERN_SUCCESS) {
3095 host = convert_port_to_host(port);
3096 ip_unlock(port);
3097 }
3098 }
3099 return host;
3100}
3101
1c79356b 3102/*
f427ee49 3103 * Routine: convert_task_to_port_with_flavor
1c79356b 3104 * Purpose:
f427ee49 3105 * Convert from a task to a port of given flavor.
1c79356b 3106 * Consumes a task ref; produces a naked send right
0a7de745 3107 * which may be invalid.
1c79356b
A
3108 * Conditions:
3109 * Nothing locked.
3110 */
f427ee49
A
3111static ipc_port_t
3112convert_task_to_port_with_flavor(
3113 task_t task,
3114 mach_task_flavor_t flavor)
1c79356b 3115{
f427ee49
A
3116 ipc_port_t port = IP_NULL;
3117 ipc_kobject_type_t kotype = IKOT_NONE;
1c79356b
A
3118
3119 itk_lock(task);
813fb2f6 3120
f427ee49
A
3121 switch (flavor) {
3122 case TASK_FLAVOR_CONTROL:
3123 case TASK_FLAVOR_NAME:
3124 port = ipc_port_make_send(task->itk_self[flavor]);
3125 break;
3126 /*
3127 * Claim a send right on the task read/inspect port, and request a no-senders
3128 * notification on that port (if none outstanding). A task reference is
3129 * deliberately not donated here because ipc_kobject_make_send_lazy_alloc_port
3130 * is used only for convenience and these ports don't control the lifecycle of
3131 * the task kobject. Instead, the task's itk_lock is used to synchronize the
3132 * handling of the no-senders notification with the task termination.
3133 */
3134 case TASK_FLAVOR_READ:
3135 case TASK_FLAVOR_INSPECT:
3136 if (task->itk_self[TASK_FLAVOR_CONTROL] == IP_NULL) {
3137 /* task is either disabled or terminated */
3138 goto exit;
3139 }
3140 kotype = (flavor == TASK_FLAVOR_READ) ? IKOT_TASK_READ : IKOT_TASK_INSPECT;
3141 (void)ipc_kobject_make_send_lazy_alloc_port((ipc_port_t *) &task->itk_self[flavor],
3142 (ipc_kobject_t)task, kotype, true, OS_PTRAUTH_DISCRIMINATOR("task.itk_self"));
3143 port = task->itk_self[flavor];
3144
3145 break;
0a7de745 3146 }
813fb2f6 3147
f427ee49 3148exit:
1c79356b 3149 itk_unlock(task);
1c79356b
A
3150 task_deallocate(task);
3151 return port;
3152}
3153
f427ee49
A
3154ipc_port_t
3155convert_task_to_port(
3156 task_t task)
3157{
3158 return convert_task_to_port_with_flavor(task, TASK_FLAVOR_CONTROL);
3159}
3160
3161ipc_port_t
3162convert_task_read_to_port(
3163 task_read_t task)
3164{
3165 return convert_task_to_port_with_flavor(task, TASK_FLAVOR_READ);
3166}
3167
813fb2f6
A
3168ipc_port_t
3169convert_task_inspect_to_port(
0a7de745 3170 task_inspect_t task)
813fb2f6 3171{
f427ee49
A
3172 return convert_task_to_port_with_flavor(task, TASK_FLAVOR_INSPECT);
3173}
813fb2f6 3174
f427ee49
A
3175ipc_port_t
3176convert_task_name_to_port(
3177 task_name_t task)
3178{
3179 return convert_task_to_port_with_flavor(task, TASK_FLAVOR_NAME);
813fb2f6
A
3180}
3181
39236c6e
A
3182/*
3183 * Routine: convert_task_suspend_token_to_port
3184 * Purpose:
3185 * Convert from a task suspension token to a port.
3186 * Consumes a task suspension token ref; produces a naked send-once right
0a7de745 3187 * which may be invalid.
39236c6e
A
3188 * Conditions:
3189 * Nothing locked.
3190 */
3191ipc_port_t
3192convert_task_suspension_token_to_port(
0a7de745 3193 task_suspension_token_t task)
39236c6e
A
3194{
3195 ipc_port_t port;
3196
3197 task_lock(task);
3198 if (task->active) {
3199 if (task->itk_resume == IP_NULL) {
cb323159
A
3200 task->itk_resume = ipc_kobject_alloc_port((ipc_kobject_t) task,
3201 IKOT_TASK_RESUME, IPC_KOBJECT_ALLOC_NONE);
39236c6e
A
3202 }
3203
3204 /*
3205 * Create a send-once right for each instance of a direct user-called
3206 * task_suspend2 call. Each time one of these send-once rights is abandoned,
3207 * the notification handler will resume the target task.
3208 */
3209 port = ipc_port_make_sonce(task->itk_resume);
3210 assert(IP_VALID(port));
3211 } else {
3212 port = IP_NULL;
3213 }
3214
3215 task_unlock(task);
3216 task_suspension_token_deallocate(task);
3217
3218 return port;
3219}
3220
1c79356b 3221/*
f427ee49 3222 * Routine: space_deallocate
1c79356b 3223 * Purpose:
f427ee49 3224 * Deallocate a space ref produced by convert_port_to_space.
1c79356b
A
3225 * Conditions:
3226 * Nothing locked.
3227 */
3228
f427ee49
A
3229void
3230space_deallocate(
3231 ipc_space_t space)
1c79356b 3232{
f427ee49
A
3233 if (space != IS_NULL) {
3234 is_release(space);
0a7de745 3235 }
1c79356b
A
3236}
3237
3238/*
f427ee49 3239 * Routine: space_read_deallocate
1c79356b 3240 * Purpose:
f427ee49 3241 * Deallocate a space read ref produced by convert_port_to_space_read.
1c79356b
A
3242 * Conditions:
3243 * Nothing locked.
3244 */
3245
3246void
f427ee49
A
3247space_read_deallocate(
3248 ipc_space_read_t space)
1c79356b 3249{
f427ee49
A
3250 if (space != IS_INSPECT_NULL) {
3251 is_release((ipc_space_t)space);
0a7de745 3252 }
1c79356b
A
3253}
3254
813fb2f6
A
3255/*
3256 * Routine: space_inspect_deallocate
3257 * Purpose:
3258 * Deallocate a space inspect ref produced by convert_port_to_space_inspect.
3259 * Conditions:
3260 * Nothing locked.
3261 */
3262
3263void
3264space_inspect_deallocate(
0a7de745 3265 ipc_space_inspect_t space)
813fb2f6 3266{
0a7de745 3267 if (space != IS_INSPECT_NULL) {
813fb2f6 3268 is_release((ipc_space_t)space);
0a7de745 3269 }
813fb2f6
A
3270}
3271
f427ee49 3272
1c79356b
A
3273/*
3274 * Routine: thread/task_set_exception_ports [kernel call]
3275 * Purpose:
3276 * Sets the thread/task exception port, flavor and
3277 * behavior for the exception types specified by the mask.
3278 * There will be one send right per exception per valid
3279 * port.
3280 * Conditions:
3281 * Nothing locked. If successful, consumes
3282 * the supplied send right.
3283 * Returns:
3284 * KERN_SUCCESS Changed the special port.
3285 * KERN_INVALID_ARGUMENT The thread is null,
3286 * Illegal mask bit set.
3287 * Illegal exception behavior
3288 * KERN_FAILURE The thread is dead.
3289 */
3290
3291kern_return_t
3292thread_set_exception_ports(
0a7de745
A
3293 thread_t thread,
3294 exception_mask_t exception_mask,
3295 ipc_port_t new_port,
3296 exception_behavior_t new_behavior,
3297 thread_state_flavor_t new_flavor)
1c79356b 3298{
0a7de745 3299 ipc_port_t old_port[EXC_TYPES_COUNT];
6601e61a 3300 boolean_t privileged = current_task()->sec_token.val[0] == 0;
0a7de745 3301 register int i;
1c79356b 3302
5ba3f43e
A
3303#if CONFIG_MACF
3304 struct label *new_label;
3305#endif
1c79356b 3306
0a7de745
A
3307 if (thread == THREAD_NULL) {
3308 return KERN_INVALID_ARGUMENT;
3309 }
3310
3311 if (exception_mask & ~EXC_MASK_VALID) {
3312 return KERN_INVALID_ARGUMENT;
3313 }
1c79356b
A
3314
3315 if (IP_VALID(new_port)) {
cb323159 3316 switch (new_behavior & ~MACH_EXCEPTION_MASK) {
1c79356b
A
3317 case EXCEPTION_DEFAULT:
3318 case EXCEPTION_STATE:
3319 case EXCEPTION_STATE_IDENTITY:
3320 break;
91447636 3321
1c79356b 3322 default:
0a7de745 3323 return KERN_INVALID_ARGUMENT;
1c79356b
A
3324 }
3325 }
3326
f427ee49 3327
0a7de745 3328 /*
1c79356b
A
3329 * Check the validity of the thread_state_flavor by calling the
3330 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in
3331 * osfmk/mach/ARCHITECTURE/thread_status.h
3332 */
0a7de745
A
3333 if (new_flavor != 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor)) {
3334 return KERN_INVALID_ARGUMENT;
3335 }
1c79356b 3336
5ba3f43e
A
3337#if CONFIG_MACF
3338 new_label = mac_exc_create_label_for_current_proc();
3339#endif
0a7de745 3340
91447636
A
3341 thread_mtx_lock(thread);
3342
3343 if (!thread->active) {
3344 thread_mtx_unlock(thread);
3345
0a7de745 3346 return KERN_FAILURE;
1c79356b
A
3347 }
3348
39236c6e
A
3349 if (thread->exc_actions == NULL) {
3350 ipc_thread_init_exc_actions(thread);
3351 }
91447636 3352 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
39037602
A
3353 if ((exception_mask & (1 << i))
3354#if CONFIG_MACF
0a7de745 3355 && mac_exc_update_action_label(&thread->exc_actions[i], new_label) == 0
39037602 3356#endif
0a7de745 3357 ) {
91447636
A
3358 old_port[i] = thread->exc_actions[i].port;
3359 thread->exc_actions[i].port = ipc_port_copy_send(new_port);
3360 thread->exc_actions[i].behavior = new_behavior;
3361 thread->exc_actions[i].flavor = new_flavor;
6601e61a 3362 thread->exc_actions[i].privileged = privileged;
0a7de745 3363 } else {
1c79356b 3364 old_port[i] = IP_NULL;
0a7de745 3365 }
91447636
A
3366 }
3367
3368 thread_mtx_unlock(thread);
3369
5ba3f43e
A
3370#if CONFIG_MACF
3371 mac_exc_free_label(new_label);
3372#endif
0a7de745
A
3373
3374 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
3375 if (IP_VALID(old_port[i])) {
1c79356b 3376 ipc_port_release_send(old_port[i]);
0a7de745
A
3377 }
3378 }
91447636 3379
0a7de745 3380 if (IP_VALID(new_port)) { /* consume send right */
1c79356b 3381 ipc_port_release_send(new_port);
0a7de745 3382 }
1c79356b 3383
0a7de745 3384 return KERN_SUCCESS;
91447636 3385}
1c79356b
A
3386
3387kern_return_t
3388task_set_exception_ports(
0a7de745
A
3389 task_t task,
3390 exception_mask_t exception_mask,
3391 ipc_port_t new_port,
3392 exception_behavior_t new_behavior,
3393 thread_state_flavor_t new_flavor)
1c79356b 3394{
0a7de745 3395 ipc_port_t old_port[EXC_TYPES_COUNT];
8ad349bb 3396 boolean_t privileged = current_task()->sec_token.val[0] == 0;
0a7de745 3397 register int i;
1c79356b 3398
5ba3f43e
A
3399#if CONFIG_MACF
3400 struct label *new_label;
0a7de745 3401#endif
5ba3f43e 3402
0a7de745
A
3403 if (task == TASK_NULL) {
3404 return KERN_INVALID_ARGUMENT;
3405 }
1c79356b 3406
0a7de745
A
3407 if (exception_mask & ~EXC_MASK_VALID) {
3408 return KERN_INVALID_ARGUMENT;
3409 }
1c79356b
A
3410
3411 if (IP_VALID(new_port)) {
cb323159 3412 switch (new_behavior & ~MACH_EXCEPTION_MASK) {
1c79356b
A
3413 case EXCEPTION_DEFAULT:
3414 case EXCEPTION_STATE:
3415 case EXCEPTION_STATE_IDENTITY:
3416 break;
91447636 3417
1c79356b 3418 default:
0a7de745 3419 return KERN_INVALID_ARGUMENT;
1c79356b
A
3420 }
3421 }
1c79356b 3422
f427ee49 3423
fe8ab488
A
3424 /*
3425 * Check the validity of the thread_state_flavor by calling the
3426 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in
3427 * osfmk/mach/ARCHITECTURE/thread_status.h
3428 */
0a7de745
A
3429 if (new_flavor != 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor)) {
3430 return KERN_INVALID_ARGUMENT;
3431 }
fe8ab488 3432
5ba3f43e
A
3433#if CONFIG_MACF
3434 new_label = mac_exc_create_label_for_current_proc();
3435#endif
0a7de745 3436
91447636
A
3437 itk_lock(task);
3438
f427ee49 3439 if (task->itk_self[TASK_FLAVOR_CONTROL] == IP_NULL) {
91447636
A
3440 itk_unlock(task);
3441
0a7de745 3442 return KERN_FAILURE;
91447636
A
3443 }
3444
3445 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
39037602
A
3446 if ((exception_mask & (1 << i))
3447#if CONFIG_MACF
0a7de745 3448 && mac_exc_update_action_label(&task->exc_actions[i], new_label) == 0
39037602 3449#endif
0a7de745 3450 ) {
1c79356b
A
3451 old_port[i] = task->exc_actions[i].port;
3452 task->exc_actions[i].port =
0a7de745 3453 ipc_port_copy_send(new_port);
1c79356b
A
3454 task->exc_actions[i].behavior = new_behavior;
3455 task->exc_actions[i].flavor = new_flavor;
8ad349bb 3456 task->exc_actions[i].privileged = privileged;
0a7de745 3457 } else {
1c79356b 3458 old_port[i] = IP_NULL;
0a7de745 3459 }
91447636 3460 }
1c79356b 3461
91447636
A
3462 itk_unlock(task);
3463
5ba3f43e
A
3464#if CONFIG_MACF
3465 mac_exc_free_label(new_label);
3466#endif
0a7de745
A
3467
3468 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
3469 if (IP_VALID(old_port[i])) {
1c79356b 3470 ipc_port_release_send(old_port[i]);
0a7de745
A
3471 }
3472 }
91447636 3473
0a7de745 3474 if (IP_VALID(new_port)) { /* consume send right */
1c79356b 3475 ipc_port_release_send(new_port);
0a7de745 3476 }
1c79356b 3477
0a7de745 3478 return KERN_SUCCESS;
91447636 3479}
1c79356b
A
3480
3481/*
3482 * Routine: thread/task_swap_exception_ports [kernel call]
3483 * Purpose:
3484 * Sets the thread/task exception port, flavor and
3485 * behavior for the exception types specified by the
3486 * mask.
3487 *
3488 * The old ports, behavior and flavors are returned
3489 * Count specifies the array sizes on input and
3490 * the number of returned ports etc. on output. The
3491 * arrays must be large enough to hold all the returned
3492 * data, MIG returnes an error otherwise. The masks
3493 * array specifies the corresponding exception type(s).
3494 *
3495 * Conditions:
3496 * Nothing locked. If successful, consumes
3497 * the supplied send right.
3498 *
3499 * Returns upto [in} CountCnt elements.
3500 * Returns:
3501 * KERN_SUCCESS Changed the special port.
3502 * KERN_INVALID_ARGUMENT The thread is null,
3503 * Illegal mask bit set.
3504 * Illegal exception behavior
3505 * KERN_FAILURE The thread is dead.
3506 */
3507
3508kern_return_t
3509thread_swap_exception_ports(
0a7de745
A
3510 thread_t thread,
3511 exception_mask_t exception_mask,
3512 ipc_port_t new_port,
3513 exception_behavior_t new_behavior,
3514 thread_state_flavor_t new_flavor,
3515 exception_mask_array_t masks,
3516 mach_msg_type_number_t *CountCnt,
3517 exception_port_array_t ports,
3518 exception_behavior_array_t behaviors,
3519 thread_state_flavor_array_t flavors)
1c79356b 3520{
0a7de745 3521 ipc_port_t old_port[EXC_TYPES_COUNT];
6601e61a 3522 boolean_t privileged = current_task()->sec_token.val[0] == 0;
0a7de745 3523 unsigned int i, j, count;
1c79356b 3524
5ba3f43e
A
3525#if CONFIG_MACF
3526 struct label *new_label;
3527#endif
3528
0a7de745
A
3529 if (thread == THREAD_NULL) {
3530 return KERN_INVALID_ARGUMENT;
3531 }
1c79356b 3532
0a7de745
A
3533 if (exception_mask & ~EXC_MASK_VALID) {
3534 return KERN_INVALID_ARGUMENT;
3535 }
1c79356b
A
3536
3537 if (IP_VALID(new_port)) {
cb323159 3538 switch (new_behavior & ~MACH_EXCEPTION_MASK) {
1c79356b
A
3539 case EXCEPTION_DEFAULT:
3540 case EXCEPTION_STATE:
3541 case EXCEPTION_STATE_IDENTITY:
3542 break;
91447636 3543
1c79356b 3544 default:
0a7de745 3545 return KERN_INVALID_ARGUMENT;
1c79356b
A
3546 }
3547 }
1c79356b 3548
f427ee49 3549
0a7de745
A
3550 if (new_flavor != 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor)) {
3551 return KERN_INVALID_ARGUMENT;
3552 }
fe8ab488 3553
5ba3f43e
A
3554#if CONFIG_MACF
3555 new_label = mac_exc_create_label_for_current_proc();
3556#endif
3557
91447636
A
3558 thread_mtx_lock(thread);
3559
3560 if (!thread->active) {
3561 thread_mtx_unlock(thread);
f427ee49
A
3562#if CONFIG_MACF
3563 mac_exc_free_label(new_label);
3564#endif
0a7de745 3565 return KERN_FAILURE;
1c79356b
A
3566 }
3567
39236c6e
A
3568 if (thread->exc_actions == NULL) {
3569 ipc_thread_init_exc_actions(thread);
3570 }
1c79356b 3571
39236c6e
A
3572 assert(EXC_TYPES_COUNT > FIRST_EXCEPTION);
3573 for (count = 0, i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT && count < *CountCnt; ++i) {
39037602
A
3574 if ((exception_mask & (1 << i))
3575#if CONFIG_MACF
0a7de745 3576 && mac_exc_update_action_label(&thread->exc_actions[i], new_label) == 0
39037602 3577#endif
0a7de745 3578 ) {
91447636
A
3579 for (j = 0; j < count; ++j) {
3580 /*
3581 * search for an identical entry, if found
3582 * set corresponding mask for this exception.
3583 */
0a7de745
A
3584 if (thread->exc_actions[i].port == ports[j] &&
3585 thread->exc_actions[i].behavior == behaviors[j] &&
3586 thread->exc_actions[i].flavor == flavors[j]) {
1c79356b
A
3587 masks[j] |= (1 << i);
3588 break;
3589 }
91447636
A
3590 }
3591
1c79356b
A
3592 if (j == count) {
3593 masks[j] = (1 << i);
91447636 3594 ports[j] = ipc_port_copy_send(thread->exc_actions[i].port);
1c79356b 3595
91447636
A
3596 behaviors[j] = thread->exc_actions[i].behavior;
3597 flavors[j] = thread->exc_actions[i].flavor;
3598 ++count;
1c79356b
A
3599 }
3600
91447636
A
3601 old_port[i] = thread->exc_actions[i].port;
3602 thread->exc_actions[i].port = ipc_port_copy_send(new_port);
3603 thread->exc_actions[i].behavior = new_behavior;
3604 thread->exc_actions[i].flavor = new_flavor;
6601e61a 3605 thread->exc_actions[i].privileged = privileged;
0a7de745 3606 } else {
1c79356b 3607 old_port[i] = IP_NULL;
0a7de745 3608 }
91447636 3609 }
1c79356b 3610
91447636
A
3611 thread_mtx_unlock(thread);
3612
5ba3f43e
A
3613#if CONFIG_MACF
3614 mac_exc_free_label(new_label);
3615#endif
0a7de745 3616
39236c6e 3617 while (--i >= FIRST_EXCEPTION) {
0a7de745 3618 if (IP_VALID(old_port[i])) {
1c79356b 3619 ipc_port_release_send(old_port[i]);
0a7de745 3620 }
39236c6e 3621 }
91447636 3622
0a7de745 3623 if (IP_VALID(new_port)) { /* consume send right */
1c79356b 3624 ipc_port_release_send(new_port);
0a7de745 3625 }
91447636 3626
1c79356b 3627 *CountCnt = count;
91447636 3628
0a7de745 3629 return KERN_SUCCESS;
91447636 3630}
1c79356b
A
3631
3632kern_return_t
3633task_swap_exception_ports(
0a7de745
A
3634 task_t task,
3635 exception_mask_t exception_mask,
3636 ipc_port_t new_port,
3637 exception_behavior_t new_behavior,
3638 thread_state_flavor_t new_flavor,
3639 exception_mask_array_t masks,
3640 mach_msg_type_number_t *CountCnt,
3641 exception_port_array_t ports,
3642 exception_behavior_array_t behaviors,
3643 thread_state_flavor_array_t flavors)
1c79356b 3644{
0a7de745 3645 ipc_port_t old_port[EXC_TYPES_COUNT];
8ad349bb 3646 boolean_t privileged = current_task()->sec_token.val[0] == 0;
0a7de745 3647 unsigned int i, j, count;
1c79356b 3648
5ba3f43e
A
3649#if CONFIG_MACF
3650 struct label *new_label;
0a7de745
A
3651#endif
3652
3653 if (task == TASK_NULL) {
3654 return KERN_INVALID_ARGUMENT;
3655 }
1c79356b 3656
0a7de745
A
3657 if (exception_mask & ~EXC_MASK_VALID) {
3658 return KERN_INVALID_ARGUMENT;
3659 }
1c79356b
A
3660
3661 if (IP_VALID(new_port)) {
cb323159 3662 switch (new_behavior & ~MACH_EXCEPTION_MASK) {
1c79356b
A
3663 case EXCEPTION_DEFAULT:
3664 case EXCEPTION_STATE:
3665 case EXCEPTION_STATE_IDENTITY:
3666 break;
91447636 3667
1c79356b 3668 default:
0a7de745 3669 return KERN_INVALID_ARGUMENT;
1c79356b
A
3670 }
3671 }
1c79356b 3672
f427ee49 3673
0a7de745
A
3674 if (new_flavor != 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor)) {
3675 return KERN_INVALID_ARGUMENT;
3676 }
fe8ab488 3677
5ba3f43e
A
3678#if CONFIG_MACF
3679 new_label = mac_exc_create_label_for_current_proc();
3680#endif
0a7de745 3681
1c79356b 3682 itk_lock(task);
91447636 3683
f427ee49 3684 if (task->itk_self[TASK_FLAVOR_CONTROL] == IP_NULL) {
1c79356b 3685 itk_unlock(task);
f427ee49
A
3686#if CONFIG_MACF
3687 mac_exc_free_label(new_label);
3688#endif
0a7de745 3689 return KERN_FAILURE;
1c79356b
A
3690 }
3691
39236c6e
A
3692 assert(EXC_TYPES_COUNT > FIRST_EXCEPTION);
3693 for (count = 0, i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT && count < *CountCnt; ++i) {
39037602
A
3694 if ((exception_mask & (1 << i))
3695#if CONFIG_MACF
0a7de745 3696 && mac_exc_update_action_label(&task->exc_actions[i], new_label) == 0
39037602 3697#endif
0a7de745 3698 ) {
1c79356b 3699 for (j = 0; j < count; j++) {
91447636
A
3700 /*
3701 * search for an identical entry, if found
3702 * set corresponding mask for this exception.
3703 */
0a7de745
A
3704 if (task->exc_actions[i].port == ports[j] &&
3705 task->exc_actions[i].behavior == behaviors[j] &&
3706 task->exc_actions[i].flavor == flavors[j]) {
1c79356b
A
3707 masks[j] |= (1 << i);
3708 break;
3709 }
91447636
A
3710 }
3711
1c79356b
A
3712 if (j == count) {
3713 masks[j] = (1 << i);
91447636 3714 ports[j] = ipc_port_copy_send(task->exc_actions[i].port);
1c79356b
A
3715 behaviors[j] = task->exc_actions[i].behavior;
3716 flavors[j] = task->exc_actions[i].flavor;
91447636 3717 ++count;
1c79356b 3718 }
91447636 3719
1c79356b 3720 old_port[i] = task->exc_actions[i].port;
39236c6e 3721
0a7de745 3722 task->exc_actions[i].port = ipc_port_copy_send(new_port);
1c79356b
A
3723 task->exc_actions[i].behavior = new_behavior;
3724 task->exc_actions[i].flavor = new_flavor;
8ad349bb 3725 task->exc_actions[i].privileged = privileged;
0a7de745 3726 } else {
1c79356b 3727 old_port[i] = IP_NULL;
0a7de745 3728 }
91447636 3729 }
1c79356b 3730
1c79356b 3731 itk_unlock(task);
91447636 3732
5ba3f43e
A
3733#if CONFIG_MACF
3734 mac_exc_free_label(new_label);
3735#endif
0a7de745 3736
39236c6e 3737 while (--i >= FIRST_EXCEPTION) {
0a7de745 3738 if (IP_VALID(old_port[i])) {
1c79356b 3739 ipc_port_release_send(old_port[i]);
0a7de745 3740 }
39236c6e 3741 }
91447636 3742
0a7de745 3743 if (IP_VALID(new_port)) { /* consume send right */
1c79356b 3744 ipc_port_release_send(new_port);
0a7de745 3745 }
91447636 3746
1c79356b
A
3747 *CountCnt = count;
3748
0a7de745 3749 return KERN_SUCCESS;
91447636 3750}
1c79356b
A
3751
3752/*
3753 * Routine: thread/task_get_exception_ports [kernel call]
3754 * Purpose:
3755 * Clones a send right for each of the thread/task's exception
3756 * ports specified in the mask and returns the behaviour
3757 * and flavor of said port.
3758 *
3759 * Returns upto [in} CountCnt elements.
3760 *
3761 * Conditions:
3762 * Nothing locked.
3763 * Returns:
3764 * KERN_SUCCESS Extracted a send right.
3765 * KERN_INVALID_ARGUMENT The thread is null,
3766 * Invalid special port,
3767 * Illegal mask bit set.
3768 * KERN_FAILURE The thread is dead.
3769 */
f427ee49
A
3770kern_return_t
3771thread_get_exception_ports(
3772 thread_t thread,
3773 exception_mask_t exception_mask,
3774 exception_mask_array_t masks,
3775 mach_msg_type_number_t *CountCnt,
3776 exception_port_array_t ports,
3777 exception_behavior_array_t behaviors,
3778 thread_state_flavor_array_t flavors);
1c79356b
A
3779
3780kern_return_t
3781thread_get_exception_ports(
0a7de745
A
3782 thread_t thread,
3783 exception_mask_t exception_mask,
3784 exception_mask_array_t masks,
3785 mach_msg_type_number_t *CountCnt,
3786 exception_port_array_t ports,
3787 exception_behavior_array_t behaviors,
3788 thread_state_flavor_array_t flavors)
1c79356b 3789{
0a7de745 3790 unsigned int i, j, count;
1c79356b 3791
0a7de745
A
3792 if (thread == THREAD_NULL) {
3793 return KERN_INVALID_ARGUMENT;
3794 }
1c79356b 3795
0a7de745
A
3796 if (exception_mask & ~EXC_MASK_VALID) {
3797 return KERN_INVALID_ARGUMENT;
3798 }
1c79356b 3799
91447636
A
3800 thread_mtx_lock(thread);
3801
3802 if (!thread->active) {
3803 thread_mtx_unlock(thread);
3804
0a7de745 3805 return KERN_FAILURE;
1c79356b
A
3806 }
3807
3808 count = 0;
3809
39236c6e
A
3810 if (thread->exc_actions == NULL) {
3811 goto done;
3812 }
3813
91447636 3814 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
1c79356b 3815 if (exception_mask & (1 << i)) {
91447636
A
3816 for (j = 0; j < count; ++j) {
3817 /*
3818 * search for an identical entry, if found
3819 * set corresponding mask for this exception.
3820 */
0a7de745
A
3821 if (thread->exc_actions[i].port == ports[j] &&
3822 thread->exc_actions[i].behavior == behaviors[j] &&
3823 thread->exc_actions[i].flavor == flavors[j]) {
1c79356b
A
3824 masks[j] |= (1 << i);
3825 break;
3826 }
91447636
A
3827 }
3828
1c79356b
A
3829 if (j == count) {
3830 masks[j] = (1 << i);
91447636
A
3831 ports[j] = ipc_port_copy_send(thread->exc_actions[i].port);
3832 behaviors[j] = thread->exc_actions[i].behavior;
3833 flavors[j] = thread->exc_actions[i].flavor;
3834 ++count;
0a7de745 3835 if (count >= *CountCnt) {
1c79356b 3836 break;
0a7de745 3837 }
1c79356b
A
3838 }
3839 }
91447636 3840 }
1c79356b 3841
39236c6e 3842done:
91447636 3843 thread_mtx_unlock(thread);
1c79356b
A
3844
3845 *CountCnt = count;
91447636 3846
0a7de745 3847 return KERN_SUCCESS;
91447636 3848}
1c79356b 3849
f427ee49
A
3850kern_return_t
3851thread_get_exception_ports_from_user(
3852 mach_port_t port,
3853 exception_mask_t exception_mask,
3854 exception_mask_array_t masks,
3855 mach_msg_type_number_t *CountCnt,
3856 exception_port_array_t ports,
3857 exception_behavior_array_t behaviors,
3858 thread_state_flavor_array_t flavors)
3859{
3860 kern_return_t kr;
3861
3862 thread_t thread = convert_port_to_thread_check_type(port, NULL, THREAD_FLAVOR_CONTROL, FALSE);
3863
3864 if (thread == THREAD_NULL) {
3865 return KERN_INVALID_ARGUMENT;
3866 }
3867
3868 kr = thread_get_exception_ports(thread, exception_mask, masks, CountCnt, ports, behaviors, flavors);
3869
3870 thread_deallocate(thread);
3871 return kr;
3872}
3873
3874kern_return_t
3875task_get_exception_ports(
3876 task_t task,
3877 exception_mask_t exception_mask,
3878 exception_mask_array_t masks,
3879 mach_msg_type_number_t *CountCnt,
3880 exception_port_array_t ports,
3881 exception_behavior_array_t behaviors,
3882 thread_state_flavor_array_t flavors);
3883
1c79356b
A
3884kern_return_t
3885task_get_exception_ports(
0a7de745
A
3886 task_t task,
3887 exception_mask_t exception_mask,
3888 exception_mask_array_t masks,
3889 mach_msg_type_number_t *CountCnt,
3890 exception_port_array_t ports,
3891 exception_behavior_array_t behaviors,
3892 thread_state_flavor_array_t flavors)
1c79356b 3893{
0a7de745 3894 unsigned int i, j, count;
1c79356b 3895
0a7de745
A
3896 if (task == TASK_NULL) {
3897 return KERN_INVALID_ARGUMENT;
3898 }
1c79356b 3899
0a7de745
A
3900 if (exception_mask & ~EXC_MASK_VALID) {
3901 return KERN_INVALID_ARGUMENT;
3902 }
1c79356b
A
3903
3904 itk_lock(task);
91447636 3905
f427ee49 3906 if (task->itk_self[TASK_FLAVOR_CONTROL] == IP_NULL) {
1c79356b 3907 itk_unlock(task);
91447636 3908
0a7de745 3909 return KERN_FAILURE;
1c79356b
A
3910 }
3911
3912 count = 0;
3913
91447636 3914 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
1c79356b 3915 if (exception_mask & (1 << i)) {
91447636
A
3916 for (j = 0; j < count; ++j) {
3917 /*
3918 * search for an identical entry, if found
3919 * set corresponding mask for this exception.
3920 */
0a7de745
A
3921 if (task->exc_actions[i].port == ports[j] &&
3922 task->exc_actions[i].behavior == behaviors[j] &&
3923 task->exc_actions[i].flavor == flavors[j]) {
1c79356b
A
3924 masks[j] |= (1 << i);
3925 break;
3926 }
91447636
A
3927 }
3928
1c79356b
A
3929 if (j == count) {
3930 masks[j] = (1 << i);
91447636 3931 ports[j] = ipc_port_copy_send(task->exc_actions[i].port);
1c79356b
A
3932 behaviors[j] = task->exc_actions[i].behavior;
3933 flavors[j] = task->exc_actions[i].flavor;
91447636 3934 ++count;
0a7de745 3935 if (count > *CountCnt) {
1c79356b 3936 break;
0a7de745 3937 }
1c79356b
A
3938 }
3939 }
91447636 3940 }
1c79356b
A
3941
3942 itk_unlock(task);
3943
3944 *CountCnt = count;
91447636 3945
0a7de745 3946 return KERN_SUCCESS;
91447636 3947}
f427ee49
A
3948
3949kern_return_t
3950task_get_exception_ports_from_user(
3951 mach_port_t port,
3952 exception_mask_t exception_mask,
3953 exception_mask_array_t masks,
3954 mach_msg_type_number_t *CountCnt,
3955 exception_port_array_t ports,
3956 exception_behavior_array_t behaviors,
3957 thread_state_flavor_array_t flavors)
3958{
3959 kern_return_t kr;
3960
3961 task_t task = convert_port_to_task_check_type(port, NULL, TASK_FLAVOR_CONTROL, FALSE);
3962
3963 if (task == TASK_NULL) {
3964 return KERN_INVALID_ARGUMENT;
3965 }
3966
3967 kr = task_get_exception_ports(task, exception_mask, masks, CountCnt, ports, behaviors, flavors);
3968
3969 task_deallocate(task);
3970 return kr;
3971}