]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kern/ipc_tt.c
xnu-2050.48.11.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@
1c79356b 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.
8f6c56a5 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.
17 *
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/*
29 * @OSF_COPYRIGHT@
30 */
31/*
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
34 * All Rights Reserved.
35 *
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.
41 *
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.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
52 *
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
91447636
A
101/* forward declarations */
102task_t convert_port_to_locked_task(ipc_port_t port);
103
1c79356b
A
104
105/*
106 * Routine: ipc_task_init
107 * Purpose:
108 * Initialize a task's IPC state.
109 *
110 * If non-null, some state will be inherited from the parent.
111 * The parent must be appropriately initialized.
112 * Conditions:
113 * Nothing locked.
114 */
115
116void
117ipc_task_init(
118 task_t task,
119 task_t parent)
120{
121 ipc_space_t space;
122 ipc_port_t kport;
0c530ab8 123 ipc_port_t nport;
1c79356b
A
124 kern_return_t kr;
125 int i;
126
127
128 kr = ipc_space_create(&ipc_table_entries[0], &space);
129 if (kr != KERN_SUCCESS)
130 panic("ipc_task_init");
131
2d21ac55 132 space->is_task = task;
1c79356b
A
133
134 kport = ipc_port_alloc_kernel();
135 if (kport == IP_NULL)
136 panic("ipc_task_init");
137
0c530ab8
A
138 nport = ipc_port_alloc_kernel();
139 if (nport == IP_NULL)
140 panic("ipc_task_init");
141
1c79356b
A
142 itk_lock_init(task);
143 task->itk_self = kport;
0c530ab8 144 task->itk_nself = nport;
1c79356b
A
145 task->itk_sself = ipc_port_make_send(kport);
146 task->itk_space = space;
1c79356b 147
2d21ac55
A
148#if CONFIG_MACF_MACH
149 if (parent)
150 mac_task_label_associate(parent, task, &parent->maclabel,
151 &task->maclabel, &kport->ip_label);
152 else
153 mac_task_label_associate_kernel(task, &task->maclabel, &kport->ip_label);
154#endif
155
1c79356b 156 if (parent == TASK_NULL) {
55e303ae
A
157 ipc_port_t port;
158
1c79356b
A
159 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
160 task->exc_actions[i].port = IP_NULL;
161 }/* for */
55e303ae
A
162
163 kr = host_get_host_port(host_priv_self(), &port);
164 assert(kr == KERN_SUCCESS);
165 task->itk_host = port;
166
1c79356b 167 task->itk_bootstrap = IP_NULL;
2d21ac55
A
168 task->itk_seatbelt = IP_NULL;
169 task->itk_gssd = IP_NULL;
2d21ac55 170 task->itk_task_access = IP_NULL;
55e303ae 171
1c79356b
A
172 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
173 task->itk_registered[i] = IP_NULL;
174 } else {
175 itk_lock(parent);
176 assert(parent->itk_self != IP_NULL);
177
178 /* inherit registered ports */
179
180 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
181 task->itk_registered[i] =
182 ipc_port_copy_send(parent->itk_registered[i]);
183
184 /* inherit exception and bootstrap ports */
185
186 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
187 task->exc_actions[i].port =
188 ipc_port_copy_send(parent->exc_actions[i].port);
189 task->exc_actions[i].flavor =
190 parent->exc_actions[i].flavor;
191 task->exc_actions[i].behavior =
192 parent->exc_actions[i].behavior;
8ad349bb
A
193 task->exc_actions[i].privileged =
194 parent->exc_actions[i].privileged;
1c79356b
A
195 }/* for */
196 task->itk_host =
197 ipc_port_copy_send(parent->itk_host);
198
199 task->itk_bootstrap =
200 ipc_port_copy_send(parent->itk_bootstrap);
201
2d21ac55
A
202 task->itk_seatbelt =
203 ipc_port_copy_send(parent->itk_seatbelt);
204
205 task->itk_gssd =
206 ipc_port_copy_send(parent->itk_gssd);
207
2d21ac55
A
208 task->itk_task_access =
209 ipc_port_copy_send(parent->itk_task_access);
210
1c79356b
A
211 itk_unlock(parent);
212 }
213}
214
215/*
216 * Routine: ipc_task_enable
217 * Purpose:
218 * Enable a task for IPC access.
219 * Conditions:
220 * Nothing locked.
221 */
222
223void
224ipc_task_enable(
225 task_t task)
226{
227 ipc_port_t kport;
0c530ab8 228 ipc_port_t nport;
1c79356b
A
229
230 itk_lock(task);
231 kport = task->itk_self;
232 if (kport != IP_NULL)
233 ipc_kobject_set(kport, (ipc_kobject_t) task, IKOT_TASK);
0c530ab8
A
234 nport = task->itk_nself;
235 if (nport != IP_NULL)
236 ipc_kobject_set(nport, (ipc_kobject_t) task, IKOT_TASK_NAME);
1c79356b
A
237 itk_unlock(task);
238}
239
240/*
241 * Routine: ipc_task_disable
242 * Purpose:
243 * Disable IPC access to a task.
244 * Conditions:
245 * Nothing locked.
246 */
247
248void
249ipc_task_disable(
250 task_t task)
251{
252 ipc_port_t kport;
0c530ab8 253 ipc_port_t nport;
1c79356b
A
254
255 itk_lock(task);
256 kport = task->itk_self;
257 if (kport != IP_NULL)
258 ipc_kobject_set(kport, IKO_NULL, IKOT_NONE);
0c530ab8
A
259 nport = task->itk_nself;
260 if (nport != IP_NULL)
261 ipc_kobject_set(nport, IKO_NULL, IKOT_NONE);
1c79356b
A
262 itk_unlock(task);
263}
264
265/*
266 * Routine: ipc_task_terminate
267 * Purpose:
268 * Clean up and destroy a task's IPC state.
269 * Conditions:
270 * Nothing locked. The task must be suspended.
271 * (Or the current thread must be in the task.)
272 */
273
274void
275ipc_task_terminate(
276 task_t task)
277{
278 ipc_port_t kport;
0c530ab8 279 ipc_port_t nport;
1c79356b
A
280 int i;
281
282 itk_lock(task);
283 kport = task->itk_self;
284
285 if (kport == IP_NULL) {
286 /* the task is already terminated (can this happen?) */
287 itk_unlock(task);
288 return;
289 }
6601e61a 290 task->itk_self = IP_NULL;
0c530ab8
A
291
292 nport = task->itk_nself;
293 assert(nport != IP_NULL);
294 task->itk_nself = IP_NULL;
295
1c79356b
A
296 itk_unlock(task);
297
298 /* release the naked send rights */
299
300 if (IP_VALID(task->itk_sself))
301 ipc_port_release_send(task->itk_sself);
302
303 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
304 if (IP_VALID(task->exc_actions[i].port)) {
305 ipc_port_release_send(task->exc_actions[i].port);
306 }
91447636
A
307 }
308
1c79356b
A
309 if (IP_VALID(task->itk_host))
310 ipc_port_release_send(task->itk_host);
311
312 if (IP_VALID(task->itk_bootstrap))
313 ipc_port_release_send(task->itk_bootstrap);
314
2d21ac55
A
315 if (IP_VALID(task->itk_seatbelt))
316 ipc_port_release_send(task->itk_seatbelt);
317
318 if (IP_VALID(task->itk_gssd))
319 ipc_port_release_send(task->itk_gssd);
320
2d21ac55
A
321 if (IP_VALID(task->itk_task_access))
322 ipc_port_release_send(task->itk_task_access);
323
1c79356b
A
324 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
325 if (IP_VALID(task->itk_registered[i]))
326 ipc_port_release_send(task->itk_registered[i]);
327
0c530ab8 328 /* destroy the kernel ports */
1c79356b 329 ipc_port_dealloc_kernel(kport);
0c530ab8 330 ipc_port_dealloc_kernel(nport);
b0d623f7
A
331
332 itk_lock_destroy(task);
1c79356b
A
333}
334
55e303ae
A
335/*
336 * Routine: ipc_task_reset
337 * Purpose:
338 * Reset a task's IPC state to protect it when
0c530ab8
A
339 * it enters an elevated security context. The
340 * task name port can remain the same - since
341 * it represents no specific privilege.
55e303ae
A
342 * Conditions:
343 * Nothing locked. The task must be suspended.
344 * (Or the current thread must be in the task.)
345 */
346
347void
348ipc_task_reset(
349 task_t task)
350{
351 ipc_port_t old_kport, new_kport;
352 ipc_port_t old_sself;
55e303ae
A
353 ipc_port_t old_exc_actions[EXC_TYPES_COUNT];
354 int i;
55e303ae
A
355
356 new_kport = ipc_port_alloc_kernel();
357 if (new_kport == IP_NULL)
358 panic("ipc_task_reset");
359
360 itk_lock(task);
361
362 old_kport = task->itk_self;
363
364 if (old_kport == IP_NULL) {
365 /* the task is already terminated (can this happen?) */
366 itk_unlock(task);
367 ipc_port_dealloc_kernel(new_kport);
368 return;
369 }
370
371 task->itk_self = new_kport;
372 old_sself = task->itk_sself;
373 task->itk_sself = ipc_port_make_send(new_kport);
374 ipc_kobject_set(old_kport, IKO_NULL, IKOT_NONE);
375 ipc_kobject_set(new_kport, (ipc_kobject_t) task, IKOT_TASK);
376
55e303ae 377 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
8ad349bb
A
378 if (!task->exc_actions[i].privileged) {
379 old_exc_actions[i] = task->exc_actions[i].port;
380 task->exc_actions[i].port = IP_NULL;
381 } else {
382 old_exc_actions[i] = IP_NULL;
383 }
55e303ae 384 }/* for */
55e303ae
A
385
386 itk_unlock(task);
387
388 /* release the naked send rights */
389
390 if (IP_VALID(old_sself))
391 ipc_port_release_send(old_sself);
392
55e303ae
A
393 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
394 if (IP_VALID(old_exc_actions[i])) {
395 ipc_port_release_send(old_exc_actions[i]);
396 }
397 }/* for */
55e303ae
A
398
399 /* destroy the kernel port */
400 ipc_port_dealloc_kernel(old_kport);
401}
402
1c79356b
A
403/*
404 * Routine: ipc_thread_init
405 * Purpose:
406 * Initialize a thread's IPC state.
407 * Conditions:
408 * Nothing locked.
409 */
410
411void
412ipc_thread_init(
413 thread_t thread)
414{
91447636
A
415 ipc_port_t kport;
416 int i;
417
418 kport = ipc_port_alloc_kernel();
419 if (kport == IP_NULL)
420 panic("ipc_thread_init");
421
422 thread->ith_self = kport;
423 thread->ith_sself = ipc_port_make_send(kport);
424
425 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i)
426 thread->exc_actions[i].port = IP_NULL;
427
428 ipc_kobject_set(kport, (ipc_kobject_t)thread, IKOT_THREAD);
429
1c79356b 430 ipc_kmsg_queue_init(&thread->ith_messages);
91447636 431
1c79356b
A
432 thread->ith_rpc_reply = IP_NULL;
433}
434
1c79356b 435void
91447636 436ipc_thread_disable(
1c79356b
A
437 thread_t thread)
438{
91447636 439 ipc_port_t kport = thread->ith_self;
1c79356b 440
91447636
A
441 if (kport != IP_NULL)
442 ipc_kobject_set(kport, IKO_NULL, IKOT_NONE);
1c79356b
A
443}
444
445/*
91447636 446 * Routine: ipc_thread_terminate
1c79356b 447 * Purpose:
91447636 448 * Clean up and destroy a thread's IPC state.
1c79356b
A
449 * Conditions:
450 * Nothing locked.
451 */
452
453void
91447636
A
454ipc_thread_terminate(
455 thread_t thread)
1c79356b 456{
91447636 457 ipc_port_t kport = thread->ith_self;
1c79356b 458
91447636
A
459 if (kport != IP_NULL) {
460 int i;
1c79356b 461
91447636
A
462 if (IP_VALID(thread->ith_sself))
463 ipc_port_release_send(thread->ith_sself);
1c79356b 464
91447636 465 thread->ith_sself = thread->ith_self = IP_NULL;
1c79356b 466
91447636
A
467 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
468 if (IP_VALID(thread->exc_actions[i].port))
469 ipc_port_release_send(thread->exc_actions[i].port);
470 }
1c79356b 471
91447636 472 ipc_port_dealloc_kernel(kport);
1c79356b
A
473 }
474
91447636 475 assert(ipc_kmsg_queue_empty(&thread->ith_messages));
1c79356b 476
91447636
A
477 if (thread->ith_rpc_reply != IP_NULL)
478 ipc_port_dealloc_reply(thread->ith_rpc_reply);
1c79356b 479
91447636 480 thread->ith_rpc_reply = IP_NULL;
1c79356b
A
481}
482
6601e61a
A
483/*
484 * Routine: ipc_thread_reset
485 * Purpose:
486 * Reset the IPC state for a given Mach thread when
487 * its task enters an elevated security context.
488 * Both the thread port and its exception ports have
489 * to be reset. Its RPC reply port cannot have any
490 * rights outstanding, so it should be fine.
491 * Conditions:
492 * Nothing locked.
493 */
494
495void
496ipc_thread_reset(
497 thread_t thread)
498{
499 ipc_port_t old_kport, new_kport;
500 ipc_port_t old_sself;
501 ipc_port_t old_exc_actions[EXC_TYPES_COUNT];
502 int i;
503
504 new_kport = ipc_port_alloc_kernel();
505 if (new_kport == IP_NULL)
506 panic("ipc_task_reset");
507
508 thread_mtx_lock(thread);
509
510 old_kport = thread->ith_self;
511
512 if (old_kport == IP_NULL) {
513 /* the is already terminated (can this happen?) */
514 thread_mtx_unlock(thread);
515 ipc_port_dealloc_kernel(new_kport);
516 return;
517 }
518
519 thread->ith_self = new_kport;
520 old_sself = thread->ith_sself;
521 thread->ith_sself = ipc_port_make_send(new_kport);
522 ipc_kobject_set(old_kport, IKO_NULL, IKOT_NONE);
523 ipc_kobject_set(new_kport, (ipc_kobject_t) thread, IKOT_THREAD);
524
525 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
526 if (!thread->exc_actions[i].privileged) {
527 old_exc_actions[i] = thread->exc_actions[i].port;
528 thread->exc_actions[i].port = IP_NULL;
529 } else {
530 old_exc_actions[i] = IP_NULL;
531 }
532 }/* for */
533
534 thread_mtx_unlock(thread);
535
536 /* release the naked send rights */
537
538 if (IP_VALID(old_sself))
539 ipc_port_release_send(old_sself);
540
541 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
542 if (IP_VALID(old_exc_actions[i])) {
543 ipc_port_release_send(old_exc_actions[i]);
544 }
545 }/* for */
546
547 /* destroy the kernel port */
548 ipc_port_dealloc_kernel(old_kport);
549}
550
1c79356b
A
551/*
552 * Routine: retrieve_task_self_fast
553 * Purpose:
554 * Optimized version of retrieve_task_self,
555 * that only works for the current task.
556 *
557 * Return a send right (possibly null/dead)
558 * for the task's user-visible self port.
559 * Conditions:
560 * Nothing locked.
561 */
562
563ipc_port_t
564retrieve_task_self_fast(
565 register task_t task)
566{
567 register ipc_port_t port;
568
569 assert(task == current_task());
570
571 itk_lock(task);
572 assert(task->itk_self != IP_NULL);
573
574 if ((port = task->itk_sself) == task->itk_self) {
575 /* no interposing */
576
577 ip_lock(port);
578 assert(ip_active(port));
579 ip_reference(port);
580 port->ip_srights++;
581 ip_unlock(port);
582 } else
583 port = ipc_port_copy_send(port);
584 itk_unlock(task);
585
586 return port;
587}
588
589/*
91447636 590 * Routine: retrieve_thread_self_fast
1c79356b 591 * Purpose:
1c79356b
A
592 * Return a send right (possibly null/dead)
593 * for the thread's user-visible self port.
91447636
A
594 *
595 * Only works for the current thread.
596 *
1c79356b
A
597 * Conditions:
598 * Nothing locked.
599 */
600
601ipc_port_t
91447636
A
602retrieve_thread_self_fast(
603 thread_t thread)
1c79356b
A
604{
605 register ipc_port_t port;
606
91447636
A
607 assert(thread == current_thread());
608
609 thread_mtx_lock(thread);
1c79356b 610
91447636
A
611 assert(thread->ith_self != IP_NULL);
612
613 if ((port = thread->ith_sself) == thread->ith_self) {
1c79356b
A
614 /* no interposing */
615
616 ip_lock(port);
617 assert(ip_active(port));
618 ip_reference(port);
619 port->ip_srights++;
620 ip_unlock(port);
91447636
A
621 }
622 else
1c79356b 623 port = ipc_port_copy_send(port);
91447636
A
624
625 thread_mtx_unlock(thread);
1c79356b
A
626
627 return port;
628}
629
630/*
631 * Routine: task_self_trap [mach trap]
632 * Purpose:
633 * Give the caller send rights for his own task port.
634 * Conditions:
635 * Nothing locked.
636 * Returns:
637 * MACH_PORT_NULL if there are any resource failures
638 * or other errors.
639 */
640
641mach_port_name_t
91447636
A
642task_self_trap(
643 __unused struct task_self_trap_args *args)
1c79356b
A
644{
645 task_t task = current_task();
646 ipc_port_t sright;
91447636 647 mach_port_name_t name;
1c79356b
A
648
649 sright = retrieve_task_self_fast(task);
91447636
A
650 name = ipc_port_copyout_send(sright, task->itk_space);
651 return name;
1c79356b
A
652}
653
654/*
655 * Routine: thread_self_trap [mach trap]
656 * Purpose:
657 * Give the caller send rights for his own thread port.
658 * Conditions:
659 * Nothing locked.
660 * Returns:
661 * MACH_PORT_NULL if there are any resource failures
662 * or other errors.
663 */
664
665mach_port_name_t
91447636
A
666thread_self_trap(
667 __unused struct thread_self_trap_args *args)
1c79356b 668{
91447636
A
669 thread_t thread = current_thread();
670 task_t task = thread->task;
1c79356b 671 ipc_port_t sright;
91447636
A
672 mach_port_name_t name;
673
674 sright = retrieve_thread_self_fast(thread);
675 name = ipc_port_copyout_send(sright, task->itk_space);
676 return name;
1c79356b 677
1c79356b
A
678}
679
680/*
681 * Routine: mach_reply_port [mach trap]
682 * Purpose:
683 * Allocate a port for the caller.
684 * Conditions:
685 * Nothing locked.
686 * Returns:
687 * MACH_PORT_NULL if there are any resource failures
688 * or other errors.
689 */
690
691mach_port_name_t
91447636
A
692mach_reply_port(
693 __unused struct mach_reply_port_args *args)
1c79356b
A
694{
695 ipc_port_t port;
696 mach_port_name_t name;
697 kern_return_t kr;
698
699 kr = ipc_port_alloc(current_task()->itk_space, &name, &port);
700 if (kr == KERN_SUCCESS)
701 ip_unlock(port);
702 else
703 name = MACH_PORT_NULL;
1c79356b
A
704 return name;
705}
706
91447636
A
707/*
708 * Routine: thread_get_special_port [kernel call]
709 * Purpose:
710 * Clones a send right for one of the thread's
711 * special ports.
712 * Conditions:
713 * Nothing locked.
714 * Returns:
715 * KERN_SUCCESS Extracted a send right.
716 * KERN_INVALID_ARGUMENT The thread is null.
717 * KERN_FAILURE The thread is dead.
718 * KERN_INVALID_ARGUMENT Invalid special port.
719 */
720
721kern_return_t
722thread_get_special_port(
723 thread_t thread,
724 int which,
725 ipc_port_t *portp)
726{
727 kern_return_t result = KERN_SUCCESS;
728 ipc_port_t *whichp;
729
730 if (thread == THREAD_NULL)
731 return (KERN_INVALID_ARGUMENT);
732
733 switch (which) {
734
735 case THREAD_KERNEL_PORT:
736 whichp = &thread->ith_sself;
737 break;
738
739 default:
740 return (KERN_INVALID_ARGUMENT);
741 }
742
743 thread_mtx_lock(thread);
744
745 if (thread->active)
746 *portp = ipc_port_copy_send(*whichp);
747 else
748 result = KERN_FAILURE;
749
750 thread_mtx_unlock(thread);
751
752 return (result);
753}
754
755/*
756 * Routine: thread_set_special_port [kernel call]
757 * Purpose:
758 * Changes one of the thread's special ports,
759 * setting it to the supplied send right.
760 * Conditions:
761 * Nothing locked. If successful, consumes
762 * the supplied send right.
763 * Returns:
764 * KERN_SUCCESS Changed the special port.
765 * KERN_INVALID_ARGUMENT The thread is null.
766 * KERN_FAILURE The thread is dead.
767 * KERN_INVALID_ARGUMENT Invalid special port.
768 */
769
770kern_return_t
771thread_set_special_port(
772 thread_t thread,
773 int which,
774 ipc_port_t port)
775{
776 kern_return_t result = KERN_SUCCESS;
777 ipc_port_t *whichp, old = IP_NULL;
778
779 if (thread == THREAD_NULL)
780 return (KERN_INVALID_ARGUMENT);
781
782 switch (which) {
783
784 case THREAD_KERNEL_PORT:
785 whichp = &thread->ith_sself;
786 break;
787
788 default:
789 return (KERN_INVALID_ARGUMENT);
790 }
791
792 thread_mtx_lock(thread);
793
794 if (thread->active) {
795 old = *whichp;
796 *whichp = port;
797 }
798 else
799 result = KERN_FAILURE;
800
801 thread_mtx_unlock(thread);
802
803 if (IP_VALID(old))
804 ipc_port_release_send(old);
805
806 return (result);
807}
808
1c79356b
A
809/*
810 * Routine: task_get_special_port [kernel call]
811 * Purpose:
812 * Clones a send right for one of the task's
813 * special ports.
814 * Conditions:
815 * Nothing locked.
816 * Returns:
817 * KERN_SUCCESS Extracted a send right.
818 * KERN_INVALID_ARGUMENT The task is null.
819 * KERN_FAILURE The task/space is dead.
820 * KERN_INVALID_ARGUMENT Invalid special port.
821 */
822
823kern_return_t
824task_get_special_port(
825 task_t task,
826 int which,
827 ipc_port_t *portp)
828{
1c79356b
A
829 ipc_port_t port;
830
831 if (task == TASK_NULL)
832 return KERN_INVALID_ARGUMENT;
833
0c530ab8
A
834 itk_lock(task);
835 if (task->itk_self == IP_NULL) {
836 itk_unlock(task);
837 return KERN_FAILURE;
838 }
839
1c79356b
A
840 switch (which) {
841 case TASK_KERNEL_PORT:
0c530ab8
A
842 port = ipc_port_copy_send(task->itk_sself);
843 break;
844
845 case TASK_NAME_PORT:
846 port = ipc_port_make_send(task->itk_nself);
1c79356b
A
847 break;
848
849 case TASK_HOST_PORT:
0c530ab8 850 port = ipc_port_copy_send(task->itk_host);
1c79356b
A
851 break;
852
853 case TASK_BOOTSTRAP_PORT:
0c530ab8 854 port = ipc_port_copy_send(task->itk_bootstrap);
1c79356b
A
855 break;
856
2d21ac55
A
857 case TASK_SEATBELT_PORT:
858 port = ipc_port_copy_send(task->itk_seatbelt);
859 break;
860
2d21ac55
A
861 case TASK_ACCESS_PORT:
862 port = ipc_port_copy_send(task->itk_task_access);
863 break;
864
1c79356b 865 default:
2d21ac55 866 itk_unlock(task);
1c79356b
A
867 return KERN_INVALID_ARGUMENT;
868 }
1c79356b
A
869 itk_unlock(task);
870
871 *portp = port;
872 return KERN_SUCCESS;
873}
874
875/*
876 * Routine: task_set_special_port [kernel call]
877 * Purpose:
878 * Changes one of the task's special ports,
879 * setting it to the supplied send right.
880 * Conditions:
881 * Nothing locked. If successful, consumes
882 * the supplied send right.
883 * Returns:
884 * KERN_SUCCESS Changed the special port.
885 * KERN_INVALID_ARGUMENT The task is null.
886 * KERN_FAILURE The task/space is dead.
887 * KERN_INVALID_ARGUMENT Invalid special port.
2d21ac55 888 * KERN_NO_ACCESS Attempted overwrite of seatbelt port.
1c79356b
A
889 */
890
891kern_return_t
892task_set_special_port(
893 task_t task,
894 int which,
895 ipc_port_t port)
896{
897 ipc_port_t *whichp;
898 ipc_port_t old;
899
900 if (task == TASK_NULL)
901 return KERN_INVALID_ARGUMENT;
902
903 switch (which) {
904 case TASK_KERNEL_PORT:
905 whichp = &task->itk_sself;
906 break;
907
908 case TASK_HOST_PORT:
909 whichp = &task->itk_host;
910 break;
911
912 case TASK_BOOTSTRAP_PORT:
913 whichp = &task->itk_bootstrap;
914 break;
915
2d21ac55
A
916 case TASK_SEATBELT_PORT:
917 whichp = &task->itk_seatbelt;
918 break;
919
2d21ac55
A
920 case TASK_ACCESS_PORT:
921 whichp = &task->itk_task_access;
922 break;
923
1c79356b
A
924 default:
925 return KERN_INVALID_ARGUMENT;
926 }/* switch */
927
928 itk_lock(task);
929 if (task->itk_self == IP_NULL) {
930 itk_unlock(task);
931 return KERN_FAILURE;
932 }
933
2d21ac55
A
934 /* do not allow overwrite of seatbelt or task access ports */
935 if ((TASK_SEATBELT_PORT == which || TASK_ACCESS_PORT == which)
936 && IP_VALID(*whichp)) {
937 itk_unlock(task);
938 return KERN_NO_ACCESS;
939 }
940
941#if CONFIG_MACF_MACH
942 if (mac_task_check_service(current_task(), task, "set_special_port")) {
943 itk_unlock(task);
944 return KERN_NO_ACCESS;
945 }
946#endif
947
1c79356b
A
948 old = *whichp;
949 *whichp = port;
950 itk_unlock(task);
951
952 if (IP_VALID(old))
953 ipc_port_release_send(old);
954 return KERN_SUCCESS;
955}
956
957
958/*
959 * Routine: mach_ports_register [kernel call]
960 * Purpose:
961 * Stash a handful of port send rights in the task.
962 * Child tasks will inherit these rights, but they
963 * must use mach_ports_lookup to acquire them.
964 *
965 * The rights are supplied in a (wired) kalloc'd segment.
966 * Rights which aren't supplied are assumed to be null.
967 * Conditions:
968 * Nothing locked. If successful, consumes
969 * the supplied rights and memory.
970 * Returns:
971 * KERN_SUCCESS Stashed the port rights.
972 * KERN_INVALID_ARGUMENT The task is null.
973 * KERN_INVALID_ARGUMENT The task is dead.
974 * KERN_INVALID_ARGUMENT Too many port rights supplied.
975 */
976
977kern_return_t
978mach_ports_register(
979 task_t task,
980 mach_port_array_t memory,
981 mach_msg_type_number_t portsCnt)
982{
983 ipc_port_t ports[TASK_PORT_REGISTER_MAX];
91447636 984 unsigned int i;
1c79356b
A
985
986 if ((task == TASK_NULL) ||
987 (portsCnt > TASK_PORT_REGISTER_MAX))
988 return KERN_INVALID_ARGUMENT;
989
990 /*
991 * Pad the port rights with nulls.
992 */
993
994 for (i = 0; i < portsCnt; i++)
995 ports[i] = memory[i];
996 for (; i < TASK_PORT_REGISTER_MAX; i++)
997 ports[i] = IP_NULL;
998
999 itk_lock(task);
1000 if (task->itk_self == IP_NULL) {
1001 itk_unlock(task);
1002 return KERN_INVALID_ARGUMENT;
1003 }
1004
1005 /*
1006 * Replace the old send rights with the new.
1007 * Release the old rights after unlocking.
1008 */
1009
1010 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) {
1011 ipc_port_t old;
1012
1013 old = task->itk_registered[i];
1014 task->itk_registered[i] = ports[i];
1015 ports[i] = old;
1016 }
1017
1018 itk_unlock(task);
1019
1020 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
1021 if (IP_VALID(ports[i]))
1022 ipc_port_release_send(ports[i]);
1023
1024 /*
1025 * Now that the operation is known to be successful,
1026 * we can free the memory.
1027 */
1028
1029 if (portsCnt != 0)
91447636 1030 kfree(memory,
1c79356b
A
1031 (vm_size_t) (portsCnt * sizeof(mach_port_t)));
1032
1033 return KERN_SUCCESS;
1034}
1035
1036/*
1037 * Routine: mach_ports_lookup [kernel call]
1038 * Purpose:
1039 * Retrieves (clones) the stashed port send rights.
1040 * Conditions:
1041 * Nothing locked. If successful, the caller gets
1042 * rights and memory.
1043 * Returns:
1044 * KERN_SUCCESS Retrieved the send rights.
1045 * KERN_INVALID_ARGUMENT The task is null.
1046 * KERN_INVALID_ARGUMENT The task is dead.
1047 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1048 */
1049
1050kern_return_t
1051mach_ports_lookup(
1052 task_t task,
1053 mach_port_array_t *portsp,
1054 mach_msg_type_number_t *portsCnt)
1055{
91447636 1056 void *memory;
1c79356b
A
1057 vm_size_t size;
1058 ipc_port_t *ports;
1059 int i;
1060
1c79356b
A
1061 if (task == TASK_NULL)
1062 return KERN_INVALID_ARGUMENT;
1063
1064 size = (vm_size_t) (TASK_PORT_REGISTER_MAX * sizeof(ipc_port_t));
1065
1066 memory = kalloc(size);
1067 if (memory == 0)
1068 return KERN_RESOURCE_SHORTAGE;
1069
1070 itk_lock(task);
1071 if (task->itk_self == IP_NULL) {
1072 itk_unlock(task);
1073
1074 kfree(memory, size);
1075 return KERN_INVALID_ARGUMENT;
1076 }
1077
1078 ports = (ipc_port_t *) memory;
1079
1080 /*
1081 * Clone port rights. Because kalloc'd memory
1082 * is wired, we won't fault while holding the task lock.
1083 */
1084
1085 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
1086 ports[i] = ipc_port_copy_send(task->itk_registered[i]);
1087
1088 itk_unlock(task);
1089
1090 *portsp = (mach_port_array_t) ports;
1091 *portsCnt = TASK_PORT_REGISTER_MAX;
1092 return KERN_SUCCESS;
1093}
1094
1095/*
1096 * Routine: convert_port_to_locked_task
1097 * Purpose:
1098 * Internal helper routine to convert from a port to a locked
1099 * task. Used by several routines that try to convert from a
1100 * task port to a reference on some task related object.
1101 * Conditions:
1102 * Nothing locked, blocking OK.
1103 */
1104task_t
1105convert_port_to_locked_task(ipc_port_t port)
1106{
2d21ac55
A
1107 int try_failed_count = 0;
1108
1c79356b
A
1109 while (IP_VALID(port)) {
1110 task_t task;
1111
1112 ip_lock(port);
1113 if (!ip_active(port) || (ip_kotype(port) != IKOT_TASK)) {
1114 ip_unlock(port);
1115 return TASK_NULL;
1116 }
1117 task = (task_t) port->ip_kobject;
1118 assert(task != TASK_NULL);
1119
1120 /*
1121 * Normal lock ordering puts task_lock() before ip_lock().
1122 * Attempt out-of-order locking here.
1123 */
1124 if (task_lock_try(task)) {
1125 ip_unlock(port);
1126 return(task);
1127 }
2d21ac55 1128 try_failed_count++;
1c79356b
A
1129
1130 ip_unlock(port);
2d21ac55 1131 mutex_pause(try_failed_count);
1c79356b
A
1132 }
1133 return TASK_NULL;
1134}
1135
1136/*
1137 * Routine: convert_port_to_task
1138 * Purpose:
1139 * Convert from a port to a task.
1140 * Doesn't consume the port ref; produces a task ref,
1141 * which may be null.
1142 * Conditions:
1143 * Nothing locked.
1144 */
1145task_t
1146convert_port_to_task(
91447636 1147 ipc_port_t port)
1c79356b 1148{
91447636 1149 task_t task = TASK_NULL;
1c79356b 1150
91447636
A
1151 if (IP_VALID(port)) {
1152 ip_lock(port);
1153
1154 if ( ip_active(port) &&
1155 ip_kotype(port) == IKOT_TASK ) {
1156 task = (task_t)port->ip_kobject;
1157 assert(task != TASK_NULL);
1158
1159 task_reference_internal(task);
1160 }
1161
1162 ip_unlock(port);
1c79356b 1163 }
91447636
A
1164
1165 return (task);
1c79356b
A
1166}
1167
0c530ab8
A
1168/*
1169 * Routine: convert_port_to_task_name
1170 * Purpose:
1171 * Convert from a port to a task name.
1172 * Doesn't consume the port ref; produces a task name ref,
1173 * which may be null.
1174 * Conditions:
1175 * Nothing locked.
1176 */
1177task_name_t
1178convert_port_to_task_name(
1179 ipc_port_t port)
1180{
1181 task_name_t task = TASK_NULL;
1182
1183 if (IP_VALID(port)) {
1184 ip_lock(port);
1185
1186 if ( ip_active(port) &&
1187 (ip_kotype(port) == IKOT_TASK ||
1188 ip_kotype(port) == IKOT_TASK_NAME)) {
1189 task = (task_name_t)port->ip_kobject;
1190 assert(task != TASK_NAME_NULL);
1191
1192 task_reference_internal(task);
1193 }
1194
1195 ip_unlock(port);
1196 }
1197
1198 return (task);
1199}
1200
1c79356b
A
1201/*
1202 * Routine: convert_port_to_space
1203 * Purpose:
1204 * Convert from a port to a space.
1205 * Doesn't consume the port ref; produces a space ref,
1206 * which may be null.
1207 * Conditions:
1208 * Nothing locked.
1209 */
1210ipc_space_t
1211convert_port_to_space(
1212 ipc_port_t port)
1213{
1214 ipc_space_t space;
1215 task_t task;
1216
1217 task = convert_port_to_locked_task(port);
1218
1219 if (task == TASK_NULL)
1220 return IPC_SPACE_NULL;
1221
1222 if (!task->active) {
1223 task_unlock(task);
1224 return IPC_SPACE_NULL;
1225 }
1226
1227 space = task->itk_space;
1228 is_reference(space);
1229 task_unlock(task);
1230 return (space);
1231}
1232
1c79356b
A
1233/*
1234 * Routine: convert_port_to_map
1235 * Purpose:
1236 * Convert from a port to a map.
1237 * Doesn't consume the port ref; produces a map ref,
1238 * which may be null.
1239 * Conditions:
1240 * Nothing locked.
1241 */
1242
1243vm_map_t
1244convert_port_to_map(
1245 ipc_port_t port)
1246{
1247 task_t task;
1248 vm_map_t map;
1249
1250 task = convert_port_to_locked_task(port);
1251
1252 if (task == TASK_NULL)
1253 return VM_MAP_NULL;
1254
1255 if (!task->active) {
1256 task_unlock(task);
1257 return VM_MAP_NULL;
1258 }
1259
1260 map = task->map;
1261 vm_map_reference_swap(map);
1262 task_unlock(task);
1263 return map;
1264}
1265
1266
1267/*
91447636 1268 * Routine: convert_port_to_thread
1c79356b 1269 * Purpose:
91447636
A
1270 * Convert from a port to a thread.
1271 * Doesn't consume the port ref; produces an thread ref,
1c79356b
A
1272 * which may be null.
1273 * Conditions:
1274 * Nothing locked.
1275 */
1276
91447636
A
1277thread_t
1278convert_port_to_thread(
1279 ipc_port_t port)
1c79356b 1280{
91447636 1281 thread_t thread = THREAD_NULL;
1c79356b 1282
91447636 1283 if (IP_VALID(port)) {
1c79356b 1284 ip_lock(port);
1c79356b 1285
91447636
A
1286 if ( ip_active(port) &&
1287 ip_kotype(port) == IKOT_THREAD ) {
1288 thread = (thread_t)port->ip_kobject;
1289 assert(thread != THREAD_NULL);
1c79356b 1290
91447636 1291 thread_reference_internal(thread);
1c79356b 1292 }
91447636
A
1293
1294 ip_unlock(port);
1c79356b 1295 }
91447636
A
1296
1297 return (thread);
1c79356b
A
1298}
1299
1300/*
91447636 1301 * Routine: port_name_to_thread
1c79356b 1302 * Purpose:
91447636
A
1303 * Convert from a port name to an thread reference
1304 * A name of MACH_PORT_NULL is valid for the null thread.
1c79356b
A
1305 * Conditions:
1306 * Nothing locked.
1307 */
91447636
A
1308thread_t
1309port_name_to_thread(
1c79356b
A
1310 mach_port_name_t name)
1311{
91447636
A
1312 thread_t thread = THREAD_NULL;
1313 ipc_port_t kport;
1c79356b
A
1314
1315 if (MACH_PORT_VALID(name)) {
91447636
A
1316 if (ipc_object_copyin(current_space(), name,
1317 MACH_MSG_TYPE_COPY_SEND,
1318 (ipc_object_t *)&kport) != KERN_SUCCESS)
1319 return (THREAD_NULL);
1c79356b 1320
91447636 1321 thread = convert_port_to_thread(kport);
1c79356b 1322
91447636
A
1323 if (IP_VALID(kport))
1324 ipc_port_release_send(kport);
1c79356b 1325 }
91447636
A
1326
1327 return (thread);
1c79356b
A
1328}
1329
1330task_t
1331port_name_to_task(
1332 mach_port_name_t name)
1333{
1334 ipc_port_t kern_port;
1335 kern_return_t kr;
1336 task_t task = TASK_NULL;
1337
1338 if (MACH_PORT_VALID(name)) {
1339 kr = ipc_object_copyin(current_space(), name,
1340 MACH_MSG_TYPE_COPY_SEND,
1341 (ipc_object_t *) &kern_port);
1342 if (kr != KERN_SUCCESS)
1343 return TASK_NULL;
1344
1345 task = convert_port_to_task(kern_port);
1346
1347 if (IP_VALID(kern_port))
1348 ipc_port_release_send(kern_port);
1349 }
1350 return task;
1351}
1352
1353/*
1354 * Routine: convert_task_to_port
1355 * Purpose:
1356 * Convert from a task to a port.
1357 * Consumes a task ref; produces a naked send right
1358 * which may be invalid.
1359 * Conditions:
1360 * Nothing locked.
1361 */
1362
1363ipc_port_t
1364convert_task_to_port(
1365 task_t task)
1366{
1367 ipc_port_t port;
1368
1369 itk_lock(task);
1370 if (task->itk_self != IP_NULL)
1c79356b
A
1371 port = ipc_port_make_send(task->itk_self);
1372 else
1373 port = IP_NULL;
1374 itk_unlock(task);
1375
1376 task_deallocate(task);
1377 return port;
1378}
1379
0c530ab8
A
1380/*
1381 * Routine: convert_task_name_to_port
1382 * Purpose:
1383 * Convert from a task name ref to a port.
1384 * Consumes a task name ref; produces a naked send right
1385 * which may be invalid.
1386 * Conditions:
1387 * Nothing locked.
1388 */
1389
1390ipc_port_t
1391convert_task_name_to_port(
1392 task_name_t task_name)
1393{
1394 ipc_port_t port;
1395
1396 itk_lock(task_name);
1397 if (task_name->itk_nself != IP_NULL)
1398 port = ipc_port_make_send(task_name->itk_nself);
1399 else
1400 port = IP_NULL;
1401 itk_unlock(task_name);
1402
1403 task_name_deallocate(task_name);
1404 return port;
1405}
1406
1c79356b 1407/*
91447636 1408 * Routine: convert_thread_to_port
1c79356b 1409 * Purpose:
91447636
A
1410 * Convert from a thread to a port.
1411 * Consumes an thread ref; produces a naked send right
1c79356b
A
1412 * which may be invalid.
1413 * Conditions:
1414 * Nothing locked.
1415 */
1416
1417ipc_port_t
91447636
A
1418convert_thread_to_port(
1419 thread_t thread)
1c79356b 1420{
91447636 1421 ipc_port_t port;
1c79356b 1422
91447636
A
1423 thread_mtx_lock(thread);
1424
1425 if (thread->ith_self != IP_NULL)
1426 port = ipc_port_make_send(thread->ith_self);
1c79356b
A
1427 else
1428 port = IP_NULL;
1c79356b 1429
91447636
A
1430 thread_mtx_unlock(thread);
1431
1432 thread_deallocate(thread);
1433
1434 return (port);
1c79356b
A
1435}
1436
1437/*
1438 * Routine: space_deallocate
1439 * Purpose:
1440 * Deallocate a space ref produced by convert_port_to_space.
1441 * Conditions:
1442 * Nothing locked.
1443 */
1444
1445void
1446space_deallocate(
1447 ipc_space_t space)
1448{
1449 if (space != IS_NULL)
1450 is_release(space);
1451}
1452
1453/*
1454 * Routine: thread/task_set_exception_ports [kernel call]
1455 * Purpose:
1456 * Sets the thread/task exception port, flavor and
1457 * behavior for the exception types specified by the mask.
1458 * There will be one send right per exception per valid
1459 * port.
1460 * Conditions:
1461 * Nothing locked. If successful, consumes
1462 * the supplied send right.
1463 * Returns:
1464 * KERN_SUCCESS Changed the special port.
1465 * KERN_INVALID_ARGUMENT The thread is null,
1466 * Illegal mask bit set.
1467 * Illegal exception behavior
1468 * KERN_FAILURE The thread is dead.
1469 */
1470
1471kern_return_t
1472thread_set_exception_ports(
91447636 1473 thread_t thread,
1c79356b 1474 exception_mask_t exception_mask,
91447636
A
1475 ipc_port_t new_port,
1476 exception_behavior_t new_behavior,
1477 thread_state_flavor_t new_flavor)
1c79356b 1478{
91447636 1479 ipc_port_t old_port[EXC_TYPES_COUNT];
6601e61a 1480 boolean_t privileged = current_task()->sec_token.val[0] == 0;
1c79356b 1481 register int i;
1c79356b 1482
91447636
A
1483 if (thread == THREAD_NULL)
1484 return (KERN_INVALID_ARGUMENT);
1c79356b 1485
b0d623f7 1486 if (exception_mask & ~EXC_MASK_VALID)
91447636 1487 return (KERN_INVALID_ARGUMENT);
1c79356b
A
1488
1489 if (IP_VALID(new_port)) {
2d21ac55 1490 switch (new_behavior & ~MACH_EXCEPTION_CODES) {
91447636 1491
1c79356b
A
1492 case EXCEPTION_DEFAULT:
1493 case EXCEPTION_STATE:
1494 case EXCEPTION_STATE_IDENTITY:
1495 break;
91447636 1496
1c79356b 1497 default:
91447636 1498 return (KERN_INVALID_ARGUMENT);
1c79356b
A
1499 }
1500 }
1501
1502 /*
1503 * Check the validity of the thread_state_flavor by calling the
1504 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in
1505 * osfmk/mach/ARCHITECTURE/thread_status.h
1506 */
91447636
A
1507 if (!VALID_THREAD_STATE_FLAVOR(new_flavor))
1508 return (KERN_INVALID_ARGUMENT);
1c79356b 1509
91447636
A
1510 thread_mtx_lock(thread);
1511
1512 if (!thread->active) {
1513 thread_mtx_unlock(thread);
1514
1515 return (KERN_FAILURE);
1c79356b
A
1516 }
1517
91447636 1518 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
1c79356b 1519 if (exception_mask & (1 << i)) {
91447636
A
1520 old_port[i] = thread->exc_actions[i].port;
1521 thread->exc_actions[i].port = ipc_port_copy_send(new_port);
1522 thread->exc_actions[i].behavior = new_behavior;
1523 thread->exc_actions[i].flavor = new_flavor;
6601e61a 1524 thread->exc_actions[i].privileged = privileged;
91447636
A
1525 }
1526 else
1c79356b 1527 old_port[i] = IP_NULL;
91447636
A
1528 }
1529
1530 thread_mtx_unlock(thread);
1531
1532 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i)
1c79356b
A
1533 if (IP_VALID(old_port[i]))
1534 ipc_port_release_send(old_port[i]);
91447636 1535
1c79356b
A
1536 if (IP_VALID(new_port)) /* consume send right */
1537 ipc_port_release_send(new_port);
1538
91447636
A
1539 return (KERN_SUCCESS);
1540}
1c79356b
A
1541
1542kern_return_t
1543task_set_exception_ports(
91447636 1544 task_t task,
1c79356b 1545 exception_mask_t exception_mask,
91447636
A
1546 ipc_port_t new_port,
1547 exception_behavior_t new_behavior,
1548 thread_state_flavor_t new_flavor)
1c79356b 1549{
91447636 1550 ipc_port_t old_port[EXC_TYPES_COUNT];
8ad349bb 1551 boolean_t privileged = current_task()->sec_token.val[0] == 0;
1c79356b 1552 register int i;
1c79356b 1553
91447636
A
1554 if (task == TASK_NULL)
1555 return (KERN_INVALID_ARGUMENT);
1c79356b 1556
b0d623f7 1557 if (exception_mask & ~EXC_MASK_VALID)
91447636 1558 return (KERN_INVALID_ARGUMENT);
1c79356b
A
1559
1560 if (IP_VALID(new_port)) {
2d21ac55 1561 switch (new_behavior & ~MACH_EXCEPTION_CODES) {
91447636 1562
1c79356b
A
1563 case EXCEPTION_DEFAULT:
1564 case EXCEPTION_STATE:
1565 case EXCEPTION_STATE_IDENTITY:
1566 break;
91447636 1567
1c79356b 1568 default:
91447636 1569 return (KERN_INVALID_ARGUMENT);
1c79356b
A
1570 }
1571 }
1c79356b 1572
91447636
A
1573 itk_lock(task);
1574
1575 if (task->itk_self == IP_NULL) {
1576 itk_unlock(task);
1577
1578 return (KERN_FAILURE);
1579 }
1580
1581 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
1c79356b
A
1582 if (exception_mask & (1 << i)) {
1583 old_port[i] = task->exc_actions[i].port;
1584 task->exc_actions[i].port =
1585 ipc_port_copy_send(new_port);
1586 task->exc_actions[i].behavior = new_behavior;
1587 task->exc_actions[i].flavor = new_flavor;
8ad349bb 1588 task->exc_actions[i].privileged = privileged;
91447636
A
1589 }
1590 else
1c79356b 1591 old_port[i] = IP_NULL;
91447636 1592 }
1c79356b 1593
91447636
A
1594 itk_unlock(task);
1595
1596 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i)
1c79356b
A
1597 if (IP_VALID(old_port[i]))
1598 ipc_port_release_send(old_port[i]);
91447636 1599
1c79356b
A
1600 if (IP_VALID(new_port)) /* consume send right */
1601 ipc_port_release_send(new_port);
1602
91447636
A
1603 return (KERN_SUCCESS);
1604}
1c79356b
A
1605
1606/*
1607 * Routine: thread/task_swap_exception_ports [kernel call]
1608 * Purpose:
1609 * Sets the thread/task exception port, flavor and
1610 * behavior for the exception types specified by the
1611 * mask.
1612 *
1613 * The old ports, behavior and flavors are returned
1614 * Count specifies the array sizes on input and
1615 * the number of returned ports etc. on output. The
1616 * arrays must be large enough to hold all the returned
1617 * data, MIG returnes an error otherwise. The masks
1618 * array specifies the corresponding exception type(s).
1619 *
1620 * Conditions:
1621 * Nothing locked. If successful, consumes
1622 * the supplied send right.
1623 *
1624 * Returns upto [in} CountCnt elements.
1625 * Returns:
1626 * KERN_SUCCESS Changed the special port.
1627 * KERN_INVALID_ARGUMENT The thread is null,
1628 * Illegal mask bit set.
1629 * Illegal exception behavior
1630 * KERN_FAILURE The thread is dead.
1631 */
1632
1633kern_return_t
1634thread_swap_exception_ports(
91447636
A
1635 thread_t thread,
1636 exception_mask_t exception_mask,
1637 ipc_port_t new_port,
1c79356b
A
1638 exception_behavior_t new_behavior,
1639 thread_state_flavor_t new_flavor,
1640 exception_mask_array_t masks,
91447636 1641 mach_msg_type_number_t *CountCnt,
1c79356b 1642 exception_port_array_t ports,
91447636
A
1643 exception_behavior_array_t behaviors,
1644 thread_state_flavor_array_t flavors)
1c79356b 1645{
91447636 1646 ipc_port_t old_port[EXC_TYPES_COUNT];
6601e61a 1647 boolean_t privileged = current_task()->sec_token.val[0] == 0;
91447636 1648 unsigned int i, j, count;
1c79356b 1649
91447636
A
1650 if (thread == THREAD_NULL)
1651 return (KERN_INVALID_ARGUMENT);
1c79356b 1652
b0d623f7 1653 if (exception_mask & ~EXC_MASK_VALID)
91447636 1654 return (KERN_INVALID_ARGUMENT);
1c79356b
A
1655
1656 if (IP_VALID(new_port)) {
2d21ac55 1657 switch (new_behavior & ~MACH_EXCEPTION_CODES) {
91447636 1658
1c79356b
A
1659 case EXCEPTION_DEFAULT:
1660 case EXCEPTION_STATE:
1661 case EXCEPTION_STATE_IDENTITY:
1662 break;
91447636 1663
1c79356b 1664 default:
91447636 1665 return (KERN_INVALID_ARGUMENT);
1c79356b
A
1666 }
1667 }
1c79356b 1668
91447636
A
1669 thread_mtx_lock(thread);
1670
1671 if (!thread->active) {
1672 thread_mtx_unlock(thread);
1673
1674 return (KERN_FAILURE);
1c79356b
A
1675 }
1676
1677 count = 0;
1678
91447636 1679 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
1c79356b 1680 if (exception_mask & (1 << i)) {
91447636
A
1681 for (j = 0; j < count; ++j) {
1682 /*
1683 * search for an identical entry, if found
1684 * set corresponding mask for this exception.
1685 */
1686 if ( thread->exc_actions[i].port == ports[j] &&
1687 thread->exc_actions[i].behavior == behaviors[j] &&
1688 thread->exc_actions[i].flavor == flavors[j] ) {
1c79356b
A
1689 masks[j] |= (1 << i);
1690 break;
1691 }
91447636
A
1692 }
1693
1c79356b
A
1694 if (j == count) {
1695 masks[j] = (1 << i);
91447636 1696 ports[j] = ipc_port_copy_send(thread->exc_actions[i].port);
1c79356b 1697
91447636
A
1698 behaviors[j] = thread->exc_actions[i].behavior;
1699 flavors[j] = thread->exc_actions[i].flavor;
1700 ++count;
1c79356b
A
1701 }
1702
91447636
A
1703 old_port[i] = thread->exc_actions[i].port;
1704 thread->exc_actions[i].port = ipc_port_copy_send(new_port);
1705 thread->exc_actions[i].behavior = new_behavior;
1706 thread->exc_actions[i].flavor = new_flavor;
6601e61a 1707 thread->exc_actions[i].privileged = privileged;
91447636 1708 if (count > *CountCnt)
1c79356b 1709 break;
91447636
A
1710 }
1711 else
1c79356b 1712 old_port[i] = IP_NULL;
91447636 1713 }
1c79356b 1714
91447636
A
1715 thread_mtx_unlock(thread);
1716
1717 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i)
1c79356b
A
1718 if (IP_VALID(old_port[i]))
1719 ipc_port_release_send(old_port[i]);
91447636 1720
1c79356b
A
1721 if (IP_VALID(new_port)) /* consume send right */
1722 ipc_port_release_send(new_port);
91447636 1723
1c79356b 1724 *CountCnt = count;
91447636
A
1725
1726 return (KERN_SUCCESS);
1727}
1c79356b
A
1728
1729kern_return_t
1730task_swap_exception_ports(
91447636
A
1731 task_t task,
1732 exception_mask_t exception_mask,
1733 ipc_port_t new_port,
1c79356b
A
1734 exception_behavior_t new_behavior,
1735 thread_state_flavor_t new_flavor,
1736 exception_mask_array_t masks,
91447636 1737 mach_msg_type_number_t *CountCnt,
1c79356b 1738 exception_port_array_t ports,
91447636
A
1739 exception_behavior_array_t behaviors,
1740 thread_state_flavor_array_t flavors)
1c79356b 1741{
91447636 1742 ipc_port_t old_port[EXC_TYPES_COUNT];
8ad349bb 1743 boolean_t privileged = current_task()->sec_token.val[0] == 0;
91447636 1744 unsigned int i, j, count;
1c79356b
A
1745
1746 if (task == TASK_NULL)
91447636 1747 return (KERN_INVALID_ARGUMENT);
1c79356b 1748
b0d623f7 1749 if (exception_mask & ~EXC_MASK_VALID)
91447636 1750 return (KERN_INVALID_ARGUMENT);
1c79356b
A
1751
1752 if (IP_VALID(new_port)) {
2d21ac55 1753 switch (new_behavior & ~MACH_EXCEPTION_CODES) {
91447636 1754
1c79356b
A
1755 case EXCEPTION_DEFAULT:
1756 case EXCEPTION_STATE:
1757 case EXCEPTION_STATE_IDENTITY:
1758 break;
91447636 1759
1c79356b 1760 default:
91447636 1761 return (KERN_INVALID_ARGUMENT);
1c79356b
A
1762 }
1763 }
1c79356b
A
1764
1765 itk_lock(task);
91447636 1766
1c79356b
A
1767 if (task->itk_self == IP_NULL) {
1768 itk_unlock(task);
91447636
A
1769
1770 return (KERN_FAILURE);
1c79356b
A
1771 }
1772
1773 count = 0;
1774
91447636 1775 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
1c79356b
A
1776 if (exception_mask & (1 << i)) {
1777 for (j = 0; j < count; j++) {
91447636
A
1778 /*
1779 * search for an identical entry, if found
1780 * set corresponding mask for this exception.
1781 */
1782 if ( task->exc_actions[i].port == ports[j] &&
1783 task->exc_actions[i].behavior == behaviors[j] &&
1784 task->exc_actions[i].flavor == flavors[j] ) {
1c79356b
A
1785 masks[j] |= (1 << i);
1786 break;
1787 }
91447636
A
1788 }
1789
1c79356b
A
1790 if (j == count) {
1791 masks[j] = (1 << i);
91447636 1792 ports[j] = ipc_port_copy_send(task->exc_actions[i].port);
1c79356b
A
1793 behaviors[j] = task->exc_actions[i].behavior;
1794 flavors[j] = task->exc_actions[i].flavor;
91447636 1795 ++count;
1c79356b 1796 }
91447636 1797
1c79356b 1798 old_port[i] = task->exc_actions[i].port;
91447636 1799 task->exc_actions[i].port = ipc_port_copy_send(new_port);
1c79356b
A
1800 task->exc_actions[i].behavior = new_behavior;
1801 task->exc_actions[i].flavor = new_flavor;
8ad349bb 1802 task->exc_actions[i].privileged = privileged;
91447636 1803 if (count > *CountCnt)
1c79356b 1804 break;
91447636
A
1805 }
1806 else
1c79356b 1807 old_port[i] = IP_NULL;
91447636 1808 }
1c79356b 1809
1c79356b 1810 itk_unlock(task);
91447636 1811
1c79356b
A
1812 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++)
1813 if (IP_VALID(old_port[i]))
1814 ipc_port_release_send(old_port[i]);
91447636 1815
1c79356b
A
1816 if (IP_VALID(new_port)) /* consume send right */
1817 ipc_port_release_send(new_port);
91447636 1818
1c79356b
A
1819 *CountCnt = count;
1820
91447636
A
1821 return (KERN_SUCCESS);
1822}
1c79356b
A
1823
1824/*
1825 * Routine: thread/task_get_exception_ports [kernel call]
1826 * Purpose:
1827 * Clones a send right for each of the thread/task's exception
1828 * ports specified in the mask and returns the behaviour
1829 * and flavor of said port.
1830 *
1831 * Returns upto [in} CountCnt elements.
1832 *
1833 * Conditions:
1834 * Nothing locked.
1835 * Returns:
1836 * KERN_SUCCESS Extracted a send right.
1837 * KERN_INVALID_ARGUMENT The thread is null,
1838 * Invalid special port,
1839 * Illegal mask bit set.
1840 * KERN_FAILURE The thread is dead.
1841 */
1842
1843kern_return_t
1844thread_get_exception_ports(
91447636
A
1845 thread_t thread,
1846 exception_mask_t exception_mask,
1c79356b 1847 exception_mask_array_t masks,
91447636 1848 mach_msg_type_number_t *CountCnt,
1c79356b 1849 exception_port_array_t ports,
91447636
A
1850 exception_behavior_array_t behaviors,
1851 thread_state_flavor_array_t flavors)
1c79356b 1852{
91447636 1853 unsigned int i, j, count;
1c79356b 1854
91447636
A
1855 if (thread == THREAD_NULL)
1856 return (KERN_INVALID_ARGUMENT);
1c79356b 1857
b0d623f7 1858 if (exception_mask & ~EXC_MASK_VALID)
91447636 1859 return (KERN_INVALID_ARGUMENT);
1c79356b 1860
91447636
A
1861 thread_mtx_lock(thread);
1862
1863 if (!thread->active) {
1864 thread_mtx_unlock(thread);
1865
1866 return (KERN_FAILURE);
1c79356b
A
1867 }
1868
1869 count = 0;
1870
91447636 1871 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
1c79356b 1872 if (exception_mask & (1 << i)) {
91447636
A
1873 for (j = 0; j < count; ++j) {
1874 /*
1875 * search for an identical entry, if found
1876 * set corresponding mask for this exception.
1877 */
1878 if ( thread->exc_actions[i].port == ports[j] &&
1879 thread->exc_actions[i].behavior ==behaviors[j] &&
1880 thread->exc_actions[i].flavor == flavors[j] ) {
1c79356b
A
1881 masks[j] |= (1 << i);
1882 break;
1883 }
91447636
A
1884 }
1885
1c79356b
A
1886 if (j == count) {
1887 masks[j] = (1 << i);
91447636
A
1888 ports[j] = ipc_port_copy_send(thread->exc_actions[i].port);
1889 behaviors[j] = thread->exc_actions[i].behavior;
1890 flavors[j] = thread->exc_actions[i].flavor;
1891 ++count;
1892 if (count >= *CountCnt)
1c79356b 1893 break;
1c79356b
A
1894 }
1895 }
91447636 1896 }
1c79356b 1897
91447636 1898 thread_mtx_unlock(thread);
1c79356b
A
1899
1900 *CountCnt = count;
91447636
A
1901
1902 return (KERN_SUCCESS);
1903}
1c79356b
A
1904
1905kern_return_t
1906task_get_exception_ports(
91447636
A
1907 task_t task,
1908 exception_mask_t exception_mask,
1c79356b 1909 exception_mask_array_t masks,
91447636 1910 mach_msg_type_number_t *CountCnt,
1c79356b 1911 exception_port_array_t ports,
91447636
A
1912 exception_behavior_array_t behaviors,
1913 thread_state_flavor_array_t flavors)
1c79356b 1914{
91447636 1915 unsigned int i, j, count;
1c79356b
A
1916
1917 if (task == TASK_NULL)
91447636 1918 return (KERN_INVALID_ARGUMENT);
1c79356b 1919
b0d623f7 1920 if (exception_mask & ~EXC_MASK_VALID)
91447636 1921 return (KERN_INVALID_ARGUMENT);
1c79356b
A
1922
1923 itk_lock(task);
91447636 1924
1c79356b
A
1925 if (task->itk_self == IP_NULL) {
1926 itk_unlock(task);
91447636
A
1927
1928 return (KERN_FAILURE);
1c79356b
A
1929 }
1930
1931 count = 0;
1932
91447636 1933 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) {
1c79356b 1934 if (exception_mask & (1 << i)) {
91447636
A
1935 for (j = 0; j < count; ++j) {
1936 /*
1937 * search for an identical entry, if found
1938 * set corresponding mask for this exception.
1939 */
1940 if ( task->exc_actions[i].port == ports[j] &&
1941 task->exc_actions[i].behavior == behaviors[j] &&
1942 task->exc_actions[i].flavor == flavors[j] ) {
1c79356b
A
1943 masks[j] |= (1 << i);
1944 break;
1945 }
91447636
A
1946 }
1947
1c79356b
A
1948 if (j == count) {
1949 masks[j] = (1 << i);
91447636 1950 ports[j] = ipc_port_copy_send(task->exc_actions[i].port);
1c79356b
A
1951 behaviors[j] = task->exc_actions[i].behavior;
1952 flavors[j] = task->exc_actions[i].flavor;
91447636
A
1953 ++count;
1954 if (count > *CountCnt)
1c79356b 1955 break;
1c79356b
A
1956 }
1957 }
91447636 1958 }
1c79356b
A
1959
1960 itk_unlock(task);
1961
1962 *CountCnt = count;
91447636
A
1963
1964 return (KERN_SUCCESS);
1965}