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 Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56/*
57 */
58
59/*
60 * 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/misc_protos.h>
75#include <kern/spl.h>
76#include <ipc/ipc_port.h>
77#include <ipc/ipc_space.h>
78
79#if CONFIG_MACF
80#include <security/mac_mach_internal.h>
81#endif
82
83/*
84 * Forward declarations
85 */
86
87boolean_t
88ref_pset_port_locked(
89 ipc_port_t port, boolean_t matchn, processor_set_t *ppset);
90
91/*
92 * ipc_host_init: set up various things.
93 */
94
95extern lck_grp_t host_notify_lock_grp;
96extern lck_attr_t host_notify_lock_attr;
97
98void ipc_host_init(void)
99{
100 ipc_port_t port;
101 int i;
102
103 lck_mtx_init(&realhost.lock, &host_notify_lock_grp, &host_notify_lock_attr);
104
105 /*
106 * Allocate and set up the two host ports.
107 */
108 port = ipc_port_alloc_kernel();
109 if (port == IP_NULL)
110 panic("ipc_host_init");
111
112 ipc_kobject_set(port, (ipc_kobject_t) &realhost, IKOT_HOST_SECURITY);
113 kernel_set_special_port(&realhost, HOST_SECURITY_PORT,
114 ipc_port_make_send(port));
115
116 port = ipc_port_alloc_kernel();
117 if (port == IP_NULL)
118 panic("ipc_host_init");
119
120 ipc_kobject_set(port, (ipc_kobject_t) &realhost, IKOT_HOST);
121 kernel_set_special_port(&realhost, HOST_PORT,
122 ipc_port_make_send(port));
123
124 port = ipc_port_alloc_kernel();
125 if (port == IP_NULL)
126 panic("ipc_host_init");
127
128 ipc_kobject_set(port, (ipc_kobject_t) &realhost, IKOT_HOST_PRIV);
129 kernel_set_special_port(&realhost, HOST_PRIV_PORT,
130 ipc_port_make_send(port));
131
132 /* the rest of the special ports will be set up later */
133
134 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
135 realhost.exc_actions[i].port = IP_NULL;
136 /* The mac framework is not yet initialized, so we defer
137 * initializing the labels to later, when they are set
138 * for the first time. */
139 realhost.exc_actions[i].label = NULL;
140 }/* for */
141
142 /*
143 * Set up ipc for default processor set.
144 */
145 ipc_pset_init(&pset0);
146 ipc_pset_enable(&pset0);
147
148 /*
149 * And for master processor
150 */
151 ipc_processor_init(master_processor);
152 ipc_processor_enable(master_processor);
153}
154
155/*
156 * Routine: host_self_trap [mach trap]
157 * Purpose:
158 * Give the caller send rights for his own host port.
159 * Conditions:
160 * Nothing locked.
161 * Returns:
162 * MACH_PORT_NULL if there are any resource failures
163 * or other errors.
164 */
165
166mach_port_name_t
167host_self_trap(
168 __unused struct host_self_trap_args *args)
169{
170 task_t self = current_task();
171 ipc_port_t sright;
172 mach_port_name_t name;
173
174 itk_lock(self);
175 sright = ipc_port_copy_send(self->itk_host);
176 itk_unlock(self);
177 name = ipc_port_copyout_send(sright, current_space());
178 return name;
179}
180
181/*
182 * ipc_processor_init:
183 *
184 * Initialize ipc access to processor by allocating port.
185 */
186
187void
188ipc_processor_init(
189 processor_t processor)
190{
191 ipc_port_t port;
192
193 port = ipc_port_alloc_kernel();
194 if (port == IP_NULL)
195 panic("ipc_processor_init");
196 processor->processor_self = port;
197}
198
199/*
200 * ipc_processor_enable:
201 *
202 * Enable ipc control of processor by setting port object.
203 */
204void
205ipc_processor_enable(
206 processor_t processor)
207{
208 ipc_port_t myport;
209
210 myport = processor->processor_self;
211 ipc_kobject_set(myport, (ipc_kobject_t) processor, IKOT_PROCESSOR);
212}
213
214/*
215 * ipc_pset_init:
216 *
217 * Initialize ipc control of a processor set by allocating its ports.
218 */
219
220void
221ipc_pset_init(
222 processor_set_t pset)
223{
224 ipc_port_t port;
225
226 port = ipc_port_alloc_kernel();
227 if (port == IP_NULL)
228 panic("ipc_pset_init");
229 pset->pset_self = port;
230
231 port = ipc_port_alloc_kernel();
232 if (port == IP_NULL)
233 panic("ipc_pset_init");
234 pset->pset_name_self = port;
235}
236
237/*
238 * ipc_pset_enable:
239 *
240 * Enable ipc access to a processor set.
241 */
242void
243ipc_pset_enable(
244 processor_set_t pset)
245{
246 ipc_kobject_set(pset->pset_self, (ipc_kobject_t) pset, IKOT_PSET);
247 ipc_kobject_set(pset->pset_name_self, (ipc_kobject_t) pset, IKOT_PSET_NAME);
248}
249
250/*
251 * processor_set_default:
252 *
253 * Return ports for manipulating default_processor set.
254 */
255kern_return_t
256processor_set_default(
257 host_t host,
258 processor_set_t *pset)
259{
260 if (host == HOST_NULL)
261 return(KERN_INVALID_ARGUMENT);
262
263 *pset = &pset0;
264
265 return (KERN_SUCCESS);
266}
267
268/*
269 * Routine: convert_port_to_host
270 * Purpose:
271 * Convert from a port to a host.
272 * Doesn't consume the port ref; the host produced may be null.
273 * Conditions:
274 * Nothing locked.
275 */
276
277host_t
278convert_port_to_host(
279 ipc_port_t port)
280{
281 host_t host = HOST_NULL;
282
283 if (IP_VALID(port)) {
284 if (ip_kotype(port) == IKOT_HOST ||
285 ip_kotype(port) == IKOT_HOST_PRIV) {
286 host = (host_t) port->ip_kobject;
287 assert(ip_active(port));
288 }
289 }
290 return host;
291}
292
293/*
294 * Routine: convert_port_to_host_priv
295 * Purpose:
296 * Convert from a port to a host.
297 * Doesn't consume the port ref; the host produced may be null.
298 * Conditions:
299 * Nothing locked.
300 */
301
302host_t
303convert_port_to_host_priv(
304 ipc_port_t port)
305{
306 host_t host = HOST_NULL;
307
308 if (IP_VALID(port)) {
309 ip_lock(port);
310 if (ip_active(port) &&
311 (ip_kotype(port) == IKOT_HOST_PRIV))
312 host = (host_t) port->ip_kobject;
313 ip_unlock(port);
314 }
315
316 return host;
317}
318
319/*
320 * Routine: convert_port_to_processor
321 * Purpose:
322 * Convert from a port to a processor.
323 * Doesn't consume the port ref;
324 * the processor produced may be null.
325 * Conditions:
326 * Nothing locked.
327 */
328
329processor_t
330convert_port_to_processor(
331 ipc_port_t port)
332{
333 processor_t processor = PROCESSOR_NULL;
334
335 if (IP_VALID(port)) {
336 ip_lock(port);
337 if (ip_active(port) &&
338 (ip_kotype(port) == IKOT_PROCESSOR))
339 processor = (processor_t) port->ip_kobject;
340 ip_unlock(port);
341 }
342
343 return processor;
344}
345
346/*
347 * Routine: convert_port_to_pset
348 * Purpose:
349 * Convert from a port to a pset.
350 * Doesn't consume the port ref; produces a pset ref,
351 * which may be null.
352 * Conditions:
353 * Nothing locked.
354 */
355
356processor_set_t
357convert_port_to_pset(
358 ipc_port_t port)
359{
360 boolean_t r;
361 processor_set_t pset = PROCESSOR_SET_NULL;
362
363 r = FALSE;
364 while (!r && IP_VALID(port)) {
365 ip_lock(port);
366 r = ref_pset_port_locked(port, FALSE, &pset);
367 /* port unlocked */
368 }
369 return pset;
370}
371
372/*
373 * Routine: convert_port_to_pset_name
374 * Purpose:
375 * Convert from a port to a pset.
376 * Doesn't consume the port ref; produces a pset ref,
377 * which may be null.
378 * Conditions:
379 * Nothing locked.
380 */
381
382processor_set_name_t
383convert_port_to_pset_name(
384 ipc_port_t port)
385{
386 boolean_t r;
387 processor_set_t pset = PROCESSOR_SET_NULL;
388
389 r = FALSE;
390 while (!r && IP_VALID(port)) {
391 ip_lock(port);
392 r = ref_pset_port_locked(port, TRUE, &pset);
393 /* port unlocked */
394 }
395 return pset;
396}
397
398boolean_t
399ref_pset_port_locked(ipc_port_t port, boolean_t matchn, processor_set_t *ppset)
400{
401 processor_set_t pset;
402
403 pset = PROCESSOR_SET_NULL;
404 if (ip_active(port) &&
405 ((ip_kotype(port) == IKOT_PSET) ||
406 (matchn && (ip_kotype(port) == IKOT_PSET_NAME)))) {
407 pset = (processor_set_t) port->ip_kobject;
408 }
409
410 *ppset = pset;
411 ip_unlock(port);
412
413 return (TRUE);
414}
415
416/*
417 * Routine: convert_host_to_port
418 * Purpose:
419 * Convert from a host to a port.
420 * Produces a naked send right which may be invalid.
421 * Conditions:
422 * Nothing locked.
423 */
424
425ipc_port_t
426convert_host_to_port(
427 host_t host)
428{
429 ipc_port_t port;
430
431 host_get_host_port(host, &port);
432 return port;
433}
434
435/*
436 * Routine: convert_processor_to_port
437 * Purpose:
438 * Convert from a processor to a port.
439 * Produces a naked send right which may be invalid.
440 * Processors are not reference counted, so nothing to release.
441 * Conditions:
442 * Nothing locked.
443 */
444
445ipc_port_t
446convert_processor_to_port(
447 processor_t processor)
448{
449 ipc_port_t port = processor->processor_self;
450
451 if (port != IP_NULL)
452 port = ipc_port_make_send(port);
453 return port;
454}
455
456/*
457 * Routine: convert_pset_to_port
458 * Purpose:
459 * Convert from a pset to a port.
460 * Produces a naked send right which may be invalid.
461 * Processor sets are not reference counted, so nothing to release.
462 * Conditions:
463 * Nothing locked.
464 */
465
466ipc_port_t
467convert_pset_to_port(
468 processor_set_t pset)
469{
470 ipc_port_t port = pset->pset_self;
471
472 if (port != IP_NULL)
473 port = ipc_port_make_send(port);
474
475 return port;
476}
477
478/*
479 * Routine: convert_pset_name_to_port
480 * Purpose:
481 * Convert from a pset to a port.
482 * Produces a naked send right which may be invalid.
483 * Processor sets are not reference counted, so nothing to release.
484 * Conditions:
485 * Nothing locked.
486 */
487
488ipc_port_t
489convert_pset_name_to_port(
490 processor_set_name_t pset)
491{
492 ipc_port_t port = pset->pset_name_self;
493
494 if (port != IP_NULL)
495 port = ipc_port_make_send(port);
496
497 return port;
498}
499
500/*
501 * Routine: convert_port_to_host_security
502 * Purpose:
503 * Convert from a port to a host security.
504 * Doesn't consume the port ref; the port produced may be null.
505 * Conditions:
506 * Nothing locked.
507 */
508
509host_t
510convert_port_to_host_security(
511 ipc_port_t port)
512{
513 host_t host = HOST_NULL;
514
515 if (IP_VALID(port)) {
516 ip_lock(port);
517 if (ip_active(port) &&
518 (ip_kotype(port) == IKOT_HOST_SECURITY))
519 host = (host_t) port->ip_kobject;
520 ip_unlock(port);
521 }
522
523 return host;
524}
525
526/*
527 * Routine: host_set_exception_ports [kernel call]
528 * Purpose:
529 * Sets the host exception port, flavor and
530 * behavior for the exception types specified by the mask.
531 * There will be one send right per exception per valid
532 * port.
533 * Conditions:
534 * Nothing locked. If successful, consumes
535 * the supplied send right.
536 * Returns:
537 * KERN_SUCCESS Changed the special port.
538 * KERN_INVALID_ARGUMENT The host_priv is not valid,
539 * Illegal mask bit set.
540 * Illegal exception behavior
541 */
542kern_return_t
543host_set_exception_ports(
544 host_priv_t host_priv,
545 exception_mask_t exception_mask,
546 ipc_port_t new_port,
547 exception_behavior_t new_behavior,
548 thread_state_flavor_t new_flavor)
549{
550 int i;
551 ipc_port_t old_port[EXC_TYPES_COUNT];
552
553#if CONFIG_MACF
554 struct label *deferred_labels[EXC_TYPES_COUNT];
555 struct label *new_label;
556#endif
557
558 if (host_priv == HOST_PRIV_NULL) {
559 return KERN_INVALID_ARGUMENT;
560 }
561
562 if (exception_mask & ~EXC_MASK_VALID) {
563 return KERN_INVALID_ARGUMENT;
564 }
565
566 if (IP_VALID(new_port)) {
567 switch (new_behavior & ~MACH_EXCEPTION_CODES) {
568 case EXCEPTION_DEFAULT:
569 case EXCEPTION_STATE:
570 case EXCEPTION_STATE_IDENTITY:
571 break;
572 default:
573 return KERN_INVALID_ARGUMENT;
574 }
575 }
576
577 /*
578 * Check the validity of the thread_state_flavor by calling the
579 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in
580 * osfmk/mach/ARCHITECTURE/thread_status.h
581 */
582 if (new_flavor != 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor))
583 return (KERN_INVALID_ARGUMENT);
584
585#if CONFIG_MACF
586 if (mac_task_check_set_host_exception_ports(current_task(), exception_mask) != 0)
587 return KERN_NO_ACCESS;
588
589 new_label = mac_exc_create_label_for_current_proc();
590
591 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
592 if (host_priv->exc_actions[i].label == NULL) {
593 deferred_labels[i] = mac_exc_create_label();
594 } else {
595 deferred_labels[i] = NULL;
596 }
597 }
598#endif
599
600 assert(host_priv == &realhost);
601
602 host_lock(host_priv);
603
604 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
605#if CONFIG_MACF
606 if (host_priv->exc_actions[i].label == NULL) {
607 // Lazy initialization (see ipc_port_init).
608 mac_exc_associate_action_label(&host_priv->exc_actions[i], deferred_labels[i]);
609 deferred_labels[i] = NULL; // Label is used, do not free.
610 }
611#endif
612
613 if ((exception_mask & (1 << i))
614#if CONFIG_MACF
615 && mac_exc_update_action_label(&host_priv->exc_actions[i], new_label) == 0
616#endif
617 ) {
618 old_port[i] = host_priv->exc_actions[i].port;
619
620 host_priv->exc_actions[i].port =
621 ipc_port_copy_send(new_port);
622 host_priv->exc_actions[i].behavior = new_behavior;
623 host_priv->exc_actions[i].flavor = new_flavor;
624 } else {
625 old_port[i] = IP_NULL;
626 }
627 }/* for */
628
629 /*
630 * Consume send rights without any lock held.
631 */
632 host_unlock(host_priv);
633
634#if CONFIG_MACF
635 mac_exc_free_label(new_label);
636#endif
637
638 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
639 if (IP_VALID(old_port[i]))
640 ipc_port_release_send(old_port[i]);
641#if CONFIG_MACF
642 if (deferred_labels[i] != NULL) {
643 /* Deferred label went unused: Another thread has completed the lazy initialization. */
644 mac_exc_free_label(deferred_labels[i]);
645 }
646#endif
647 }
648 if (IP_VALID(new_port)) /* consume send right */
649 ipc_port_release_send(new_port);
650
651 return KERN_SUCCESS;
652}
653
654/*
655 * Routine: host_get_exception_ports [kernel call]
656 * Purpose:
657 * Clones a send right for each of the host's exception
658 * ports specified in the mask and returns the behaviour
659 * and flavor of said port.
660 *
661 * Returns upto [in} CountCnt elements.
662 *
663 * Conditions:
664 * Nothing locked.
665 * Returns:
666 * KERN_SUCCESS Extracted a send right.
667 * KERN_INVALID_ARGUMENT Invalid host_priv specified,
668 * Invalid special port,
669 * Illegal mask bit set.
670 * KERN_FAILURE The thread is dead.
671 */
672kern_return_t
673host_get_exception_ports(
674 host_priv_t host_priv,
675 exception_mask_t exception_mask,
676 exception_mask_array_t masks,
677 mach_msg_type_number_t * CountCnt,
678 exception_port_array_t ports,
679 exception_behavior_array_t behaviors,
680 thread_state_flavor_array_t flavors )
681{
682 unsigned int i, j, count;
683
684 if (host_priv == HOST_PRIV_NULL)
685 return KERN_INVALID_ARGUMENT;
686
687 if (exception_mask & ~EXC_MASK_VALID) {
688 return KERN_INVALID_ARGUMENT;
689 }
690
691 assert (host_priv == &realhost);
692
693 host_lock(host_priv);
694
695 count = 0;
696
697 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
698 if (exception_mask & (1 << i)) {
699 for (j = 0; j < count; j++) {
700/*
701 * search for an identical entry, if found
702 * set corresponding mask for this exception.
703 */
704 if (host_priv->exc_actions[i].port == ports[j] &&
705 host_priv->exc_actions[i].behavior == behaviors[j]
706 && host_priv->exc_actions[i].flavor == flavors[j])
707 {
708 masks[j] |= (1 << i);
709 break;
710 }
711 }/* for */
712 if (j == count) {
713 masks[j] = (1 << i);
714 ports[j] =
715 ipc_port_copy_send(host_priv->exc_actions[i].port);
716 behaviors[j] = host_priv->exc_actions[i].behavior;
717 flavors[j] = host_priv->exc_actions[i].flavor;
718 count++;
719 if (count > *CountCnt) {
720 break;
721 }
722 }
723 }
724 }/* for */
725 host_unlock(host_priv);
726
727 *CountCnt = count;
728 return KERN_SUCCESS;
729}
730
731kern_return_t
732host_swap_exception_ports(
733 host_priv_t host_priv,
734 exception_mask_t exception_mask,
735 ipc_port_t new_port,
736 exception_behavior_t new_behavior,
737 thread_state_flavor_t new_flavor,
738 exception_mask_array_t masks,
739 mach_msg_type_number_t * CountCnt,
740 exception_port_array_t ports,
741 exception_behavior_array_t behaviors,
742 thread_state_flavor_array_t flavors )
743{
744 unsigned int i,
745 j,
746 count;
747 ipc_port_t old_port[EXC_TYPES_COUNT];
748
749#if CONFIG_MACF
750 struct label *deferred_labels[EXC_TYPES_COUNT];
751 struct label *new_label;
752#endif
753
754 if (host_priv == HOST_PRIV_NULL)
755 return KERN_INVALID_ARGUMENT;
756
757 if (exception_mask & ~EXC_MASK_VALID) {
758 return KERN_INVALID_ARGUMENT;
759 }
760
761 if (IP_VALID(new_port)) {
762 switch (new_behavior) {
763 case EXCEPTION_DEFAULT:
764 case EXCEPTION_STATE:
765 case EXCEPTION_STATE_IDENTITY:
766 break;
767 default:
768 return KERN_INVALID_ARGUMENT;
769 }
770 }
771
772 if (new_flavor != 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor))
773 return (KERN_INVALID_ARGUMENT);
774
775#if CONFIG_MACF
776 if (mac_task_check_set_host_exception_ports(current_task(), exception_mask) != 0)
777 return KERN_NO_ACCESS;
778
779 new_label = mac_exc_create_label_for_current_proc();
780
781 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
782 if (host_priv->exc_actions[i].label == NULL) {
783 deferred_labels[i] = mac_exc_create_label();
784 } else {
785 deferred_labels[i] = NULL;
786 }
787 }
788#endif /* CONFIG_MACF */
789
790 host_lock(host_priv);
791
792 assert(EXC_TYPES_COUNT > FIRST_EXCEPTION);
793 for (count=0, i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT && count < *CountCnt; i++) {
794#if CONFIG_MACF
795 if (host_priv->exc_actions[i].label == NULL) {
796 // Lazy initialization (see ipc_port_init).
797 mac_exc_associate_action_label(&host_priv->exc_actions[i], deferred_labels[i]);
798 deferred_labels[i] = NULL; // Label is used, do not free.
799 }
800#endif
801
802 if ((exception_mask & (1 << i))
803#if CONFIG_MACF
804 && mac_exc_update_action_label(&host_priv->exc_actions[i], new_label) == 0
805#endif
806 ) {
807 for (j = 0; j < count; j++) {
808/*
809 * search for an identical entry, if found
810 * set corresponding mask for this exception.
811 */
812 if (host_priv->exc_actions[i].port == ports[j] &&
813 host_priv->exc_actions[i].behavior == behaviors[j]
814 && host_priv->exc_actions[i].flavor == flavors[j])
815 {
816 masks[j] |= (1 << i);
817 break;
818 }
819 }/* for */
820 if (j == count) {
821 masks[j] = (1 << i);
822 ports[j] =
823 ipc_port_copy_send(host_priv->exc_actions[i].port);
824 behaviors[j] = host_priv->exc_actions[i].behavior;
825 flavors[j] = host_priv->exc_actions[i].flavor;
826 count++;
827 }
828 old_port[i] = host_priv->exc_actions[i].port;
829 host_priv->exc_actions[i].port =
830 ipc_port_copy_send(new_port);
831 host_priv->exc_actions[i].behavior = new_behavior;
832 host_priv->exc_actions[i].flavor = new_flavor;
833 } else {
834 old_port[i] = IP_NULL;
835 }
836 }/* for */
837 host_unlock(host_priv);
838
839#if CONFIG_MACF
840 mac_exc_free_label(new_label);
841#endif
842
843 /*
844 * Consume send rights without any lock held.
845 */
846 while (--i >= FIRST_EXCEPTION) {
847 if (IP_VALID(old_port[i]))
848 ipc_port_release_send(old_port[i]);
849#if CONFIG_MACF
850 if (deferred_labels[i] != NULL) {
851 mac_exc_free_label(deferred_labels[i]); // Label unused.
852 }
853#endif
854 }
855
856 if (IP_VALID(new_port)) /* consume send right */
857 ipc_port_release_send(new_port);
858 *CountCnt = count;
859
860 return KERN_SUCCESS;
861}
862