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