2 * Copyright (c) 2011 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <mach/mach_types.h>
30 #include <mach/mach_traps.h>
31 #include <mach/mach_vm_server.h>
32 #include <mach/mach_port_server.h>
33 #include <mach/mach_host_server.h>
34 #include <mach/mach_voucher_server.h>
35 #include <mach/vm_map.h>
36 #include <kern/task.h>
37 #include <kern/ipc_tt.h>
38 #include <kern/kalloc.h>
39 #include <vm/vm_protos.h>
40 #include <kdp/kdp_dyld.h>
43 mach_port_get_attributes(
45 mach_port_name_t name
,
47 mach_port_info_t info
,
48 mach_msg_type_number_t
*count
);
50 extern lck_mtx_t g_dyldinfo_mtx
;
53 _kernelrpc_mach_vm_allocate_trap(struct _kernelrpc_mach_vm_allocate_trap_args
*args
)
55 mach_vm_offset_t addr
;
56 task_t task
= port_name_to_task(args
->target
);
57 int rv
= MACH_SEND_INVALID_DEST
;
59 if (task
!= current_task()) {
63 if (copyin(args
->addr
, (char *)&addr
, sizeof(addr
))) {
67 rv
= mach_vm_allocate_external(task
->map
, &addr
, args
->size
, args
->flags
);
68 if (rv
== KERN_SUCCESS
) {
69 rv
= copyout(&addr
, args
->addr
, sizeof(addr
));
74 task_deallocate(task
);
80 _kernelrpc_mach_vm_deallocate_trap(struct _kernelrpc_mach_vm_deallocate_args
*args
)
82 task_t task
= port_name_to_task(args
->target
);
83 int rv
= MACH_SEND_INVALID_DEST
;
85 if (task
!= current_task()) {
89 rv
= mach_vm_deallocate(task
->map
, args
->address
, args
->size
);
93 task_deallocate(task
);
99 _kernelrpc_mach_vm_protect_trap(struct _kernelrpc_mach_vm_protect_args
*args
)
101 task_t task
= port_name_to_task(args
->target
);
102 int rv
= MACH_SEND_INVALID_DEST
;
104 if (task
!= current_task()) {
108 rv
= mach_vm_protect(task
->map
, args
->address
, args
->size
,
109 args
->set_maximum
, args
->new_protection
);
113 task_deallocate(task
);
119 _kernelrpc_mach_vm_map_trap(struct _kernelrpc_mach_vm_map_trap_args
*args
)
121 mach_vm_offset_t addr
;
122 task_t task
= port_name_to_task(args
->target
);
123 int rv
= MACH_SEND_INVALID_DEST
;
125 if (task
!= current_task()) {
129 if (copyin(args
->addr
, (char *)&addr
, sizeof(addr
))) {
133 rv
= mach_vm_map_external(task
->map
, &addr
, args
->size
, args
->mask
, args
->flags
,
134 IPC_PORT_NULL
, 0, FALSE
, args
->cur_protection
, VM_PROT_ALL
,
136 if (rv
== KERN_SUCCESS
) {
137 rv
= copyout(&addr
, args
->addr
, sizeof(addr
));
142 task_deallocate(task
);
148 _kernelrpc_mach_vm_purgable_control_trap(
149 struct _kernelrpc_mach_vm_purgable_control_trap_args
*args
)
152 task_t task
= port_name_to_task(args
->target
);
153 int rv
= MACH_SEND_INVALID_DEST
;
155 if (task
!= current_task()) {
159 if (copyin(args
->state
, (char *)&state
, sizeof(state
))) {
163 rv
= mach_vm_purgable_control(task
->map
,
167 if (rv
== KERN_SUCCESS
) {
168 rv
= copyout(&state
, args
->state
, sizeof(state
));
173 task_deallocate(task
);
179 _kernelrpc_mach_port_allocate_trap(struct _kernelrpc_mach_port_allocate_args
*args
)
181 task_t task
= port_name_to_task(args
->target
);
182 mach_port_name_t name
;
183 int rv
= MACH_SEND_INVALID_DEST
;
185 if (task
!= current_task()) {
189 rv
= mach_port_allocate(task
->itk_space
, args
->right
, &name
);
190 if (rv
== KERN_SUCCESS
) {
191 rv
= copyout(&name
, args
->name
, sizeof(name
));
197 task_deallocate(task
);
203 _kernelrpc_mach_port_deallocate_trap(struct _kernelrpc_mach_port_deallocate_args
*args
)
205 task_t task
= port_name_to_task(args
->target
);
206 int rv
= MACH_SEND_INVALID_DEST
;
208 if (task
!= current_task()) {
212 rv
= mach_port_deallocate(task
->itk_space
, args
->name
);
216 task_deallocate(task
);
222 _kernelrpc_mach_port_mod_refs_trap(struct _kernelrpc_mach_port_mod_refs_args
*args
)
224 task_t task
= port_name_to_task(args
->target
);
225 int rv
= MACH_SEND_INVALID_DEST
;
227 if (task
!= current_task()) {
231 rv
= mach_port_mod_refs(task
->itk_space
, args
->name
, args
->right
, args
->delta
);
235 task_deallocate(task
);
242 _kernelrpc_mach_port_move_member_trap(struct _kernelrpc_mach_port_move_member_args
*args
)
244 task_t task
= port_name_to_task(args
->target
);
245 int rv
= MACH_SEND_INVALID_DEST
;
247 if (task
!= current_task()) {
251 rv
= mach_port_move_member(task
->itk_space
, args
->member
, args
->after
);
255 task_deallocate(task
);
261 _kernelrpc_mach_port_insert_right_trap(struct _kernelrpc_mach_port_insert_right_args
*args
)
263 task_t task
= port_name_to_task(args
->target
);
265 mach_msg_type_name_t disp
;
266 int rv
= MACH_SEND_INVALID_DEST
;
268 if (task
!= current_task()) {
272 if (args
->name
== args
->poly
) {
273 switch (args
->polyPoly
) {
274 case MACH_MSG_TYPE_MAKE_SEND
:
275 case MACH_MSG_TYPE_COPY_SEND
:
276 /* fastpath MAKE_SEND / COPY_SEND which is the most common case */
277 rv
= ipc_object_insert_send_right(task
->itk_space
, args
->poly
,
286 rv
= ipc_object_copyin(task
->itk_space
, args
->poly
, args
->polyPoly
,
287 (ipc_object_t
*)&port
, 0, NULL
, IPC_OBJECT_COPYIN_FLAGS_ALLOW_IMMOVABLE_SEND
);
288 if (rv
!= KERN_SUCCESS
) {
291 disp
= ipc_object_copyin_type(args
->polyPoly
);
293 rv
= mach_port_insert_right(task
->itk_space
, args
->name
, port
, disp
);
294 if (rv
!= KERN_SUCCESS
&& IP_VALID(port
)) {
295 ipc_object_destroy(ip_to_object(port
), disp
);
300 task_deallocate(task
);
306 _kernelrpc_mach_port_get_attributes_trap(struct _kernelrpc_mach_port_get_attributes_args
*args
)
308 task_read_t task
= port_name_to_task_read_no_eval(args
->target
);
309 int rv
= MACH_SEND_INVALID_DEST
;
310 mach_msg_type_number_t count
;
312 if (task
!= current_task()) {
316 // MIG does not define the type or size of the mach_port_info_t out array
317 // anywhere, so derive them from the field in the generated reply struct
318 #define MACH_PORT_INFO_OUT (((__Reply__mach_port_get_attributes_from_user_t*)NULL)->port_info_out)
319 #define MACH_PORT_INFO_STACK_LIMIT 80 // current size is 68 == 17 * sizeof(integer_t)
320 _Static_assert(sizeof(MACH_PORT_INFO_OUT
) < MACH_PORT_INFO_STACK_LIMIT
,
321 "mach_port_info_t has grown significantly, reevaluate stack usage");
322 const mach_msg_type_number_t max_count
= (sizeof(MACH_PORT_INFO_OUT
) / sizeof(MACH_PORT_INFO_OUT
[0]));
323 typeof(MACH_PORT_INFO_OUT
[0]) info
[max_count
];
326 * zero out our stack buffer because not all flavors of
327 * port_get_attributes initialize the whole struct
329 bzero(info
, sizeof(MACH_PORT_INFO_OUT
));
331 if (copyin(CAST_USER_ADDR_T(args
->count
), &count
, sizeof(count
))) {
332 rv
= MACH_SEND_INVALID_DATA
;
335 if (count
> max_count
) {
339 rv
= mach_port_get_attributes(task
->itk_space
, args
->name
, args
->flavor
, info
, &count
);
340 if (rv
== KERN_SUCCESS
) {
341 rv
= copyout(&count
, CAST_USER_ADDR_T(args
->count
), sizeof(count
));
343 if (rv
== KERN_SUCCESS
&& count
> 0) {
344 rv
= copyout(info
, CAST_USER_ADDR_T(args
->info
), count
* sizeof(info
[0]));
349 task_deallocate(task
);
355 _kernelrpc_mach_port_insert_member_trap(struct _kernelrpc_mach_port_insert_member_args
*args
)
357 task_t task
= port_name_to_task(args
->target
);
358 int rv
= MACH_SEND_INVALID_DEST
;
360 if (task
!= current_task()) {
364 rv
= mach_port_insert_member(task
->itk_space
, args
->name
, args
->pset
);
368 task_deallocate(task
);
375 _kernelrpc_mach_port_extract_member_trap(struct _kernelrpc_mach_port_extract_member_args
*args
)
377 task_t task
= port_name_to_task(args
->target
);
378 int rv
= MACH_SEND_INVALID_DEST
;
380 if (task
!= current_task()) {
384 rv
= mach_port_extract_member(task
->itk_space
, args
->name
, args
->pset
);
388 task_deallocate(task
);
394 _kernelrpc_mach_port_construct_trap(struct _kernelrpc_mach_port_construct_args
*args
)
396 task_t task
= port_name_to_task(args
->target
);
397 mach_port_name_t name
;
398 int rv
= MACH_SEND_INVALID_DEST
;
399 mach_port_options_t options
;
401 if (copyin(args
->options
, (char *)&options
, sizeof(options
))) {
402 rv
= MACH_SEND_INVALID_DATA
;
406 if (task
!= current_task()) {
410 rv
= mach_port_construct(task
->itk_space
, &options
, args
->context
, &name
);
411 if (rv
== KERN_SUCCESS
) {
412 rv
= copyout(&name
, args
->name
, sizeof(name
));
417 task_deallocate(task
);
423 _kernelrpc_mach_port_destruct_trap(struct _kernelrpc_mach_port_destruct_args
*args
)
425 task_t task
= port_name_to_task(args
->target
);
426 int rv
= MACH_SEND_INVALID_DEST
;
428 if (task
!= current_task()) {
432 rv
= mach_port_destruct(task
->itk_space
, args
->name
, args
->srdelta
, args
->guard
);
436 task_deallocate(task
);
442 _kernelrpc_mach_port_guard_trap(struct _kernelrpc_mach_port_guard_args
*args
)
444 task_t task
= port_name_to_task(args
->target
);
445 int rv
= MACH_SEND_INVALID_DEST
;
447 if (task
!= current_task()) {
451 rv
= mach_port_guard(task
->itk_space
, args
->name
, args
->guard
, args
->strict
);
455 task_deallocate(task
);
461 _kernelrpc_mach_port_unguard_trap(struct _kernelrpc_mach_port_unguard_args
*args
)
463 task_t task
= port_name_to_task(args
->target
);
464 int rv
= MACH_SEND_INVALID_DEST
;
466 if (task
!= current_task()) {
470 rv
= mach_port_unguard(task
->itk_space
, args
->name
, args
->guard
);
474 task_deallocate(task
);
480 _kernelrpc_mach_port_type_trap(struct _kernelrpc_mach_port_type_args
*args
)
482 task_t task
= port_name_to_task(args
->target
);
483 int rv
= MACH_SEND_INVALID_DEST
;
484 mach_port_type_t type
;
486 if (task
!= current_task()) {
490 rv
= mach_port_type(task
->itk_space
, args
->name
, &type
);
491 if (rv
== KERN_SUCCESS
) {
492 rv
= copyout(&type
, args
->ptype
, sizeof(type
));
497 task_deallocate(task
);
503 _kernelrpc_mach_port_request_notification_trap(
504 struct _kernelrpc_mach_port_request_notification_args
*args
)
506 task_t task
= port_name_to_task(args
->target
);
507 int rv
= MACH_SEND_INVALID_DEST
;
508 ipc_port_t notify
, previous
;
509 mach_msg_type_name_t disp
;
510 mach_port_name_t previous_name
= MACH_PORT_NULL
;
512 if (task
!= current_task()) {
516 disp
= ipc_object_copyin_type(args
->notifyPoly
);
517 if (disp
!= MACH_MSG_TYPE_PORT_SEND_ONCE
) {
521 if (MACH_PORT_VALID(args
->notify
)) {
522 rv
= ipc_object_copyin(task
->itk_space
, args
->notify
, args
->notifyPoly
,
523 (ipc_object_t
*)¬ify
, 0, NULL
, 0);
525 notify
= CAST_MACH_NAME_TO_PORT(args
->notify
);
527 if (rv
!= KERN_SUCCESS
) {
531 rv
= mach_port_request_notification(task
->itk_space
, args
->name
,
532 args
->msgid
, args
->sync
, notify
, &previous
);
533 if (rv
!= KERN_SUCCESS
) {
534 ipc_object_destroy(ip_to_object(notify
), disp
);
538 if (IP_VALID(previous
)) {
539 // Remove once <rdar://problem/45522961> is fixed.
540 // We need to make ith_knote NULL as ipc_object_copyout() uses
541 // thread-argument-passing and its value should not be garbage
542 current_thread()->ith_knote
= ITH_KNOTE_NULL
;
543 rv
= ipc_object_copyout(task
->itk_space
, ip_to_object(previous
),
544 MACH_MSG_TYPE_PORT_SEND_ONCE
, IPC_OBJECT_COPYOUT_FLAGS_NONE
, NULL
, NULL
, &previous_name
);
545 if (rv
!= KERN_SUCCESS
) {
550 rv
= copyout(&previous_name
, args
->previous
, sizeof(previous_name
));
554 task_deallocate(task
);
560 host_create_mach_voucher_trap(struct host_create_mach_voucher_args
*args
)
562 host_t host
= port_name_to_host(args
->host
);
563 ipc_voucher_t new_voucher
= IV_NULL
;
564 ipc_port_t voucher_port
= IPC_PORT_NULL
;
565 mach_port_name_t voucher_name
= 0;
566 kern_return_t kr
= KERN_SUCCESS
;
568 if (host
== HOST_NULL
) {
569 return MACH_SEND_INVALID_DEST
;
571 if (args
->recipes_size
< 0) {
572 return KERN_INVALID_ARGUMENT
;
574 if (args
->recipes_size
> MACH_VOUCHER_ATTR_MAX_RAW_RECIPE_ARRAY_SIZE
) {
575 return MIG_ARRAY_TOO_LARGE
;
578 /* keep small recipes on the stack for speed */
579 uint8_t buf
[MACH_VOUCHER_TRAP_STACK_LIMIT
];
580 uint8_t *krecipes
= buf
;
582 if (args
->recipes_size
> MACH_VOUCHER_TRAP_STACK_LIMIT
) {
583 krecipes
= kheap_alloc(KHEAP_TEMP
, args
->recipes_size
, Z_WAITOK
);
584 if (krecipes
== NULL
) {
585 return KERN_RESOURCE_SHORTAGE
;
589 if (copyin(CAST_USER_ADDR_T(args
->recipes
), (void *)krecipes
, args
->recipes_size
)) {
590 kr
= KERN_MEMORY_ERROR
;
594 kr
= host_create_mach_voucher(host
, krecipes
, args
->recipes_size
, &new_voucher
);
595 if (kr
!= KERN_SUCCESS
) {
599 voucher_port
= convert_voucher_to_port(new_voucher
);
600 voucher_name
= ipc_port_copyout_send(voucher_port
, current_space());
602 kr
= copyout(&voucher_name
, args
->voucher
, sizeof(voucher_name
));
605 if (args
->recipes_size
> MACH_VOUCHER_TRAP_STACK_LIMIT
) {
606 kheap_free(KHEAP_TEMP
, krecipes
, args
->recipes_size
);
613 mach_voucher_extract_attr_recipe_trap(struct mach_voucher_extract_attr_recipe_args
*args
)
615 ipc_voucher_t voucher
= IV_NULL
;
616 kern_return_t kr
= KERN_SUCCESS
;
617 mach_msg_type_number_t sz
= 0;
619 if (copyin(args
->recipe_size
, (void *)&sz
, sizeof(sz
))) {
620 return KERN_MEMORY_ERROR
;
623 if (sz
> MACH_VOUCHER_ATTR_MAX_RAW_RECIPE_ARRAY_SIZE
) {
624 return MIG_ARRAY_TOO_LARGE
;
627 voucher
= convert_port_name_to_voucher(args
->voucher_name
);
628 if (voucher
== IV_NULL
) {
629 return MACH_SEND_INVALID_DEST
;
632 /* keep small recipes on the stack for speed */
633 uint8_t buf
[MACH_VOUCHER_TRAP_STACK_LIMIT
];
634 uint8_t *krecipe
= buf
;
635 mach_msg_type_number_t max_sz
= sz
;
637 if (max_sz
> MACH_VOUCHER_TRAP_STACK_LIMIT
) {
638 krecipe
= kheap_alloc(KHEAP_TEMP
, max_sz
, Z_WAITOK
);
640 return KERN_RESOURCE_SHORTAGE
;
644 if (copyin(CAST_USER_ADDR_T(args
->recipe
), (void *)krecipe
, max_sz
)) {
645 kr
= KERN_MEMORY_ERROR
;
649 kr
= mach_voucher_extract_attr_recipe(voucher
, args
->key
,
650 (mach_voucher_attr_raw_recipe_t
)krecipe
, &sz
);
651 assert(sz
<= max_sz
);
653 if (kr
== KERN_SUCCESS
&& sz
> 0) {
654 kr
= copyout(krecipe
, CAST_USER_ADDR_T(args
->recipe
), sz
);
656 if (kr
== KERN_SUCCESS
) {
657 kr
= copyout(&sz
, args
->recipe_size
, sizeof(sz
));
662 if (max_sz
> MACH_VOUCHER_TRAP_STACK_LIMIT
) {
663 kheap_free(KHEAP_TEMP
, krecipe
, max_sz
);
666 ipc_voucher_release(voucher
);
671 * Mach Trap: task_dyld_process_info_notify_get_trap
673 * Return an array of active dyld notifier port names for current_task(). User
674 * is responsible for allocating the memory for the mach port names array
675 * and deallocating the port names inside the array returned.
677 * Does not consume any reference.
680 * names_addr: Address for mach port names array. (In param only)
681 * names_count_addr: Number of active dyld notifier ports. (In-Out param)
682 * In: Number of slots available for copyout in caller
683 * Out: Actual number of ports copied out
687 * KERN_SUCCESS: A valid namesCnt is returned. (Can be zero)
688 * KERN_INVALID_ARGUMENT: Arguments are invalid.
689 * KERN_MEMORY_ERROR: Memory copyio operations failed.
690 * KERN_NO_SPACE: User allocated memory for port names copyout is insufficient.
692 * Other error code see task_info().
695 task_dyld_process_info_notify_get_trap(struct task_dyld_process_info_notify_get_trap_args
*args
)
697 struct task_dyld_info dyld_info
;
698 mach_msg_type_number_t info_count
= TASK_DYLD_INFO_COUNT
;
699 mach_port_name_t copyout_names
[DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
];
700 ipc_port_t copyout_ports
[DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
];
701 ipc_port_t release_ports
[DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
];
702 uint32_t copyout_count
= 0, release_count
= 0, active_count
= 0;
703 mach_vm_address_t ports_addr
; /* a user space address */
704 mach_port_name_t new_name
;
705 natural_t user_names_count
= 0;
711 if ((mach_port_name_array_t
)args
->names_addr
== NULL
|| (natural_t
*)args
->names_count_addr
== NULL
) {
712 return KERN_INVALID_ARGUMENT
;
715 kr
= copyin((vm_map_address_t
)args
->names_count_addr
, &user_names_count
, sizeof(natural_t
));
717 return KERN_MEMORY_FAILURE
;
720 if (user_names_count
== 0) {
721 return KERN_NO_SPACE
;
724 kr
= task_info(current_task(), TASK_DYLD_INFO
, (task_info_t
)&dyld_info
, &info_count
);
729 if (dyld_info
.all_image_info_format
== TASK_DYLD_ALL_IMAGE_INFO_32
) {
730 ports_addr
= (mach_vm_address_t
)(dyld_info
.all_image_info_addr
+
731 offsetof(struct user32_dyld_all_image_infos
, notifyMachPorts
));
733 ports_addr
= (mach_vm_address_t
)(dyld_info
.all_image_info_addr
+
734 offsetof(struct user64_dyld_all_image_infos
, notifyMachPorts
));
737 lck_mtx_lock(&g_dyldinfo_mtx
);
738 itk_lock(current_task());
740 if (current_task()->itk_dyld_notify
== NULL
) {
741 itk_unlock(current_task());
742 (void)copyoutmap_atomic32(current_task()->map
, MACH_PORT_NULL
, (vm_map_address_t
)ports_addr
); /* reset magic */
743 lck_mtx_unlock(&g_dyldinfo_mtx
);
745 kr
= copyout(©out_count
, (vm_map_address_t
)args
->names_count_addr
, sizeof(natural_t
));
746 return kr
? KERN_MEMORY_ERROR
: KERN_SUCCESS
;
749 for (int slot
= 0; slot
< DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
; slot
++) {
750 portp
= ¤t_task()->itk_dyld_notify
[slot
];
751 if (*portp
== IPC_PORT_NULL
) {
754 sright
= ipc_port_copy_send(*portp
);
755 if (IP_VALID(sright
)) {
756 copyout_ports
[active_count
++] = sright
; /* donates */
757 sright
= IPC_PORT_NULL
;
759 release_ports
[release_count
++] = *portp
; /* donates */
760 *portp
= IPC_PORT_NULL
;
765 task_dyld_process_info_update_helper(current_task(), active_count
,
766 (vm_map_address_t
)ports_addr
, release_ports
, release_count
);
767 /* itk_lock, g_dyldinfo_mtx are unlocked upon return */
769 for (int i
= 0; i
< active_count
; i
++) {
770 sright
= copyout_ports
[i
]; /* donates */
771 copyout_ports
[i
] = IPC_PORT_NULL
;
773 assert(IP_VALID(sright
));
774 ip_reference(sright
);
776 * Below we consume each send right in copyout_ports, and if copyout_send
777 * succeeds, replace it with a port ref; otherwise release the port ref.
779 * We can reuse copyout_ports array for this purpose since
780 * copyout_count <= active_count.
782 new_name
= ipc_port_copyout_send(sright
, current_space()); /* consumes */
783 if (MACH_PORT_VALID(new_name
)) {
784 copyout_names
[copyout_count
] = new_name
;
785 copyout_ports
[copyout_count
] = sright
; /* now holds port ref */
792 assert(copyout_count
<= active_count
);
794 if (user_names_count
< copyout_count
) {
799 /* copyout to caller's local copy */
800 kr
= copyout(copyout_names
, (vm_map_address_t
)args
->names_addr
,
801 copyout_count
* sizeof(mach_port_name_t
));
803 kr
= KERN_MEMORY_ERROR
;
807 kr
= copyout(©out_count
, (vm_map_address_t
)args
->names_count_addr
, sizeof(natural_t
));
809 kr
= KERN_MEMORY_ERROR
;
813 /* now, release port refs on copyout_ports */
814 for (int i
= 0; i
< copyout_count
; i
++) {
815 sright
= copyout_ports
[i
];
816 assert(IP_VALID(sright
));
825 * No locks are held beyond this point.
827 * Release port refs on copyout_ports, and deallocate ports that we copied out
830 for (int i
= 0; i
< copyout_count
; i
++) {
831 sright
= copyout_ports
[i
];
832 assert(IP_VALID(sright
));
834 if (ipc_right_lookup_write(current_space(), copyout_names
[i
], &entry
)) {
835 /* userspace has deallocated the name we copyout */
839 /* space is locked and active */
840 if (entry
->ie_object
== ip_to_object(sright
) ||
841 IE_BITS_TYPE(entry
->ie_bits
) == MACH_PORT_TYPE_DEAD_NAME
) {
842 (void)ipc_right_dealloc(current_space(), copyout_names
[i
], entry
); /* unlocks space */
844 is_write_unlock(current_space());
847 /* space is unlocked */