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