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