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 | |
87 | boolean_t |
88 | ref_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 | |
95 | extern lck_grp_t host_notify_lock_grp; |
96 | extern lck_attr_t host_notify_lock_attr; |
97 | |
98 | void 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 | |
166 | mach_port_name_t |
167 | host_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 | |
187 | void |
188 | ipc_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 | */ |
204 | void |
205 | ipc_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 | |
220 | void |
221 | ipc_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 | */ |
242 | void |
243 | ipc_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 | */ |
255 | kern_return_t |
256 | processor_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 | |
277 | host_t |
278 | convert_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 | |
302 | host_t |
303 | convert_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 | |
329 | processor_t |
330 | convert_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 | |
356 | processor_set_t |
357 | convert_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 | |
382 | processor_set_name_t |
383 | convert_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 | |
398 | boolean_t |
399 | ref_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 | |
425 | ipc_port_t |
426 | convert_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 | |
445 | ipc_port_t |
446 | convert_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 | |
466 | ipc_port_t |
467 | convert_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 | |
488 | ipc_port_t |
489 | convert_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 | |
509 | host_t |
510 | convert_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 | */ |
542 | kern_return_t |
543 | host_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 | */ |
672 | kern_return_t |
673 | host_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 | |
731 | kern_return_t |
732 | host_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 | |