]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kern/ipc_tt.c
xnu-6153.141.1.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
5ba3f43e
A
105#if CONFIG_EMBEDDED && !SECURE_KERNEL
106extern int cs_relax_platform_task_ports;
107#endif
108
91447636
A
109/* forward declarations */
110task_t convert_port_to_locked_task(ipc_port_t port);
813fb2f6 111task_inspect_t convert_port_to_locked_task_inspect(ipc_port_t port);
5ba3f43e
A
112static void ipc_port_bind_special_reply_port_locked(ipc_port_t port);
113static kern_return_t ipc_port_unbind_special_reply_port(thread_t thread, boolean_t unbind_active_port);
114kern_return_t task_conversion_eval(task_t caller, task_t victim);
1c79356b
A
115
116/*
117 * Routine: ipc_task_init
118 * Purpose:
119 * Initialize a task's IPC state.
120 *
121 * If non-null, some state will be inherited from the parent.
122 * The parent must be appropriately initialized.
123 * Conditions:
124 * Nothing locked.
125 */
126
127void
128ipc_task_init(
0a7de745
A
129 task_t task,
130 task_t parent)
1c79356b
A
131{
132 ipc_space_t space;
133 ipc_port_t kport;
0c530ab8 134 ipc_port_t nport;
1c79356b
A
135 kern_return_t kr;
136 int i;
137
138
ea3f0419 139 kr = ipc_space_create(&ipc_table_entries[0], IPC_LABEL_NONE, &space);
0a7de745 140 if (kr != KERN_SUCCESS) {
1c79356b 141 panic("ipc_task_init");
0a7de745 142 }
1c79356b 143
2d21ac55 144 space->is_task = task;
1c79356b
A
145
146 kport = ipc_port_alloc_kernel();
0a7de745 147 if (kport == IP_NULL) {
1c79356b 148 panic("ipc_task_init");
0a7de745 149 }
1c79356b 150
0c530ab8 151 nport = ipc_port_alloc_kernel();
0a7de745 152 if (nport == IP_NULL) {
0c530ab8 153 panic("ipc_task_init");
0a7de745 154 }
0c530ab8 155
1c79356b
A
156 itk_lock_init(task);
157 task->itk_self = kport;
0c530ab8 158 task->itk_nself = nport;
39236c6e 159 task->itk_resume = IP_NULL; /* Lazily allocated on-demand */
39037602
A
160 if (task_is_a_corpse_fork(task)) {
161 /*
162 * No sender's notification for corpse would not
163 * work with a naked send right in kernel.
164 */
165 task->itk_sself = IP_NULL;
166 } else {
167 task->itk_sself = ipc_port_make_send(kport);
168 }
fe8ab488 169 task->itk_debug_control = IP_NULL;
1c79356b 170 task->itk_space = space;
1c79356b 171
5ba3f43e 172#if CONFIG_MACF
b226f5e5 173 task->exc_actions[0].label = NULL;
5ba3f43e
A
174 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
175 mac_exc_associate_action_label(&task->exc_actions[i], mac_exc_create_label());
176 }
177#endif
b226f5e5
A
178
179 /* always zero-out the first (unused) array element */
b226f5e5 180 bzero(&task->exc_actions[0], sizeof(task->exc_actions[0]));
0a7de745 181
1c79356b 182 if (parent == TASK_NULL) {
55e303ae 183 ipc_port_t port;
1c79356b
A
184 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
185 task->exc_actions[i].port = IP_NULL;
b226f5e5
A
186 task->exc_actions[i].flavor = 0;
187 task->exc_actions[i].behavior = 0;
188 task->exc_actions[i].privileged = FALSE;
1c79356b 189 }/* for */
0a7de745 190
55e303ae
A
191 kr = host_get_host_port(host_priv_self(), &port);
192 assert(kr == KERN_SUCCESS);
193 task->itk_host = port;
194
1c79356b 195 task->itk_bootstrap = IP_NULL;
2d21ac55
A
196 task->itk_seatbelt = IP_NULL;
197 task->itk_gssd = IP_NULL;
2d21ac55 198 task->itk_task_access = IP_NULL;
55e303ae 199
0a7de745 200 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) {
1c79356b 201 task->itk_registered[i] = IP_NULL;
0a7de745 202 }
1c79356b
A
203 } else {
204 itk_lock(parent);
205 assert(parent->itk_self != IP_NULL);
206
207 /* inherit registered ports */
208
0a7de745 209 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) {
1c79356b 210 task->itk_registered[i] =
0a7de745
A
211 ipc_port_copy_send(parent->itk_registered[i]);
212 }
1c79356b
A
213
214 /* inherit exception and bootstrap ports */
215
216 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
0a7de745
A
217 task->exc_actions[i].port =
218 ipc_port_copy_send(parent->exc_actions[i].port);
219 task->exc_actions[i].flavor =
220 parent->exc_actions[i].flavor;
221 task->exc_actions[i].behavior =
222 parent->exc_actions[i].behavior;
223 task->exc_actions[i].privileged =
224 parent->exc_actions[i].privileged;
39037602 225#if CONFIG_MACF
0a7de745 226 mac_exc_inherit_action_label(parent->exc_actions + i, task->exc_actions + i);
39037602 227#endif
1c79356b
A
228 }/* for */
229 task->itk_host =
0a7de745 230 ipc_port_copy_send(parent->itk_host);
1c79356b
A
231
232 task->itk_bootstrap =
0a7de745 233 ipc_port_copy_send(parent->itk_bootstrap);
1c79356b 234
2d21ac55 235 task->itk_seatbelt =
0a7de745 236 ipc_port_copy_send(parent->itk_seatbelt);
2d21ac55
A
237
238 task->itk_gssd =
0a7de745 239 ipc_port_copy_send(parent->itk_gssd);
2d21ac55 240
2d21ac55 241 task->itk_task_access =
0a7de745 242 ipc_port_copy_send(parent->itk_task_access);
2d21ac55 243
1c79356b
A
244 itk_unlock(parent);
245 }
246}
247
248/*
249 * Routine: ipc_task_enable
250 * Purpose:
251 * Enable a task for IPC access.
252 * Conditions:
253 * Nothing locked.
254 */
255
256void
257ipc_task_enable(
0a7de745 258 task_t task)
1c79356b
A
259{
260 ipc_port_t kport;
0c530ab8 261 ipc_port_t nport;
1c79356b
A
262
263 itk_lock(task);
264 kport = task->itk_self;
0a7de745 265 if (kport != IP_NULL) {
1c79356b 266 ipc_kobject_set(kport, (ipc_kobject_t) task, IKOT_TASK);
0a7de745 267 }
0c530ab8 268 nport = task->itk_nself;
0a7de745 269 if (nport != IP_NULL) {
0c530ab8 270 ipc_kobject_set(nport, (ipc_kobject_t) task, IKOT_TASK_NAME);
0a7de745 271 }
1c79356b
A
272 itk_unlock(task);
273}
274
275/*
276 * Routine: ipc_task_disable
277 * Purpose:
278 * Disable IPC access to a task.
279 * Conditions:
280 * Nothing locked.
281 */
282
283void
284ipc_task_disable(
0a7de745 285 task_t task)
1c79356b
A
286{
287 ipc_port_t kport;
0c530ab8 288 ipc_port_t nport;
39236c6e 289 ipc_port_t rport;
1c79356b
A
290
291 itk_lock(task);
292 kport = task->itk_self;
0a7de745 293 if (kport != IP_NULL) {
1c79356b 294 ipc_kobject_set(kport, IKO_NULL, IKOT_NONE);
0a7de745 295 }
0c530ab8 296 nport = task->itk_nself;
0a7de745 297 if (nport != IP_NULL) {
0c530ab8 298 ipc_kobject_set(nport, IKO_NULL, IKOT_NONE);
0a7de745 299 }
39236c6e
A
300
301 rport = task->itk_resume;
302 if (rport != IP_NULL) {
303 /*
304 * From this point onwards this task is no longer accepting
305 * resumptions.
306 *
307 * There are still outstanding suspensions on this task,
308 * even as it is being torn down. Disconnect the task
0a7de745 309 * from the rport, thereby "orphaning" the rport. The rport
39236c6e
A
310 * itself will go away only when the last suspension holder
311 * destroys his SO right to it -- when he either
312 * exits, or tries to actually use that last SO right to
313 * resume this (now non-existent) task.
314 */
315 ipc_kobject_set(rport, IKO_NULL, IKOT_NONE);
316 }
1c79356b
A
317 itk_unlock(task);
318}
319
320/*
321 * Routine: ipc_task_terminate
322 * Purpose:
323 * Clean up and destroy a task's IPC state.
324 * Conditions:
325 * Nothing locked. The task must be suspended.
326 * (Or the current thread must be in the task.)
327 */
328
329void
330ipc_task_terminate(
0a7de745 331 task_t task)
1c79356b
A
332{
333 ipc_port_t kport;
0c530ab8 334 ipc_port_t nport;
0a7de745 335 ipc_port_t rport;
1c79356b
A
336 int i;
337
338 itk_lock(task);
339 kport = task->itk_self;
340
341 if (kport == IP_NULL) {
342 /* the task is already terminated (can this happen?) */
343 itk_unlock(task);
344 return;
345 }
6601e61a 346 task->itk_self = IP_NULL;
0c530ab8
A
347
348 nport = task->itk_nself;
349 assert(nport != IP_NULL);
350 task->itk_nself = IP_NULL;
351
39236c6e
A
352 rport = task->itk_resume;
353 task->itk_resume = IP_NULL;
354
1c79356b
A
355 itk_unlock(task);
356
357 /* release the naked send rights */
358
0a7de745 359 if (IP_VALID(task->itk_sself)) {
1c79356b 360 ipc_port_release_send(task->itk_sself);
0a7de745 361 }
1c79356b
A
362
363 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
364 if (IP_VALID(task->exc_actions[i].port)) {
365 ipc_port_release_send(task->exc_actions[i].port);
366 }
39037602 367#if CONFIG_MACF
5ba3f43e 368 mac_exc_free_action_label(task->exc_actions + i);
39037602 369#endif
91447636
A
370 }
371
0a7de745 372 if (IP_VALID(task->itk_host)) {
1c79356b 373 ipc_port_release_send(task->itk_host);
0a7de745 374 }
1c79356b 375
0a7de745 376 if (IP_VALID(task->itk_bootstrap)) {
1c79356b 377 ipc_port_release_send(task->itk_bootstrap);
0a7de745 378 }
1c79356b 379
0a7de745 380 if (IP_VALID(task->itk_seatbelt)) {
2d21ac55 381 ipc_port_release_send(task->itk_seatbelt);
0a7de745
A
382 }
383
384 if (IP_VALID(task->itk_gssd)) {
2d21ac55 385 ipc_port_release_send(task->itk_gssd);
0a7de745 386 }
2d21ac55 387
0a7de745 388 if (IP_VALID(task->itk_task_access)) {
2d21ac55 389 ipc_port_release_send(task->itk_task_access);
0a7de745 390 }
2d21ac55 391
0a7de745 392 if (IP_VALID(task->itk_debug_control)) {
fe8ab488 393 ipc_port_release_send(task->itk_debug_control);
0a7de745 394 }
fe8ab488 395
0a7de745
A
396 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) {
397 if (IP_VALID(task->itk_registered[i])) {
1c79356b 398 ipc_port_release_send(task->itk_registered[i]);
0a7de745
A
399 }
400 }
1c79356b 401
0c530ab8 402 /* destroy the kernel ports */
1c79356b 403 ipc_port_dealloc_kernel(kport);
0c530ab8 404 ipc_port_dealloc_kernel(nport);
0a7de745
A
405 if (rport != IP_NULL) {
406 ipc_port_dealloc_kernel(rport);
407 }
b0d623f7
A
408
409 itk_lock_destroy(task);
1c79356b
A
410}
411
55e303ae
A
412/*
413 * Routine: ipc_task_reset
414 * Purpose:
415 * Reset a task's IPC state to protect it when
0c530ab8
A
416 * it enters an elevated security context. The
417 * task name port can remain the same - since
418 * it represents no specific privilege.
55e303ae
A
419 * Conditions:
420 * Nothing locked. The task must be suspended.
421 * (Or the current thread must be in the task.)
422 */
423
424void
425ipc_task_reset(
0a7de745 426 task_t task)
55e303ae
A
427{
428 ipc_port_t old_kport, new_kport;
429 ipc_port_t old_sself;
55e303ae
A
430 ipc_port_t old_exc_actions[EXC_TYPES_COUNT];
431 int i;
55e303ae 432
5ba3f43e
A
433#if CONFIG_MACF
434 /* Fresh label to unset credentials in existing labels. */
435 struct label *unset_label = mac_exc_create_label();
436#endif
0a7de745 437
cb323159
A
438 new_kport = ipc_kobject_alloc_port((ipc_kobject_t)task, IKOT_TASK,
439 IPC_KOBJECT_ALLOC_MAKE_SEND);
55e303ae
A
440
441 itk_lock(task);
442
443 old_kport = task->itk_self;
444
445 if (old_kport == IP_NULL) {
446 /* the task is already terminated (can this happen?) */
447 itk_unlock(task);
cb323159 448 ipc_port_release_send(new_kport);
55e303ae 449 ipc_port_dealloc_kernel(new_kport);
5ba3f43e
A
450#if CONFIG_MACF
451 mac_exc_free_label(unset_label);
452#endif
55e303ae
A
453 return;
454 }
455
55e303ae 456 old_sself = task->itk_sself;
cb323159 457 task->itk_sself = task->itk_self = new_kport;
39037602
A
458
459 /* Set the old kport to IKOT_NONE and update the exec token while under the port lock */
460 ip_lock(old_kport);
461 ipc_kobject_set_atomically(old_kport, IKO_NULL, IKOT_NONE);
462 task->exec_token += 1;
463 ip_unlock(old_kport);
464
55e303ae 465 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
3e170ce0
A
466 old_exc_actions[i] = IP_NULL;
467
468 if (i == EXC_CORPSE_NOTIFY && task_corpse_pending_report(task)) {
469 continue;
470 }
471
8ad349bb 472 if (!task->exc_actions[i].privileged) {
39037602 473#if CONFIG_MACF
5ba3f43e 474 mac_exc_update_action_label(task->exc_actions + i, unset_label);
39037602 475#endif
8ad349bb
A
476 old_exc_actions[i] = task->exc_actions[i].port;
477 task->exc_actions[i].port = IP_NULL;
8ad349bb 478 }
55e303ae 479 }/* for */
0a7de745 480
fe8ab488
A
481 if (IP_VALID(task->itk_debug_control)) {
482 ipc_port_release_send(task->itk_debug_control);
483 }
484 task->itk_debug_control = IP_NULL;
0a7de745 485
55e303ae
A
486 itk_unlock(task);
487
5ba3f43e
A
488#if CONFIG_MACF
489 mac_exc_free_label(unset_label);
490#endif
491
55e303ae
A
492 /* release the naked send rights */
493
0a7de745 494 if (IP_VALID(old_sself)) {
55e303ae 495 ipc_port_release_send(old_sself);
0a7de745 496 }
55e303ae 497
55e303ae
A
498 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
499 if (IP_VALID(old_exc_actions[i])) {
500 ipc_port_release_send(old_exc_actions[i]);
501 }
502 }/* for */
55e303ae
A
503
504 /* destroy the kernel port */
505 ipc_port_dealloc_kernel(old_kport);
506}
507
1c79356b
A
508/*
509 * Routine: ipc_thread_init
510 * Purpose:
511 * Initialize a thread's IPC state.
512 * Conditions:
513 * Nothing locked.
514 */
515
516void
517ipc_thread_init(
0a7de745 518 thread_t thread)
1c79356b 519{
0a7de745 520 ipc_port_t kport;
91447636 521
cb323159
A
522 kport = ipc_kobject_alloc_port((ipc_kobject_t)thread, IKOT_THREAD,
523 IPC_KOBJECT_ALLOC_MAKE_SEND);
91447636 524
cb323159 525 thread->ith_sself = thread->ith_self = kport;
5ba3f43e 526 thread->ith_special_reply_port = NULL;
39236c6e 527 thread->exc_actions = NULL;
91447636 528
39236c6e
A
529#if IMPORTANCE_INHERITANCE
530 thread->ith_assertions = 0;
531#endif
532
1c79356b 533 ipc_kmsg_queue_init(&thread->ith_messages);
91447636 534
1c79356b
A
535 thread->ith_rpc_reply = IP_NULL;
536}
537
39236c6e
A
538void
539ipc_thread_init_exc_actions(
0a7de745 540 thread_t thread)
39236c6e
A
541{
542 assert(thread->exc_actions == NULL);
543
544 thread->exc_actions = kalloc(sizeof(struct exception_action) * EXC_TYPES_COUNT);
545 bzero(thread->exc_actions, sizeof(struct exception_action) * EXC_TYPES_COUNT);
39037602
A
546
547#if CONFIG_MACF
548 for (size_t i = 0; i < EXC_TYPES_COUNT; ++i) {
5ba3f43e 549 mac_exc_associate_action_label(thread->exc_actions + i, mac_exc_create_label());
39037602
A
550 }
551#endif
39236c6e
A
552}
553
554void
555ipc_thread_destroy_exc_actions(
0a7de745 556 thread_t thread)
39236c6e
A
557{
558 if (thread->exc_actions != NULL) {
39037602
A
559#if CONFIG_MACF
560 for (size_t i = 0; i < EXC_TYPES_COUNT; ++i) {
5ba3f43e 561 mac_exc_free_action_label(thread->exc_actions + i);
39037602
A
562 }
563#endif
564
0a7de745
A
565 kfree(thread->exc_actions,
566 sizeof(struct exception_action) * EXC_TYPES_COUNT);
39236c6e
A
567 thread->exc_actions = NULL;
568 }
569}
570
1c79356b 571void
91447636 572ipc_thread_disable(
0a7de745 573 thread_t thread)
1c79356b 574{
0a7de745 575 ipc_port_t kport = thread->ith_self;
1c79356b 576
0a7de745 577 if (kport != IP_NULL) {
91447636 578 ipc_kobject_set(kport, IKO_NULL, IKOT_NONE);
0a7de745 579 }
cb323159
A
580
581 /* unbind the thread special reply port */
582 if (IP_VALID(thread->ith_special_reply_port)) {
583 ipc_port_unbind_special_reply_port(thread, TRUE);
584 }
1c79356b
A
585}
586
587/*
91447636 588 * Routine: ipc_thread_terminate
1c79356b 589 * Purpose:
91447636 590 * Clean up and destroy a thread's IPC state.
1c79356b
A
591 * Conditions:
592 * Nothing locked.
593 */
594
595void
91447636 596ipc_thread_terminate(
0a7de745 597 thread_t thread)
1c79356b 598{
0a7de745 599 ipc_port_t kport = thread->ith_self;
1c79356b 600
91447636 601 if (kport != IP_NULL) {
0a7de745 602 int i;
1c79356b 603
0a7de745 604 if (IP_VALID(thread->ith_sself)) {
91447636 605 ipc_port_release_send(thread->ith_sself);
0a7de745 606 }
1c79356b 607
91447636 608 thread->ith_sself = thread->ith_self = IP_NULL;
1c79356b 609
39236c6e
A
610 if (thread->exc_actions != NULL) {
611 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
0a7de745 612 if (IP_VALID(thread->exc_actions[i].port)) {
39236c6e 613 ipc_port_release_send(thread->exc_actions[i].port);
0a7de745 614 }
39236c6e
A
615 }
616 ipc_thread_destroy_exc_actions(thread);
617 }
1c79356b 618
91447636 619 ipc_port_dealloc_kernel(kport);
1c79356b
A
620 }
621
39236c6e
A
622#if IMPORTANCE_INHERITANCE
623 assert(thread->ith_assertions == 0);
624#endif
625
91447636 626 assert(ipc_kmsg_queue_empty(&thread->ith_messages));
1c79356b 627
0a7de745 628 if (thread->ith_rpc_reply != IP_NULL) {
91447636 629 ipc_port_dealloc_reply(thread->ith_rpc_reply);
0a7de745 630 }
1c79356b 631
91447636 632 thread->ith_rpc_reply = IP_NULL;
1c79356b
A
633}
634
6601e61a
A
635/*
636 * Routine: ipc_thread_reset
637 * Purpose:
638 * Reset the IPC state for a given Mach thread when
639 * its task enters an elevated security context.
0a7de745 640 * Both the thread port and its exception ports have
6601e61a
A
641 * to be reset. Its RPC reply port cannot have any
642 * rights outstanding, so it should be fine.
643 * Conditions:
644 * Nothing locked.
645 */
646
647void
648ipc_thread_reset(
0a7de745 649 thread_t thread)
6601e61a
A
650{
651 ipc_port_t old_kport, new_kport;
652 ipc_port_t old_sself;
653 ipc_port_t old_exc_actions[EXC_TYPES_COUNT];
0a7de745
A
654 boolean_t has_old_exc_actions = FALSE;
655 int i;
6601e61a 656
5ba3f43e
A
657#if CONFIG_MACF
658 struct label *new_label = mac_exc_create_label();
659#endif
0a7de745 660
cb323159
A
661 new_kport = ipc_kobject_alloc_port((ipc_kobject_t)thread, IKOT_THREAD,
662 IPC_KOBJECT_ALLOC_MAKE_SEND);
6601e61a
A
663
664 thread_mtx_lock(thread);
665
666 old_kport = thread->ith_self;
cb323159 667 old_sself = thread->ith_sself;
6601e61a 668
3e170ce0 669 if (old_kport == IP_NULL && thread->inspection == FALSE) {
6601e61a
A
670 /* the is already terminated (can this happen?) */
671 thread_mtx_unlock(thread);
cb323159 672 ipc_port_release_send(new_kport);
6601e61a 673 ipc_port_dealloc_kernel(new_kport);
5ba3f43e
A
674#if CONFIG_MACF
675 mac_exc_free_label(new_label);
676#endif
6601e61a
A
677 return;
678 }
679
cb323159 680 thread->ith_sself = thread->ith_self = new_kport;
3e170ce0
A
681 if (old_kport != IP_NULL) {
682 ipc_kobject_set(old_kport, IKO_NULL, IKOT_NONE);
683 }
6601e61a 684
39236c6e
A
685 /*
686 * Only ports that were set by root-owned processes
0a7de745 687 * (privileged ports) should survive
39236c6e
A
688 */
689 if (thread->exc_actions != NULL) {
690 has_old_exc_actions = TRUE;
691 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
692 if (thread->exc_actions[i].privileged) {
693 old_exc_actions[i] = IP_NULL;
694 } else {
39037602 695#if CONFIG_MACF
5ba3f43e 696 mac_exc_update_action_label(thread->exc_actions + i, new_label);
39037602 697#endif
39236c6e 698 old_exc_actions[i] = thread->exc_actions[i].port;
0a7de745 699 thread->exc_actions[i].port = IP_NULL;
39236c6e 700 }
6601e61a 701 }
39236c6e 702 }
6601e61a
A
703
704 thread_mtx_unlock(thread);
705
5ba3f43e
A
706#if CONFIG_MACF
707 mac_exc_free_label(new_label);
708#endif
0a7de745 709
6601e61a
A
710 /* release the naked send rights */
711
0a7de745 712 if (IP_VALID(old_sself)) {
6601e61a 713 ipc_port_release_send(old_sself);
0a7de745 714 }
6601e61a 715
39236c6e
A
716 if (has_old_exc_actions) {
717 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
6601e61a
A
718 ipc_port_release_send(old_exc_actions[i]);
719 }
39236c6e 720 }
6601e61a
A
721
722 /* destroy the kernel port */
3e170ce0
A
723 if (old_kport != IP_NULL) {
724 ipc_port_dealloc_kernel(old_kport);
725 }
5ba3f43e
A
726
727 /* unbind the thread special reply port */
728 if (IP_VALID(thread->ith_special_reply_port)) {
729 ipc_port_unbind_special_reply_port(thread, TRUE);
730 }
6601e61a
A
731}
732
1c79356b
A
733/*
734 * Routine: retrieve_task_self_fast
735 * Purpose:
736 * Optimized version of retrieve_task_self,
737 * that only works for the current task.
738 *
739 * Return a send right (possibly null/dead)
740 * for the task's user-visible self port.
741 * Conditions:
742 * Nothing locked.
743 */
744
745ipc_port_t
746retrieve_task_self_fast(
0a7de745 747 task_t task)
1c79356b 748{
cb323159 749 __assert_only ipc_port_t sright;
39037602 750 ipc_port_t port;
1c79356b
A
751
752 assert(task == current_task());
753
754 itk_lock(task);
755 assert(task->itk_self != IP_NULL);
756
757 if ((port = task->itk_sself) == task->itk_self) {
758 /* no interposing */
cb323159
A
759 sright = ipc_port_copy_send(port);
760 assert(sright == port);
0a7de745 761 } else {
1c79356b 762 port = ipc_port_copy_send(port);
0a7de745 763 }
1c79356b
A
764 itk_unlock(task);
765
766 return port;
767}
768
769/*
91447636 770 * Routine: retrieve_thread_self_fast
1c79356b 771 * Purpose:
1c79356b
A
772 * Return a send right (possibly null/dead)
773 * for the thread's user-visible self port.
91447636
A
774 *
775 * Only works for the current thread.
776 *
1c79356b
A
777 * Conditions:
778 * Nothing locked.
779 */
780
781ipc_port_t
91447636 782retrieve_thread_self_fast(
0a7de745 783 thread_t thread)
1c79356b 784{
cb323159 785 __assert_only ipc_port_t sright;
39037602 786 ipc_port_t port;
1c79356b 787
91447636
A
788 assert(thread == current_thread());
789
790 thread_mtx_lock(thread);
1c79356b 791
91447636
A
792 assert(thread->ith_self != IP_NULL);
793
794 if ((port = thread->ith_sself) == thread->ith_self) {
1c79356b 795 /* no interposing */
cb323159
A
796 sright = ipc_port_copy_send(port);
797 assert(sright == port);
0a7de745 798 } else {
1c79356b 799 port = ipc_port_copy_send(port);
0a7de745 800 }
91447636
A
801
802 thread_mtx_unlock(thread);
1c79356b
A
803
804 return port;
805}
806
807/*
808 * Routine: task_self_trap [mach trap]
809 * Purpose:
810 * Give the caller send rights for his own task port.
811 * Conditions:
812 * Nothing locked.
813 * Returns:
814 * MACH_PORT_NULL if there are any resource failures
815 * or other errors.
816 */
817
818mach_port_name_t
91447636
A
819task_self_trap(
820 __unused struct task_self_trap_args *args)
1c79356b
A
821{
822 task_t task = current_task();
823 ipc_port_t sright;
91447636 824 mach_port_name_t name;
1c79356b
A
825
826 sright = retrieve_task_self_fast(task);
91447636
A
827 name = ipc_port_copyout_send(sright, task->itk_space);
828 return name;
1c79356b
A
829}
830
831/*
832 * Routine: thread_self_trap [mach trap]
833 * Purpose:
834 * Give the caller send rights for his own thread port.
835 * Conditions:
836 * Nothing locked.
837 * Returns:
838 * MACH_PORT_NULL if there are any resource failures
839 * or other errors.
840 */
841
842mach_port_name_t
91447636
A
843thread_self_trap(
844 __unused struct thread_self_trap_args *args)
1c79356b 845{
91447636
A
846 thread_t thread = current_thread();
847 task_t task = thread->task;
1c79356b 848 ipc_port_t sright;
91447636
A
849 mach_port_name_t name;
850
851 sright = retrieve_thread_self_fast(thread);
852 name = ipc_port_copyout_send(sright, task->itk_space);
853 return name;
1c79356b
A
854}
855
856/*
857 * Routine: mach_reply_port [mach trap]
858 * Purpose:
859 * Allocate a port for the caller.
860 * Conditions:
861 * Nothing locked.
862 * Returns:
863 * MACH_PORT_NULL if there are any resource failures
864 * or other errors.
865 */
866
867mach_port_name_t
91447636
A
868mach_reply_port(
869 __unused struct mach_reply_port_args *args)
1c79356b
A
870{
871 ipc_port_t port;
872 mach_port_name_t name;
873 kern_return_t kr;
874
94ff46dc
A
875 kr = ipc_port_alloc(current_task()->itk_space, IPC_PORT_INIT_MESSAGE_QUEUE,
876 &name, &port);
0a7de745 877 if (kr == KERN_SUCCESS) {
1c79356b 878 ip_unlock(port);
0a7de745 879 } else {
1c79356b 880 name = MACH_PORT_NULL;
0a7de745 881 }
1c79356b
A
882 return name;
883}
884
5ba3f43e
A
885/*
886 * Routine: thread_get_special_reply_port [mach trap]
887 * Purpose:
888 * Allocate a special reply port for the calling thread.
889 * Conditions:
890 * Nothing locked.
891 * Returns:
d9a64523 892 * mach_port_name_t: send right & receive right for special reply port.
5ba3f43e
A
893 * MACH_PORT_NULL if there are any resource failures
894 * or other errors.
895 */
896
897mach_port_name_t
898thread_get_special_reply_port(
899 __unused struct thread_get_special_reply_port_args *args)
900{
901 ipc_port_t port;
902 mach_port_name_t name;
903 kern_return_t kr;
904 thread_t thread = current_thread();
94ff46dc
A
905 ipc_port_init_flags_t flags = IPC_PORT_INIT_MESSAGE_QUEUE |
906 IPC_PORT_INIT_MAKE_SEND_RIGHT | IPC_PORT_INIT_SPECIAL_REPLY;
5ba3f43e
A
907
908 /* unbind the thread special reply port */
909 if (IP_VALID(thread->ith_special_reply_port)) {
910 kr = ipc_port_unbind_special_reply_port(thread, TRUE);
911 if (kr != KERN_SUCCESS) {
912 return MACH_PORT_NULL;
913 }
914 }
915
94ff46dc 916 kr = ipc_port_alloc(current_task()->itk_space, flags, &name, &port);
5ba3f43e
A
917 if (kr == KERN_SUCCESS) {
918 ipc_port_bind_special_reply_port_locked(port);
919 ip_unlock(port);
920 } else {
921 name = MACH_PORT_NULL;
922 }
923 return name;
924}
925
926/*
927 * Routine: ipc_port_bind_special_reply_port_locked
928 * Purpose:
929 * Bind the given port to current thread as a special reply port.
930 * Conditions:
931 * Port locked.
932 * Returns:
933 * None.
934 */
935
936static void
937ipc_port_bind_special_reply_port_locked(
938 ipc_port_t port)
939{
940 thread_t thread = current_thread();
941 assert(thread->ith_special_reply_port == NULL);
94ff46dc
A
942 assert(port->ip_specialreply);
943 assert(port->ip_sync_link_state == PORT_SYNC_LINK_ANY);
5ba3f43e
A
944
945 ip_reference(port);
946 thread->ith_special_reply_port = port;
cb323159 947 port->ip_messages.imq_srp_owner_thread = thread;
d9a64523 948
cb323159 949 ipc_special_reply_port_bits_reset(port);
5ba3f43e
A
950}
951
952/*
953 * Routine: ipc_port_unbind_special_reply_port
954 * Purpose:
955 * Unbind the thread's special reply port.
d9a64523
A
956 * If the special port has threads waiting on turnstile,
957 * update it's inheritor.
5ba3f43e
A
958 * Condition:
959 * Nothing locked.
960 * Returns:
961 * None.
962 */
963static kern_return_t
964ipc_port_unbind_special_reply_port(
965 thread_t thread,
966 boolean_t unbind_active_port)
967{
968 ipc_port_t special_reply_port = thread->ith_special_reply_port;
969
970 ip_lock(special_reply_port);
971
972 /* Return error if port active and unbind_active_port set to FALSE */
973 if (unbind_active_port == FALSE && ip_active(special_reply_port)) {
974 ip_unlock(special_reply_port);
975 return KERN_FAILURE;
976 }
977
978 thread->ith_special_reply_port = NULL;
d9a64523 979 ipc_port_adjust_special_reply_port_locked(special_reply_port, NULL,
cb323159 980 IPC_PORT_ADJUST_UNLINK_THREAD, FALSE);
5ba3f43e
A
981 /* port unlocked */
982
983 ip_release(special_reply_port);
984 return KERN_SUCCESS;
985}
986
91447636
A
987/*
988 * Routine: thread_get_special_port [kernel call]
989 * Purpose:
990 * Clones a send right for one of the thread's
991 * special ports.
992 * Conditions:
993 * Nothing locked.
994 * Returns:
995 * KERN_SUCCESS Extracted a send right.
996 * KERN_INVALID_ARGUMENT The thread is null.
997 * KERN_FAILURE The thread is dead.
998 * KERN_INVALID_ARGUMENT Invalid special port.
999 */
1000
1001kern_return_t
1002thread_get_special_port(
0a7de745
A
1003 thread_t thread,
1004 int which,
1005 ipc_port_t *portp)
91447636 1006{
0a7de745
A
1007 kern_return_t result = KERN_SUCCESS;
1008 ipc_port_t *whichp;
91447636 1009
0a7de745
A
1010 if (thread == THREAD_NULL) {
1011 return KERN_INVALID_ARGUMENT;
1012 }
91447636
A
1013
1014 switch (which) {
91447636
A
1015 case THREAD_KERNEL_PORT:
1016 whichp = &thread->ith_sself;
1017 break;
1018
1019 default:
0a7de745 1020 return KERN_INVALID_ARGUMENT;
91447636
A
1021 }
1022
0a7de745 1023 thread_mtx_lock(thread);
91447636 1024
0a7de745 1025 if (thread->active) {
91447636 1026 *portp = ipc_port_copy_send(*whichp);
0a7de745 1027 } else {
91447636 1028 result = KERN_FAILURE;
0a7de745 1029 }
91447636
A
1030
1031 thread_mtx_unlock(thread);
1032
0a7de745 1033 return result;
91447636
A
1034}
1035
1036/*
1037 * Routine: thread_set_special_port [kernel call]
1038 * Purpose:
1039 * Changes one of the thread's special ports,
1040 * setting it to the supplied send right.
1041 * Conditions:
1042 * Nothing locked. If successful, consumes
1043 * the supplied send right.
1044 * Returns:
1045 * KERN_SUCCESS Changed the special port.
1046 * KERN_INVALID_ARGUMENT The thread is null.
1047 * KERN_FAILURE The thread is dead.
1048 * KERN_INVALID_ARGUMENT Invalid special port.
1049 */
1050
1051kern_return_t
1052thread_set_special_port(
0a7de745
A
1053 thread_t thread,
1054 int which,
1055 ipc_port_t port)
91447636 1056{
0a7de745
A
1057 kern_return_t result = KERN_SUCCESS;
1058 ipc_port_t *whichp, old = IP_NULL;
91447636 1059
0a7de745
A
1060 if (thread == THREAD_NULL) {
1061 return KERN_INVALID_ARGUMENT;
1062 }
91447636
A
1063
1064 switch (which) {
91447636
A
1065 case THREAD_KERNEL_PORT:
1066 whichp = &thread->ith_sself;
1067 break;
1068
1069 default:
0a7de745 1070 return KERN_INVALID_ARGUMENT;
91447636
A
1071 }
1072
1073 thread_mtx_lock(thread);
1074
1075 if (thread->active) {
1076 old = *whichp;
1077 *whichp = port;
0a7de745 1078 } else {
91447636 1079 result = KERN_FAILURE;
0a7de745 1080 }
91447636
A
1081
1082 thread_mtx_unlock(thread);
1083
0a7de745 1084 if (IP_VALID(old)) {
91447636 1085 ipc_port_release_send(old);
0a7de745 1086 }
91447636 1087
0a7de745 1088 return result;
91447636
A
1089}
1090
1c79356b
A
1091/*
1092 * Routine: task_get_special_port [kernel call]
1093 * Purpose:
1094 * Clones a send right for one of the task's
1095 * special ports.
1096 * Conditions:
1097 * Nothing locked.
1098 * Returns:
1099 * KERN_SUCCESS Extracted a send right.
1100 * KERN_INVALID_ARGUMENT The task is null.
1101 * KERN_FAILURE The task/space is dead.
1102 * KERN_INVALID_ARGUMENT Invalid special port.
1103 */
1104
1105kern_return_t
1106task_get_special_port(
0a7de745
A
1107 task_t task,
1108 int which,
1109 ipc_port_t *portp)
1c79356b 1110{
1c79356b
A
1111 ipc_port_t port;
1112
0a7de745 1113 if (task == TASK_NULL) {
1c79356b 1114 return KERN_INVALID_ARGUMENT;
0a7de745 1115 }
1c79356b 1116
0c530ab8
A
1117 itk_lock(task);
1118 if (task->itk_self == IP_NULL) {
1119 itk_unlock(task);
1120 return KERN_FAILURE;
1121 }
1122
1c79356b 1123 switch (which) {
39037602 1124 case TASK_KERNEL_PORT:
0c530ab8
A
1125 port = ipc_port_copy_send(task->itk_sself);
1126 break;
1127
39037602 1128 case TASK_NAME_PORT:
0c530ab8 1129 port = ipc_port_make_send(task->itk_nself);
1c79356b
A
1130 break;
1131
39037602 1132 case TASK_HOST_PORT:
0c530ab8 1133 port = ipc_port_copy_send(task->itk_host);
1c79356b
A
1134 break;
1135
39037602 1136 case TASK_BOOTSTRAP_PORT:
0c530ab8 1137 port = ipc_port_copy_send(task->itk_bootstrap);
1c79356b
A
1138 break;
1139
39037602 1140 case TASK_SEATBELT_PORT:
2d21ac55
A
1141 port = ipc_port_copy_send(task->itk_seatbelt);
1142 break;
1143
39037602 1144 case TASK_ACCESS_PORT:
2d21ac55
A
1145 port = ipc_port_copy_send(task->itk_task_access);
1146 break;
39236c6e 1147
39037602 1148 case TASK_DEBUG_CONTROL_PORT:
fe8ab488
A
1149 port = ipc_port_copy_send(task->itk_debug_control);
1150 break;
1151
39037602 1152 default:
0a7de745 1153 itk_unlock(task);
1c79356b
A
1154 return KERN_INVALID_ARGUMENT;
1155 }
1c79356b
A
1156 itk_unlock(task);
1157
1158 *portp = port;
1159 return KERN_SUCCESS;
1160}
1161
1162/*
1163 * Routine: task_set_special_port [kernel call]
1164 * Purpose:
1165 * Changes one of the task's special ports,
1166 * setting it to the supplied send right.
1167 * Conditions:
1168 * Nothing locked. If successful, consumes
1169 * the supplied send right.
1170 * Returns:
1171 * KERN_SUCCESS Changed the special port.
1172 * KERN_INVALID_ARGUMENT The task is null.
1173 * KERN_FAILURE The task/space is dead.
1174 * KERN_INVALID_ARGUMENT Invalid special port.
4ba76501 1175 * KERN_NO_ACCESS Restricted access to set port.
1c79356b
A
1176 */
1177
1178kern_return_t
1179task_set_special_port(
0a7de745
A
1180 task_t task,
1181 int which,
1182 ipc_port_t port)
1c79356b 1183{
0a7de745 1184 if (task == TASK_NULL) {
1c79356b 1185 return KERN_INVALID_ARGUMENT;
0a7de745 1186 }
1c79356b 1187
cb323159
A
1188 if (task_is_driver(current_task())) {
1189 return KERN_NO_ACCESS;
1190 }
1191
4ba76501
A
1192 switch (which) {
1193 case TASK_KERNEL_PORT:
1194 case TASK_HOST_PORT:
1195#if CONFIG_CSR
1196 if (csr_check(CSR_ALLOW_KERNEL_DEBUGGER) == 0) {
1197 /*
1198 * Only allow setting of task-self / task-host
1199 * special ports from user-space when SIP is
1200 * disabled (for Mach-on-Mach emulation).
1201 */
1202 break;
1203 }
1204#endif
1205 return KERN_NO_ACCESS;
1206 default:
1207 break;
1208 }
1209
1210 return task_set_special_port_internal(task, which, port);
1211}
1212
1213/*
1214 * Routine: task_set_special_port_internal
1215 * Purpose:
1216 * Changes one of the task's special ports,
1217 * setting it to the supplied send right.
1218 * Conditions:
1219 * Nothing locked. If successful, consumes
1220 * the supplied send right.
1221 * Returns:
1222 * KERN_SUCCESS Changed the special port.
1223 * KERN_INVALID_ARGUMENT The task is null.
1224 * KERN_FAILURE The task/space is dead.
1225 * KERN_INVALID_ARGUMENT Invalid special port.
1226 * KERN_NO_ACCESS Restricted access to overwrite port.
1227 */
1228
1229kern_return_t
1230task_set_special_port_internal(
1231 task_t task,
1232 int which,
1233 ipc_port_t port)
1234{
1235 ipc_port_t *whichp;
1236 ipc_port_t old;
1237
1238 if (task == TASK_NULL) {
1239 return KERN_INVALID_ARGUMENT;
1240 }
1241
1c79356b 1242 switch (which) {
39037602 1243 case TASK_KERNEL_PORT:
0a7de745
A
1244 whichp = &task->itk_sself;
1245 break;
1c79356b 1246
39037602 1247 case TASK_HOST_PORT:
0a7de745
A
1248 whichp = &task->itk_host;
1249 break;
1c79356b 1250
39037602 1251 case TASK_BOOTSTRAP_PORT:
0a7de745
A
1252 whichp = &task->itk_bootstrap;
1253 break;
1c79356b 1254
39037602 1255 case TASK_SEATBELT_PORT:
0a7de745
A
1256 whichp = &task->itk_seatbelt;
1257 break;
2d21ac55 1258
39037602 1259 case TASK_ACCESS_PORT:
0a7de745
A
1260 whichp = &task->itk_task_access;
1261 break;
fe8ab488 1262
39037602 1263 case TASK_DEBUG_CONTROL_PORT:
0a7de745
A
1264 whichp = &task->itk_debug_control;
1265 break;
fe8ab488 1266
39037602 1267 default:
0a7de745 1268 return KERN_INVALID_ARGUMENT;
1c79356b
A
1269 }/* switch */
1270
1271 itk_lock(task);
1272 if (task->itk_self == IP_NULL) {
1273 itk_unlock(task);
1274 return KERN_FAILURE;
1275 }
1276
4ba76501
A
1277 /* Never allow overwrite of seatbelt, or task access ports */
1278 switch (which) {
1279 case TASK_SEATBELT_PORT:
1280 case TASK_ACCESS_PORT:
1281 if (IP_VALID(*whichp)) {
1282 itk_unlock(task);
1283 return KERN_NO_ACCESS;
1284 }
1285 break;
1286 default:
1287 break;
2d21ac55
A
1288 }
1289
1c79356b
A
1290 old = *whichp;
1291 *whichp = port;
1292 itk_unlock(task);
1293
0a7de745 1294 if (IP_VALID(old)) {
1c79356b 1295 ipc_port_release_send(old);
0a7de745 1296 }
1c79356b
A
1297 return KERN_SUCCESS;
1298}
1299
1c79356b
A
1300/*
1301 * Routine: mach_ports_register [kernel call]
1302 * Purpose:
1303 * Stash a handful of port send rights in the task.
1304 * Child tasks will inherit these rights, but they
1305 * must use mach_ports_lookup to acquire them.
1306 *
1307 * The rights are supplied in a (wired) kalloc'd segment.
1308 * Rights which aren't supplied are assumed to be null.
1309 * Conditions:
1310 * Nothing locked. If successful, consumes
1311 * the supplied rights and memory.
1312 * Returns:
1313 * KERN_SUCCESS Stashed the port rights.
1314 * KERN_INVALID_ARGUMENT The task is null.
1315 * KERN_INVALID_ARGUMENT The task is dead.
39236c6e 1316 * KERN_INVALID_ARGUMENT The memory param is null.
1c79356b
A
1317 * KERN_INVALID_ARGUMENT Too many port rights supplied.
1318 */
1319
1320kern_return_t
1321mach_ports_register(
0a7de745
A
1322 task_t task,
1323 mach_port_array_t memory,
1324 mach_msg_type_number_t portsCnt)
1c79356b
A
1325{
1326 ipc_port_t ports[TASK_PORT_REGISTER_MAX];
91447636 1327 unsigned int i;
1c79356b
A
1328
1329 if ((task == TASK_NULL) ||
39236c6e 1330 (portsCnt > TASK_PORT_REGISTER_MAX) ||
0a7de745 1331 (portsCnt && memory == NULL)) {
1c79356b 1332 return KERN_INVALID_ARGUMENT;
0a7de745 1333 }
1c79356b
A
1334
1335 /*
1336 * Pad the port rights with nulls.
1337 */
1338
0a7de745 1339 for (i = 0; i < portsCnt; i++) {
1c79356b 1340 ports[i] = memory[i];
0a7de745
A
1341 }
1342 for (; i < TASK_PORT_REGISTER_MAX; i++) {
1c79356b 1343 ports[i] = IP_NULL;
0a7de745 1344 }
1c79356b
A
1345
1346 itk_lock(task);
1347 if (task->itk_self == IP_NULL) {
1348 itk_unlock(task);
1349 return KERN_INVALID_ARGUMENT;
1350 }
1351
1352 /*
1353 * Replace the old send rights with the new.
1354 * Release the old rights after unlocking.
1355 */
1356
1357 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) {
1358 ipc_port_t old;
1359
1360 old = task->itk_registered[i];
1361 task->itk_registered[i] = ports[i];
1362 ports[i] = old;
1363 }
1364
1365 itk_unlock(task);
1366
0a7de745
A
1367 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) {
1368 if (IP_VALID(ports[i])) {
1c79356b 1369 ipc_port_release_send(ports[i]);
0a7de745
A
1370 }
1371 }
1c79356b
A
1372
1373 /*
1374 * Now that the operation is known to be successful,
1375 * we can free the memory.
1376 */
1377
0a7de745 1378 if (portsCnt != 0) {
91447636 1379 kfree(memory,
0a7de745
A
1380 (vm_size_t) (portsCnt * sizeof(mach_port_t)));
1381 }
1c79356b
A
1382
1383 return KERN_SUCCESS;
1384}
1385
1386/*
1387 * Routine: mach_ports_lookup [kernel call]
1388 * Purpose:
1389 * Retrieves (clones) the stashed port send rights.
1390 * Conditions:
1391 * Nothing locked. If successful, the caller gets
1392 * rights and memory.
1393 * Returns:
1394 * KERN_SUCCESS Retrieved the send rights.
1395 * KERN_INVALID_ARGUMENT The task is null.
1396 * KERN_INVALID_ARGUMENT The task is dead.
1397 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1398 */
1399
1400kern_return_t
1401mach_ports_lookup(
0a7de745
A
1402 task_t task,
1403 mach_port_array_t *portsp,
1404 mach_msg_type_number_t *portsCnt)
1c79356b 1405{
91447636 1406 void *memory;
1c79356b
A
1407 vm_size_t size;
1408 ipc_port_t *ports;
1409 int i;
1410
0a7de745 1411 if (task == TASK_NULL) {
1c79356b 1412 return KERN_INVALID_ARGUMENT;
0a7de745 1413 }
1c79356b
A
1414
1415 size = (vm_size_t) (TASK_PORT_REGISTER_MAX * sizeof(ipc_port_t));
1416
1417 memory = kalloc(size);
0a7de745 1418 if (memory == 0) {
1c79356b 1419 return KERN_RESOURCE_SHORTAGE;
0a7de745 1420 }
1c79356b
A
1421
1422 itk_lock(task);
1423 if (task->itk_self == IP_NULL) {
1424 itk_unlock(task);
1425
1426 kfree(memory, size);
1427 return KERN_INVALID_ARGUMENT;
1428 }
1429
1430 ports = (ipc_port_t *) memory;
1431
1432 /*
1433 * Clone port rights. Because kalloc'd memory
1434 * is wired, we won't fault while holding the task lock.
1435 */
1436
0a7de745 1437 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) {
1c79356b 1438 ports[i] = ipc_port_copy_send(task->itk_registered[i]);
0a7de745 1439 }
1c79356b
A
1440
1441 itk_unlock(task);
1442
1443 *portsp = (mach_port_array_t) ports;
1444 *portsCnt = TASK_PORT_REGISTER_MAX;
1445 return KERN_SUCCESS;
1446}
1447
94ff46dc
A
1448extern zone_t task_zone;
1449
5ba3f43e
A
1450kern_return_t
1451task_conversion_eval(task_t caller, task_t victim)
1452{
1453 /*
1454 * Tasks are allowed to resolve their own task ports, and the kernel is
1455 * allowed to resolve anyone's task port.
1456 */
1457 if (caller == kernel_task) {
1458 return KERN_SUCCESS;
1459 }
1460
1461 if (caller == victim) {
1462 return KERN_SUCCESS;
1463 }
1464
1465 /*
1466 * Only the kernel can can resolve the kernel's task port. We've established
1467 * by this point that the caller is not kernel_task.
1468 */
d9a64523 1469 if (victim == TASK_NULL || victim == kernel_task) {
5ba3f43e
A
1470 return KERN_INVALID_SECURITY;
1471 }
1472
94ff46dc
A
1473 zone_require(victim, task_zone);
1474
5ba3f43e
A
1475#if CONFIG_EMBEDDED
1476 /*
1477 * On embedded platforms, only a platform binary can resolve the task port
1478 * of another platform binary.
1479 */
1480 if ((victim->t_flags & TF_PLATFORM) && !(caller->t_flags & TF_PLATFORM)) {
1481#if SECURE_KERNEL
1482 return KERN_INVALID_SECURITY;
1483#else
1484 if (cs_relax_platform_task_ports) {
1485 return KERN_SUCCESS;
1486 } else {
1487 return KERN_INVALID_SECURITY;
1488 }
1489#endif /* SECURE_KERNEL */
1490 }
1491#endif /* CONFIG_EMBEDDED */
1492
1493 return KERN_SUCCESS;
1494}
1495
1c79356b
A
1496/*
1497 * Routine: convert_port_to_locked_task
1498 * Purpose:
1499 * Internal helper routine to convert from a port to a locked
1500 * task. Used by several routines that try to convert from a
1501 * task port to a reference on some task related object.
1502 * Conditions:
1503 * Nothing locked, blocking OK.
1504 */
1505task_t
1506convert_port_to_locked_task(ipc_port_t port)
1507{
5ba3f43e 1508 int try_failed_count = 0;
2d21ac55 1509
1c79356b 1510 while (IP_VALID(port)) {
5ba3f43e 1511 task_t ct = current_task();
1c79356b
A
1512 task_t task;
1513
1514 ip_lock(port);
1515 if (!ip_active(port) || (ip_kotype(port) != IKOT_TASK)) {
1516 ip_unlock(port);
1517 return TASK_NULL;
1518 }
ea3f0419 1519 task = (task_t) ip_get_kobject(port);
1c79356b
A
1520 assert(task != TASK_NULL);
1521
5ba3f43e 1522 if (task_conversion_eval(ct, task)) {
813fb2f6
A
1523 ip_unlock(port);
1524 return TASK_NULL;
1525 }
1526
1c79356b
A
1527 /*
1528 * Normal lock ordering puts task_lock() before ip_lock().
1529 * Attempt out-of-order locking here.
1530 */
1531 if (task_lock_try(task)) {
1532 ip_unlock(port);
0a7de745 1533 return task;
1c79356b 1534 }
2d21ac55 1535 try_failed_count++;
1c79356b
A
1536
1537 ip_unlock(port);
2d21ac55 1538 mutex_pause(try_failed_count);
1c79356b
A
1539 }
1540 return TASK_NULL;
1541}
1542
813fb2f6
A
1543/*
1544 * Routine: convert_port_to_locked_task_inspect
1545 * Purpose:
1546 * Internal helper routine to convert from a port to a locked
1547 * task inspect right. Used by internal routines that try to convert from a
1548 * task inspect port to a reference on some task related object.
1549 * Conditions:
1550 * Nothing locked, blocking OK.
1551 */
1552task_inspect_t
1553convert_port_to_locked_task_inspect(ipc_port_t port)
1554{
0a7de745 1555 int try_failed_count = 0;
813fb2f6
A
1556
1557 while (IP_VALID(port)) {
1558 task_inspect_t task;
1559
1560 ip_lock(port);
1561 if (!ip_active(port) || (ip_kotype(port) != IKOT_TASK)) {
1562 ip_unlock(port);
1563 return TASK_INSPECT_NULL;
1564 }
ea3f0419 1565 task = (task_inspect_t) ip_get_kobject(port);
813fb2f6
A
1566 assert(task != TASK_INSPECT_NULL);
1567 /*
1568 * Normal lock ordering puts task_lock() before ip_lock().
1569 * Attempt out-of-order locking here.
1570 */
1571 if (task_lock_try((task_t)task)) {
1572 ip_unlock(port);
1573 return task;
1574 }
1575 try_failed_count++;
1576
1577 ip_unlock(port);
1578 mutex_pause(try_failed_count);
1579 }
1580 return TASK_INSPECT_NULL;
1581}
1582
cb323159
A
1583static task_t
1584convert_port_to_task_locked(
1585 ipc_port_t port,
1586 uint32_t *exec_token)
39037602 1587{
cb323159
A
1588 task_t task = TASK_NULL;
1589
1590 ip_lock_held(port);
1591 require_ip_active(port);
1592
1593 if (ip_kotype(port) == IKOT_TASK) {
1594 task_t ct = current_task();
ea3f0419 1595 task = (task_t) ip_get_kobject(port);
cb323159
A
1596 assert(task != TASK_NULL);
1597
1598 if (task_conversion_eval(ct, task)) {
1599 return TASK_NULL;
1600 }
1601
1602 if (exec_token) {
1603 *exec_token = task->exec_token;
1604 }
1605 task_reference_internal(task);
1606 }
1607
1608 return task;
39037602
A
1609}
1610
1611/*
1612 * Routine: convert_port_to_task_with_exec_token
1613 * Purpose:
1614 * Convert from a port to a task and return
1615 * the exec token stored in the task.
1616 * Doesn't consume the port ref; produces a task ref,
1617 * which may be null.
1618 * Conditions:
1619 * Nothing locked.
1620 */
1621task_t
1622convert_port_to_task_with_exec_token(
0a7de745
A
1623 ipc_port_t port,
1624 uint32_t *exec_token)
1c79356b 1625{
0a7de745 1626 task_t task = TASK_NULL;
1c79356b 1627
91447636
A
1628 if (IP_VALID(port)) {
1629 ip_lock(port);
cb323159
A
1630 if (ip_active(port)) {
1631 task = convert_port_to_task_locked(port, exec_token);
91447636 1632 }
91447636 1633 ip_unlock(port);
1c79356b 1634 }
91447636 1635
0a7de745 1636 return task;
1c79356b
A
1637}
1638
cb323159
A
1639/*
1640 * Routine: convert_port_to_task
1641 * Purpose:
1642 * Convert from a port to a task.
1643 * Doesn't consume the port ref; produces a task ref,
1644 * which may be null.
1645 * Conditions:
1646 * Nothing locked.
1647 */
1648task_t
1649convert_port_to_task(
1650 ipc_port_t port)
1651{
1652 return convert_port_to_task_with_exec_token(port, NULL);
1653}
1654
1655
0c530ab8
A
1656/*
1657 * Routine: convert_port_to_task_name
1658 * Purpose:
1659 * Convert from a port to a task name.
1660 * Doesn't consume the port ref; produces a task name ref,
1661 * which may be null.
1662 * Conditions:
1663 * Nothing locked.
1664 */
1665task_name_t
1666convert_port_to_task_name(
0a7de745 1667 ipc_port_t port)
0c530ab8 1668{
0a7de745 1669 task_name_t task = TASK_NULL;
0c530ab8
A
1670
1671 if (IP_VALID(port)) {
1672 ip_lock(port);
1673
0a7de745
A
1674 if (ip_active(port) &&
1675 (ip_kotype(port) == IKOT_TASK ||
1676 ip_kotype(port) == IKOT_TASK_NAME)) {
ea3f0419 1677 task = (task_name_t) ip_get_kobject(port);
0c530ab8
A
1678 assert(task != TASK_NAME_NULL);
1679
1680 task_reference_internal(task);
1681 }
1682
1683 ip_unlock(port);
1684 }
1685
0a7de745 1686 return task;
0c530ab8
A
1687}
1688
cb323159
A
1689static task_inspect_t
1690convert_port_to_task_inspect_locked(
1691 ipc_port_t port)
1692{
1693 task_inspect_t task = TASK_INSPECT_NULL;
1694
1695 ip_lock_held(port);
1696 require_ip_active(port);
1697
1698 if (ip_kotype(port) == IKOT_TASK) {
ea3f0419 1699 task = (task_inspect_t) ip_get_kobject(port);
cb323159
A
1700 assert(task != TASK_INSPECT_NULL);
1701
1702 task_reference_internal(task);
1703 }
1704
1705 return task;
1706}
1707
813fb2f6
A
1708/*
1709 * Routine: convert_port_to_task_inspect
1710 * Purpose:
1711 * Convert from a port to a task inspection right
1712 * Doesn't consume the port ref; produces a task ref,
1713 * which may be null.
1714 * Conditions:
1715 * Nothing locked.
1716 */
1717task_inspect_t
1718convert_port_to_task_inspect(
0a7de745 1719 ipc_port_t port)
813fb2f6
A
1720{
1721 task_inspect_t task = TASK_INSPECT_NULL;
1722
1723 if (IP_VALID(port)) {
1724 ip_lock(port);
cb323159
A
1725 if (ip_active(port)) {
1726 task = convert_port_to_task_inspect_locked(port);
813fb2f6 1727 }
813fb2f6
A
1728 ip_unlock(port);
1729 }
1730
0a7de745 1731 return task;
813fb2f6
A
1732}
1733
39236c6e
A
1734/*
1735 * Routine: convert_port_to_task_suspension_token
1736 * Purpose:
1737 * Convert from a port to a task suspension token.
1738 * Doesn't consume the port ref; produces a suspension token ref,
1739 * which may be null.
1740 * Conditions:
1741 * Nothing locked.
1742 */
1743task_suspension_token_t
1744convert_port_to_task_suspension_token(
0a7de745 1745 ipc_port_t port)
39236c6e 1746{
0a7de745 1747 task_suspension_token_t task = TASK_NULL;
39236c6e
A
1748
1749 if (IP_VALID(port)) {
1750 ip_lock(port);
1751
0a7de745
A
1752 if (ip_active(port) &&
1753 ip_kotype(port) == IKOT_TASK_RESUME) {
ea3f0419 1754 task = (task_suspension_token_t) ip_get_kobject(port);
39236c6e
A
1755 assert(task != TASK_NULL);
1756
1757 task_reference_internal(task);
1758 }
1759
1760 ip_unlock(port);
1761 }
1762
0a7de745 1763 return task;
39236c6e
A
1764}
1765
1c79356b
A
1766/*
1767 * Routine: convert_port_to_space
1768 * Purpose:
1769 * Convert from a port to a space.
1770 * Doesn't consume the port ref; produces a space ref,
1771 * which may be null.
1772 * Conditions:
1773 * Nothing locked.
1774 */
1775ipc_space_t
1776convert_port_to_space(
0a7de745 1777 ipc_port_t port)
1c79356b
A
1778{
1779 ipc_space_t space;
1780 task_t task;
1781
1782 task = convert_port_to_locked_task(port);
1783
0a7de745 1784 if (task == TASK_NULL) {
1c79356b 1785 return IPC_SPACE_NULL;
0a7de745 1786 }
1c79356b
A
1787
1788 if (!task->active) {
1789 task_unlock(task);
1790 return IPC_SPACE_NULL;
1791 }
0a7de745 1792
1c79356b
A
1793 space = task->itk_space;
1794 is_reference(space);
1795 task_unlock(task);
0a7de745 1796 return space;
1c79356b
A
1797}
1798
813fb2f6
A
1799/*
1800 * Routine: convert_port_to_space_inspect
1801 * Purpose:
1802 * Convert from a port to a space inspect right.
1803 * Doesn't consume the port ref; produces a space inspect ref,
1804 * which may be null.
1805 * Conditions:
1806 * Nothing locked.
1807 */
1808ipc_space_inspect_t
1809convert_port_to_space_inspect(
0a7de745 1810 ipc_port_t port)
813fb2f6
A
1811{
1812 ipc_space_inspect_t space;
1813 task_inspect_t task;
1814
1815 task = convert_port_to_locked_task_inspect(port);
1816
0a7de745 1817 if (task == TASK_INSPECT_NULL) {
813fb2f6 1818 return IPC_SPACE_INSPECT_NULL;
0a7de745 1819 }
813fb2f6
A
1820
1821 if (!task->active) {
1822 task_unlock(task);
1823 return IPC_SPACE_INSPECT_NULL;
1824 }
1825
1826 space = (ipc_space_inspect_t)task->itk_space;
1827 is_reference((ipc_space_t)space);
1828 task_unlock((task_t)task);
1829 return space;
1830}
1831
1c79356b
A
1832/*
1833 * Routine: convert_port_to_map
1834 * Purpose:
1835 * Convert from a port to a map.
1836 * Doesn't consume the port ref; produces a map ref,
1837 * which may be null.
1838 * Conditions:
1839 * Nothing locked.
1840 */
1841
1842vm_map_t
1843convert_port_to_map(
0a7de745 1844 ipc_port_t port)
1c79356b
A
1845{
1846 task_t task;
1847 vm_map_t map;
1848
1849 task = convert_port_to_locked_task(port);
0a7de745
A
1850
1851 if (task == TASK_NULL) {
1c79356b 1852 return VM_MAP_NULL;
0a7de745 1853 }
1c79356b
A
1854
1855 if (!task->active) {
1856 task_unlock(task);
1857 return VM_MAP_NULL;
1858 }
0a7de745 1859
1c79356b
A
1860 map = task->map;
1861 vm_map_reference_swap(map);
1862 task_unlock(task);
1863 return map;
1864}
1865
1866
1867/*
91447636 1868 * Routine: convert_port_to_thread
1c79356b 1869 * Purpose:
91447636
A
1870 * Convert from a port to a thread.
1871 * Doesn't consume the port ref; produces an thread ref,
1c79356b
A
1872 * which may be null.
1873 * Conditions:
1874 * Nothing locked.
1875 */
1876
cb323159
A
1877static thread_t
1878convert_port_to_thread_locked(
1879 ipc_port_t port,
1880 port_to_thread_options_t options)
1c79356b 1881{
0a7de745 1882 thread_t thread = THREAD_NULL;
1c79356b 1883
cb323159
A
1884 ip_lock_held(port);
1885 require_ip_active(port);
1c79356b 1886
cb323159 1887 if (ip_kotype(port) == IKOT_THREAD) {
ea3f0419 1888 thread = (thread_t) ip_get_kobject(port);
cb323159 1889 assert(thread != THREAD_NULL);
d9a64523 1890
cb323159
A
1891 if (options & PORT_TO_THREAD_NOT_CURRENT_THREAD) {
1892 if (thread == current_thread()) {
1893 return THREAD_NULL;
1894 }
1895 }
1896
1897 if (options & PORT_TO_THREAD_IN_CURRENT_TASK) {
1898 if (thread->task != current_task()) {
1899 return THREAD_NULL;
1900 }
1901 } else {
d9a64523
A
1902 /* Use task conversion rules for thread control conversions */
1903 if (task_conversion_eval(current_task(), thread->task) != KERN_SUCCESS) {
813fb2f6
A
1904 return THREAD_NULL;
1905 }
1c79356b 1906 }
91447636 1907
cb323159
A
1908 thread_reference_internal(thread);
1909 }
1910
1911 return thread;
1912}
1913
1914thread_t
1915convert_port_to_thread(
1916 ipc_port_t port)
1917{
1918 thread_t thread = THREAD_NULL;
1919
1920 if (IP_VALID(port)) {
1921 ip_lock(port);
1922 if (ip_active(port)) {
1923 thread = convert_port_to_thread_locked(port, PORT_TO_THREAD_NONE);
1924 }
91447636 1925 ip_unlock(port);
1c79356b 1926 }
91447636 1927
0a7de745 1928 return thread;
1c79356b
A
1929}
1930
813fb2f6
A
1931/*
1932 * Routine: convert_port_to_thread_inspect
1933 * Purpose:
1934 * Convert from a port to a thread inspection right
1935 * Doesn't consume the port ref; produces a thread ref,
1936 * which may be null.
1937 * Conditions:
1938 * Nothing locked.
1939 */
1940thread_inspect_t
1941convert_port_to_thread_inspect(
0a7de745 1942 ipc_port_t port)
813fb2f6
A
1943{
1944 thread_inspect_t thread = THREAD_INSPECT_NULL;
1945
1946 if (IP_VALID(port)) {
1947 ip_lock(port);
1948
1949 if (ip_active(port) &&
1950 ip_kotype(port) == IKOT_THREAD) {
ea3f0419 1951 thread = (thread_inspect_t) ip_get_kobject(port);
813fb2f6
A
1952 assert(thread != THREAD_INSPECT_NULL);
1953 thread_reference_internal((thread_t)thread);
1954 }
1955 ip_unlock(port);
1956 }
1957
1958 return thread;
1959}
1960
1961/*
1962 * Routine: convert_thread_inspect_to_port
1963 * Purpose:
1964 * Convert from a thread inspect reference to a port.
1965 * Consumes a thread ref;
1966 * As we never export thread inspect ports, always
1967 * creates a NULL port.
1968 * Conditions:
1969 * Nothing locked.
1970 */
1971
1972ipc_port_t
1973convert_thread_inspect_to_port(thread_inspect_t thread)
1974{
1975 thread_deallocate(thread);
1976 return IP_NULL;
1977}
1978
1979
1c79356b 1980/*
91447636 1981 * Routine: port_name_to_thread
1c79356b 1982 * Purpose:
91447636
A
1983 * Convert from a port name to an thread reference
1984 * A name of MACH_PORT_NULL is valid for the null thread.
1c79356b
A
1985 * Conditions:
1986 * Nothing locked.
1987 */
91447636
A
1988thread_t
1989port_name_to_thread(
cb323159
A
1990 mach_port_name_t name,
1991 port_to_thread_options_t options)
1c79356b 1992{
0a7de745
A
1993 thread_t thread = THREAD_NULL;
1994 ipc_port_t kport;
cb323159 1995 kern_return_t kr;
1c79356b
A
1996
1997 if (MACH_PORT_VALID(name)) {
cb323159
A
1998 kr = ipc_port_translate_send(current_space(), name, &kport);
1999 if (kr == KERN_SUCCESS) {
2000 thread = convert_port_to_thread_locked(kport, options);
2001 ip_unlock(kport);
0a7de745 2002 }
1c79356b 2003 }
91447636 2004
0a7de745 2005 return thread;
1c79356b
A
2006}
2007
2008task_t
2009port_name_to_task(
2010 mach_port_name_t name)
2011{
cb323159 2012 ipc_port_t kport;
1c79356b
A
2013 kern_return_t kr;
2014 task_t task = TASK_NULL;
2015
2016 if (MACH_PORT_VALID(name)) {
cb323159
A
2017 kr = ipc_port_translate_send(current_space(), name, &kport);
2018 if (kr == KERN_SUCCESS) {
2019 task = convert_port_to_task_locked(kport, NULL);
2020 ip_unlock(kport);
0a7de745 2021 }
1c79356b
A
2022 }
2023 return task;
2024}
2025
813fb2f6
A
2026task_inspect_t
2027port_name_to_task_inspect(
2028 mach_port_name_t name)
2029{
cb323159 2030 ipc_port_t kport;
813fb2f6
A
2031 kern_return_t kr;
2032 task_inspect_t ti = TASK_INSPECT_NULL;
2033
2034 if (MACH_PORT_VALID(name)) {
cb323159
A
2035 kr = ipc_port_translate_send(current_space(), name, &kport);
2036 if (kr == KERN_SUCCESS) {
2037 ti = convert_port_to_task_inspect_locked(kport);
2038 ip_unlock(kport);
0a7de745 2039 }
813fb2f6
A
2040 }
2041 return ti;
2042}
2043
39037602
A
2044/*
2045 * Routine: port_name_to_host
2046 * Purpose:
2047 * Convert from a port name to a host pointer.
2048 * NOTE: This does _not_ return a +1 reference to the host_t
2049 * Conditions:
2050 * Nothing locked.
2051 */
2052host_t
2053port_name_to_host(
2054 mach_port_name_t name)
2055{
39037602
A
2056 host_t host = HOST_NULL;
2057 kern_return_t kr;
2058 ipc_port_t port;
2059
2060 if (MACH_PORT_VALID(name)) {
2061 kr = ipc_port_translate_send(current_space(), name, &port);
2062 if (kr == KERN_SUCCESS) {
2063 host = convert_port_to_host(port);
2064 ip_unlock(port);
2065 }
2066 }
2067 return host;
2068}
2069
1c79356b
A
2070/*
2071 * Routine: convert_task_to_port
2072 * Purpose:
2073 * Convert from a task to a port.
2074 * Consumes a task ref; produces a naked send right
0a7de745 2075 * which may be invalid.
1c79356b
A
2076 * Conditions:
2077 * Nothing locked.
2078 */
2079
2080ipc_port_t
2081convert_task_to_port(
0a7de745 2082 task_t task)
1c79356b
A
2083{
2084 ipc_port_t port;
2085
2086 itk_lock(task);
813fb2f6 2087
0a7de745 2088 if (task->itk_self != IP_NULL) {
1c79356b 2089 port = ipc_port_make_send(task->itk_self);
0a7de745 2090 } else {
1c79356b 2091 port = IP_NULL;
0a7de745 2092 }
813fb2f6 2093
1c79356b
A
2094 itk_unlock(task);
2095
2096 task_deallocate(task);
2097 return port;
2098}
2099
813fb2f6
A
2100/*
2101 * Routine: convert_task_inspect_to_port
2102 * Purpose:
2103 * Convert from a task inspect reference to a port.
2104 * Consumes a task ref;
2105 * As we never export task inspect ports, always
2106 * creates a NULL port.
2107 * Conditions:
2108 * Nothing locked.
2109 */
2110ipc_port_t
2111convert_task_inspect_to_port(
0a7de745 2112 task_inspect_t task)
813fb2f6
A
2113{
2114 task_deallocate(task);
2115
2116 return IP_NULL;
2117}
2118
39236c6e
A
2119/*
2120 * Routine: convert_task_suspend_token_to_port
2121 * Purpose:
2122 * Convert from a task suspension token to a port.
2123 * Consumes a task suspension token ref; produces a naked send-once right
0a7de745 2124 * which may be invalid.
39236c6e
A
2125 * Conditions:
2126 * Nothing locked.
2127 */
2128ipc_port_t
2129convert_task_suspension_token_to_port(
0a7de745 2130 task_suspension_token_t task)
39236c6e
A
2131{
2132 ipc_port_t port;
2133
2134 task_lock(task);
2135 if (task->active) {
2136 if (task->itk_resume == IP_NULL) {
cb323159
A
2137 task->itk_resume = ipc_kobject_alloc_port((ipc_kobject_t) task,
2138 IKOT_TASK_RESUME, IPC_KOBJECT_ALLOC_NONE);
39236c6e
A
2139 }
2140
2141 /*
2142 * Create a send-once right for each instance of a direct user-called
2143 * task_suspend2 call. Each time one of these send-once rights is abandoned,
2144 * the notification handler will resume the target task.
2145 */
2146 port = ipc_port_make_sonce(task->itk_resume);
2147 assert(IP_VALID(port));
2148 } else {
2149 port = IP_NULL;
2150 }
2151
2152 task_unlock(task);
2153 task_suspension_token_deallocate(task);
2154
2155 return port;
2156}
2157
2158
0c530ab8
A
2159/*
2160 * Routine: convert_task_name_to_port
2161 * Purpose:
2162 * Convert from a task name ref to a port.
2163 * Consumes a task name ref; produces a naked send right
0a7de745 2164 * which may be invalid.
0c530ab8
A
2165 * Conditions:
2166 * Nothing locked.
2167 */
2168
2169ipc_port_t
2170convert_task_name_to_port(
0a7de745 2171 task_name_t task_name)
0c530ab8
A
2172{
2173 ipc_port_t port;
2174
2175 itk_lock(task_name);
0a7de745 2176 if (task_name->itk_nself != IP_NULL) {
0c530ab8 2177 port = ipc_port_make_send(task_name->itk_nself);
0a7de745 2178 } else {
0c530ab8 2179 port = IP_NULL;
0a7de745 2180 }
0c530ab8
A
2181 itk_unlock(task_name);
2182
2183 task_name_deallocate(task_name);
2184 return port;
2185}
2186
1c79356b 2187/*
91447636 2188 * Routine: convert_thread_to_port
1c79356b 2189 * Purpose:
91447636
A
2190 * Convert from a thread to a port.
2191 * Consumes an thread ref; produces a naked send right
1c79356b
A
2192 * which may be invalid.
2193 * Conditions:
2194 * Nothing locked.
2195 */
2196
2197ipc_port_t
91447636 2198convert_thread_to_port(
0a7de745 2199 thread_t thread)
1c79356b 2200{
0a7de745 2201 ipc_port_t port;
1c79356b 2202
91447636
A
2203 thread_mtx_lock(thread);
2204
0a7de745 2205 if (thread->ith_self != IP_NULL) {
91447636 2206 port = ipc_port_make_send(thread->ith_self);
0a7de745 2207 } else {
1c79356b 2208 port = IP_NULL;
0a7de745 2209 }
1c79356b 2210
91447636
A
2211 thread_mtx_unlock(thread);
2212
2213 thread_deallocate(thread);
2214
0a7de745 2215 return port;
1c79356b
A
2216}
2217
2218/*
2219 * Routine: space_deallocate
2220 * Purpose:
2221 * Deallocate a space ref produced by convert_port_to_space.
2222 * Conditions:
2223 * Nothing locked.
2224 */
2225
2226void
2227space_deallocate(
0a7de745 2228 ipc_space_t space)
1c79356b 2229{
0a7de745 2230 if (space != IS_NULL) {
1c79356b 2231 is_release(space);
0a7de745 2232 }
1c79356b
A
2233}
2234
813fb2f6
A
2235/*
2236 * Routine: space_inspect_deallocate
2237 * Purpose:
2238 * Deallocate a space inspect ref produced by convert_port_to_space_inspect.
2239 * Conditions:
2240 * Nothing locked.
2241 */
2242
2243void
2244space_inspect_deallocate(
0a7de745 2245 ipc_space_inspect_t space)
813fb2f6 2246{
0a7de745 2247 if (space != IS_INSPECT_NULL) {
813fb2f6 2248 is_release((ipc_space_t)space);
0a7de745 2249 }
813fb2f6
A
2250}
2251
1c79356b
A
2252/*
2253 * Routine: thread/task_set_exception_ports [kernel call]
2254 * Purpose:
2255 * Sets the thread/task exception port, flavor and
2256 * behavior for the exception types specified by the mask.
2257 * There will be one send right per exception per valid
2258 * port.
2259 * Conditions:
2260 * Nothing locked. If successful, consumes
2261 * the supplied send right.
2262 * Returns:
2263 * KERN_SUCCESS Changed the special port.
2264 * KERN_INVALID_ARGUMENT The thread is null,
2265 * Illegal mask bit set.
2266 * Illegal exception behavior
2267 * KERN_FAILURE The thread is dead.
2268 */
2269
2270kern_return_t
2271thread_set_exception_ports(
0a7de745
A
2272 thread_t thread,
2273 exception_mask_t exception_mask,
2274 ipc_port_t new_port,
2275 exception_behavior_t new_behavior,
2276 thread_state_flavor_t new_flavor)
1c79356b 2277{
0a7de745 2278 ipc_port_t old_port[EXC_TYPES_COUNT];
6601e61a 2279 boolean_t privileged = current_task()->sec_token.val[0] == 0;
0a7de745 2280 register int i;
1c79356b 2281
5ba3f43e
A
2282#if CONFIG_MACF
2283 struct label *new_label;
2284#endif
1c79356b 2285
0a7de745
A
2286 if (thread == THREAD_NULL) {
2287 return KERN_INVALID_ARGUMENT;
2288 }
2289
2290 if (exception_mask & ~EXC_MASK_VALID) {
2291 return KERN_INVALID_ARGUMENT;
2292 }
1c79356b
A
2293
2294 if (IP_VALID(new_port)) {
cb323159 2295 switch (new_behavior & ~MACH_EXCEPTION_MASK) {
1c79356b
A
2296 case EXCEPTION_DEFAULT:
2297 case EXCEPTION_STATE:
2298 case EXCEPTION_STATE_IDENTITY:
2299 break;
91447636 2300
1c79356b 2301 default:
0a7de745 2302 return KERN_INVALID_ARGUMENT;
1c79356b
A
2303 }
2304 }
2305
0a7de745 2306 /*
1c79356b
A
2307 * Check the validity of the thread_state_flavor by calling the
2308 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in
2309 * osfmk/mach/ARCHITECTURE/thread_status.h
2310 */
0a7de745
A
2311 if (new_flavor != 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor)) {
2312 return KERN_INVALID_ARGUMENT;
2313 }
1c79356b 2314
5ba3f43e
A
2315#if CONFIG_MACF
2316 new_label = mac_exc_create_label_for_current_proc();
2317#endif
0a7de745 2318
91447636
A
2319 thread_mtx_lock(thread);
2320
2321 if (!thread->active) {
2322 thread_mtx_unlock(thread);
2323
0a7de745 2324 return KERN_FAILURE;
1c79356b
A
2325 }
2326
39236c6e
A
2327 if (thread->exc_actions == NULL) {
2328 ipc_thread_init_exc_actions(thread);
2329 }
91447636 2330 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
39037602
A
2331 if ((exception_mask & (1 << i))
2332#if CONFIG_MACF
0a7de745 2333 && mac_exc_update_action_label(&thread->exc_actions[i], new_label) == 0
39037602 2334#endif
0a7de745 2335 ) {
91447636
A
2336 old_port[i] = thread->exc_actions[i].port;
2337 thread->exc_actions[i].port = ipc_port_copy_send(new_port);
2338 thread->exc_actions[i].behavior = new_behavior;
2339 thread->exc_actions[i].flavor = new_flavor;
6601e61a 2340 thread->exc_actions[i].privileged = privileged;
0a7de745 2341 } else {
1c79356b 2342 old_port[i] = IP_NULL;
0a7de745 2343 }
91447636
A
2344 }
2345
2346 thread_mtx_unlock(thread);
2347
5ba3f43e
A
2348#if CONFIG_MACF
2349 mac_exc_free_label(new_label);
2350#endif
0a7de745
A
2351
2352 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
2353 if (IP_VALID(old_port[i])) {
1c79356b 2354 ipc_port_release_send(old_port[i]);
0a7de745
A
2355 }
2356 }
91447636 2357
0a7de745 2358 if (IP_VALID(new_port)) { /* consume send right */
1c79356b 2359 ipc_port_release_send(new_port);
0a7de745 2360 }
1c79356b 2361
0a7de745 2362 return KERN_SUCCESS;
91447636 2363}
1c79356b
A
2364
2365kern_return_t
2366task_set_exception_ports(
0a7de745
A
2367 task_t task,
2368 exception_mask_t exception_mask,
2369 ipc_port_t new_port,
2370 exception_behavior_t new_behavior,
2371 thread_state_flavor_t new_flavor)
1c79356b 2372{
0a7de745 2373 ipc_port_t old_port[EXC_TYPES_COUNT];
8ad349bb 2374 boolean_t privileged = current_task()->sec_token.val[0] == 0;
0a7de745 2375 register int i;
1c79356b 2376
5ba3f43e
A
2377#if CONFIG_MACF
2378 struct label *new_label;
0a7de745 2379#endif
5ba3f43e 2380
0a7de745
A
2381 if (task == TASK_NULL) {
2382 return KERN_INVALID_ARGUMENT;
2383 }
1c79356b 2384
0a7de745
A
2385 if (exception_mask & ~EXC_MASK_VALID) {
2386 return KERN_INVALID_ARGUMENT;
2387 }
1c79356b
A
2388
2389 if (IP_VALID(new_port)) {
cb323159 2390 switch (new_behavior & ~MACH_EXCEPTION_MASK) {
1c79356b
A
2391 case EXCEPTION_DEFAULT:
2392 case EXCEPTION_STATE:
2393 case EXCEPTION_STATE_IDENTITY:
2394 break;
91447636 2395
1c79356b 2396 default:
0a7de745 2397 return KERN_INVALID_ARGUMENT;
1c79356b
A
2398 }
2399 }
1c79356b 2400
fe8ab488
A
2401 /*
2402 * Check the validity of the thread_state_flavor by calling the
2403 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in
2404 * osfmk/mach/ARCHITECTURE/thread_status.h
2405 */
0a7de745
A
2406 if (new_flavor != 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor)) {
2407 return KERN_INVALID_ARGUMENT;
2408 }
fe8ab488 2409
5ba3f43e
A
2410#if CONFIG_MACF
2411 new_label = mac_exc_create_label_for_current_proc();
2412#endif
0a7de745 2413
91447636
A
2414 itk_lock(task);
2415
2416 if (task->itk_self == IP_NULL) {
2417 itk_unlock(task);
2418
0a7de745 2419 return KERN_FAILURE;
91447636
A
2420 }
2421
2422 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
39037602
A
2423 if ((exception_mask & (1 << i))
2424#if CONFIG_MACF
0a7de745 2425 && mac_exc_update_action_label(&task->exc_actions[i], new_label) == 0
39037602 2426#endif
0a7de745 2427 ) {
1c79356b
A
2428 old_port[i] = task->exc_actions[i].port;
2429 task->exc_actions[i].port =
0a7de745 2430 ipc_port_copy_send(new_port);
1c79356b
A
2431 task->exc_actions[i].behavior = new_behavior;
2432 task->exc_actions[i].flavor = new_flavor;
8ad349bb 2433 task->exc_actions[i].privileged = privileged;
0a7de745 2434 } else {
1c79356b 2435 old_port[i] = IP_NULL;
0a7de745 2436 }
91447636 2437 }
1c79356b 2438
91447636
A
2439 itk_unlock(task);
2440
5ba3f43e
A
2441#if CONFIG_MACF
2442 mac_exc_free_label(new_label);
2443#endif
0a7de745
A
2444
2445 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
2446 if (IP_VALID(old_port[i])) {
1c79356b 2447 ipc_port_release_send(old_port[i]);
0a7de745
A
2448 }
2449 }
91447636 2450
0a7de745 2451 if (IP_VALID(new_port)) { /* consume send right */
1c79356b 2452 ipc_port_release_send(new_port);
0a7de745 2453 }
1c79356b 2454
0a7de745 2455 return KERN_SUCCESS;
91447636 2456}
1c79356b
A
2457
2458/*
2459 * Routine: thread/task_swap_exception_ports [kernel call]
2460 * Purpose:
2461 * Sets the thread/task exception port, flavor and
2462 * behavior for the exception types specified by the
2463 * mask.
2464 *
2465 * The old ports, behavior and flavors are returned
2466 * Count specifies the array sizes on input and
2467 * the number of returned ports etc. on output. The
2468 * arrays must be large enough to hold all the returned
2469 * data, MIG returnes an error otherwise. The masks
2470 * array specifies the corresponding exception type(s).
2471 *
2472 * Conditions:
2473 * Nothing locked. If successful, consumes
2474 * the supplied send right.
2475 *
2476 * Returns upto [in} CountCnt elements.
2477 * Returns:
2478 * KERN_SUCCESS Changed the special port.
2479 * KERN_INVALID_ARGUMENT The thread is null,
2480 * Illegal mask bit set.
2481 * Illegal exception behavior
2482 * KERN_FAILURE The thread is dead.
2483 */
2484
2485kern_return_t
2486thread_swap_exception_ports(
0a7de745
A
2487 thread_t thread,
2488 exception_mask_t exception_mask,
2489 ipc_port_t new_port,
2490 exception_behavior_t new_behavior,
2491 thread_state_flavor_t new_flavor,
2492 exception_mask_array_t masks,
2493 mach_msg_type_number_t *CountCnt,
2494 exception_port_array_t ports,
2495 exception_behavior_array_t behaviors,
2496 thread_state_flavor_array_t flavors)
1c79356b 2497{
0a7de745 2498 ipc_port_t old_port[EXC_TYPES_COUNT];
6601e61a 2499 boolean_t privileged = current_task()->sec_token.val[0] == 0;
0a7de745 2500 unsigned int i, j, count;
1c79356b 2501
5ba3f43e
A
2502#if CONFIG_MACF
2503 struct label *new_label;
2504#endif
2505
0a7de745
A
2506 if (thread == THREAD_NULL) {
2507 return KERN_INVALID_ARGUMENT;
2508 }
1c79356b 2509
0a7de745
A
2510 if (exception_mask & ~EXC_MASK_VALID) {
2511 return KERN_INVALID_ARGUMENT;
2512 }
1c79356b
A
2513
2514 if (IP_VALID(new_port)) {
cb323159 2515 switch (new_behavior & ~MACH_EXCEPTION_MASK) {
1c79356b
A
2516 case EXCEPTION_DEFAULT:
2517 case EXCEPTION_STATE:
2518 case EXCEPTION_STATE_IDENTITY:
2519 break;
91447636 2520
1c79356b 2521 default:
0a7de745 2522 return KERN_INVALID_ARGUMENT;
1c79356b
A
2523 }
2524 }
1c79356b 2525
0a7de745
A
2526 if (new_flavor != 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor)) {
2527 return KERN_INVALID_ARGUMENT;
2528 }
fe8ab488 2529
5ba3f43e
A
2530#if CONFIG_MACF
2531 new_label = mac_exc_create_label_for_current_proc();
2532#endif
2533
91447636
A
2534 thread_mtx_lock(thread);
2535
2536 if (!thread->active) {
2537 thread_mtx_unlock(thread);
2538
0a7de745 2539 return KERN_FAILURE;
1c79356b
A
2540 }
2541
39236c6e
A
2542 if (thread->exc_actions == NULL) {
2543 ipc_thread_init_exc_actions(thread);
2544 }
1c79356b 2545
39236c6e
A
2546 assert(EXC_TYPES_COUNT > FIRST_EXCEPTION);
2547 for (count = 0, i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT && count < *CountCnt; ++i) {
39037602
A
2548 if ((exception_mask & (1 << i))
2549#if CONFIG_MACF
0a7de745 2550 && mac_exc_update_action_label(&thread->exc_actions[i], new_label) == 0
39037602 2551#endif
0a7de745 2552 ) {
91447636
A
2553 for (j = 0; j < count; ++j) {
2554 /*
2555 * search for an identical entry, if found
2556 * set corresponding mask for this exception.
2557 */
0a7de745
A
2558 if (thread->exc_actions[i].port == ports[j] &&
2559 thread->exc_actions[i].behavior == behaviors[j] &&
2560 thread->exc_actions[i].flavor == flavors[j]) {
1c79356b
A
2561 masks[j] |= (1 << i);
2562 break;
2563 }
91447636
A
2564 }
2565
1c79356b
A
2566 if (j == count) {
2567 masks[j] = (1 << i);
91447636 2568 ports[j] = ipc_port_copy_send(thread->exc_actions[i].port);
1c79356b 2569
91447636
A
2570 behaviors[j] = thread->exc_actions[i].behavior;
2571 flavors[j] = thread->exc_actions[i].flavor;
2572 ++count;
1c79356b
A
2573 }
2574
91447636
A
2575 old_port[i] = thread->exc_actions[i].port;
2576 thread->exc_actions[i].port = ipc_port_copy_send(new_port);
2577 thread->exc_actions[i].behavior = new_behavior;
2578 thread->exc_actions[i].flavor = new_flavor;
6601e61a 2579 thread->exc_actions[i].privileged = privileged;
0a7de745 2580 } else {
1c79356b 2581 old_port[i] = IP_NULL;
0a7de745 2582 }
91447636 2583 }
1c79356b 2584
91447636
A
2585 thread_mtx_unlock(thread);
2586
5ba3f43e
A
2587#if CONFIG_MACF
2588 mac_exc_free_label(new_label);
2589#endif
0a7de745 2590
39236c6e 2591 while (--i >= FIRST_EXCEPTION) {
0a7de745 2592 if (IP_VALID(old_port[i])) {
1c79356b 2593 ipc_port_release_send(old_port[i]);
0a7de745 2594 }
39236c6e 2595 }
91447636 2596
0a7de745 2597 if (IP_VALID(new_port)) { /* consume send right */
1c79356b 2598 ipc_port_release_send(new_port);
0a7de745 2599 }
91447636 2600
1c79356b 2601 *CountCnt = count;
91447636 2602
0a7de745 2603 return KERN_SUCCESS;
91447636 2604}
1c79356b
A
2605
2606kern_return_t
2607task_swap_exception_ports(
0a7de745
A
2608 task_t task,
2609 exception_mask_t exception_mask,
2610 ipc_port_t new_port,
2611 exception_behavior_t new_behavior,
2612 thread_state_flavor_t new_flavor,
2613 exception_mask_array_t masks,
2614 mach_msg_type_number_t *CountCnt,
2615 exception_port_array_t ports,
2616 exception_behavior_array_t behaviors,
2617 thread_state_flavor_array_t flavors)
1c79356b 2618{
0a7de745 2619 ipc_port_t old_port[EXC_TYPES_COUNT];
8ad349bb 2620 boolean_t privileged = current_task()->sec_token.val[0] == 0;
0a7de745 2621 unsigned int i, j, count;
1c79356b 2622
5ba3f43e
A
2623#if CONFIG_MACF
2624 struct label *new_label;
0a7de745
A
2625#endif
2626
2627 if (task == TASK_NULL) {
2628 return KERN_INVALID_ARGUMENT;
2629 }
1c79356b 2630
0a7de745
A
2631 if (exception_mask & ~EXC_MASK_VALID) {
2632 return KERN_INVALID_ARGUMENT;
2633 }
1c79356b
A
2634
2635 if (IP_VALID(new_port)) {
cb323159 2636 switch (new_behavior & ~MACH_EXCEPTION_MASK) {
1c79356b
A
2637 case EXCEPTION_DEFAULT:
2638 case EXCEPTION_STATE:
2639 case EXCEPTION_STATE_IDENTITY:
2640 break;
91447636 2641
1c79356b 2642 default:
0a7de745 2643 return KERN_INVALID_ARGUMENT;
1c79356b
A
2644 }
2645 }
1c79356b 2646
0a7de745
A
2647 if (new_flavor != 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor)) {
2648 return KERN_INVALID_ARGUMENT;
2649 }
fe8ab488 2650
5ba3f43e
A
2651#if CONFIG_MACF
2652 new_label = mac_exc_create_label_for_current_proc();
2653#endif
0a7de745 2654
1c79356b 2655 itk_lock(task);
91447636 2656
1c79356b
A
2657 if (task->itk_self == IP_NULL) {
2658 itk_unlock(task);
91447636 2659
0a7de745 2660 return KERN_FAILURE;
1c79356b
A
2661 }
2662
39236c6e
A
2663 assert(EXC_TYPES_COUNT > FIRST_EXCEPTION);
2664 for (count = 0, i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT && count < *CountCnt; ++i) {
39037602
A
2665 if ((exception_mask & (1 << i))
2666#if CONFIG_MACF
0a7de745 2667 && mac_exc_update_action_label(&task->exc_actions[i], new_label) == 0
39037602 2668#endif
0a7de745 2669 ) {
1c79356b 2670 for (j = 0; j < count; j++) {
91447636
A
2671 /*
2672 * search for an identical entry, if found
2673 * set corresponding mask for this exception.
2674 */
0a7de745
A
2675 if (task->exc_actions[i].port == ports[j] &&
2676 task->exc_actions[i].behavior == behaviors[j] &&
2677 task->exc_actions[i].flavor == flavors[j]) {
1c79356b
A
2678 masks[j] |= (1 << i);
2679 break;
2680 }
91447636
A
2681 }
2682
1c79356b
A
2683 if (j == count) {
2684 masks[j] = (1 << i);
91447636 2685 ports[j] = ipc_port_copy_send(task->exc_actions[i].port);
1c79356b
A
2686 behaviors[j] = task->exc_actions[i].behavior;
2687 flavors[j] = task->exc_actions[i].flavor;
91447636 2688 ++count;
1c79356b 2689 }
91447636 2690
1c79356b 2691 old_port[i] = task->exc_actions[i].port;
39236c6e 2692
0a7de745 2693 task->exc_actions[i].port = ipc_port_copy_send(new_port);
1c79356b
A
2694 task->exc_actions[i].behavior = new_behavior;
2695 task->exc_actions[i].flavor = new_flavor;
8ad349bb 2696 task->exc_actions[i].privileged = privileged;
0a7de745 2697 } else {
1c79356b 2698 old_port[i] = IP_NULL;
0a7de745 2699 }
91447636 2700 }
1c79356b 2701
1c79356b 2702 itk_unlock(task);
91447636 2703
5ba3f43e
A
2704#if CONFIG_MACF
2705 mac_exc_free_label(new_label);
2706#endif
0a7de745 2707
39236c6e 2708 while (--i >= FIRST_EXCEPTION) {
0a7de745 2709 if (IP_VALID(old_port[i])) {
1c79356b 2710 ipc_port_release_send(old_port[i]);
0a7de745 2711 }
39236c6e 2712 }
91447636 2713
0a7de745 2714 if (IP_VALID(new_port)) { /* consume send right */
1c79356b 2715 ipc_port_release_send(new_port);
0a7de745 2716 }
91447636 2717
1c79356b
A
2718 *CountCnt = count;
2719
0a7de745 2720 return KERN_SUCCESS;
91447636 2721}
1c79356b
A
2722
2723/*
2724 * Routine: thread/task_get_exception_ports [kernel call]
2725 * Purpose:
2726 * Clones a send right for each of the thread/task's exception
2727 * ports specified in the mask and returns the behaviour
2728 * and flavor of said port.
2729 *
2730 * Returns upto [in} CountCnt elements.
2731 *
2732 * Conditions:
2733 * Nothing locked.
2734 * Returns:
2735 * KERN_SUCCESS Extracted a send right.
2736 * KERN_INVALID_ARGUMENT The thread is null,
2737 * Invalid special port,
2738 * Illegal mask bit set.
2739 * KERN_FAILURE The thread is dead.
2740 */
2741
2742kern_return_t
2743thread_get_exception_ports(
0a7de745
A
2744 thread_t thread,
2745 exception_mask_t exception_mask,
2746 exception_mask_array_t masks,
2747 mach_msg_type_number_t *CountCnt,
2748 exception_port_array_t ports,
2749 exception_behavior_array_t behaviors,
2750 thread_state_flavor_array_t flavors)
1c79356b 2751{
0a7de745 2752 unsigned int i, j, count;
1c79356b 2753
0a7de745
A
2754 if (thread == THREAD_NULL) {
2755 return KERN_INVALID_ARGUMENT;
2756 }
1c79356b 2757
0a7de745
A
2758 if (exception_mask & ~EXC_MASK_VALID) {
2759 return KERN_INVALID_ARGUMENT;
2760 }
1c79356b 2761
91447636
A
2762 thread_mtx_lock(thread);
2763
2764 if (!thread->active) {
2765 thread_mtx_unlock(thread);
2766
0a7de745 2767 return KERN_FAILURE;
1c79356b
A
2768 }
2769
2770 count = 0;
2771
39236c6e
A
2772 if (thread->exc_actions == NULL) {
2773 goto done;
2774 }
2775
91447636 2776 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
1c79356b 2777 if (exception_mask & (1 << i)) {
91447636
A
2778 for (j = 0; j < count; ++j) {
2779 /*
2780 * search for an identical entry, if found
2781 * set corresponding mask for this exception.
2782 */
0a7de745
A
2783 if (thread->exc_actions[i].port == ports[j] &&
2784 thread->exc_actions[i].behavior == behaviors[j] &&
2785 thread->exc_actions[i].flavor == flavors[j]) {
1c79356b
A
2786 masks[j] |= (1 << i);
2787 break;
2788 }
91447636
A
2789 }
2790
1c79356b
A
2791 if (j == count) {
2792 masks[j] = (1 << i);
91447636
A
2793 ports[j] = ipc_port_copy_send(thread->exc_actions[i].port);
2794 behaviors[j] = thread->exc_actions[i].behavior;
2795 flavors[j] = thread->exc_actions[i].flavor;
2796 ++count;
0a7de745 2797 if (count >= *CountCnt) {
1c79356b 2798 break;
0a7de745 2799 }
1c79356b
A
2800 }
2801 }
91447636 2802 }
1c79356b 2803
39236c6e 2804done:
91447636 2805 thread_mtx_unlock(thread);
1c79356b
A
2806
2807 *CountCnt = count;
91447636 2808
0a7de745 2809 return KERN_SUCCESS;
91447636 2810}
1c79356b
A
2811
2812kern_return_t
2813task_get_exception_ports(
0a7de745
A
2814 task_t task,
2815 exception_mask_t exception_mask,
2816 exception_mask_array_t masks,
2817 mach_msg_type_number_t *CountCnt,
2818 exception_port_array_t ports,
2819 exception_behavior_array_t behaviors,
2820 thread_state_flavor_array_t flavors)
1c79356b 2821{
0a7de745 2822 unsigned int i, j, count;
1c79356b 2823
0a7de745
A
2824 if (task == TASK_NULL) {
2825 return KERN_INVALID_ARGUMENT;
2826 }
1c79356b 2827
0a7de745
A
2828 if (exception_mask & ~EXC_MASK_VALID) {
2829 return KERN_INVALID_ARGUMENT;
2830 }
1c79356b
A
2831
2832 itk_lock(task);
91447636 2833
1c79356b
A
2834 if (task->itk_self == IP_NULL) {
2835 itk_unlock(task);
91447636 2836
0a7de745 2837 return KERN_FAILURE;
1c79356b
A
2838 }
2839
2840 count = 0;
2841
91447636 2842 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
1c79356b 2843 if (exception_mask & (1 << i)) {
91447636
A
2844 for (j = 0; j < count; ++j) {
2845 /*
2846 * search for an identical entry, if found
2847 * set corresponding mask for this exception.
2848 */
0a7de745
A
2849 if (task->exc_actions[i].port == ports[j] &&
2850 task->exc_actions[i].behavior == behaviors[j] &&
2851 task->exc_actions[i].flavor == flavors[j]) {
1c79356b
A
2852 masks[j] |= (1 << i);
2853 break;
2854 }
91447636
A
2855 }
2856
1c79356b
A
2857 if (j == count) {
2858 masks[j] = (1 << i);
91447636 2859 ports[j] = ipc_port_copy_send(task->exc_actions[i].port);
1c79356b
A
2860 behaviors[j] = task->exc_actions[i].behavior;
2861 flavors[j] = task->exc_actions[i].flavor;
91447636 2862 ++count;
0a7de745 2863 if (count > *CountCnt) {
1c79356b 2864 break;
0a7de745 2865 }
1c79356b
A
2866 }
2867 }
91447636 2868 }
1c79356b
A
2869
2870 itk_unlock(task);
2871
2872 *CountCnt = count;
91447636 2873
0a7de745 2874 return KERN_SUCCESS;
91447636 2875}