void ipc_object_destroy( ipc_object_t object, mach_msg_type_name_t msgt_name) { assert(IO_VALID(object)); assert(io_otype(object) == IOT_PORT); switch (msgt_name) { case MACH_MSG_TYPE_PORT_SEND: ipc_port_release_send((ipc_port_t) object); break; case MACH_MSG_TYPE_PORT_SEND_ONCE: ipc_notify_send_once((ipc_port_t) object); break; case MACH_MSG_TYPE_PORT_RECEIVE: ipc_port_release_receive((ipc_port_t) object); break; default: panic("ipc_object_destroy: strange rights"); } }
void ipc_object_destroy_dest( ipc_object_t object, mach_msg_type_name_t msgt_name) { assert(IO_VALID(object)); assert(io_otype(object) == IOT_PORT); switch (msgt_name) { case MACH_MSG_TYPE_PORT_SEND: ipc_port_release_send((ipc_port_t) object); break; case MACH_MSG_TYPE_PORT_SEND_ONCE: if (io_active(object) && !ip_full_kernel((ipc_port_t) object)) ipc_notify_send_once((ipc_port_t) object); else ipc_port_release_sonce((ipc_port_t) object); break; default: panic("ipc_object_destroy_dest: strange rights"); } }
kern_return_t mach_port_insert_right( ipc_space_t space, mach_port_name_t name, ipc_port_t poly, mach_msg_type_name_t polyPoly) { if (space == IS_NULL) return KERN_INVALID_TASK; if (!MACH_PORT_VALID(name) || !MACH_MSG_TYPE_PORT_ANY_RIGHT(polyPoly)) return KERN_INVALID_VALUE; if (!IO_VALID((ipc_object_t) poly)) return KERN_INVALID_CAPABILITY; return ipc_object_copyout_name(space, (ipc_object_t) poly, polyPoly, FALSE, name); }
void ipc_object_copyout_dest( ipc_space_t space, ipc_object_t object, mach_msg_type_name_t msgt_name, mach_port_name_t *namep) { mach_port_name_t name; assert(IO_VALID(object)); assert(io_active(object)); io_release(object); /* * If the space is the receiver/owner of the object, * then we quietly consume the right and return * the space's name for the object. Otherwise * we destroy the right and return MACH_PORT_NULL. */ switch (msgt_name) { case MACH_MSG_TYPE_PORT_SEND: { ipc_port_t port = (ipc_port_t) object; ipc_port_t nsrequest = IP_NULL; mach_port_mscount_t mscount; if (port->ip_receiver == space) name = port->ip_receiver_name; else name = MACH_PORT_NULL; assert(port->ip_srights > 0); if (--port->ip_srights == 0 && port->ip_nsrequest != IP_NULL) { nsrequest = port->ip_nsrequest; port->ip_nsrequest = IP_NULL; mscount = port->ip_mscount; ip_unlock(port); ipc_notify_no_senders(nsrequest, mscount); } else ip_unlock(port); break; } case MACH_MSG_TYPE_PORT_SEND_ONCE: { ipc_port_t port = (ipc_port_t) object; assert(port->ip_sorights > 0); if (port->ip_receiver == space) { /* quietly consume the send-once right */ port->ip_sorights--; name = port->ip_receiver_name; ip_unlock(port); } else { /* * A very bizarre case. The message * was received, but before this copyout * happened the space lost receive rights. * We can't quietly consume the soright * out from underneath some other task, * so generate a send-once notification. */ ip_reference(port); /* restore ref */ ip_unlock(port); ipc_notify_send_once(port); name = MACH_PORT_NULL; } break; } default: panic("ipc_object_copyout_dest: strange rights"); name = MACH_PORT_DEAD; } *namep = name; }
kern_return_t ipc_object_copyout_name( ipc_space_t space, ipc_object_t object, mach_msg_type_name_t msgt_name, boolean_t overflow, mach_port_name_t name) { mach_port_name_t oname; ipc_entry_t oentry; ipc_entry_t entry; kern_return_t kr; #if IMPORTANCE_INHERITANCE int assertcnt = 0; ipc_importance_task_t task_imp = IIT_NULL; #endif /* IMPORTANCE_INHERITANCE */ assert(IO_VALID(object)); assert(io_otype(object) == IOT_PORT); kr = ipc_entry_alloc_name(space, name, &entry); if (kr != KERN_SUCCESS) return kr; /* space is write-locked and active */ if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) && ipc_right_reverse(space, object, &oname, &oentry)) { /* object is locked and active */ if (name != oname) { io_unlock(object); if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE) ipc_entry_dealloc(space, name, entry); is_write_unlock(space); return KERN_RIGHT_EXISTS; } assert(entry == oentry); assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE); } else { if (ipc_right_inuse(space, name, entry)) return KERN_NAME_EXISTS; assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE); assert(entry->ie_object == IO_NULL); io_lock(object); if (!io_active(object)) { io_unlock(object); ipc_entry_dealloc(space, name, entry); is_write_unlock(space); return KERN_INVALID_CAPABILITY; } entry->ie_object = object; } /* space is write-locked and active, object is locked and active */ #if IMPORTANCE_INHERITANCE /* * We are slamming a receive right into the space, without * first having been enqueued on a port destined there. So, * we have to arrange to boost the task appropriately if this * port has assertions (and the task wants them). */ if (msgt_name == MACH_MSG_TYPE_PORT_RECEIVE) { ipc_port_t port = (ipc_port_t)object; if (space->is_task != TASK_NULL) { task_imp = space->is_task->task_imp_base; if (ipc_importance_task_is_any_receiver_type(task_imp)) { assertcnt = port->ip_impcount; ipc_importance_task_reference(task_imp); } } /* take port out of limbo */ assert(port->ip_tempowner != 0); port->ip_tempowner = 0; } #endif /* IMPORTANCE_INHERITANCE */ kr = ipc_right_copyout(space, name, entry, msgt_name, overflow, object); /* object is unlocked */ is_write_unlock(space); #if IMPORTANCE_INHERITANCE /* * Add the assertions to the task that we captured before */ if (task_imp != IIT_NULL) { ipc_importance_task_hold_internal_assertion(task_imp, assertcnt); ipc_importance_task_release(task_imp); } #endif /* IMPORTANCE_INHERITANCE */ return kr; }
kern_return_t ipc_object_copyout( ipc_space_t space, ipc_object_t object, mach_msg_type_name_t msgt_name, boolean_t overflow, mach_port_name_t *namep) { mach_port_name_t name; ipc_entry_t entry; kern_return_t kr; assert(IO_VALID(object)); assert(io_otype(object) == IOT_PORT); is_write_lock(space); for (;;) { if (!is_active(space)) { is_write_unlock(space); return KERN_INVALID_TASK; } if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) && ipc_right_reverse(space, object, &name, &entry)) { /* object is locked and active */ assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE); break; } name = CAST_MACH_PORT_TO_NAME(object); kr = ipc_entry_get(space, &name, &entry); if (kr != KERN_SUCCESS) { /* unlocks/locks space, so must start again */ kr = ipc_entry_grow_table(space, ITS_SIZE_NONE); if (kr != KERN_SUCCESS) return kr; /* space is unlocked */ continue; } assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE); assert(entry->ie_object == IO_NULL); io_lock(object); if (!io_active(object)) { io_unlock(object); ipc_entry_dealloc(space, name, entry); is_write_unlock(space); return KERN_INVALID_CAPABILITY; } entry->ie_object = object; break; } /* space is write-locked and active, object is locked and active */ kr = ipc_right_copyout(space, name, entry, msgt_name, overflow, object); /* object is unlocked */ is_write_unlock(space); if (kr == KERN_SUCCESS) *namep = name; return kr; }
void ipc_object_copyin_from_kernel( ipc_object_t object, mach_msg_type_name_t msgt_name) { assert(IO_VALID(object)); switch (msgt_name) { case MACH_MSG_TYPE_MOVE_RECEIVE: { ipc_port_t port = (ipc_port_t) object; ip_lock(port); assert(ip_active(port)); if (port->ip_destination != IP_NULL) { assert(port->ip_receiver == ipc_space_kernel); /* relevant part of ipc_port_clear_receiver */ ipc_port_set_mscount(port, 0); port->ip_receiver_name = MACH_PORT_NULL; port->ip_destination = IP_NULL; } ip_unlock(port); break; } case MACH_MSG_TYPE_COPY_SEND: { ipc_port_t port = (ipc_port_t) object; ip_lock(port); if (ip_active(port)) { assert(port->ip_srights > 0); port->ip_srights++; } ip_reference(port); ip_unlock(port); break; } case MACH_MSG_TYPE_MAKE_SEND: { ipc_port_t port = (ipc_port_t) object; ip_lock(port); if (ip_active(port)) { assert(port->ip_receiver_name != MACH_PORT_NULL); assert((port->ip_receiver == ipc_space_kernel) || (port->ip_receiver->is_node_id != HOST_LOCAL_NODE)); port->ip_mscount++; } port->ip_srights++; ip_reference(port); ip_unlock(port); break; } case MACH_MSG_TYPE_MOVE_SEND: { /* move naked send right into the message */ assert(((ipc_port_t)object)->ip_srights); break; } case MACH_MSG_TYPE_MAKE_SEND_ONCE: { ipc_port_t port = (ipc_port_t) object; ip_lock(port); if (ip_active(port)) { assert(port->ip_receiver_name != MACH_PORT_NULL); } port->ip_sorights++; ip_reference(port); ip_unlock(port); break; } case MACH_MSG_TYPE_MOVE_SEND_ONCE: { /* move naked send-once right into the message */ assert(((ipc_port_t)object)->ip_sorights); break; } default: panic("ipc_object_copyin_from_kernel: strange rights"); } }
kern_return_t ipc_object_copyout_name( ipc_space_t space, ipc_object_t object, mach_msg_type_name_t msgt_name, boolean_t overflow, mach_port_name_t name) { mach_port_name_t oname; ipc_entry_t oentry; ipc_entry_t entry; kern_return_t kr; assert(IO_VALID(object)); assert(io_otype(object) == IOT_PORT); kr = ipc_entry_alloc_name(space, name, &entry); if (kr != KERN_SUCCESS) return kr; /* space is write-locked and active */ if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) && ipc_right_reverse(space, object, &oname, &oentry)) { /* object is locked and active */ if (name != oname) { io_unlock(object); if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE) ipc_entry_dealloc(space, name, entry); is_write_unlock(space); return KERN_RIGHT_EXISTS; } assert(entry == oentry); assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE); } else { if (ipc_right_inuse(space, name, entry)) return KERN_NAME_EXISTS; assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE); assert(entry->ie_object == IO_NULL); io_lock(object); if (!io_active(object)) { io_unlock(object); ipc_entry_dealloc(space, name, entry); is_write_unlock(space); return KERN_INVALID_CAPABILITY; } entry->ie_object = object; } /* space is write-locked and active, object is locked and active */ kr = ipc_right_copyout(space, name, entry, msgt_name, overflow, object); /* object is unlocked */ is_write_unlock(space); return kr; }
void ipc_object_copyin_from_kernel( ipc_object_t object, mach_msg_type_name_t msgt_name) { assert(IO_VALID(object)); switch (msgt_name) { case MACH_MSG_TYPE_MOVE_RECEIVE: { ipc_port_t port = (ipc_port_t) object; ip_lock(port); assert(ip_active(port)); assert(port->ip_receiver_name != MACH_PORT_NULL); assert(port->ip_receiver == ipc_space_kernel); /* relevant part of ipc_port_clear_receiver */ ipc_port_set_mscount(port, 0); port->ip_receiver_name = MACH_PORT_NULL; port->ip_destination = IP_NULL; ipc_port_flag_protected_payload_clear(port); ip_unlock(port); break; } case MACH_MSG_TYPE_COPY_SEND: { ipc_port_t port = (ipc_port_t) object; ip_lock(port); if (ip_active(port)) { assert(port->ip_srights > 0); port->ip_srights++; } ip_reference(port); ip_unlock(port); break; } case MACH_MSG_TYPE_MAKE_SEND: { ipc_port_t port = (ipc_port_t) object; ip_lock(port); assert(ip_active(port)); assert(port->ip_receiver_name != MACH_PORT_NULL); assert(port->ip_receiver == ipc_space_kernel); ip_reference(port); port->ip_mscount++; port->ip_srights++; ip_unlock(port); break; } case MACH_MSG_TYPE_MOVE_SEND: /* move naked send right into the message */ break; case MACH_MSG_TYPE_MAKE_SEND_ONCE: { ipc_port_t port = (ipc_port_t) object; ip_lock(port); assert(ip_active(port)); assert(port->ip_receiver_name != MACH_PORT_NULL); assert(port->ip_receiver == ipc_space_kernel); ip_reference(port); port->ip_sorights++; ip_unlock(port); break; } case MACH_MSG_TYPE_MOVE_SEND_ONCE: /* move naked send-once right into the message */ break; default: #if MACH_ASSERT assert(!"ipc_object_copyin_from_kernel: strange rights"); #else panic("ipc_object_copyin_from_kernel: strange rights"); #endif } }
kern_return_t ipc_right_copyout( ipc_space_t space, mach_port_t name, ipc_entry_t entry, mach_msg_type_name_t msgt_name, boolean_t overflow, ipc_object_t object) { ipc_entry_bits_t bits = entry->ie_bits; ipc_port_t port; assert(IO_VALID(object)); assert(io_otype(object) == IOT_PORT); assert(io_active(object)); assert(entry->ie_object == object); port = (ipc_port_t) object; switch (msgt_name) { case MACH_MSG_TYPE_PORT_SEND_ONCE: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE); assert(port->ip_sorights > 0); /* transfer send-once right and ref to entry */ ip_unlock(port); entry->ie_bits = bits | (MACH_PORT_TYPE_SEND_ONCE | 1); break; case MACH_MSG_TYPE_PORT_SEND: assert(port->ip_srights > 0); if (bits & MACH_PORT_TYPE_SEND) { mach_port_urefs_t urefs = IE_BITS_UREFS(bits); assert(port->ip_srights > 1); assert(urefs > 0); assert(urefs < MACH_PORT_UREFS_MAX); if (urefs+1 == MACH_PORT_UREFS_MAX) { if (overflow) { /* leave urefs pegged to maximum */ port->ip_srights--; ip_release(port); ip_unlock(port); return KERN_SUCCESS; } ip_unlock(port); return KERN_UREFS_OVERFLOW; } port->ip_srights--; ip_release(port); ip_unlock(port); } else if (bits & MACH_PORT_TYPE_RECEIVE) { assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE); assert(IE_BITS_UREFS(bits) == 0); /* transfer send right to entry */ ip_release(port); ip_unlock(port); } else { assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE); assert(IE_BITS_UREFS(bits) == 0); /* transfer send right and ref to entry */ ip_unlock(port); /* entry is locked holding ref, so can use port */ entry->ie_name = name; ipc_reverse_insert(space, (ipc_object_t) port, entry); } entry->ie_bits = (bits | MACH_PORT_TYPE_SEND) + 1; break; case MACH_MSG_TYPE_PORT_RECEIVE: { ipc_port_t dest; assert(port->ip_mscount == 0); assert(port->ip_receiver_name == MACH_PORT_NULL); dest = port->ip_destination; port->ip_receiver_name = name; port->ip_receiver = space; /* * Clear the protected payload field to retain * the behavior of mach_msg. */ ipc_port_flag_protected_payload_clear(port); assert((bits & MACH_PORT_TYPE_RECEIVE) == 0); if (bits & MACH_PORT_TYPE_SEND) { assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND); assert(IE_BITS_UREFS(bits) > 0); assert(port->ip_srights > 0); ip_release(port); ip_unlock(port); /* entry is locked holding ref, so can use port */ ipc_reverse_remove(space, (ipc_object_t) port); } else { assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE); assert(IE_BITS_UREFS(bits) == 0); /* transfer ref to entry */ ip_unlock(port); } entry->ie_bits = bits | MACH_PORT_TYPE_RECEIVE; if (dest != IP_NULL) ipc_port_release(dest); break; } default: #if MACH_ASSERT assert(!"ipc_right_copyout: strange rights"); #else panic("ipc_right_copyout: strange rights"); #endif } return KERN_SUCCESS; }