* Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
- *
+ *
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
- *
+ *
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
- *
+ *
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
- *
+ *
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
/*
* @OSF_COPYRIGHT@
*/
-/*
+/*
* Mach Operating System
* Copyright (c) 1991,1990 Carnegie Mellon University
* All Rights Reserved.
- *
+ *
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
- *
+ *
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
+ *
* Carnegie Mellon requests users of this software to return to
- *
+ *
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
- *
+ *
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
#include <ipc/ipc_hash.h>
#include <ipc/ipc_table.h>
#include <ipc/ipc_right.h>
+
+#include <security/mac_mach_internal.h>
+#include <device/device_types.h>
#endif
/*
#if !MACH_IPC_DEBUG
kern_return_t
mach_port_get_srights(
- __unused ipc_space_t space,
- __unused mach_port_name_t name,
- __unused mach_port_rights_t *srightsp)
+ __unused ipc_space_t space,
+ __unused mach_port_name_t name,
+ __unused mach_port_rights_t *srightsp)
{
- return KERN_FAILURE;
+ return KERN_FAILURE;
}
#else
kern_return_t
mach_port_get_srights(
- ipc_space_t space,
- mach_port_name_t name,
- mach_port_rights_t *srightsp)
+ ipc_space_t space,
+ mach_port_name_t name,
+ mach_port_rights_t *srightsp)
{
ipc_port_t port;
kern_return_t kr;
mach_port_rights_t srights;
- if (space == IS_NULL)
+ if (space == IS_NULL) {
return KERN_INVALID_TASK;
+ }
kr = ipc_port_translate_receive(space, name, &port);
- if (kr != KERN_SUCCESS)
+ if (kr != KERN_SUCCESS) {
return kr;
+ }
/* port is locked and active */
srights = port->ip_srights;
#if !MACH_IPC_DEBUG
kern_return_t
-mach_port_space_info(
- __unused ipc_space_t space,
- __unused ipc_info_space_t *infop,
- __unused ipc_info_name_array_t *tablep,
- __unused mach_msg_type_number_t *tableCntp,
+mach_port_space_info_from_user(
+ __unused mach_port_t port,
+ __unused ipc_info_space_t *infop,
+ __unused ipc_info_name_array_t *tablep,
+ __unused mach_msg_type_number_t *tableCntp,
__unused ipc_info_tree_name_array_t *treep,
- __unused mach_msg_type_number_t *treeCntp)
+ __unused mach_msg_type_number_t *treeCntp)
{
- return KERN_FAILURE;
+ return KERN_FAILURE;
}
+
#else
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,
+ 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);
+
+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_map_copy_t copy;
- if (space == IS_NULL)
+ if (space == IS_NULL) {
return KERN_INVALID_TASK;
+ }
+
+#if !(DEVELOPMENT || DEBUG) && CONFIG_MACF
+ const boolean_t dbg_ok = (mac_task_check_expose_task(kernel_task, TASK_FLAVOR_CONTROL) == 0);
+#else
+ const boolean_t dbg_ok = TRUE;
+#endif
/* start with in-line memory */
is_read_lock(space);
if (!is_active(space)) {
is_read_unlock(space);
- if (table_size != 0)
+ if (table_size != 0) {
kmem_free(ipc_kernel_map,
- table_addr, table_size);
+ 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));
+ 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)
+ if (table_size_needed == table_size) {
break;
+ }
is_read_unlock(space);
if (table_size != table_size_needed) {
- if (table_size != 0)
+ if (table_size != 0) {
kmem_free(ipc_kernel_map, table_addr, table_size);
- kr = kmem_alloc(ipc_kernel_map, &table_addr, table_size_needed);
+ }
+ 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 */
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) {
- ipc_port_t port = (ipc_port_t) entry->ie_object;
+ ipc_port_t port = ip_object_to_port(entry->ie_object);
assert(IP_VALID(port));
ip_lock(port);
}
iin->iin_urefs = IE_BITS_UREFS(bits);
- iin->iin_object = (natural_t)VM_KERNEL_ADDRPERM((uintptr_t)entry->ie_object);
+ 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;
}
/* prepare the table out-of-line data for return */
if (table_size > 0) {
- if (table_size > infop->iis_table_size * sizeof(ipc_info_name_t))
+ 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 - infop->iis_table_size * sizeof(ipc_info_name_t));
+ 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_PAGE_MASK(ipc_kernel_map)),
vm_map_round_page(table_addr + table_size,
- VM_MAP_PAGE_MASK(ipc_kernel_map)),
+ 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)table_size, TRUE, ©);
+ 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;
*treeCntp = 0;
return KERN_SUCCESS;
}
+
+kern_return_t
+mach_port_space_info_from_user(
+ mach_port_t port,
+ 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)
+{
+ kern_return_t kr;
+
+ ipc_space_t space = convert_port_to_space_check_type(port, NULL, TASK_FLAVOR_READ, FALSE);
+
+ if (space == IPC_SPACE_NULL) {
+ return KERN_INVALID_ARGUMENT;
+ }
+
+ kr = mach_port_space_info(space, infop, tablep, tableCntp, treep, treeCntp);
+
+ ipc_space_release(space);
+ return kr;
+}
+#endif /* MACH_IPC_DEBUG */
+
+/*
+ * Routine: mach_port_space_basic_info
+ * Purpose:
+ * Returns basic information about an IPC space.
+ * Conditions:
+ * Nothing locked.
+ * Returns:
+ * KERN_SUCCESS Returned information.
+ * KERN_FAILURE The call is not supported.
+ * KERN_INVALID_TASK The space is dead.
+ */
+
+#if !MACH_IPC_DEBUG
+kern_return_t
+mach_port_space_basic_info(
+ __unused ipc_space_t space,
+ __unused ipc_info_space_basic_t *infop)
+{
+ return KERN_FAILURE;
+}
+#else
+kern_return_t
+mach_port_space_basic_info(
+ ipc_space_t space,
+ ipc_info_space_basic_t *infop)
+{
+ if (space == IS_NULL) {
+ return KERN_INVALID_TASK;
+ }
+
+
+ is_read_lock(space);
+ if (!is_active(space)) {
+ is_read_unlock(space);
+ return KERN_INVALID_TASK;
+ }
+
+ /* get the basic space info */
+ infop->iisb_genno_mask = MACH_PORT_NGEN(MACH_PORT_DEAD);
+ infop->iisb_table_size = space->is_table_size;
+ infop->iisb_table_next = space->is_table_next->its_size;
+ infop->iisb_table_inuse = space->is_table_size - space->is_table_free - 1;
+ infop->iisb_reserved[0] = 0;
+ infop->iisb_reserved[1] = 0;
+
+ is_read_unlock(space);
+
+ return KERN_SUCCESS;
+}
#endif /* MACH_IPC_DEBUG */
/*
#if !MACH_IPC_DEBUG
kern_return_t
mach_port_dnrequest_info(
- __unused ipc_space_t space,
- __unused mach_port_name_t name,
- __unused unsigned int *totalp,
- __unused unsigned int *usedp)
+ __unused ipc_space_t space,
+ __unused mach_port_name_t name,
+ __unused unsigned int *totalp,
+ __unused unsigned int *usedp)
{
- return KERN_FAILURE;
+ return KERN_FAILURE;
}
#else
kern_return_t
mach_port_dnrequest_info(
- ipc_space_t space,
- mach_port_name_t name,
- unsigned int *totalp,
- unsigned int *usedp)
+ ipc_space_t space,
+ mach_port_name_t name,
+ unsigned int *totalp,
+ unsigned int *usedp)
{
unsigned int total, used;
ipc_port_t port;
kern_return_t kr;
- if (space == IS_NULL)
+ if (space == IS_NULL) {
return KERN_INVALID_TASK;
+ }
kr = ipc_port_translate_receive(space, name, &port);
- if (kr != KERN_SUCCESS)
+ if (kr != KERN_SUCCESS) {
return kr;
+ }
/* port is locked and active */
if (port->ip_requests == IPR_NULL) {
total = requests->ipr_size->its_size;
for (index = 1, used = 0;
- index < total; index++) {
+ index < total; index++) {
ipc_port_request_t ipr = &requests[index];
- if (ipr->ipr_name != MACH_PORT_NULL)
+ if (ipr->ipr_name != MACH_PORT_NULL) {
used++;
+ }
}
}
ip_unlock(port);
#if !MACH_IPC_DEBUG
kern_return_t
-mach_port_kobject(
- __unused ipc_space_t space,
- __unused mach_port_name_t name,
- __unused natural_t *typep,
- __unused mach_vm_address_t *addrp)
+mach_port_kobject_from_user(
+ __unused mach_port_t port,
+ __unused mach_port_name_t name,
+ __unused natural_t *typep,
+ __unused mach_vm_address_t *addrp)
{
- return KERN_FAILURE;
+ return KERN_FAILURE;
+}
+
+kern_return_t
+mach_port_kobject_description_from_user(
+ __unused mach_port_t port,
+ __unused mach_port_name_t name,
+ __unused natural_t *typep,
+ __unused mach_vm_address_t *addrp,
+ __unused kobject_description_t des)
+{
+ return KERN_FAILURE;
}
#else
kern_return_t
-mach_port_kobject(
- ipc_space_t space,
- mach_port_name_t name,
- natural_t *typep,
- mach_vm_address_t *addrp)
+mach_port_kobject_description(
+ ipc_space_t space,
+ mach_port_name_t name,
+ natural_t *typep,
+ mach_vm_address_t *addrp,
+ kobject_description_t desc);
+
+kern_return_t
+mach_port_kobject_description(
+ ipc_space_t space,
+ mach_port_name_t name,
+ natural_t *typep,
+ mach_vm_address_t *addrp,
+ kobject_description_t desc)
{
ipc_entry_t entry;
ipc_port_t port;
kern_return_t kr;
mach_vm_address_t kaddr;
+ io_object_t obj = NULL;
- if (space == IS_NULL)
+ if (space == IS_NULL) {
return KERN_INVALID_TASK;
+ }
kr = ipc_right_lookup_read(space, name, &entry);
- if (kr != KERN_SUCCESS)
+ if (kr != KERN_SUCCESS) {
return kr;
+ }
/* space is read-locked and active */
if ((entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE) == 0) {
return KERN_INVALID_RIGHT;
}
- port = (ipc_port_t) entry->ie_object;
+ port = ip_object_to_port(entry->ie_object);
assert(port != IP_NULL);
ip_lock(port);
}
*typep = (unsigned int) ip_kotype(port);
- kaddr = (mach_vm_address_t)port->ip_kobject;
+ kaddr = (mach_vm_address_t)ip_get_kobject(port);
+ *addrp = 0;
+
+ if (desc) {
+ *desc = '\0';
+ switch (ip_kotype(port)) {
+ case IKOT_IOKIT_OBJECT:
+ case IKOT_IOKIT_CONNECT:
+ case IKOT_IOKIT_IDENT:
+ case IKOT_UEXT_OBJECT:
+ obj = (io_object_t) kaddr;
+ iokit_add_reference(obj, IKOT_IOKIT_OBJECT);
+ break;
+
+ default:
+ break;
+ }
+ }
+#if (DEVELOPMENT || DEBUG)
+ *addrp = VM_KERNEL_UNSLIDE_OR_PERM(kaddr);
+#endif
+
ip_unlock(port);
- if (0 != kaddr && is_ipc_kobject(*typep))
- *addrp = VM_KERNEL_ADDRPERM(VM_KERNEL_UNSLIDE(kaddr));
- else
- *addrp = 0;
+ if (obj) {
+ iokit_port_object_description(obj, desc);
+ iokit_remove_reference(obj);
+ }
return KERN_SUCCESS;
}
+
+kern_return_t
+mach_port_kobject(
+ ipc_space_t space,
+ mach_port_name_t name,
+ natural_t *typep,
+ mach_vm_address_t *addrp);
+
+kern_return_t
+mach_port_kobject(
+ ipc_space_t space,
+ mach_port_name_t name,
+ natural_t *typep,
+ mach_vm_address_t *addrp)
+{
+ return mach_port_kobject_description(space, name, typep, addrp, NULL);
+}
+
+kern_return_t
+mach_port_kobject_description_from_user(
+ mach_port_t port,
+ mach_port_name_t name,
+ natural_t *typep,
+ mach_vm_address_t *addrp,
+ kobject_description_t desc)
+{
+ kern_return_t kr;
+
+ ipc_space_t space = convert_port_to_space_check_type(port, NULL, TASK_FLAVOR_READ, FALSE);
+
+ if (space == IPC_SPACE_NULL) {
+ return KERN_INVALID_ARGUMENT;
+ }
+
+ kr = mach_port_kobject_description(space, name, typep, addrp, desc);
+
+ ipc_space_release(space);
+ return kr;
+}
+
+kern_return_t
+mach_port_kobject_from_user(
+ mach_port_t port,
+ mach_port_name_t name,
+ natural_t *typep,
+ mach_vm_address_t *addrp)
+{
+ return mach_port_kobject_description_from_user(port, name, typep, addrp, NULL);
+}
+
#endif /* MACH_IPC_DEBUG */
+
/*
* Routine: mach_port_kernel_object [Legacy kernel call]
* Purpose:
#if !MACH_IPC_DEBUG
kern_return_t
-mach_port_kernel_object(
- __unused ipc_space_t space,
- __unused mach_port_name_t name,
- __unused unsigned int *typep,
- __unused unsigned int *addrp)
+mach_port_kernel_object_from_user(
+ __unused mach_port_t port,
+ __unused mach_port_name_t name,
+ __unused unsigned int *typep,
+ __unused unsigned int *addrp)
{
- return KERN_FAILURE;
+ return KERN_FAILURE;
}
#else
kern_return_t
mach_port_kernel_object(
- ipc_space_t space,
- mach_port_name_t name,
- unsigned int *typep,
- unsigned int *addrp)
+ ipc_space_t space,
+ mach_port_name_t name,
+ unsigned int *typep,
+ unsigned int *addrp);
+
+kern_return_t
+mach_port_kernel_object(
+ ipc_space_t space,
+ mach_port_name_t name,
+ unsigned int *typep,
+ unsigned int *addrp)
{
mach_vm_address_t addr = 0;
kern_return_t kr;
*addrp = (unsigned int) addr;
return kr;
}
+
+kern_return_t
+mach_port_kernel_object_from_user(
+ mach_port_t port,
+ mach_port_name_t name,
+ unsigned int *typep,
+ unsigned int *addrp)
+{
+ kern_return_t kr;
+
+ ipc_space_t space = convert_port_to_space_check_type(port, NULL, TASK_FLAVOR_READ, FALSE);
+
+ if (space == IPC_SPACE_NULL) {
+ return KERN_INVALID_ARGUMENT;
+ }
+
+ kr = mach_port_kernel_object(space, name, typep, addrp);
+
+ ipc_space_release(space);
+ return kr;
+}
#endif /* MACH_IPC_DEBUG */
+
+#if (DEVELOPMENT || DEBUG)
+kern_return_t
+mach_port_special_reply_port_reset_link(
+ ipc_space_t space,
+ mach_port_name_t name,
+ boolean_t *srp_lost_link)
+{
+ ipc_port_t port;
+ kern_return_t kr;
+ thread_t thread = current_thread();
+
+ if (space != current_space()) {
+ return KERN_INVALID_TASK;
+ }
+
+ if (!MACH_PORT_VALID(name)) {
+ return KERN_INVALID_NAME;
+ }
+
+ if (!IP_VALID(thread->ith_special_reply_port)) {
+ return KERN_INVALID_VALUE;
+ }
+
+ kr = ipc_port_translate_receive(space, name, &port);
+ if (kr != KERN_SUCCESS) {
+ return kr;
+ }
+
+ if (thread->ith_special_reply_port != port) {
+ ip_unlock(port);
+ return KERN_INVALID_ARGUMENT;
+ }
+
+ imq_lock(&port->ip_messages);
+ *srp_lost_link = (port->ip_srp_lost_link == 1)? TRUE : FALSE;
+ port->ip_srp_lost_link = 0;
+ imq_unlock(&port->ip_messages);
+
+ ip_unlock(port);
+ return KERN_SUCCESS;
+}
+#else
+kern_return_t
+mach_port_special_reply_port_reset_link(
+ __unused ipc_space_t space,
+ __unused mach_port_name_t name,
+ __unused boolean_t *srp_lost_link)
+{
+ return KERN_NOT_SUPPORTED;
+}
+#endif