kern_return_t mach_port_space_info( ipc_space_t space, ipc_info_space_t *infop, ipc_info_name_array_t *tablep, mach_msg_type_number_t *tableCntp, __unused ipc_info_tree_name_array_t *treep, __unused mach_msg_type_number_t *treeCntp) { ipc_info_name_t *table_info; vm_offset_t table_addr; vm_size_t table_size, table_size_needed; ipc_entry_t table; ipc_entry_num_t tsize; mach_port_index_t index; kern_return_t kr; vm_map_copy_t copy; if (space == IS_NULL) return KERN_INVALID_TASK; #if !(DEVELOPMENT | DEBUG) const boolean_t dbg_ok = (mac_task_check_expose_task(kernel_task) == 0); #else const boolean_t dbg_ok = TRUE; #endif /* start with in-line memory */ table_size = 0; for (;;) { is_read_lock(space); if (!is_active(space)) { is_read_unlock(space); if (table_size != 0) kmem_free(ipc_kernel_map, table_addr, table_size); return KERN_INVALID_TASK; } table_size_needed = vm_map_round_page((space->is_table_size * sizeof(ipc_info_name_t)), VM_MAP_PAGE_MASK(ipc_kernel_map)); if (table_size_needed == table_size) break; is_read_unlock(space); if (table_size != table_size_needed) { if (table_size != 0) kmem_free(ipc_kernel_map, table_addr, table_size); kr = kmem_alloc(ipc_kernel_map, &table_addr, table_size_needed, VM_KERN_MEMORY_IPC); if (kr != KERN_SUCCESS) { return KERN_RESOURCE_SHORTAGE; } table_size = table_size_needed; } } /* space is read-locked and active; we have enough wired memory */ /* get the overall space info */ infop->iis_genno_mask = MACH_PORT_NGEN(MACH_PORT_DEAD); infop->iis_table_size = space->is_table_size; infop->iis_table_next = space->is_table_next->its_size; /* walk the table for this space */ table = space->is_table; tsize = space->is_table_size; table_info = (ipc_info_name_array_t)table_addr; for (index = 0; index < tsize; index++) { ipc_info_name_t *iin = &table_info[index]; ipc_entry_t entry = &table[index]; ipc_entry_bits_t bits; bits = entry->ie_bits; iin->iin_name = MACH_PORT_MAKE(index, IE_BITS_GEN(bits)); iin->iin_collision = 0; iin->iin_type = IE_BITS_TYPE(bits); if ((entry->ie_bits & MACH_PORT_TYPE_PORT_RIGHTS) != MACH_PORT_TYPE_NONE && entry->ie_request != IE_REQ_NONE) { __IGNORE_WCASTALIGN(ipc_port_t port = (ipc_port_t) entry->ie_object); assert(IP_VALID(port)); ip_lock(port); iin->iin_type |= ipc_port_request_type(port, iin->iin_name, entry->ie_request); ip_unlock(port); } iin->iin_urefs = IE_BITS_UREFS(bits); iin->iin_object = (dbg_ok) ? (natural_t)VM_KERNEL_ADDRPERM((uintptr_t)entry->ie_object) : 0; iin->iin_next = entry->ie_next; iin->iin_hash = entry->ie_index; } is_read_unlock(space); /* prepare the table out-of-line data for return */ if (table_size > 0) { vm_size_t used_table_size; used_table_size = infop->iis_table_size * sizeof(ipc_info_name_t); if (table_size > used_table_size) bzero((char *)&table_info[infop->iis_table_size], table_size - used_table_size); kr = vm_map_unwire( ipc_kernel_map, vm_map_trunc_page(table_addr, VM_MAP_PAGE_MASK(ipc_kernel_map)), vm_map_round_page(table_addr + table_size, VM_MAP_PAGE_MASK(ipc_kernel_map)), FALSE); assert(kr == KERN_SUCCESS); kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)table_addr, (vm_map_size_t)used_table_size, TRUE, ©); assert(kr == KERN_SUCCESS); *tablep = (ipc_info_name_t *)copy; *tableCntp = infop->iis_table_size; } else { *tablep = (ipc_info_name_t *)0; *tableCntp = 0; } /* splay tree is obsolete, no work to do... */ *treep = (ipc_info_tree_name_t *)0; *treeCntp = 0; return KERN_SUCCESS; }
/* * processor_set_things: * * Common internals for processor_set_{threads,tasks} */ kern_return_t processor_set_things( processor_set_t pset, void **thing_list, mach_msg_type_number_t *count, int type) { unsigned int i; task_t task; thread_t thread; task_t *task_list; unsigned int actual_tasks; vm_size_t task_size, task_size_needed; thread_t *thread_list; unsigned int actual_threads; vm_size_t thread_size, thread_size_needed; void *addr, *newaddr; vm_size_t size, size_needed; if (pset == PROCESSOR_SET_NULL || pset != &pset0) return (KERN_INVALID_ARGUMENT); task_size = 0; task_size_needed = 0; task_list = NULL; actual_tasks = 0; thread_size = 0; thread_size_needed = 0; thread_list = NULL; actual_threads = 0; for (;;) { lck_mtx_lock(&tasks_threads_lock); /* do we have the memory we need? */ if (type == PSET_THING_THREAD) thread_size_needed = threads_count * sizeof(void *); #if !CONFIG_MACF else #endif task_size_needed = tasks_count * sizeof(void *); if (task_size_needed <= task_size && thread_size_needed <= thread_size) break; /* unlock and allocate more memory */ lck_mtx_unlock(&tasks_threads_lock); /* grow task array */ if (task_size_needed > task_size) { if (task_size != 0) kfree(task_list, task_size); assert(task_size_needed > 0); task_size = task_size_needed; task_list = (task_t *)kalloc(task_size); if (task_list == NULL) { if (thread_size != 0) kfree(thread_list, thread_size); return (KERN_RESOURCE_SHORTAGE); } } /* grow thread array */ if (thread_size_needed > thread_size) { if (thread_size != 0) kfree(thread_list, thread_size); assert(thread_size_needed > 0); thread_size = thread_size_needed; thread_list = (thread_t *)kalloc(thread_size); if (thread_list == 0) { if (task_size != 0) kfree(task_list, task_size); return (KERN_RESOURCE_SHORTAGE); } } } /* OK, have memory and the list locked */ /* If we need it, get the thread list */ if (type == PSET_THING_THREAD) { for (thread = (thread_t)queue_first(&threads); !queue_end(&threads, (queue_entry_t)thread); thread = (thread_t)queue_next(&thread->threads)) { #if defined(SECURE_KERNEL) if (thread->task != kernel_task) { #endif thread_reference_internal(thread); thread_list[actual_threads++] = thread; #if defined(SECURE_KERNEL) } #endif } } #if !CONFIG_MACF else { #endif /* get a list of the tasks */ for (task = (task_t)queue_first(&tasks); !queue_end(&tasks, (queue_entry_t)task); task = (task_t)queue_next(&task->tasks)) { #if defined(SECURE_KERNEL) if (task != kernel_task) { #endif task_reference_internal(task); task_list[actual_tasks++] = task; #if defined(SECURE_KERNEL) } #endif } #if !CONFIG_MACF } #endif lck_mtx_unlock(&tasks_threads_lock); #if CONFIG_MACF unsigned int j, used; /* for each task, make sure we are allowed to examine it */ for (i = used = 0; i < actual_tasks; i++) { if (mac_task_check_expose_task(task_list[i])) { task_deallocate(task_list[i]); continue; } task_list[used++] = task_list[i]; } actual_tasks = used; task_size_needed = actual_tasks * sizeof(void *); if (type == PSET_THING_THREAD) { /* for each thread (if any), make sure it's task is in the allowed list */ for (i = used = 0; i < actual_threads; i++) { boolean_t found_task = FALSE; task = thread_list[i]->task; for (j = 0; j < actual_tasks; j++) { if (task_list[j] == task) { found_task = TRUE; break; } } if (found_task) thread_list[used++] = thread_list[i]; else thread_deallocate(thread_list[i]); } actual_threads = used; thread_size_needed = actual_threads * sizeof(void *); /* done with the task list */ for (i = 0; i < actual_tasks; i++) task_deallocate(task_list[i]); kfree(task_list, task_size); task_size = 0; actual_tasks = 0; task_list = NULL; } #endif if (type == PSET_THING_THREAD) { if (actual_threads == 0) { /* no threads available to return */ assert(task_size == 0); if (thread_size != 0) kfree(thread_list, thread_size); *thing_list = NULL; *count = 0; return KERN_SUCCESS; } size_needed = actual_threads * sizeof(void *); size = thread_size; addr = thread_list; } else { if (actual_tasks == 0) { /* no tasks available to return */ assert(thread_size == 0); if (task_size != 0) kfree(task_list, task_size); *thing_list = NULL; *count = 0; return KERN_SUCCESS; } size_needed = actual_tasks * sizeof(void *); size = task_size; addr = task_list; } /* if we allocated too much, must copy */ if (size_needed < size) { newaddr = kalloc(size_needed); if (newaddr == 0) { for (i = 0; i < actual_tasks; i++) { if (type == PSET_THING_THREAD) thread_deallocate(thread_list[i]); else task_deallocate(task_list[i]); } if (size) kfree(addr, size); return (KERN_RESOURCE_SHORTAGE); } bcopy((void *) addr, (void *) newaddr, size_needed); kfree(addr, size); addr = newaddr; size = size_needed; } *thing_list = (void **)addr; *count = (unsigned int)size / sizeof(void *); return (KERN_SUCCESS); }