xref: /trueos/sys/compat/mach/kern/ipc_tt.c (revision f9c0c7e0e57d53445c6ecd3943afc874c49aae9c)
1 /*
2  * Copyright 1991-1998 by Open Software Foundation, Inc.
3  *              All Rights Reserved
4  *
5  * Permission to use, copy, modify, and distribute this software and
6  * its documentation for any purpose and without fee is hereby granted,
7  * provided that the above copyright notice appears in all copies and
8  * that both the copyright notice and this permission notice appear in
9  * supporting documentation.
10  *
11  * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
12  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13  * FOR A PARTICULAR PURPOSE.
14  *
15  * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
16  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
17  * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
18  * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
19  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  */
21 /*
22  * MkLinux
23  */
24 /* CMU_HIST */
25 /*
26  * Revision 2.12  91/06/25  10:28:49  rpd
27  * 	Changed the convert_foo_to_bar functions
28  * 	to use ipc_port_t instead of mach_port_t.
29  * 	[91/05/27            rpd]
30  *
31  * Revision 2.11  91/06/17  15:47:09  jsb
32  * 	Renamed NORMA conditionals. Moved norma code to norma/kern_task.c.
33  * 	[91/06/17  10:50:57  jsb]
34  *
35  * Revision 2.10  91/06/06  17:07:15  jsb
36  * 	NORMA_TASK support.
37  * 	[91/05/14  09:17:09  jsb]
38  *
39  * Revision 2.9  91/05/14  16:42:54  mrt
40  * 	Correcting copyright
41  *
42  * Revision 2.8  91/03/16  14:50:24  rpd
43  * 	Removed ith_saved.
44  * 	[91/02/16            rpd]
45  *
46  * Revision 2.7  91/02/05  17:27:08  mrt
47  * 	Changed to new Mach copyright
48  * 	[91/02/01  16:13:42  mrt]
49  *
50  * Revision 2.6  91/01/08  15:16:05  rpd
51  * 	Added retrieve_task_self_fast, retrieve_thread_self_fast.
52  * 	[90/12/27            rpd]
53  *
54  * Revision 2.5  90/11/05  14:31:08  rpd
55  * 	Changed ip_reference to ipc_port_reference.
56  * 	Use new ip_reference and ip_release.
57  * 	[90/10/29            rpd]
58  *
59  * Revision 2.4  90/06/02  14:54:33  rpd
60  * 	Converted to new IPC.
61  * 	[90/03/26  22:05:07  rpd]
62  *
63  *
64  * Condensed history:
65  *	Modified for pure kernel (dbg).
66  *	Support thread_exception_abort (dlb).
67  *	Added kernel monitor support (tfl).
68  *	Added task/thread kernel port interposing (rpd).
69  *	Improvements/fixes for task_secure (rpd).
70  * 	New translation cache (rpd).
71  *	Move old stuff under MACH_IPC_XXXHACK (rpd).
72  *	Created from mach_ipc.c (rpd).
73  */
74 /* CMU_ENDHIST */
75 /*
76  * Mach Operating System
77  * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
78  * All Rights Reserved.
79  *
80  * Permission to use, copy, modify and distribute this software and its
81  * documentation is hereby granted, provided that both the copyright
82  * notice and this permission notice appear in all copies of the
83  * software, derivative works or modified versions, and any portions
84  * thereof, and that both notices appear in supporting documentation.
85  *
86  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
87  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
88  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
89  *
90  * Carnegie Mellon requests users of this software to return to
91  *
92  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
93  *  School of Computer Science
94  *  Carnegie Mellon University
95  *  Pittsburgh PA 15213-3890
96  *
97  * any improvements or extensions that they make and grant Carnegie Mellon
98  * the rights to redistribute these changes.
99  */
100 /*
101  */
102 
103 /*
104  * File:	ipc_tt.c
105  * Purpose:
106  *	Task and thread related IPC functions.
107  */
108 
109 #include <sys/cdefs.h>
110 #include <sys/types.h>
111 #include <sys/syslog.h>
112 #include <sys/mach/mach_types.h>
113 #include <sys/mach/kern_return.h>
114 #include <sys/mach/mach_param.h>
115 #include <sys/mach/task_special_ports.h>
116 #include <sys/mach/thread_special_ports.h>
117 #include <sys/mach/thread_status.h>
118 #include <sys/mach/exception.h>
119 #if 0
120 #include <sys/mach/mach_traps.h>
121 #include <sys/mach/mach_server.h>
122 #endif
123 #include <sys/mach/mach_host_server.h>
124 #include <sys/mach/ipc_tt.h>
125 #if 0
126 #include <kern/thread_act.h>
127 #include <kern/misc_protos.h>
128 #endif
129 #include <sys/mach/host_special_ports.h>
130 #include <sys/mach/host.h>
131 #include <sys/mach/thread.h>
132 #include <sys/mach/mach_init.h>
133 #include <sys/mach/task_server.h>
134 #include <sys/mach/host_priv_server.h>
135 
136 #define THR_ACT_NULL NULL
137 
138 
139 
140 /*
141  *	Routine:	ipc_task_init
142  *	Purpose:
143  *		Initialize a task's IPC state.
144  *
145  *		If non-null, some state will be inherited from the parent.
146  *		The parent must be appropriately initialized.
147  *	Conditions:
148  *		Nothing locked.
149  */
150 
151 void
ipc_task_init(task_t task,task_t parent)152 ipc_task_init(
153 	task_t		task,
154 	task_t		parent)
155 {
156 	ipc_space_t space;
157 	ipc_port_t kport;
158 	kern_return_t kr;
159 	int i;
160 
161 
162 	kr = ipc_space_create(&ipc_table_entries[0], &space);
163 	if (kr != KERN_SUCCESS)
164 		panic("ipc_task_init");
165 
166 
167 	kport = ipc_port_alloc_kernel();
168 	if (kport == IP_NULL)
169 		panic("ipc_task_init");
170 
171 	task->itk_self = kport;
172 	task->itk_sself = ipc_port_make_send(kport);
173 	task->itk_space = space;
174 	space->is_task = task;
175 
176 	if (parent == TASK_NULL) {
177 		for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
178 			task->exc_actions[i].port = IP_NULL;
179 		}/* for */
180 		task->exc_actions[EXC_MACH_SYSCALL].port =
181 			ipc_port_make_send(realhost.host_self);
182 		task->itk_bootstrap = IP_NULL;
183 		for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
184 			task->itk_registered[i] = IP_NULL;
185 	} else {
186 		itk_lock(parent);
187 		assert(parent->itk_self != IP_NULL);
188 
189 		/* inherit registered ports */
190 
191 		for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
192 			task->itk_registered[i] =
193 				ipc_port_copy_send(parent->itk_registered[i]);
194 
195 		/* inherit exception and bootstrap ports */
196 
197 		for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
198 		    task->exc_actions[i].port =
199 		  		ipc_port_copy_send(parent->exc_actions[i].port);
200 		    task->exc_actions[i].flavor =
201 				parent->exc_actions[i].flavor;
202 		    task->exc_actions[i].behavior =
203 				parent->exc_actions[i].behavior;
204 		}/* for */
205 		task->itk_bootstrap =
206 			ipc_port_copy_send(parent->itk_bootstrap);
207 
208 		itk_unlock(parent);
209 	}
210 }
211 
212 /*
213  *	Routine:	ipc_task_enable
214  *	Purpose:
215  *		Enable a task for IPC access.
216  *	Conditions:
217  *		Nothing locked.
218  */
219 
220 void
ipc_task_enable(task_t task)221 ipc_task_enable(
222 	task_t		task)
223 {
224 	ipc_port_t kport;
225 
226 	itk_lock(task);
227 	kport = task->itk_self;
228 	if (kport != IP_NULL)
229 		ipc_kobject_set(kport, (ipc_kobject_t) task, IKOT_TASK);
230 	itk_unlock(task);
231 }
232 
233 /*
234  *	Routine:	ipc_task_disable
235  *	Purpose:
236  *		Disable IPC access to a task.
237  *	Conditions:
238  *		Nothing locked.
239  */
240 
241 void
ipc_task_disable(task_t task)242 ipc_task_disable(
243 	task_t		task)
244 {
245 	ipc_port_t kport;
246 
247 	itk_lock(task);
248 	kport = task->itk_self;
249 	if (kport != IP_NULL)
250 		ipc_kobject_set(kport, IKO_NULL, IKOT_NONE);
251 	itk_unlock(task);
252 }
253 
254 /*
255  *	Routine:	ipc_task_terminate
256  *	Purpose:
257  *		Clean up and destroy a task's IPC state.
258  *	Conditions:
259  *		Nothing locked.  The task must be suspended.
260  *		(Or the current thread must be in the task.)
261  */
262 
263 void
ipc_task_terminate(task_t task)264 ipc_task_terminate(
265 	task_t		task)
266 {
267 	ipc_port_t kport;
268 	int i;
269 
270 	itk_lock(task);
271 	kport = task->itk_self;
272 
273 	if (kport == IP_NULL) {
274 		/* the task is already terminated (can this happen?) */
275 		itk_unlock(task);
276 		return;
277 	}
278 
279 	task->itk_self = IP_NULL;
280 	itk_unlock(task);
281 
282 	/* release the naked send rights */
283 
284 	if (IP_VALID(task->itk_sself))
285 		ipc_port_release_send(task->itk_sself);
286 
287 	for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
288 		if (IP_VALID(task->exc_actions[i].port)) {
289 			ipc_port_release_send(task->exc_actions[i].port);
290 		}
291 	}/* for */
292 	if (IP_VALID(task->itk_bootstrap))
293 		ipc_port_release_send(task->itk_bootstrap);
294 
295 	for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
296 		if (IP_VALID(task->itk_registered[i]))
297 			ipc_port_release_send(task->itk_registered[i]);
298 
299 	/* destroy the space, leaving just a reference for it */
300 
301 	if (!task->kernel_loaded)
302 		ipc_space_destroy(task->itk_space);
303 
304 	/* destroy the kernel port */
305 
306 	ipc_port_dealloc_kernel(kport);
307 }
308 
309 /*
310  *	Routine:	ipc_thread_init
311  *	Purpose:
312  *		Initialize a thread's IPC state.
313  *	Conditions:
314  *		Nothing locked.
315  */
316 
317 void
ipc_thread_init(thread_t thread)318 ipc_thread_init(
319 	thread_t	thread)
320 {
321 	ipc_thread_links_init(thread);
322 	ipc_kmsg_queue_init(&thread->ith_messages);
323 	thread->ith_mig_reply = MACH_PORT_NULL;
324 	thread->ith_rpc_reply = IP_NULL;
325 }
326 
327 /*
328  *	Routine:	ipc_thread_terminate
329  *	Purpose:
330  *		Clean up and destroy a thread's IPC state.
331  *	Conditions:
332  *		Nothing locked.  The thread must be suspended.
333  *		(Or be the current thread.)
334  */
335 
336 void
ipc_thread_terminate(thread_t thread)337 ipc_thread_terminate(
338 	thread_t	thread)
339 {
340 	assert(ipc_kmsg_queue_empty(&thread->ith_messages));
341 
342         if (thread->ith_rpc_reply != IP_NULL)
343             ipc_port_dealloc_reply(thread->ith_rpc_reply);
344 	thread->ith_rpc_reply = IP_NULL;
345 }
346 
347 /*
348  *	Routine:	ipc_thr_act_init
349  *	Purpose:
350  *		Initialize an thr_act's IPC state.
351  *	Conditions:
352  *		Nothing locked.
353  */
354 
355 void
ipc_thr_act_init(thread_act_t thr_act)356 ipc_thr_act_init(thread_act_t thr_act)
357 {
358 	ipc_port_t kport; int i;
359 
360 	kport = ipc_port_alloc_kernel();
361 	if (kport == IP_NULL)
362 		panic("ipc_thr_act_init");
363 
364 	thr_act->ith_self = kport;
365 	thr_act->ith_sself = ipc_port_make_send(kport);
366 
367 	for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++)
368 		thr_act->exc_actions[i].port = IP_NULL;
369 
370 	thr_act->exc_actions[EXC_MACH_SYSCALL].port =
371 					ipc_port_make_send(realhost.host_self);
372 
373 	ipc_kobject_set(kport, (ipc_kobject_t) thr_act, IKOT_ACT);
374 }
375 
376 #if 0
377 
378 void
379 ipc_thr_act_disable(thread_act_t thr_act)
380 {
381 	int i;
382 	ipc_port_t kport;
383 
384 	act_lock(thr_act);
385 	kport = thr_act->ith_self;
386 
387 	if (kport != IP_NULL)
388 		ipc_kobject_set(kport, IKO_NULL, IKOT_NONE);
389 	act_unlock(thr_act);
390 }
391 
392 
393 void
394 ipc_thr_act_disable_act_locked(thread_act_t thr_act)
395 {
396 	int i;
397 	ipc_port_t kport;
398 
399 	kport = thr_act->ith_self;
400 
401 	if (kport != IP_NULL)
402 		ipc_kobject_set(kport, IKO_NULL, IKOT_NONE);
403 }
404 #endif
405 
406 void
ipc_thr_act_terminate(thread_act_t thr_act)407 ipc_thr_act_terminate(thread_act_t thr_act)
408 {
409 	ipc_port_t kport; int i;
410 
411 	act_lock(thr_act);
412 	kport = thr_act->ith_self;
413 
414 	if (kport == IP_NULL) {
415 		/* the thread is already terminated (can this happen?) */
416 		act_unlock(thr_act);
417 		return;
418 	}
419 
420 	thr_act->ith_self = IP_NULL;
421 	act_unlock(thr_act);
422 
423 	/* release the naked send rights */
424 
425 	if (IP_VALID(thr_act->ith_sself))
426 		ipc_port_release_send(thr_act->ith_sself);
427 	for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
428 	    if (IP_VALID(thr_act->exc_actions[i].port))
429 		ipc_port_release_send(thr_act->exc_actions[i].port);
430 	}
431 
432 	/* destroy the kernel port */
433 	ipc_port_dealloc_kernel(kport);
434 }
435 
436 
437 /*
438  *	Routine:	retrieve_task_self_fast
439  *	Purpose:
440  *		Optimized version of retrieve_task_self,
441  *		that only works for the current task.
442  *
443  *		Return a send right (possibly null/dead)
444  *		for the task's user-visible self port.
445  *	Conditions:
446  *		Nothing locked.
447  */
448 
449 ipc_port_t
retrieve_task_self_fast(register task_t task)450 retrieve_task_self_fast(
451 	register task_t		task)
452 {
453 	register ipc_port_t port;
454 
455 	assert(task == current_task());
456 
457 	itk_lock(task);
458 	assert(task->itk_self != IP_NULL);
459 
460 	if ((port = task->itk_sself) == task->itk_self) {
461 		/* no interposing */
462 		itk_unlock(task);
463 		ip_lock(port);
464 		assert(ip_active(port));
465 		ip_reference(port);
466 		port->ip_srights++;
467 		ip_unlock(port);
468 	} else {
469 		itk_unlock(task);
470 		port = ipc_port_copy_send(port);
471 	}
472 
473 	return (port);
474 }
475 
476 /*
477  *	Routine:	retrieve_act_self_fast
478  *	Purpose:
479  *		Optimized version of retrieve_thread_self,
480  *		that only works for the current thread.
481  *
482  *		Return a send right (possibly null/dead)
483  *		for the thread's user-visible self port.
484  *	Conditions:
485  *		Nothing locked.
486  */
487 
488 ipc_port_t
retrieve_thread_self_fast(thread_t thr_act)489 retrieve_thread_self_fast(thread_t thr_act)
490 {
491 	register ipc_port_t port;
492 
493 	assert(thr_act == current_act());
494 	act_lock(thr_act);
495 	assert(thr_act->ith_self != IP_NULL);
496 
497 	if ((port = thr_act->ith_sself) == thr_act->ith_self) {
498 		/* no interposing */
499 
500 		ip_lock(port);
501 		assert(ip_active(port));
502 		ip_reference(port);
503 		port->ip_srights++;
504 		ip_unlock(port);
505 	} else
506 		port = ipc_port_copy_send(port);
507 	act_unlock(thr_act);
508 
509 	return port;
510 }
511 
512 /*
513  *	Routine:	mach_task_self [mach trap]
514  *	Purpose:
515  *		Give the caller send rights for his own task port.
516  *	Conditions:
517  *		Nothing locked.
518  *	Returns:
519  *		MACH_PORT_NULL if there are any resource failures
520  *		or other errors.
521  */
522 
523 mach_port_name_t
mach_task_self(void)524 mach_task_self(void)
525 {
526 	task_t task = current_task();
527 	ipc_space_t space = current_space();
528 	ipc_port_t sright;
529 
530 	sright = retrieve_task_self_fast(task);
531 	return ipc_port_copyout_send(sright, space);
532 }
533 
534 /*
535  *	Routine:	mach_thread_self [mach trap]
536  *	Purpose:
537  *		Give the caller send rights for his own thread port.
538  *	Conditions:
539  *		Nothing locked.
540  *	Returns:
541  *		MACH_PORT_NULL if there are any resource failures
542  *		or other errors.
543  */
544 
545 mach_port_name_t
mach_thread_self(void)546 mach_thread_self(void)
547 {
548 	thread_t thr_act = current_thread();
549 	ipc_space_t space = current_space();
550 	ipc_port_t sright;
551 
552 	sright = retrieve_thread_self_fast(thr_act);
553 	return ipc_port_copyout_send(sright, space);
554 }
555 
556 /*
557  *	Routine:	mach_reply_port [mach trap]
558  *	Purpose:
559  *		Allocate a port for the caller.
560  *	Conditions:
561  *		Nothing locked.
562  *	Returns:
563  *		MACH_PORT_NULL if there are any resource failures
564  *		or other errors.
565  */
566 
567 mach_port_name_t
mach_reply_port(void)568 mach_reply_port(void)
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_NAME_NULL;
579 
580 	return name;
581 }
582 
583 /*
584  *	Routine:	task_get_special_port [kernel call]
585  *	Purpose:
586  *		Clones a send right for one of the task's
587  *		special ports.
588  *	Conditions:
589  *		Nothing locked.
590  *	Returns:
591  *		KERN_SUCCESS		Extracted a send right.
592  *		KERN_INVALID_ARGUMENT	The task is null.
593  *		KERN_FAILURE		The task/space is dead.
594  *		KERN_INVALID_ARGUMENT	Invalid special port.
595  */
596 
597 kern_return_t
task_get_special_port(task_t task,int which,ipc_port_t * portp)598 task_get_special_port(
599 	task_t		task,
600 	int		which,
601 	ipc_port_t	*portp)
602 {
603 	ipc_port_t port;
604 
605 	if (task == TASK_NULL)
606 		return KERN_INVALID_ARGUMENT;
607 
608 	switch (which) {
609 	case TASK_KERNEL_PORT:
610 		port = ipc_port_copy_send(task->itk_sself);
611 		break;
612 
613 	    case TASK_NAME_PORT:
614 		port = ipc_port_make_send(task->itk_nself);
615 		break;
616 
617 	    case TASK_HOST_PORT:
618 		port = ipc_port_copy_send(task->itk_host);
619 		break;
620 
621 	    case TASK_BOOTSTRAP_PORT:
622 			port = ipc_port_copy_send(task->itk_bootstrap);
623 		break;
624 
625 	    case TASK_SEATBELT_PORT:
626 		port = ipc_port_copy_send(task->itk_seatbelt);
627 		break;
628 
629 	    case TASK_ACCESS_PORT:
630 		port = ipc_port_copy_send(task->itk_task_access);
631 		break;
632 
633 		case TASK_DEBUG_CONTROL_PORT:
634 		port = ipc_port_copy_send(task->itk_debug_control);
635 		break;
636 	    default:
637 		return KERN_INVALID_ARGUMENT;
638 	}
639 
640 	*portp = port;
641 	return KERN_SUCCESS;
642 }
643 
644 /*
645  *	Routine:	task_set_special_port [kernel call]
646  *	Purpose:
647  *		Changes one of the task's special ports,
648  *		setting it to the supplied send right.
649  *	Conditions:
650  *		Nothing locked.  If successful, consumes
651  *		the supplied send right.
652  *	Returns:
653  *		KERN_SUCCESS		Changed the special port.
654  *		KERN_INVALID_ARGUMENT	The task is null.
655  *		KERN_FAILURE		The task/space is dead.
656  *		KERN_INVALID_ARGUMENT	Invalid special port.
657  */
658 
659 kern_return_t
task_set_special_port(task_t task,int which,ipc_port_t port)660 task_set_special_port(
661 	task_t		task,
662 	int		which,
663 	ipc_port_t	port)
664 {
665 	ipc_port_t *whichp;
666 	ipc_port_t old;
667 
668 #if VERBOSE_DEBUGGING
669 	printf("task_set_special_port(task=%p, which=%d, port=%p)\n",task, which, port);
670 #endif
671 	/* we only support the current task */
672 	if (task == TASK_NULL)
673 		return KERN_INVALID_ARGUMENT;
674 
675 	switch (which) {
676 	case TASK_KERNEL_PORT:
677 		whichp = &task->itk_sself;
678 		break;
679 	case TASK_HOST_PORT:
680 		whichp = &task->itk_host;
681 		break;
682 	case TASK_BOOTSTRAP_PORT:
683 		whichp = &task->itk_bootstrap;
684 		break;
685 	case TASK_SEATBELT_PORT:
686 		whichp = &task->itk_seatbelt;
687 		break;
688 	case TASK_ACCESS_PORT:
689 		whichp = &task->itk_task_access;
690 		break;
691 	case TASK_DEBUG_CONTROL_PORT:
692 		whichp = &task->itk_debug_control;
693 		break;
694 	default:
695 		return KERN_INVALID_ARGUMENT;
696 	}/* switch */
697 
698 	if ((TASK_SEATBELT_PORT == which  || TASK_ACCESS_PORT == which)
699 		&& IP_VALID(*whichp)) {
700 			itk_unlock(task);
701 			return KERN_NO_ACCESS;
702 	}
703 	itk_lock(task);
704 	if (task->itk_self == IP_NULL) {
705 		itk_unlock(task);
706 		return KERN_FAILURE;
707 	}
708 
709 	old = *whichp;
710 	*whichp = port;
711 	itk_unlock(task);
712 
713 	if (IP_VALID(old))
714 		ipc_port_release_send(old);
715 	return KERN_SUCCESS;
716 }
717 
718 
719 /*
720  *	Routine:	mach_ports_register [kernel call]
721  *	Purpose:
722  *		Stash a handful of port send rights in the task.
723  *		Child tasks will inherit these rights, but they
724  *		must use mach_ports_lookup to acquire them.
725  *
726  *		The rights are supplied in a (wired) kalloc'd segment.
727  *		Rights which aren't supplied are assumed to be null.
728  *	Conditions:
729  *		Nothing locked.  If successful, consumes
730  *		the supplied rights and memory.
731  *	Returns:
732  *		KERN_SUCCESS		Stashed the port rights.
733  *		KERN_INVALID_ARGUMENT	The task is null.
734  *		KERN_INVALID_ARGUMENT	The task is dead.
735  *		KERN_INVALID_ARGUMENT	Too many port rights supplied.
736  */
737 
738 kern_return_t
mach_ports_register(task_t task,mach_port_array_t memory,mach_msg_type_number_t portsCnt)739 mach_ports_register(
740 	task_t			task,
741 	mach_port_array_t	memory,
742 	mach_msg_type_number_t	portsCnt)
743 {
744 	ipc_port_t ports[TASK_PORT_REGISTER_MAX];
745 	int i;
746 
747 	if ((task == TASK_NULL) ||
748 	    (portsCnt > TASK_PORT_REGISTER_MAX))
749 		return KERN_INVALID_ARGUMENT;
750 
751 	/*
752 	 *	Pad the port rights with nulls.
753 	 */
754 
755 	for (i = 0; i < portsCnt; i++)
756 		ports[i] = (ipc_port_t) memory[i];
757 	for (; i < TASK_PORT_REGISTER_MAX; i++)
758 		ports[i] = IP_NULL;
759 
760 	itk_lock(task);
761 	if (task->itk_self == IP_NULL) {
762 		itk_unlock(task);
763 		return KERN_INVALID_ARGUMENT;
764 	}
765 
766 	/*
767 	 *	Replace the old send rights with the new.
768 	 *	Release the old rights after unlocking.
769 	 */
770 
771 	for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) {
772 		ipc_port_t old;
773 
774 		old = task->itk_registered[i];
775 		task->itk_registered[i] = ports[i];
776 		ports[i] = old;
777 	}
778 
779 	itk_unlock(task);
780 
781 	for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
782 		if (IP_VALID(ports[i]))
783 			ipc_port_release_send(ports[i]);
784 
785 	/*
786 	 *	Now that the operation is known to be successful,
787 	 *	we can free the memory.
788 	 */
789 
790 	if (portsCnt != 0)
791 		kfree((vm_offset_t) memory,
792 		      (vm_size_t) (portsCnt * sizeof(mach_port_t)));
793 
794 	return KERN_SUCCESS;
795 }
796 
797 /*
798  *	Routine:	mach_ports_lookup [kernel call]
799  *	Purpose:
800  *		Retrieves (clones) the stashed port send rights.
801  *	Conditions:
802  *		Nothing locked.  If successful, the caller gets
803  *		rights and memory.
804  *	Returns:
805  *		KERN_SUCCESS		Retrieved the send rights.
806  *		KERN_INVALID_ARGUMENT	The task is null.
807  *		KERN_INVALID_ARGUMENT	The task is dead.
808  *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
809  */
810 
811 kern_return_t
mach_ports_lookup(task_t task,mach_port_array_t * portsp,mach_msg_type_number_t * portsCnt)812 mach_ports_lookup(
813 	task_t			task,
814 	mach_port_array_t	*portsp,
815 	mach_msg_type_number_t	*portsCnt)
816 {
817 	vm_offset_t memory;
818 	vm_size_t size;
819 	ipc_port_t *ports;
820 	int i;
821 
822 	if (task == TASK_NULL)
823 		return KERN_INVALID_ARGUMENT;
824 
825 	size = (vm_size_t) (TASK_PORT_REGISTER_MAX * sizeof(ipc_port_t));
826 
827 	memory = KALLOC(size, rt);
828 	if (memory == 0)
829 		return KERN_RESOURCE_SHORTAGE;
830 
831 	itk_lock(task);
832 	if (task->itk_self == IP_NULL) {
833 		itk_unlock(task);
834 
835 		KFREE(memory, size, rt);
836 		return KERN_INVALID_ARGUMENT;
837 	}
838 
839 	ports = (ipc_port_t *) memory;
840 
841 	/*
842 	 *	Clone port rights.  Because kalloc'd memory
843 	 *	is wired, we won't fault while holding the task lock.
844 	 */
845 
846 	for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
847 		ports[i] = ipc_port_copy_send(task->itk_registered[i]);
848 
849 	itk_unlock(task);
850 
851 	*portsp = (mach_port_array_t) ports;
852 	*portsCnt = TASK_PORT_REGISTER_MAX;
853 	return KERN_SUCCESS;
854 }
855 
856 /*
857  *	Routine:	convert_port_to_task
858  *	Purpose:
859  *		Convert from a port to a task.
860  *		Doesn't consume the port ref; produces a task ref,
861  *		which may be null.
862  *	Conditions:
863  *		Nothing locked.
864  */
865 
866 task_t
convert_port_to_task(ipc_port_t port)867 convert_port_to_task(
868 	ipc_port_t	port)
869 {
870 	boolean_t r;
871 	task_t task = TASK_NULL;
872 
873 	/* currently only handle current task */
874 	return (current_task());
875 
876 	r = FALSE;
877 	while (!r && IP_VALID(port)) {
878 		ip_lock(port);
879 		r = ref_task_port_locked(port, &task);
880 		/* port unlocked */
881 	}
882 
883 	return task;
884 }
885 
886 boolean_t
ref_task_port_locked(ipc_port_t port,task_t * ptask)887 ref_task_port_locked( ipc_port_t port, task_t *ptask )
888 {
889 	task_t task;
890 
891 	task = TASK_NULL;
892 	if (ip_active(port) &&
893 		(ip_kotype(port) == IKOT_TASK)) {
894 		task = (task_t) port->ip_kobject;
895 		assert(task != TASK_NULL);
896 
897 		/*
898 		 * Normal lock ordering puts task_lock() before ip_lock().
899 		 * Allow out-of-order locking here, inlining
900 		 * task_reference() to accomodate it.
901 		 */
902 		if (!task_lock_try(task)) {
903 			ip_unlock(port);
904 			return (FALSE);
905 		}
906 		task->ref_count++;
907 		task_unlock(task);
908 	}
909 	*ptask = task;
910 	ip_unlock(port);
911 	return (TRUE);
912 }
913 
914 /*
915  *	Routine:	convert_port_to_space
916  *	Purpose:
917  *		Convert from a port to a space.
918  *		Doesn't consume the port ref; produces a space ref,
919  *		which may be null.
920  *	Conditions:
921  *		Nothing locked.
922  */
923 
924 ipc_space_t
convert_port_to_space(ipc_port_t port)925 convert_port_to_space(
926 	ipc_port_t	port)
927 {
928 	boolean_t r;
929 	ipc_space_t space = IS_NULL;
930 
931 	r = FALSE;
932 	while (!r && IP_VALID(port)) {
933 		ip_lock(port);
934 		r = ref_space_port_locked(port, &space);
935 		/* port unlocked */
936 	}
937 	return space;
938 }
939 
940 boolean_t
ref_space_port_locked(ipc_port_t port,ipc_space_t * pspace)941 ref_space_port_locked( ipc_port_t port, ipc_space_t *pspace )
942 {
943 	ipc_space_t space;
944 
945 	space = IS_NULL;
946 	if (ip_active(port) &&
947 		(ip_kotype(port) == IKOT_TASK)) {
948 		space = ((task_t) port->ip_kobject)->itk_space;
949 
950 		/*
951 		 * Normal lock ordering puts ipc_space lock before
952 		 * ip_lock(). Allow out-of-order locking here, inlining
953 		 * is_reference() to accomodate it.
954 		 */
955 		if (!mtx_trylock(&space->is_ref_lock_data)) {
956 			ip_unlock(port);
957 			return (FALSE);
958 		}
959 		space->is_references++;
960 		mtx_unlock(&space->is_ref_lock_data);
961 	}
962 	*pspace = space;
963 	ip_unlock(port);
964 	return (TRUE);
965 }
966 
967 /*
968  *	Routine:	convert_port_to_map
969  *	Purpose:
970  *		Convert from a port to a map.
971  *		Doesn't consume the port ref; produces a map ref,
972  *		which may be null.
973  *	Conditions:
974  *		Nothing locked.
975  */
976 
977 vm_map_t
convert_port_to_map(ipc_port_t port)978 convert_port_to_map(
979 	ipc_port_t	port)
980 {
981 	task_t task;
982 	vm_map_t map;
983 
984 	task = convert_port_to_task(port);
985 
986 	if (task == TASK_NULL)
987 		return VM_MAP_NULL;
988 
989 	map = &task->itk_p->p_vmspace->vm_map;
990 	task_deallocate(task);
991 	return (map);
992 }
993 
994 static boolean_t
ref_act_port_locked(ipc_port_t port,thread_act_t * pthr_act)995 ref_act_port_locked( ipc_port_t port, thread_act_t *pthr_act )
996 {
997 	thread_act_t thr_act;
998 
999 	thr_act = 0;
1000 	if (ip_active(port) &&
1001 		(ip_kotype(port) == IKOT_ACT)) {
1002 		thr_act = (thread_act_t) port->ip_kobject;
1003 		assert(thr_act != THR_ACT_NULL);
1004 
1005 		/*
1006 		 * Normal lock ordering is act_lock(), then ip_lock().
1007 		 * Allow out-of-order locking here, using
1008 		 * act_reference_act_locked() to accomodate it.
1009 		 */
1010 		if (!act_lock_try(thr_act)) {
1011 			ip_unlock(port);
1012 			return (FALSE);
1013 		}
1014 		act_locked_act_reference(thr_act);
1015 		act_unlock(thr_act);
1016 	}
1017 	*pthr_act = thr_act;
1018 	ip_unlock(port);
1019 	return (TRUE);
1020 }
1021 
1022 /*
1023  *	Routine:	convert_port_to_act
1024  *	Purpose:
1025  *		Convert from a port to a thr_act.
1026  *		Doesn't consume the port ref; produces an thr_act ref,
1027  *		which may be null.
1028  *	Conditions:
1029  *		Nothing locked.
1030  */
1031 
1032 thread_act_t
convert_port_to_thread(ipc_port_t port)1033 convert_port_to_thread( ipc_port_t port )
1034 {
1035 	boolean_t r;
1036 	thread_act_t thr_act = 0;
1037 
1038 	r = FALSE;
1039 	while (!r && IP_VALID(port)) {
1040 		ip_lock(port);
1041 		r = ref_act_port_locked(port, &thr_act);
1042 		/* port unlocked */
1043 	}
1044 	return (thr_act);
1045 }
1046 
1047 /*
1048  *	Routine:	convert_task_to_port
1049  *	Purpose:
1050  *		Convert from a task to a port.
1051  *		Consumes a task ref; produces a naked send right
1052  *		which may be invalid.
1053  *	Conditions:
1054  *		Nothing locked.
1055  */
1056 
1057 ipc_port_t
convert_task_to_port(task_t task)1058 convert_task_to_port(
1059 	task_t		task)
1060 {
1061 	ipc_port_t port;
1062 
1063 	itk_lock(task);
1064 	if (task->itk_self != IP_NULL)
1065 		port = ipc_port_make_send(task->itk_self);
1066 	else
1067 		port = IP_NULL;
1068 	itk_unlock(task);
1069 
1070 	task_deallocate(task);
1071 	return port;
1072 }
1073 
1074 /*
1075  *	Routine:	convert_act_to_port
1076  *	Purpose:
1077  *		Convert from a thr_act to a port.
1078  *		Consumes an thr_act ref; produces a naked send right
1079  *		which may be invalid.
1080  *	Conditions:
1081  *		Nothing locked.
1082  */
1083 
1084 ipc_port_t
convert_thread_to_port(thread_t thr_act)1085 convert_thread_to_port(thread_t thr_act)
1086 {
1087 	ipc_port_t port;
1088 
1089 	act_lock(thr_act);
1090 	if (thr_act->ith_self != IP_NULL)
1091 		port = ipc_port_make_send(thr_act->ith_self);
1092 	else
1093 		port = IP_NULL;
1094 	act_unlock(thr_act);
1095 
1096 	act_deallocate(thr_act);
1097 	return port;
1098 }
1099 
1100 /*
1101  *	Routine:	space_deallocate
1102  *	Purpose:
1103  *		Deallocate a space ref produced by convert_port_to_space.
1104  *	Conditions:
1105  *		Nothing locked.
1106  */
1107 
1108 void
space_deallocate(ipc_space_t space)1109 space_deallocate(
1110 	ipc_space_t	space)
1111 {
1112 	if (space != IS_NULL)
1113 		is_release(space);
1114 }
1115 
1116 /*
1117  *	Routine:	host/task_set_exception_ports [kernel call]
1118  *	Purpose:
1119  *			Sets the host/task exception port, flavor and
1120  *			behavior for the exception types specified by the mask.
1121  *			There will be one send right per exception per valid
1122  *			port.
1123  *	Conditions:
1124  *		Nothing locked.  If successful, consumes
1125  *		the supplied send right.
1126  *	Returns:
1127  *		KERN_SUCCESS		Changed the special port.
1128  *		KERN_INVALID_ARGUMENT	The thread is null,
1129  *					Illegal mask bit set.
1130  *					Illegal exception behavior
1131  *		KERN_FAILURE		The thread is dead.
1132  */
1133 
1134 kern_return_t
host_set_exception_ports(host_t host,exception_mask_t exception_mask,ipc_port_t new_port,exception_behavior_t new_behavior,thread_state_flavor_t new_flavor)1135 host_set_exception_ports(
1136 	host_t		 	host,
1137 	exception_mask_t		exception_mask,
1138 	ipc_port_t			new_port,
1139 	exception_behavior_t		new_behavior,
1140 	thread_state_flavor_t		new_flavor)
1141 {
1142 	register int	i;
1143 	ipc_port_t	old_port[EXC_TYPES_COUNT];
1144 
1145 	if (!host)
1146 		return KERN_INVALID_ARGUMENT;
1147 
1148 	if (exception_mask & ~EXC_MASK_ALL)
1149 		return KERN_INVALID_ARGUMENT;
1150 
1151 	if (IP_VALID(new_port)) {
1152 		switch (new_behavior) {
1153 		case EXCEPTION_DEFAULT:
1154 		case EXCEPTION_STATE:
1155 		case EXCEPTION_STATE_IDENTITY:
1156 			break;
1157 		default:
1158 			return KERN_INVALID_ARGUMENT;
1159 		}
1160 	}
1161 	/* Cannot easily check "flavor", but that just means that the flavor
1162 	 * in the generated exception message might be garbage. GIGO */
1163 
1164 	host_lock(host);
1165 
1166 	for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
1167 		if (exception_mask & (1 << i)) {
1168 			old_port[i] = host->exc_actions[i].port;
1169 			host->exc_actions[i].port =
1170 				ipc_port_copy_send(new_port);
1171 			host->exc_actions[i].behavior = new_behavior;
1172 			host->exc_actions[i].flavor = new_flavor;
1173 		} else
1174 			old_port[i] = IP_NULL;
1175 	}/* for */
1176 	/*
1177 	 * Consume send rights without any lock held.
1178 	 */
1179 	host_unlock(host);
1180 	for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++)
1181 		if (IP_VALID(old_port[i]))
1182 			ipc_port_release_send(old_port[i]);
1183 	if (IP_VALID(new_port))		 /* consume send right */
1184 		ipc_port_release_send(new_port);
1185 
1186         return KERN_SUCCESS;
1187 }/* thread_set_exception_port */
1188 
1189 kern_return_t
task_set_exception_ports(task_t task,exception_mask_t exception_mask,ipc_port_t new_port,exception_behavior_t new_behavior,thread_state_flavor_t new_flavor)1190 task_set_exception_ports(
1191 	task_t				task,
1192 	exception_mask_t		exception_mask,
1193 	ipc_port_t			new_port,
1194 	exception_behavior_t		new_behavior,
1195 	thread_state_flavor_t		new_flavor)
1196 {
1197 	register int	i;
1198 	ipc_port_t	old_port[EXC_TYPES_COUNT];
1199 
1200 	if (task == TASK_NULL) {
1201 		return KERN_INVALID_ARGUMENT;
1202 	}
1203 
1204 	if (exception_mask & ~EXC_MASK_ALL) {
1205 		return KERN_INVALID_ARGUMENT;
1206 	}
1207 
1208 	if (IP_VALID(new_port)) {
1209 		switch (new_behavior) {
1210 		case EXCEPTION_DEFAULT:
1211 		case EXCEPTION_STATE:
1212 		case EXCEPTION_STATE_IDENTITY:
1213 			break;
1214 		default:
1215 			return KERN_INVALID_ARGUMENT;
1216 		}
1217 	}
1218 	/* Cannot easily check "new_flavor", but that just means that
1219 	 * the flavor in the generated exception message might be garbage:
1220 	 * GIGO */
1221 
1222         itk_lock(task);
1223         if (task->itk_self == IP_NULL) {
1224                 itk_unlock(task);
1225                 return KERN_FAILURE;
1226         }
1227 
1228 	for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
1229 		if (exception_mask & (1 << i)) {
1230 			old_port[i] = task->exc_actions[i].port;
1231 			task->exc_actions[i].port =
1232 				ipc_port_copy_send(new_port);
1233 			task->exc_actions[i].behavior = new_behavior;
1234 			task->exc_actions[i].flavor = new_flavor;
1235 		} else
1236 			old_port[i] = IP_NULL;
1237 	}/* for */
1238 
1239 	/*
1240 	 * Consume send rights without any lock held.
1241 	 */
1242         itk_unlock(task);
1243 	for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++)
1244 		if (IP_VALID(old_port[i]))
1245 			ipc_port_release_send(old_port[i]);
1246 	if (IP_VALID(new_port))		 /* consume send right */
1247 		ipc_port_release_send(new_port);
1248 
1249         return KERN_SUCCESS;
1250 }/* task_set_exception_port */
1251 
1252 /*
1253  *	Routine:	host/task_swap_exception_ports [kernel call]
1254  *	Purpose:
1255  *			Sets the thread/task exception port, flavor and
1256  *			behavior for the exception types specified by the
1257  *			mask.
1258  *
1259  *			The old ports, behavior and flavors are returned
1260  *			Count specifies the array sizes on input and
1261  *			the number of returned ports etc. on output.  The
1262  *			arrays must be large enough to hold all the returned
1263  *			data, MIG returnes an error otherwise.  The masks
1264  *			array specifies the corresponding exception type(s).
1265  *
1266  *	Conditions:
1267  *		Nothing locked.  If successful, consumes
1268  *		the supplied send right.
1269  *
1270  *		Returns upto [in} CountCnt elements.
1271  *	Returns:
1272  *		KERN_SUCCESS		Changed the special port.
1273  *		KERN_INVALID_ARGUMENT	The thread is null,
1274  *					Illegal mask bit set.
1275  *					Illegal exception behavior
1276  *		KERN_FAILURE		The thread is dead.
1277  */
1278 
1279 kern_return_t
host_swap_exception_ports(host_t host,exception_mask_t exception_mask,ipc_port_t new_port,exception_behavior_t new_behavior,thread_state_flavor_t new_flavor,exception_mask_array_t masks,mach_msg_type_number_t * CountCnt,exception_port_array_t ports,exception_behavior_array_t behaviors,thread_state_flavor_array_t flavors)1280 host_swap_exception_ports(
1281 	host_t			host,
1282 	exception_mask_t		exception_mask,
1283 	ipc_port_t			new_port,
1284 	exception_behavior_t		new_behavior,
1285 	thread_state_flavor_t		new_flavor,
1286 	exception_mask_array_t		masks,
1287 	mach_msg_type_number_t		* CountCnt,
1288 	exception_port_array_t		ports,
1289 	exception_behavior_array_t      behaviors,
1290 	thread_state_flavor_array_t     flavors	)
1291 {
1292 	register int	i,
1293 			j,
1294 			count;
1295 	ipc_port_t	old_port[EXC_TYPES_COUNT];
1296 
1297 	if (!host)
1298 		return KERN_INVALID_ARGUMENT;
1299 
1300 	if (exception_mask & ~EXC_MASK_ALL) {
1301 		return KERN_INVALID_ARGUMENT;
1302 	}
1303 
1304 	if (IP_VALID(new_port)) {
1305 		switch (new_behavior) {
1306 		case EXCEPTION_DEFAULT:
1307 		case EXCEPTION_STATE:
1308 		case EXCEPTION_STATE_IDENTITY:
1309 			break;
1310 		default:
1311 			return KERN_INVALID_ARGUMENT;
1312 		}
1313 	}
1314 	/* Cannot easily check "new_flavor", but that just means that
1315 	 * the flavor in the generated exception message might be garbage:
1316 	 * GIGO */
1317 
1318 	host_lock(host);
1319 	for (count = 0, i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
1320 		if (exception_mask & (1 << i)) {
1321 			for (j = 0; j < count; j++) {
1322 /*
1323  *				search for an identical entry, if found
1324  *				set corresponding mask for this exception.
1325  */
1326 				if (host->exc_actions[i].port == ports[j] &&
1327 				  host->exc_actions[i].behavior ==behaviors[j]
1328 				  && host->exc_actions[i].flavor ==flavors[j])
1329 				{
1330 					masks[j] |= (1 << i);
1331 					break;
1332 				}
1333 			}/* for */
1334 			if (j == count) {
1335 				masks[j] = (1 << i);
1336 				ports[j] =
1337 				ipc_port_copy_send(host->exc_actions[i].port);
1338 
1339 				behaviors[j] = host->exc_actions[i].behavior;
1340 				flavors[j] = host->exc_actions[i].flavor;
1341 				count++;
1342 			}
1343 
1344 			old_port[i] = host->exc_actions[i].port;
1345 			host->exc_actions[i].port =
1346 				ipc_port_copy_send(new_port);
1347 			host->exc_actions[i].behavior = new_behavior;
1348 			host->exc_actions[i].flavor = new_flavor;
1349 			if (count > *CountCnt) {
1350 				break;
1351 			}
1352 		} else
1353 			old_port[i] = IP_NULL;
1354 	}/* for */
1355 
1356 	/*
1357 	 * Consume send rights without any lock held.
1358 	 */
1359 	host_unlock(host);
1360 	for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++)
1361 		if (IP_VALID(old_port[i]))
1362 			ipc_port_release_send(old_port[i]);
1363 	if (IP_VALID(new_port))		 /* consume send right */
1364 		ipc_port_release_send(new_port);
1365 	*CountCnt = count;
1366 	return KERN_SUCCESS;
1367 }/* thread_swap_exception_ports */
1368 
1369 kern_return_t
task_swap_exception_ports(task_t task,exception_mask_t exception_mask,ipc_port_t new_port,exception_behavior_t new_behavior,thread_state_flavor_t new_flavor,exception_mask_array_t masks,mach_msg_type_number_t * CountCnt,exception_port_array_t ports,exception_behavior_array_t behaviors,thread_state_flavor_array_t flavors)1370 task_swap_exception_ports(
1371 	task_t				task,
1372 	exception_mask_t		exception_mask,
1373 	ipc_port_t			new_port,
1374 	exception_behavior_t		new_behavior,
1375 	thread_state_flavor_t		new_flavor,
1376 	exception_mask_array_t		masks,
1377 	mach_msg_type_number_t		* CountCnt,
1378 	exception_port_array_t		ports,
1379 	exception_behavior_array_t      behaviors,
1380 	thread_state_flavor_array_t     flavors		)
1381 {
1382 	register int	i,
1383 			j,
1384 			count;
1385 	ipc_port_t	old_port[EXC_TYPES_COUNT];
1386 
1387 	if (task == TASK_NULL)
1388 		return KERN_INVALID_ARGUMENT;
1389 
1390 	if (exception_mask & ~EXC_MASK_ALL) {
1391 		return KERN_INVALID_ARGUMENT;
1392 	}
1393 
1394 	if (IP_VALID(new_port)) {
1395 		switch (new_behavior) {
1396 		case EXCEPTION_DEFAULT:
1397 		case EXCEPTION_STATE:
1398 		case EXCEPTION_STATE_IDENTITY:
1399 			break;
1400 		default:
1401 			return KERN_INVALID_ARGUMENT;
1402 		}
1403 	}
1404 	/* Cannot easily check "new_flavor", but that just means that
1405 	 * the flavor in the generated exception message might be garbage:
1406 	 * GIGO */
1407 
1408 	itk_lock(task);
1409 	if (task->itk_self == IP_NULL) {
1410 		itk_unlock(task);
1411 		return KERN_FAILURE;
1412 	}
1413 
1414 	count = 0;
1415 
1416 	for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
1417 		if (exception_mask & (1 << i)) {
1418 			for (j = 0; j < count; j++) {
1419 /*
1420  *				search for an identical entry, if found
1421  *				set corresponding mask for this exception.
1422  */
1423 				if (task->exc_actions[i].port == ports[j] &&
1424 				  task->exc_actions[i].behavior == behaviors[j]
1425 				  && task->exc_actions[i].flavor == flavors[j])
1426 				{
1427 					masks[j] |= (1 << i);
1428 					break;
1429 				}
1430 			}/* for */
1431 			if (j == count) {
1432 				masks[j] = (1 << i);
1433 				ports[j] =
1434 				ipc_port_copy_send(task->exc_actions[i].port);
1435 				behaviors[j] = task->exc_actions[i].behavior;
1436 				flavors[j] = task->exc_actions[i].flavor;
1437 				count++;
1438 			}
1439 			old_port[i] = task->exc_actions[i].port;
1440 			task->exc_actions[i].port =
1441 				ipc_port_copy_send(new_port);
1442 			task->exc_actions[i].behavior = new_behavior;
1443 			task->exc_actions[i].flavor = new_flavor;
1444 			if (count > *CountCnt) {
1445 				break;
1446 			}
1447 		} else
1448 			old_port[i] = IP_NULL;
1449 	}/* for */
1450 
1451 
1452 	/*
1453 	 * Consume send rights without any lock held.
1454 	 */
1455 	itk_unlock(task);
1456 	for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++)
1457 		if (IP_VALID(old_port[i]))
1458 			ipc_port_release_send(old_port[i]);
1459 	if (IP_VALID(new_port))		 /* consume send right */
1460 		ipc_port_release_send(new_port);
1461 	*CountCnt = count;
1462 
1463 	return KERN_SUCCESS;
1464 }/* task_swap_exception_ports */
1465 
1466 
1467 /*
1468  *	Routine:	host/task_get_exception_ports [kernel call]
1469  *	Purpose:
1470  *		Clones a send right for each of the thread/task's exception
1471  *		ports specified in the mask and returns the behaviour
1472  *		and flavor of said port.
1473  *
1474  *		Returns upto [in} CountCnt elements.
1475  *
1476  *	Conditions:
1477  *		Nothing locked.
1478  *	Returns:
1479  *		KERN_SUCCESS		Extracted a send right.
1480  *		KERN_INVALID_ARGUMENT	The thread is null,
1481  *					Invalid special port,
1482  *					Illegal mask bit set.
1483  *		KERN_FAILURE		The thread is dead.
1484  */
1485 
1486 kern_return_t
host_get_exception_ports(host_t host,exception_mask_t exception_mask,exception_mask_array_t masks,mach_msg_type_number_t * CountCnt,exception_port_array_t ports,exception_behavior_array_t behaviors,thread_state_flavor_array_t flavors)1487 host_get_exception_ports(
1488 	host_t			host,
1489 	exception_mask_t                exception_mask,
1490 	exception_mask_array_t		masks,
1491 	mach_msg_type_number_t		* CountCnt,
1492 	exception_port_array_t		ports,
1493 	exception_behavior_array_t      behaviors,
1494 	thread_state_flavor_array_t     flavors		)
1495 {
1496 	register int	i,
1497 			j,
1498 			count;
1499 
1500 	if (!host)
1501 		return KERN_INVALID_ARGUMENT;
1502 
1503 	if (exception_mask & ~EXC_MASK_ALL) {
1504 		return KERN_INVALID_ARGUMENT;
1505 	}
1506 
1507 	host_lock(host);
1508 	for (count = 0, i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
1509 		if (exception_mask & (1 << i)) {
1510 			for (j = 0; j < count; j++) {
1511 /*
1512  *				search for an identical entry, if found
1513  *				set corresponding mask for this exception.
1514  */
1515 				if (host->exc_actions[i].port == ports[j] &&
1516 				  host->exc_actions[i].behavior ==behaviors[j]
1517 				  && host->exc_actions[i].flavor == flavors[j])
1518 				{
1519 					masks[j] |= (1 << i);
1520 					break;
1521 				}
1522 			}/* for */
1523 			if (j == count) {
1524 				masks[j] = (1 << i);
1525 				ports[j] =
1526 				ipc_port_copy_send(host->exc_actions[i].port);
1527 				behaviors[j] = host->exc_actions[i].behavior;
1528 				flavors[j] = host->exc_actions[i].flavor;
1529 				count++;
1530 				if (count >= *CountCnt) {
1531 					break;
1532 				}
1533 			}
1534 		}
1535 	}/* for */
1536 
1537 	host_unlock(host);
1538 
1539 	*CountCnt = count;
1540 	return KERN_SUCCESS;
1541 }/* thread_get_exception_ports */
1542 
1543 kern_return_t
task_get_exception_ports(task_t task,exception_mask_t exception_mask,exception_mask_array_t masks,mach_msg_type_number_t * CountCnt,exception_port_array_t ports,exception_behavior_array_t behaviors,thread_state_flavor_array_t flavors)1544 task_get_exception_ports(
1545 	task_t				task,
1546 	exception_mask_t                exception_mask,
1547 	exception_mask_array_t		masks,
1548 	mach_msg_type_number_t		* CountCnt,
1549 	exception_port_array_t		ports,
1550 	exception_behavior_array_t      behaviors,
1551 	thread_state_flavor_array_t     flavors		)
1552 {
1553 	register int	i,
1554 			j,
1555 			count;
1556 
1557 	if (task == TASK_NULL)
1558 		return KERN_INVALID_ARGUMENT;
1559 
1560 	if (exception_mask & ~EXC_MASK_ALL) {
1561 		return KERN_INVALID_ARGUMENT;
1562 	}
1563 
1564 	itk_lock(task);
1565 	if (task->itk_self == IP_NULL) {
1566 		itk_unlock(task);
1567 		return KERN_FAILURE;
1568 	}
1569 
1570 	count = 0;
1571 
1572 	for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
1573 		if (exception_mask & (1 << i)) {
1574 			for (j = 0; j < count; j++) {
1575 /*
1576  *				search for an identical entry, if found
1577  *				set corresponding mask for this exception.
1578  */
1579 				if (task->exc_actions[i].port == ports[j] &&
1580 				  task->exc_actions[i].behavior == behaviors[j]
1581 				  && task->exc_actions[i].flavor == flavors[j])
1582 				{
1583 					masks[j] |= (1 << i);
1584 					break;
1585 				}
1586 			}/* for */
1587 			if (j == count) {
1588 				masks[j] = (1 << i);
1589 				ports[j] =
1590 				  ipc_port_copy_send(task->exc_actions[i].port);
1591 				behaviors[j] = task->exc_actions[i].behavior;
1592 				flavors[j] = task->exc_actions[i].flavor;
1593 				count++;
1594 				if (count > *CountCnt) {
1595 					break;
1596 				}
1597 			}
1598 		}
1599 	}/* for */
1600 
1601 	itk_unlock(task);
1602 
1603 	*CountCnt = count;
1604 	return KERN_SUCCESS;
1605 }/* task_get_exception_ports */
1606