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/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
92extern lck_grp_t host_notify_lock_grp;
93
94IPC_KOBJECT_DEFINE(IKOT_HOST,
95 .iko_op_stable = true,
96 .iko_op_permanent = true);
97IPC_KOBJECT_DEFINE(IKOT_HOST_PRIV,
98 .iko_op_stable = true,
99 .iko_op_permanent = true);
100
101IPC_KOBJECT_DEFINE(IKOT_PROCESSOR,
102 .iko_op_stable = true,
103 .iko_op_permanent = true);
104IPC_KOBJECT_DEFINE(IKOT_PSET,
105 .iko_op_stable = true,
106 .iko_op_permanent = true);
107IPC_KOBJECT_DEFINE(IKOT_PSET_NAME,
108 .iko_op_stable = true,
109 .iko_op_permanent = true);
110
111void
112ipc_host_init(void)
113{
114 ipc_port_t port;
115 int i;
116
117 lck_mtx_init(lck: &realhost.lock, grp: &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(kobject: (ipc_kobject_t) &realhost, type: IKOT_HOST,
123 options: IPC_KOBJECT_ALLOC_MAKE_SEND);
124 kernel_set_special_port(host_priv: &realhost, HOST_PORT, port);
125
126 port = ipc_kobject_alloc_port(kobject: (ipc_kobject_t) &realhost, type: IKOT_HOST_PRIV,
127 options: IPC_KOBJECT_ALLOC_MAKE_SEND);
128 kernel_set_special_port(host_priv: &realhost, HOST_PRIV_PORT, port);
129
130 /* the rest of the special ports will be set up later */
131
132 bzero(s: &realhost.exc_actions[0], n: 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(pset: &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
167mach_port_name_t
168host_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(port: 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
188void
189ipc_processor_init(
190 processor_t processor)
191{
192 processor->processor_self = ipc_kobject_alloc_port(kobject: processor,
193 type: IKOT_PROCESSOR, options: 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
202void
203ipc_pset_init(
204 processor_set_t pset)
205{
206 pset->pset_self = ipc_kobject_alloc_port(kobject: pset,
207 type: IKOT_PSET, options: IPC_KOBJECT_ALLOC_NONE);
208 pset->pset_name_self = ipc_kobject_alloc_port(kobject: pset,
209 type: IKOT_PSET_NAME, options: IPC_KOBJECT_ALLOC_NONE);
210}
211
212/*
213 * processor_set_default:
214 *
215 * Return ports for manipulating default_processor set.
216 */
217kern_return_t
218processor_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
240host_t
241convert_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
268host_t
269convert_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, type: 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
299processor_t
300convert_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, type: 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
322processor_set_t
323convert_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, type: 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
345processor_set_name_t
346convert_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
369ipc_port_t
370host_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 kobject: host_self(), kotype: IKOT_HOST);
378 } else if (kotype == IKOT_HOST_PRIV) {
379 port = ipc_kobject_copy_send(port,
380 kobject: host_priv_self(), kotype: 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
403ipc_port_t
404convert_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
425ipc_port_t
426convert_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, kobject: processor, kotype: 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
447ipc_port_t
448convert_pset_to_port(
449 processor_set_t pset)
450{
451 return ipc_kobject_make_send(port: pset->pset_self, kobject: pset, kotype: 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
464ipc_port_t
465convert_pset_name_to_port(
466 processor_set_name_t pset)
467{
468 return ipc_kobject_make_send(port: pset->pset_name_self, kobject: pset, kotype: 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 */
488kern_return_t
489host_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 if (exception_mask & ~EXC_MASK_VALID) {
509 return KERN_INVALID_ARGUMENT;
510 }
511
512 if (IP_VALID(new_port)) {
513 switch (new_behavior & ~MACH_EXCEPTION_MASK) {
514 case EXCEPTION_DEFAULT:
515 case EXCEPTION_STATE:
516 case EXCEPTION_STATE_IDENTITY:
517 case EXCEPTION_IDENTITY_PROTECTED:
518 break;
519 default:
520 return KERN_INVALID_ARGUMENT;
521 }
522 }
523
524 /*
525 * Check the validity of the thread_state_flavor by calling the
526 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in
527 * osfmk/mach/ARCHITECTURE/thread_status.h
528 */
529 if (new_flavor != 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor)) {
530 return KERN_INVALID_ARGUMENT;
531 }
532
533 if (((new_behavior & ~MACH_EXCEPTION_MASK) == EXCEPTION_IDENTITY_PROTECTED ||
534 (new_behavior & MACH_EXCEPTION_BACKTRACE_PREFERRED))
535 && !(new_behavior & MACH_EXCEPTION_CODES)) {
536 return KERN_INVALID_ARGUMENT;
537 }
538
539 if (!set_exception_behavior_allowed(new_port, new_behavior, NULL, mask: exception_mask, level: "host")) {
540 return KERN_NO_ACCESS;
541 }
542
543#if CONFIG_MACF
544 if (mac_task_check_set_host_exception_ports(task: current_task(), exception_mask) != 0) {
545 return KERN_NO_ACCESS;
546 }
547
548 new_label = mac_exc_create_label_for_current_proc();
549
550 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
551 if (mac_exc_label(action: &host_priv->exc_actions[i]) == NULL) {
552 deferred_labels[i] = mac_exc_create_label(action: &host_priv->exc_actions[i]);
553 } else {
554 deferred_labels[i] = NULL;
555 }
556 }
557#endif
558
559 host_lock(host_priv);
560
561 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
562#if CONFIG_MACF
563 if (mac_exc_label(action: &host_priv->exc_actions[i]) == NULL) {
564 // Lazy initialization (see ipc_port_init).
565 mac_exc_associate_action_label(action: &host_priv->exc_actions[i], label: deferred_labels[i]);
566 deferred_labels[i] = NULL; // Label is used, do not free.
567 }
568#endif
569
570 if ((exception_mask & (1 << i))
571#if CONFIG_MACF
572 && mac_exc_update_action_label(action: &host_priv->exc_actions[i], newlabel: new_label) == 0
573#endif
574 ) {
575 old_port[i] = host_priv->exc_actions[i].port;
576
577 host_priv->exc_actions[i].port =
578 exception_port_copy_send(port: new_port);
579 host_priv->exc_actions[i].behavior = new_behavior;
580 host_priv->exc_actions[i].flavor = new_flavor;
581 } else {
582 old_port[i] = IP_NULL;
583 }
584 }/* for */
585
586 /*
587 * Consume send rights without any lock held.
588 */
589 host_unlock(host_priv);
590
591#if CONFIG_MACF
592 mac_exc_free_label(label: new_label);
593#endif
594
595 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
596 if (IP_VALID(old_port[i])) {
597 ipc_port_release_send(port: old_port[i]);
598 }
599#if CONFIG_MACF
600 if (deferred_labels[i] != NULL) {
601 /* Deferred label went unused: Another thread has completed the lazy initialization. */
602 mac_exc_free_label(label: deferred_labels[i]);
603 }
604#endif
605 }
606 if (IP_VALID(new_port)) { /* consume send right */
607 ipc_port_release_send(port: new_port);
608 }
609
610 return KERN_SUCCESS;
611}
612
613/*
614 * Routine: host_get_exception_ports [kernel call]
615 * Purpose:
616 * Clones a send right for each of the host's exception
617 * ports specified in the mask and returns the behaviour
618 * and flavor of said port.
619 *
620 * Returns upto [in} CountCnt elements.
621 *
622 * Conditions:
623 * Nothing locked.
624 * Returns:
625 * KERN_SUCCESS Extracted a send right.
626 * KERN_INVALID_ARGUMENT Invalid host_priv specified,
627 * Invalid special port,
628 * Illegal mask bit set.
629 * KERN_FAILURE The thread is dead.
630 */
631kern_return_t
632host_get_exception_ports(
633 host_priv_t host_priv,
634 exception_mask_t exception_mask,
635 exception_mask_array_t masks,
636 mach_msg_type_number_t * CountCnt,
637 exception_port_array_t ports,
638 exception_behavior_array_t behaviors,
639 thread_state_flavor_array_t flavors )
640{
641 unsigned int i, j, count;
642
643 if (host_priv == HOST_PRIV_NULL) {
644 return KERN_INVALID_ARGUMENT;
645 }
646
647 if (exception_mask & ~EXC_MASK_VALID) {
648 return KERN_INVALID_ARGUMENT;
649 }
650
651 host_lock(host_priv);
652
653 count = 0;
654
655 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
656 if (exception_mask & (1 << i)) {
657 for (j = 0; j < count; j++) {
658/*
659 * search for an identical entry, if found
660 * set corresponding mask for this exception.
661 */
662 if (host_priv->exc_actions[i].port == ports[j] &&
663 host_priv->exc_actions[i].behavior == behaviors[j]
664 && host_priv->exc_actions[i].flavor == flavors[j]) {
665 masks[j] |= (1 << i);
666 break;
667 }
668 }/* for */
669 if (j == count && count < *CountCnt) {
670 masks[j] = (1 << i);
671 ports[j] =
672 exception_port_copy_send(port: host_priv->exc_actions[i].port);
673 behaviors[j] = host_priv->exc_actions[i].behavior;
674 flavors[j] = host_priv->exc_actions[i].flavor;
675 count++;
676 }
677 }
678 }/* for */
679 host_unlock(host_priv);
680
681 *CountCnt = count;
682 return KERN_SUCCESS;
683}
684
685kern_return_t
686host_swap_exception_ports(
687 host_priv_t host_priv,
688 exception_mask_t exception_mask,
689 ipc_port_t new_port,
690 exception_behavior_t new_behavior,
691 thread_state_flavor_t new_flavor,
692 exception_mask_array_t masks,
693 mach_msg_type_number_t * CountCnt,
694 exception_port_array_t ports,
695 exception_behavior_array_t behaviors,
696 thread_state_flavor_array_t flavors )
697{
698 unsigned int i,
699 j,
700 count;
701 ipc_port_t old_port[EXC_TYPES_COUNT];
702
703#if CONFIG_MACF
704 struct label *deferred_labels[EXC_TYPES_COUNT];
705 struct label *new_label;
706#endif
707
708 if (host_priv == HOST_PRIV_NULL) {
709 return KERN_INVALID_ARGUMENT;
710 }
711
712 if (exception_mask & ~EXC_MASK_VALID) {
713 return KERN_INVALID_ARGUMENT;
714 }
715
716 if (IP_VALID(new_port)) {
717 switch (new_behavior & ~MACH_EXCEPTION_MASK) {
718 case EXCEPTION_DEFAULT:
719 case EXCEPTION_STATE:
720 case EXCEPTION_STATE_IDENTITY:
721 case EXCEPTION_IDENTITY_PROTECTED:
722 break;
723 default:
724 return KERN_INVALID_ARGUMENT;
725 }
726 }
727
728 if (new_flavor != 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor)) {
729 return KERN_INVALID_ARGUMENT;
730 }
731
732 if (((new_behavior & ~MACH_EXCEPTION_MASK) == EXCEPTION_IDENTITY_PROTECTED ||
733 (new_behavior & MACH_EXCEPTION_BACKTRACE_PREFERRED))
734 && !(new_behavior & MACH_EXCEPTION_CODES)) {
735 return KERN_INVALID_ARGUMENT;
736 }
737
738 if (!set_exception_behavior_allowed(new_port, new_behavior, NULL, mask: exception_mask, level: "host")) {
739 return KERN_NO_ACCESS;
740 }
741
742#if CONFIG_MACF
743 if (mac_task_check_set_host_exception_ports(task: current_task(), exception_mask) != 0) {
744 return KERN_NO_ACCESS;
745 }
746
747 new_label = mac_exc_create_label_for_current_proc();
748
749 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
750 if (mac_exc_label(action: &host_priv->exc_actions[i]) == NULL) {
751 deferred_labels[i] = mac_exc_create_label(action: &host_priv->exc_actions[i]);
752 } else {
753 deferred_labels[i] = NULL;
754 }
755 }
756#endif /* CONFIG_MACF */
757
758 host_lock(host_priv);
759
760 assert(EXC_TYPES_COUNT > FIRST_EXCEPTION);
761 for (count = 0, i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT && count < *CountCnt; i++) {
762#if CONFIG_MACF
763 if (mac_exc_label(action: &host_priv->exc_actions[i]) == NULL) {
764 // Lazy initialization (see ipc_port_init).
765 mac_exc_associate_action_label(action: &host_priv->exc_actions[i], label: deferred_labels[i]);
766 deferred_labels[i] = NULL; // Label is used, do not free.
767 }
768#endif
769
770 if ((exception_mask & (1 << i))
771#if CONFIG_MACF
772 && mac_exc_update_action_label(action: &host_priv->exc_actions[i], newlabel: new_label) == 0
773#endif
774 ) {
775 for (j = 0; j < count; j++) {
776/*
777 * search for an identical entry, if found
778 * set corresponding mask for this exception.
779 */
780 if (host_priv->exc_actions[i].port == ports[j] &&
781 host_priv->exc_actions[i].behavior == behaviors[j]
782 && host_priv->exc_actions[i].flavor == flavors[j]) {
783 masks[j] |= (1 << i);
784 break;
785 }
786 }/* for */
787 if (j == count) {
788 masks[j] = (1 << i);
789 ports[j] =
790 exception_port_copy_send(port: host_priv->exc_actions[i].port);
791 behaviors[j] = host_priv->exc_actions[i].behavior;
792 flavors[j] = host_priv->exc_actions[i].flavor;
793 count++;
794 }
795 old_port[i] = host_priv->exc_actions[i].port;
796 host_priv->exc_actions[i].port =
797 exception_port_copy_send(port: new_port);
798 host_priv->exc_actions[i].behavior = new_behavior;
799 host_priv->exc_actions[i].flavor = new_flavor;
800 } else {
801 old_port[i] = IP_NULL;
802 }
803 }/* for */
804 host_unlock(host_priv);
805
806#if CONFIG_MACF
807 mac_exc_free_label(label: new_label);
808#endif
809
810 /*
811 * Consume send rights without any lock held.
812 */
813 while (--i >= FIRST_EXCEPTION) {
814 if (IP_VALID(old_port[i])) {
815 ipc_port_release_send(port: old_port[i]);
816 }
817#if CONFIG_MACF
818 if (deferred_labels[i] != NULL) {
819 mac_exc_free_label(label: deferred_labels[i]); // Label unused.
820 }
821#endif
822 }
823
824 if (IP_VALID(new_port)) { /* consume send right */
825 ipc_port_release_send(port: new_port);
826 }
827 *CountCnt = count;
828
829 return KERN_SUCCESS;
830}
831