X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/2d21ac55c334faf3a56e5634905ed6987fc787d4..ebb1b9f42b62218f29061826217bb0f71cd375a6:/osfmk/ipc/mach_port.c diff --git a/osfmk/ipc/mach_port.c b/osfmk/ipc/mach_port.c index e220fc9fb..adfc70bcb 100644 --- a/osfmk/ipc/mach_port.c +++ b/osfmk/ipc/mach_port.c @@ -128,6 +128,9 @@ static mach_port_qos_t qos_template; * Routine: mach_port_names_helper * Purpose: * A helper function for mach_port_names. + * + * Conditions: + * Space containing entry is [at least] read-locked. */ void @@ -141,44 +144,51 @@ mach_port_names_helper( { ipc_entry_bits_t bits; ipc_port_request_index_t request; - mach_port_type_t type; + mach_port_type_t type = 0; ipc_entry_num_t actual; + ipc_port_t port; bits = entry->ie_bits; request = entry->ie_request; - if (bits & MACH_PORT_TYPE_SEND_RIGHTS) { - ipc_port_t port; - boolean_t died; + port = (ipc_port_t) entry->ie_object; - port = (ipc_port_t) entry->ie_object; - assert(port != IP_NULL); + if (bits & MACH_PORT_TYPE_RECEIVE) { + assert(IP_VALID(port)); - /* - * The timestamp serializes mach_port_names - * with ipc_port_destroy. If the port died, - * but after mach_port_names started, pretend - * that it isn't dead. - */ + if (request != IE_REQ_NONE) { + ip_lock(port); + assert(ip_active(port)); + type |= ipc_port_request_type(port, name, request); + ip_unlock(port); + } - ip_lock(port); - died = (!ip_active(port) && - IP_TIMESTAMP_ORDER(port->ip_timestamp, timestamp)); - ip_unlock(port); + } else if (bits & MACH_PORT_TYPE_SEND_RIGHTS) { + mach_port_type_t reqtype; - if (died) { - /* pretend this is a dead-name entry */ + assert(IP_VALID(port)); + ip_lock(port); + reqtype = (request != IE_REQ_NONE) ? + ipc_port_request_type(port, name, request) : 0; + + /* + * If the port is alive, or was alive when the mach_port_names + * started, then return that fact. Otherwise, pretend we found + * a dead name entry. + */ + if (ip_active(port) || IP_TIMESTAMP_ORDER(timestamp, port->ip_timestamp)) { + type |= reqtype; + } else { bits &= ~(IE_BITS_TYPE_MASK); bits |= MACH_PORT_TYPE_DEAD_NAME; - if (request != 0) + /* account for additional reference for dead-name notification */ + if (reqtype != 0) bits++; - request = 0; } + ip_unlock(port); } - type = IE_BITS_TYPE(bits); - if (request != 0) - type |= MACH_PORT_TYPE_DNREQUEST; + type |= IE_BITS_TYPE(bits); actual = *actualp; names[actual] = name; @@ -436,6 +446,11 @@ mach_port_type( kr = ipc_right_info(space, name, entry, typep, &urefs); if (kr == KERN_SUCCESS) is_write_unlock(space); +#if 1 + /* JMM - workaround rdar://problem/9121297 (CF being too picky on these bits). */ + *typep &= ~(MACH_PORT_TYPE_SPREQUEST | MACH_PORT_TYPE_SPREQUEST_DELAYED); +#endif + /* space is unlocked */ return kr; } @@ -644,9 +659,11 @@ mach_port_allocate_full( return KERN_RESOURCE_SHORTAGE; } else { mach_msg_size_t size = qosp->len + MAX_TRAILER_SIZE; + if (right != MACH_PORT_RIGHT_RECEIVE) return (KERN_INVALID_VALUE); - kmsg = (ipc_kmsg_t)ipc_kmsg_alloc(size); + + kmsg = (ipc_kmsg_t)ipc_kmsg_prealloc(size); if (kmsg == IKM_NULL) return (KERN_RESOURCE_SHORTAGE); } @@ -992,6 +1009,88 @@ mach_port_set_seqno( return KERN_SUCCESS; } +/* + * Routine: mach_port_get_context [kernel call] + * Purpose: + * Returns a receive right's context pointer. + * Conditions: + * Nothing locked. + * Returns: + * KERN_SUCCESS Set context pointer. + * KERN_INVALID_TASK The space is null. + * KERN_INVALID_TASK The space is dead. + * KERN_INVALID_NAME The name doesn't denote a right. + * KERN_INVALID_RIGHT Name doesn't denote receive rights. + */ + +kern_return_t +mach_port_get_context( + ipc_space_t space, + mach_port_name_t name, + mach_vm_address_t *context) +{ + ipc_port_t port; + kern_return_t kr; + + if (space == IS_NULL) + return KERN_INVALID_TASK; + + if (!MACH_PORT_VALID(name)) + return KERN_INVALID_RIGHT; + + kr = ipc_port_translate_receive(space, name, &port); + if (kr != KERN_SUCCESS) + return kr; + + /* port is locked and active */ + *context = port->ip_context; + + ip_unlock(port); + return KERN_SUCCESS; +} + + +/* + * Routine: mach_port_set_context [kernel call] + * Purpose: + * Changes a receive right's context pointer. + * Conditions: + * Nothing locked. + * Returns: + * KERN_SUCCESS Set context pointer. + * KERN_INVALID_TASK The space is null. + * KERN_INVALID_TASK The space is dead. + * KERN_INVALID_NAME The name doesn't denote a right. + * KERN_INVALID_RIGHT Name doesn't denote receive rights. + */ + +kern_return_t +mach_port_set_context( + ipc_space_t space, + mach_port_name_t name, + mach_vm_address_t context) +{ + ipc_port_t port; + kern_return_t kr; + + if (space == IS_NULL) + return KERN_INVALID_TASK; + + if (!MACH_PORT_VALID(name)) + return KERN_INVALID_RIGHT; + + kr = ipc_port_translate_receive(space, name, &port); + if (kr != KERN_SUCCESS) + return kr; + + /* port is locked and active */ + port->ip_context = context; + + ip_unlock(port); + return KERN_SUCCESS; +} + + /* * Routine: mach_port_gst_helper * Purpose: @@ -1103,7 +1202,7 @@ mach_port_get_set_status( /* the port set must be active */ names = (mach_port_name_t *) addr; - maxnames = size / sizeof(mach_port_name_t); + maxnames = (ipc_entry_num_t)(size / sizeof(mach_port_name_t)); actual = 0; table = space->is_table; @@ -1388,6 +1487,18 @@ mach_port_request_notification( break; } + case MACH_NOTIFY_SEND_POSSIBLE: + + if (!MACH_PORT_VALID(name)) { + return KERN_INVALID_ARGUMENT; + } + + kr = ipc_right_request_alloc(space, name, sync != 0, + TRUE, notify, previousp); + if (kr != KERN_SUCCESS) + return kr; + break; + case MACH_NOTIFY_DEAD_NAME: if (!MACH_PORT_VALID(name)) { @@ -1399,8 +1510,8 @@ mach_port_request_notification( return KERN_INVALID_ARGUMENT; } - kr = ipc_right_dnrequest(space, name, sync != 0, - notify, previousp); + kr = ipc_right_request_alloc(space, name, sync != 0, + FALSE, notify, previousp); if (kr != KERN_SUCCESS) return kr; break; @@ -1593,7 +1704,7 @@ mach_port_get_attributes( return kr; /* port is locked and active */ - table = port->ip_dnrequests; + table = port->ip_requests; if (table == IPR_NULL) *(int *)info = 0; else @@ -1660,7 +1771,7 @@ mach_port_set_attributes( return kr; /* port is locked and active */ - kr = ipc_port_dngrow(port, *(int *)info); + kr = ipc_port_request_grow(port, *(int *)info); if (kr != KERN_SUCCESS) return kr; break; @@ -1786,6 +1897,12 @@ task_set_port_space( kern_return_t kr; is_write_lock(space); + + if (!space->is_active) { + is_write_unlock(space); + return KERN_INVALID_TASK; + } + kr = ipc_entry_grow_table(space, table_entries); if (kr == KERN_SUCCESS) is_write_unlock(space);