1 /*
2 * Copyright (c) 2000-2009 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * @OSF_COPYRIGHT@
30 */
31 /*
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989,1988 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 [email protected]
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56 /*
57 */
58
59 /*
60 * kern/ipc_host.c
61 *
62 * Routines to implement host ports.
63 */
64 #include <mach/message.h>
65 #include <mach/mach_traps.h>
66 #include <mach/mach_host_server.h>
67 #include <mach/host_priv_server.h>
68 #include <kern/host.h>
69 #include <kern/processor.h>
70 #include <kern/task.h>
71 #include <kern/thread.h>
72 #include <kern/ipc_host.h>
73 #include <kern/ipc_kobject.h>
74 #include <kern/ux_handler.h>
75 #include <kern/misc_protos.h>
76 #include <kern/spl.h>
77 #include <ipc/ipc_port.h>
78 #include <ipc/ipc_space.h>
79
80 #if CONFIG_CSR
81 #include <sys/csr.h>
82 #endif
83
84 #if CONFIG_MACF
85 #include <security/mac_mach_internal.h>
86 #endif
87
88 /*
89 * ipc_host_init: set up various things.
90 */
91
92 extern lck_grp_t host_notify_lock_grp;
93
94 IPC_KOBJECT_DEFINE(IKOT_HOST,
95 .iko_op_stable = true,
96 .iko_op_permanent = true);
97 IPC_KOBJECT_DEFINE(IKOT_HOST_PRIV,
98 .iko_op_stable = true,
99 .iko_op_permanent = true);
100
101 IPC_KOBJECT_DEFINE(IKOT_PROCESSOR,
102 .iko_op_stable = true,
103 .iko_op_permanent = true);
104 IPC_KOBJECT_DEFINE(IKOT_PSET,
105 .iko_op_stable = true,
106 .iko_op_permanent = true);
107 IPC_KOBJECT_DEFINE(IKOT_PSET_NAME,
108 .iko_op_stable = true,
109 .iko_op_permanent = true);
110
111 void
ipc_host_init(void)112 ipc_host_init(void)
113 {
114 ipc_port_t port;
115 int i;
116
117 lck_mtx_init(&realhost.lock, &host_notify_lock_grp, LCK_ATTR_NULL);
118
119 /*
120 * Allocate and set up the two host ports.
121 */
122 port = ipc_kobject_alloc_port((ipc_kobject_t) &realhost, IKOT_HOST,
123 IPC_KOBJECT_ALLOC_MAKE_SEND);
124 kernel_set_special_port(&realhost, HOST_PORT, port);
125
126 port = ipc_kobject_alloc_port((ipc_kobject_t) &realhost, IKOT_HOST_PRIV,
127 IPC_KOBJECT_ALLOC_MAKE_SEND);
128 kernel_set_special_port(&realhost, HOST_PRIV_PORT, port);
129
130 /* the rest of the special ports will be set up later */
131
132 bzero(&realhost.exc_actions[0], sizeof(realhost.exc_actions[0]));
133 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
134 realhost.exc_actions[i].port = IP_NULL;
135 /* The mac framework is not yet initialized, so we defer
136 * initializing the labels to later, when they are set
137 * for the first time. */
138 realhost.exc_actions[i].label = NULL;
139 /* initialize the entire exception action struct */
140 realhost.exc_actions[i].behavior = 0;
141 realhost.exc_actions[i].flavor = 0;
142 realhost.exc_actions[i].privileged = FALSE;
143 } /* for */
144
145 /*
146 * Set up ipc for default processor set.
147 */
148 ipc_pset_init(&pset0);
149
150 /*
151 * And for master processor
152 */
153 ipc_processor_init(master_processor);
154 }
155
156 /*
157 * Routine: host_self_trap [mach trap]
158 * Purpose:
159 * Give the caller send rights for his own host port.
160 * Conditions:
161 * Nothing locked.
162 * Returns:
163 * MACH_PORT_NULL if there are any resource failures
164 * or other errors.
165 */
166
167 mach_port_name_t
host_self_trap(__unused struct host_self_trap_args * args)168 host_self_trap(
169 __unused struct host_self_trap_args *args)
170 {
171 task_t self = current_task();
172 ipc_port_t sright;
173 mach_port_name_t name;
174
175 itk_lock(self);
176 sright = host_port_copy_send(self->itk_host);
177 itk_unlock(self);
178 name = ipc_port_copyout_send(sright, current_space());
179 return name;
180 }
181
182 /*
183 * ipc_processor_init:
184 *
185 * Initialize ipc access to processor by allocating port.
186 */
187
188 void
ipc_processor_init(processor_t processor)189 ipc_processor_init(
190 processor_t processor)
191 {
192 processor->processor_self = ipc_kobject_alloc_port(processor,
193 IKOT_PROCESSOR, IPC_KOBJECT_ALLOC_NONE);
194 }
195
196 /*
197 * ipc_pset_init:
198 *
199 * Initialize ipc control of a processor set by allocating its ports.
200 */
201
202 void
ipc_pset_init(processor_set_t pset)203 ipc_pset_init(
204 processor_set_t pset)
205 {
206 pset->pset_self = ipc_kobject_alloc_port(pset,
207 IKOT_PSET, IPC_KOBJECT_ALLOC_NONE);
208 pset->pset_name_self = ipc_kobject_alloc_port(pset,
209 IKOT_PSET_NAME, IPC_KOBJECT_ALLOC_NONE);
210 }
211
212 /*
213 * processor_set_default:
214 *
215 * Return ports for manipulating default_processor set.
216 */
217 kern_return_t
processor_set_default(host_t host,processor_set_t * pset)218 processor_set_default(
219 host_t host,
220 processor_set_t *pset)
221 {
222 if (host == HOST_NULL) {
223 return KERN_INVALID_ARGUMENT;
224 }
225
226 *pset = &pset0;
227
228 return KERN_SUCCESS;
229 }
230
231 /*
232 * Routine: convert_port_to_host
233 * Purpose:
234 * Convert from a port to a host.
235 * Doesn't consume the port ref; the host produced may be null.
236 * Conditions:
237 * Nothing locked.
238 */
239
240 host_t
convert_port_to_host(ipc_port_t port)241 convert_port_to_host(
242 ipc_port_t port)
243 {
244 host_t host = HOST_NULL;
245 ipc_kobject_type_t type;
246
247 if (IP_VALID(port)) {
248 type = ip_kotype(port);
249 if (type == IKOT_HOST || type == IKOT_HOST_PRIV) {
250 host = (host_t)ipc_kobject_get_stable(port, type);
251 if (host && host != &realhost) {
252 panic("unexpected host object: %p", host);
253 }
254 }
255 }
256 return host;
257 }
258
259 /*
260 * Routine: convert_port_to_host_priv
261 * Purpose:
262 * Convert from a port to a host.
263 * Doesn't consume the port ref; the host produced may be null.
264 * Conditions:
265 * Nothing locked.
266 */
267
268 host_t
convert_port_to_host_priv(ipc_port_t port)269 convert_port_to_host_priv(
270 ipc_port_t port)
271 {
272 host_t host = HOST_NULL;
273
274 /* reject translation if itk_host is not host_priv */
275 if (port != current_task()->itk_host) {
276 return HOST_NULL;
277 }
278
279 if (IP_VALID(port)) {
280 host = ipc_kobject_get_stable(port, IKOT_HOST_PRIV);
281 if (host && host != &realhost) {
282 panic("unexpected host object: %p", host);
283 }
284 }
285
286 return host;
287 }
288
289 /*
290 * Routine: convert_port_to_processor
291 * Purpose:
292 * Convert from a port to a processor.
293 * Doesn't consume the port ref;
294 * the processor produced may be null.
295 * Conditions:
296 * Nothing locked.
297 */
298
299 processor_t
convert_port_to_processor(ipc_port_t port)300 convert_port_to_processor(
301 ipc_port_t port)
302 {
303 processor_t processor = PROCESSOR_NULL;
304
305 if (IP_VALID(port)) {
306 processor = ipc_kobject_get_stable(port, IKOT_PROCESSOR);
307 }
308
309 return processor;
310 }
311
312 /*
313 * Routine: convert_port_to_pset
314 * Purpose:
315 * Convert from a port to a pset.
316 * Doesn't consume the port ref
317 * which may be null.
318 * Conditions:
319 * Nothing locked.
320 */
321
322 processor_set_t
convert_port_to_pset(ipc_port_t port)323 convert_port_to_pset(
324 ipc_port_t port)
325 {
326 processor_set_t pset = PROCESSOR_SET_NULL;
327
328 if (IP_VALID(port)) {
329 pset = ipc_kobject_get_stable(port, IKOT_PSET);
330 }
331
332 return pset;
333 }
334
335 /*
336 * Routine: convert_port_to_pset_name
337 * Purpose:
338 * Convert from a port to a pset.
339 * Doesn't consume the port ref
340 * which may be null.
341 * Conditions:
342 * Nothing locked.
343 */
344
345 processor_set_name_t
convert_port_to_pset_name(ipc_port_t port)346 convert_port_to_pset_name(
347 ipc_port_t port)
348 {
349 processor_set_t pset = PROCESSOR_SET_NULL;
350 ipc_kobject_type_t type;
351
352 if (IP_VALID(port)) {
353 type = ip_kotype(port);
354 if (type == IKOT_PSET || type == IKOT_PSET_NAME) {
355 pset = ipc_kobject_get_stable(port, type);
356 }
357 }
358 return pset;
359 }
360
361 /*
362 * Routine: host_port_copy_send
363 * Purpose:
364 * Copies a send right for a host port (priv or not)
365 * Conditions:
366 * Nothing locked.
367 */
368
369 ipc_port_t
host_port_copy_send(ipc_port_t port)370 host_port_copy_send(ipc_port_t port)
371 {
372 if (IP_VALID(port)) {
373 ipc_kobject_type_t kotype = ip_kotype(port);
374
375 if (kotype == IKOT_HOST) {
376 port = ipc_kobject_copy_send(port,
377 host_self(), IKOT_HOST);
378 } else if (kotype == IKOT_HOST_PRIV) {
379 port = ipc_kobject_copy_send(port,
380 host_priv_self(), IKOT_HOST_PRIV);
381 #if CONFIG_CSR
382 } else if (kotype == IKOT_NONE &&
383 (csr_check(CSR_ALLOW_KERNEL_DEBUGGER) == 0)) {
384 port = ipc_port_copy_send_mqueue(port);
385 #endif
386 } else {
387 panic("port %p is an invalid host port", port);
388 }
389 }
390
391 return port;
392 }
393
394 /*
395 * Routine: convert_host_to_port
396 * Purpose:
397 * Convert from a host to a port.
398 * Produces a naked send right which may be invalid.
399 * Conditions:
400 * Nothing locked.
401 */
402
403 ipc_port_t
convert_host_to_port(host_t host)404 convert_host_to_port(
405 host_t host)
406 {
407 ipc_port_t port = IP_NULL;
408 __assert_only kern_return_t kr;
409
410 kr = host_get_host_port(host, &port);
411 assert(kr == KERN_SUCCESS);
412 return port;
413 }
414
415 /*
416 * Routine: convert_processor_to_port
417 * Purpose:
418 * Convert from a processor to a port.
419 * Produces a naked send right which may be invalid.
420 * Processors are not reference counted, so nothing to release.
421 * Conditions:
422 * Nothing locked.
423 */
424
425 ipc_port_t
convert_processor_to_port(processor_t processor)426 convert_processor_to_port(
427 processor_t processor)
428 {
429 ipc_port_t port = processor->processor_self;
430
431 if (port != IP_NULL) {
432 port = ipc_kobject_make_send(port, processor, IKOT_PROCESSOR);
433 }
434 return port;
435 }
436
437 /*
438 * Routine: convert_pset_to_port
439 * Purpose:
440 * Convert from a pset to a port.
441 * Produces a naked send right which may be invalid.
442 * Processor sets are not reference counted, so nothing to release.
443 * Conditions:
444 * Nothing locked.
445 */
446
447 ipc_port_t
convert_pset_to_port(processor_set_t pset)448 convert_pset_to_port(
449 processor_set_t pset)
450 {
451 return ipc_kobject_make_send(pset->pset_self, pset, IKOT_PSET);
452 }
453
454 /*
455 * Routine: convert_pset_name_to_port
456 * Purpose:
457 * Convert from a pset to a port.
458 * Produces a naked send right which may be invalid.
459 * Processor sets are not reference counted, so nothing to release.
460 * Conditions:
461 * Nothing locked.
462 */
463
464 ipc_port_t
convert_pset_name_to_port(processor_set_name_t pset)465 convert_pset_name_to_port(
466 processor_set_name_t pset)
467 {
468 return ipc_kobject_make_send(pset->pset_name_self, pset, IKOT_PSET_NAME);
469 }
470
471 /*
472 * Routine: host_set_exception_ports [kernel call]
473 * Purpose:
474 * Sets the host exception port, flavor and
475 * behavior for the exception types specified by the mask.
476 * There will be one send right per exception per valid
477 * port.
478 * Conditions:
479 * Nothing locked. If successful, consumes
480 * the supplied send right.
481 * Returns:
482 * KERN_SUCCESS Changed the special port.
483 * KERN_INVALID_ARGUMENT The host_priv is not valid,
484 * Illegal mask bit set.
485 * Illegal exception behavior
486 * KERN_NO_ACCESS Restricted access to set port
487 */
488 kern_return_t
host_set_exception_ports(host_priv_t host_priv,exception_mask_t exception_mask,ipc_port_t new_port,exception_behavior_t new_behavior,thread_state_flavor_t new_flavor)489 host_set_exception_ports(
490 host_priv_t host_priv,
491 exception_mask_t exception_mask,
492 ipc_port_t new_port,
493 exception_behavior_t new_behavior,
494 thread_state_flavor_t new_flavor)
495 {
496 int i;
497 ipc_port_t old_port[EXC_TYPES_COUNT];
498
499 #if CONFIG_MACF
500 struct label *deferred_labels[EXC_TYPES_COUNT];
501 struct label *new_label;
502 #endif
503
504 if (host_priv == HOST_PRIV_NULL) {
505 return KERN_INVALID_ARGUMENT;
506 }
507
508 kern_return_t kr = set_exception_ports_validation(NULL, exception_mask, new_port, new_behavior, new_flavor, false);
509 if (kr != KERN_SUCCESS) {
510 return kr;
511 }
512
513 #if CONFIG_MACF
514 if (mac_task_check_set_host_exception_ports(current_task(), exception_mask) != 0) {
515 return KERN_NO_ACCESS;
516 }
517
518 new_label = mac_exc_create_label_for_current_proc();
519
520 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
521 if (mac_exc_label(&host_priv->exc_actions[i]) == NULL) {
522 deferred_labels[i] = mac_exc_create_label(&host_priv->exc_actions[i]);
523 } else {
524 deferred_labels[i] = NULL;
525 }
526 }
527 #endif
528
529 host_lock(host_priv);
530
531 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
532 #if CONFIG_MACF
533 if (mac_exc_label(&host_priv->exc_actions[i]) == NULL) {
534 // Lazy initialization (see ipc_port_init).
535 mac_exc_associate_action_label(&host_priv->exc_actions[i], deferred_labels[i]);
536 deferred_labels[i] = NULL; // Label is used, do not free.
537 }
538 #endif
539
540 if ((exception_mask & (1 << i))
541 #if CONFIG_MACF
542 && mac_exc_update_action_label(&host_priv->exc_actions[i], new_label) == 0
543 #endif
544 ) {
545 old_port[i] = host_priv->exc_actions[i].port;
546
547 host_priv->exc_actions[i].port =
548 exception_port_copy_send(new_port);
549 host_priv->exc_actions[i].behavior = new_behavior;
550 host_priv->exc_actions[i].flavor = new_flavor;
551 } else {
552 old_port[i] = IP_NULL;
553 }
554 }/* for */
555
556 /*
557 * Consume send rights without any lock held.
558 */
559 host_unlock(host_priv);
560
561 #if CONFIG_MACF
562 mac_exc_free_label(new_label);
563 #endif
564
565 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
566 if (IP_VALID(old_port[i])) {
567 ipc_port_release_send(old_port[i]);
568 }
569 #if CONFIG_MACF
570 if (deferred_labels[i] != NULL) {
571 /* Deferred label went unused: Another thread has completed the lazy initialization. */
572 mac_exc_free_label(deferred_labels[i]);
573 }
574 #endif
575 }
576 if (IP_VALID(new_port)) { /* consume send right */
577 ipc_port_release_send(new_port);
578 }
579
580 return KERN_SUCCESS;
581 }
582
583 /*
584 * Routine: host_get_exception_ports [kernel call]
585 * Purpose:
586 * Clones a send right for each of the host's exception
587 * ports specified in the mask and returns the behaviour
588 * and flavor of said port.
589 *
590 * Returns upto [in} CountCnt elements.
591 *
592 * Conditions:
593 * Nothing locked.
594 * Returns:
595 * KERN_SUCCESS Extracted a send right.
596 * KERN_INVALID_ARGUMENT Invalid host_priv specified,
597 * Invalid special port,
598 * Illegal mask bit set.
599 * KERN_FAILURE The thread is dead.
600 */
601 kern_return_t
host_get_exception_ports(host_priv_t host_priv,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)602 host_get_exception_ports(
603 host_priv_t host_priv,
604 exception_mask_t exception_mask,
605 exception_mask_array_t masks,
606 mach_msg_type_number_t * CountCnt,
607 exception_port_array_t ports,
608 exception_behavior_array_t behaviors,
609 thread_state_flavor_array_t flavors )
610 {
611 unsigned int i, j, count;
612
613 if (host_priv == HOST_PRIV_NULL) {
614 return KERN_INVALID_ARGUMENT;
615 }
616
617 if (exception_mask & ~EXC_MASK_VALID) {
618 return KERN_INVALID_ARGUMENT;
619 }
620
621 host_lock(host_priv);
622
623 count = 0;
624
625 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
626 if (exception_mask & (1 << i)) {
627 for (j = 0; j < count; j++) {
628 /*
629 * search for an identical entry, if found
630 * set corresponding mask for this exception.
631 */
632 if (host_priv->exc_actions[i].port == ports[j] &&
633 host_priv->exc_actions[i].behavior == behaviors[j]
634 && host_priv->exc_actions[i].flavor == flavors[j]) {
635 masks[j] |= (1 << i);
636 break;
637 }
638 }/* for */
639 if (j == count && count < *CountCnt) {
640 masks[j] = (1 << i);
641 ports[j] =
642 exception_port_copy_send(host_priv->exc_actions[i].port);
643 behaviors[j] = host_priv->exc_actions[i].behavior;
644 flavors[j] = host_priv->exc_actions[i].flavor;
645 count++;
646 }
647 }
648 }/* for */
649 host_unlock(host_priv);
650
651 *CountCnt = count;
652 return KERN_SUCCESS;
653 }
654
655 kern_return_t
host_swap_exception_ports(host_priv_t host_priv,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)656 host_swap_exception_ports(
657 host_priv_t host_priv,
658 exception_mask_t exception_mask,
659 ipc_port_t new_port,
660 exception_behavior_t new_behavior,
661 thread_state_flavor_t new_flavor,
662 exception_mask_array_t masks,
663 mach_msg_type_number_t * CountCnt,
664 exception_port_array_t ports,
665 exception_behavior_array_t behaviors,
666 thread_state_flavor_array_t flavors )
667 {
668 unsigned int i,
669 j,
670 count;
671 ipc_port_t old_port[EXC_TYPES_COUNT];
672
673 #if CONFIG_MACF
674 struct label *deferred_labels[EXC_TYPES_COUNT];
675 struct label *new_label;
676 #endif
677
678 if (host_priv == HOST_PRIV_NULL) {
679 return KERN_INVALID_ARGUMENT;
680 }
681
682 kern_return_t kr = set_exception_ports_validation(NULL, exception_mask, new_port, new_behavior, new_flavor, false);
683 if (kr != KERN_SUCCESS) {
684 return kr;
685 }
686
687 #if CONFIG_MACF
688 if (mac_task_check_set_host_exception_ports(current_task(), exception_mask) != 0) {
689 return KERN_NO_ACCESS;
690 }
691
692 new_label = mac_exc_create_label_for_current_proc();
693
694 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
695 if (mac_exc_label(&host_priv->exc_actions[i]) == NULL) {
696 deferred_labels[i] = mac_exc_create_label(&host_priv->exc_actions[i]);
697 } else {
698 deferred_labels[i] = NULL;
699 }
700 }
701 #endif /* CONFIG_MACF */
702
703 host_lock(host_priv);
704
705 assert(EXC_TYPES_COUNT > FIRST_EXCEPTION);
706 for (count = 0, i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT && count < *CountCnt; i++) {
707 #if CONFIG_MACF
708 if (mac_exc_label(&host_priv->exc_actions[i]) == NULL) {
709 // Lazy initialization (see ipc_port_init).
710 mac_exc_associate_action_label(&host_priv->exc_actions[i], deferred_labels[i]);
711 deferred_labels[i] = NULL; // Label is used, do not free.
712 }
713 #endif
714
715 if ((exception_mask & (1 << i))
716 #if CONFIG_MACF
717 && mac_exc_update_action_label(&host_priv->exc_actions[i], new_label) == 0
718 #endif
719 ) {
720 for (j = 0; j < count; j++) {
721 /*
722 * search for an identical entry, if found
723 * set corresponding mask for this exception.
724 */
725 if (host_priv->exc_actions[i].port == ports[j] &&
726 host_priv->exc_actions[i].behavior == behaviors[j]
727 && host_priv->exc_actions[i].flavor == flavors[j]) {
728 masks[j] |= (1 << i);
729 break;
730 }
731 }/* for */
732 if (j == count) {
733 masks[j] = (1 << i);
734 ports[j] =
735 exception_port_copy_send(host_priv->exc_actions[i].port);
736 behaviors[j] = host_priv->exc_actions[i].behavior;
737 flavors[j] = host_priv->exc_actions[i].flavor;
738 count++;
739 }
740 old_port[i] = host_priv->exc_actions[i].port;
741 host_priv->exc_actions[i].port =
742 exception_port_copy_send(new_port);
743 host_priv->exc_actions[i].behavior = new_behavior;
744 host_priv->exc_actions[i].flavor = new_flavor;
745 } else {
746 old_port[i] = IP_NULL;
747 }
748 }/* for */
749 host_unlock(host_priv);
750
751 #if CONFIG_MACF
752 mac_exc_free_label(new_label);
753 #endif
754
755 /*
756 * Consume send rights without any lock held.
757 */
758 while (--i >= FIRST_EXCEPTION) {
759 if (IP_VALID(old_port[i])) {
760 ipc_port_release_send(old_port[i]);
761 }
762 #if CONFIG_MACF
763 if (deferred_labels[i] != NULL) {
764 mac_exc_free_label(deferred_labels[i]); // Label unused.
765 }
766 #endif
767 }
768
769 if (IP_VALID(new_port)) { /* consume send right */
770 ipc_port_release_send(new_port);
771 }
772 *CountCnt = count;
773
774 return KERN_SUCCESS;
775 }
776