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"); } }
struct label *io_getlabel (ipc_object_t objp) { ipc_port_t port = (ipc_port_t)objp; assert(io_otype(objp) == IOT_PORT); if (ip_kotype(port) == IKOT_LABELH) return &((ipc_labelh_t) port->ip_kobject)->lh_label; else return &port->ip_label; }
boolean_t ipc_right_reverse( ipc_space_t space, ipc_object_t object, mach_port_t *namep, ipc_entry_t *entryp) { ipc_port_t port; mach_port_t name; ipc_entry_t entry; /* would switch on io_otype to handle multiple types of object */ assert(space->is_active); assert(io_otype(object) == IOT_PORT); port = (ipc_port_t) object; ip_lock(port); if (!ip_active(port)) { ip_unlock(port); return FALSE; } if (port->ip_receiver == space) { name = port->ip_receiver_name; assert(name != MACH_PORT_NULL); entry = ipc_entry_lookup(space, name); assert(entry != IE_NULL); assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE); assert(port == (ipc_port_t) entry->ie_object); *namep = name; *entryp = entry; return TRUE; } if ((*entryp = ipc_reverse_lookup(space, (ipc_object_t) port))) { *namep = (*entryp)->ie_name; assert((entry = *entryp) != IE_NULL); assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_SEND); assert(port == (ipc_port_t) entry->ie_object); return TRUE; } ip_unlock(port); return FALSE; }
kern_return_t mach_set_port_label( ipc_space_t space, mach_port_name_t name, vm_offset_t labelstr) { #ifdef MAC ipc_entry_t entry; kern_return_t kr; struct label inl; int rc; if (space == IS_NULL || space->is_task == NULL) return KERN_INVALID_TASK; if (!MACH_PORT_VALID(name)) return KERN_INVALID_NAME; mac_init_port_label(&inl); rc = mac_internalize_port_label(&inl, labelstr); if (rc) return KERN_INVALID_ARGUMENT; kr = ipc_right_lookup_write(space, name, &entry); if (kr != KERN_SUCCESS) return kr; if (io_otype(entry->ie_object) != IOT_PORT) { is_write_unlock(space); return KERN_INVALID_RIGHT; } ipc_port_t port = (ipc_port_t) entry->ie_object; ip_lock(port); rc = mac_check_port_relabel(&space->is_task->maclabel, &port->ip_label, &inl); if (rc) kr = KERN_NO_ACCESS; else mac_copy_port_label(&inl, &port->ip_label); ip_unlock(port); is_write_unlock(space); return kr; #else return KERN_INVALID_ARGUMENT; #endif }
void ipc_object_print( ipc_object_t object) { int kotype; iprintf("%s", io_active(object) ? "active" : "dead"); printf(", refs=%d", object->io_references); printf(", otype=%d", io_otype(object)); kotype = io_kotype(object); if (kotype >= 0 && kotype < IKOT_MAX_TYPE) printf(", kotype=%d %s\n", io_kotype(object), ikot_print_array[kotype]); else printf(", kotype=0x%x %s\n", io_kotype(object), ikot_print_array[IKOT_UNKNOWN]); }
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; }
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_port_destroy( ipc_port_t port) { ipc_port_t pdrequest, nsrequest; ipc_mqueue_t mqueue; ipc_kmsg_queue_t kmqueue; ipc_kmsg_t kmsg; ipc_thread_t sender; ipc_port_request_t dnrequests; thread_pool_t thread_pool; assert(ip_active(port)); /* port->ip_receiver_name is garbage */ /* port->ip_receiver/port->ip_destination is garbage */ assert(io_otype((ipc_object_t)port) == IOT_PORT); assert(port->ip_pset == IPS_NULL); assert(port->ip_mscount == 0); assert(port->ip_seqno == 0); /* first check for a backup port */ pdrequest = port->ip_pdrequest; if (pdrequest != IP_NULL) { /* we assume the ref for pdrequest */ port->ip_pdrequest = IP_NULL; /* make port be in limbo */ port->ip_receiver_name = MACH_PORT_NAME_NULL; port->ip_destination = IP_NULL; ip_unlock(port); if (!ipc_port_check_circularity(port, pdrequest)) { /* consumes our refs for port and pdrequest */ ipc_notify_port_destroyed(pdrequest, port); return; } else { /* consume pdrequest and destroy port */ ipc_port_release_sonce(pdrequest); } ip_lock(port); assert(ip_active(port)); assert(port->ip_pset == IPS_NULL); assert(port->ip_mscount == 0); assert(port->ip_seqno == 0); assert(port->ip_pdrequest == IP_NULL); assert(port->ip_receiver_name == MACH_PORT_NAME_NULL); assert(port->ip_destination == IP_NULL); /* fall through and destroy the port */ } /* * rouse all blocked senders * * This must be done with the port locked, because * ipc_mqueue_send can play with the ip_blocked queue * of a dead port. */ while ((sender = ipc_thread_dequeue(&port->ip_blocked)) != ITH_NULL) { sender->ith_state = MACH_MSG_SUCCESS; thread_go(sender); } /* once port is dead, we don't need to keep it locked */ port->ip_object.io_bits &= ~IO_BITS_ACTIVE; port->ip_timestamp = ipc_port_timestamp(); /* save for later */ dnrequests = port->ip_dnrequests; port->ip_dnrequests = IPR_NULL; ip_unlock(port); /* wakeup any threads waiting on this pool port for an activation */ if ((thread_pool = &port->ip_thread_pool) != THREAD_POOL_NULL) thread_pool_wakeup(thread_pool); /* throw away no-senders request */ nsrequest = port->ip_nsrequest; if (nsrequest != IP_NULL) ipc_notify_send_once(nsrequest); /* consumes ref */ /* destroy any queued messages */ mqueue = &port->ip_messages; kmqueue = &mqueue->imq_messages; while ((kmsg = ipc_kmsg_dequeue(kmqueue)) != IKM_NULL) { assert(kmsg->ikm_header->msgh_remote_port == (mach_port_t) port); port->ip_msgcount--; ipc_port_release(port); kmsg->ikm_header->msgh_remote_port = MACH_PORT_NULL; ipc_kmsg_destroy(kmsg); } /* generate dead-name notifications */ if (dnrequests != IPR_NULL) { ipc_port_dnnotify(port, dnrequests); } if (ip_kotype(port) != IKOT_NONE) ipc_kobject_destroy(port); /* XXXX Perhaps should verify that ip_thread_pool is empty! */ ipc_port_release(port); /* consume caller's ref */ }
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; }