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