kern_return_t ipc_object_copyin( ipc_space_t space, mach_port_name_t name, mach_msg_type_name_t msgt_name, ipc_object_t *objectp) { ipc_entry_t entry; ipc_port_t soright; kern_return_t kr; /* * Could first try a read lock when doing * MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND, * and MACH_MSG_TYPE_MAKE_SEND_ONCE. */ kr = ipc_right_lookup_write(space, name, &entry); if (kr != KERN_SUCCESS) return kr; /* space is write-locked and active */ kr = ipc_right_copyin(space, name, entry, msgt_name, TRUE, objectp, &soright); if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE) ipc_entry_dealloc(space, name, entry); is_write_unlock(space); if ((kr == KERN_SUCCESS) && (soright != IP_NULL)) ipc_notify_port_deleted(soright, name); return kr; }
kern_return_t mach_port_type( ipc_space_t space, mach_port_name_t name, mach_port_type_t *typep) { mach_port_urefs_t urefs; ipc_entry_t entry; kern_return_t kr; if (space == IS_NULL) return KERN_INVALID_TASK; if (name == MACH_PORT_NULL) return KERN_INVALID_NAME; if (name == MACH_PORT_DEAD) { *typep = MACH_PORT_TYPE_DEAD_NAME; return KERN_SUCCESS; } kr = ipc_right_lookup_write(space, name, &entry); if (kr != KERN_SUCCESS) return kr; /* space is write-locked and active */ kr = ipc_right_info(space, name, entry, typep, &urefs); if (kr == KERN_SUCCESS) is_write_unlock(space); /* space is unlocked */ return kr; }
kern_return_t mach_port_mod_refs( ipc_space_t space, mach_port_name_t name, mach_port_right_t right, mach_port_delta_t delta) { ipc_entry_t entry; kern_return_t kr; if (space == IS_NULL) return KERN_INVALID_TASK; if (right >= MACH_PORT_RIGHT_NUMBER) return KERN_INVALID_VALUE; if (!MACH_PORT_VALID(name)) { if (right == MACH_PORT_RIGHT_SEND || right == MACH_PORT_RIGHT_SEND_ONCE) return KERN_SUCCESS; return KERN_INVALID_NAME; } kr = ipc_right_lookup_write(space, name, &entry); if (kr != KERN_SUCCESS) return kr; /* space is write-locked and active */ kr = ipc_right_delta(space, name, entry, right, delta); /* unlocks */ return kr; }
kern_return_t ipc_object_copyin( ipc_space_t space, mach_port_name_t name, mach_msg_type_name_t msgt_name, ipc_object_t *objectp) { ipc_entry_t entry; ipc_port_t soright; ipc_port_t release_port; kern_return_t kr; queue_head_t links_data; queue_t links = &links_data; wait_queue_link_t wql; queue_init(links); /* * Could first try a read lock when doing * MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND, * and MACH_MSG_TYPE_MAKE_SEND_ONCE. */ kr = ipc_right_lookup_write(space, name, &entry); if (kr != KERN_SUCCESS) return kr; /* space is write-locked and active */ release_port = IP_NULL; kr = ipc_right_copyin(space, name, entry, msgt_name, TRUE, objectp, &soright, &release_port, links); if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE) ipc_entry_dealloc(space, name, entry); is_write_unlock(space); while(!queue_empty(links)) { wql = (wait_queue_link_t) dequeue(links); wait_queue_link_free(wql); } if (release_port != IP_NULL) ip_release(release_port); if ((kr == KERN_SUCCESS) && (soright != IP_NULL)) ipc_notify_port_deleted(soright, name); return kr; }
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 }
kern_return_t ipc_object_copyin( ipc_space_t space, mach_port_name_t name, mach_msg_type_name_t msgt_name, ipc_object_t *objectp) { ipc_entry_t entry; ipc_port_t soright; ipc_port_t release_port; kern_return_t kr; int assertcnt = 0; /* * Could first try a read lock when doing * MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND, * and MACH_MSG_TYPE_MAKE_SEND_ONCE. */ kr = ipc_right_lookup_write(space, name, &entry); if (kr != KERN_SUCCESS) return kr; /* space is write-locked and active */ release_port = IP_NULL; kr = ipc_right_copyin(space, name, entry, msgt_name, TRUE, objectp, &soright, &release_port, &assertcnt); if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE) ipc_entry_dealloc(space, name, entry); is_write_unlock(space); #if IMPORTANCE_INHERITANCE if (0 < assertcnt && ipc_importance_task_is_any_receiver_type(current_task()->task_imp_base)) { ipc_importance_task_drop_internal_assertion(current_task()->task_imp_base, assertcnt); } #endif /* IMPORTANCE_INHERITANCE */ if (release_port != IP_NULL) ip_release(release_port); if ((kr == KERN_SUCCESS) && (soright != IP_NULL)) ipc_notify_port_deleted(soright, name); return kr; }
/* * Get a label handle representing the given port's port label. */ kern_return_t mach_get_label( ipc_space_t space, mach_port_name_t name, mach_port_name_t *outlabel) { ipc_entry_t entry; ipc_port_t port; struct label outl; kern_return_t kr; int dead; if (!MACH_PORT_VALID(name)) return KERN_INVALID_NAME; /* Lookup the port name in the task's space. */ kr = ipc_right_lookup_write(space, name, &entry); if (kr != KERN_SUCCESS) return kr; port = (ipc_port_t) entry->ie_object; dead = ipc_right_check(space, port, name, entry); if (dead) { is_write_unlock(space); return KERN_INVALID_RIGHT; } /* port is now locked */ is_write_unlock(space); /* Make sure we are not dealing with a label handle. */ if (ip_kotype(port) == IKOT_LABELH) { /* already is a label handle! */ ip_unlock(port); return KERN_INVALID_ARGUMENT; } /* Copy the port label and stash it in a new label handle. */ mac_init_port_label(&outl); mac_copy_port_label(&port->ip_label, &outl); kr = labelh_new_user(space, &outl, outlabel); ip_unlock(port); return KERN_SUCCESS; }
kern_return_t mach_port_deallocate( ipc_space_t space, mach_port_name_t name) { ipc_entry_t entry; kern_return_t kr; if (space == IS_NULL) return KERN_INVALID_TASK; if (!MACH_PORT_VALID(name)) return KERN_SUCCESS; kr = ipc_right_lookup_write(space, name, &entry); if (kr != KERN_SUCCESS) return kr; /* space is write-locked */ kr = ipc_right_dealloc(space, name, entry); /* unlocks space */ return kr; }
kern_return_t mach_get_label_text( ipc_space_t space, mach_port_name_t name, vm_offset_t policies, vm_offset_t outlabel) { ipc_entry_t entry; kern_return_t kr; struct label *l; int dead; if (space == IS_NULL || space->is_task == NULL) return KERN_INVALID_TASK; if (!MACH_PORT_VALID(name)) return KERN_INVALID_NAME; kr = ipc_right_lookup_write(space, name, &entry); if (kr != KERN_SUCCESS) return kr; dead = ipc_right_check(space, entry->ie_object, name, entry); if (dead) { is_write_unlock(space); return KERN_INVALID_RIGHT; } /* object (port) is now locked */ is_write_unlock(space); l = io_getlabel(entry->ie_object); mac_externalize_port_label(l, policies, outlabel, 512, 0); io_unlocklabel(entry->ie_object); io_unlock(entry->ie_object); return KERN_SUCCESS; }
kern_return_t mach_port_destroy( ipc_space_t space, mach_port_name_t name) { ipc_entry_t entry; kern_return_t kr; if (space == IS_NULL) return KERN_INVALID_TASK; if (!MACH_PORT_VALID(name)) return KERN_SUCCESS; kr = ipc_right_lookup_write(space, name, &entry); if (kr != KERN_SUCCESS) return kr; /* space is write-locked and active */ kr = ipc_right_destroy(space, name, entry); is_write_unlock(space); return kr; }
kern_return_t ipc_right_dnrequest( ipc_space_t space, mach_port_t name, boolean_t immediate, ipc_port_t notify, ipc_port_t *previousp) { ipc_port_t previous; for (;;) { ipc_entry_t entry; ipc_entry_bits_t bits; kern_return_t kr; kr = ipc_right_lookup_write(space, name, &entry); if (kr != KERN_SUCCESS) return kr; /* space is write-locked and active */ bits = entry->ie_bits; if (bits & MACH_PORT_TYPE_PORT_RIGHTS) { ipc_port_t port; ipc_port_request_index_t request; port = (ipc_port_t) entry->ie_object; assert(port != IP_NULL); if (!ipc_right_check(space, port, name, entry)) { /* port is locked and active */ if (notify == IP_NULL) { previous = ipc_right_dncancel_macro( space, port, name, entry); ip_unlock(port); is_write_unlock(space); break; } /* * If a registered soright exists, * want to atomically switch with it. * If ipc_port_dncancel finds us a * soright, then the following * ipc_port_dnrequest will reuse * that slot, so we are guaranteed * not to unlock and retry. */ previous = ipc_right_dncancel_macro(space, port, name, entry); kr = ipc_port_dnrequest(port, name, notify, &request); if (kr != KERN_SUCCESS) { assert(previous == IP_NULL); is_write_unlock(space); kr = ipc_port_dngrow(port); /* port is unlocked */ if (kr != KERN_SUCCESS) return kr; continue; } assert(request != 0); ip_unlock(port); entry->ie_request = request; is_write_unlock(space); break; } bits = entry->ie_bits; assert(bits & MACH_PORT_TYPE_DEAD_NAME); } if ((bits & MACH_PORT_TYPE_DEAD_NAME) && immediate && (notify != IP_NULL)) { mach_port_urefs_t urefs = IE_BITS_UREFS(bits); assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME); assert(urefs > 0); if (MACH_PORT_UREFS_OVERFLOW(urefs, 1)) { is_write_unlock(space); return KERN_UREFS_OVERFLOW; } entry->ie_bits = bits + 1; /* increment urefs */ is_write_unlock(space); ipc_notify_dead_name(notify, name); previous = IP_NULL; break; } is_write_unlock(space); if (bits & MACH_PORT_TYPE_PORT_OR_DEAD) return KERN_INVALID_ARGUMENT; else return KERN_INVALID_RIGHT; } *previousp = previous; return KERN_SUCCESS; }
kern_return_t mach_port_get_refs( ipc_space_t space, mach_port_name_t name, mach_port_right_t right, mach_port_urefs_t *urefsp) { mach_port_type_t type; mach_port_urefs_t urefs; ipc_entry_t entry; kern_return_t kr; if (space == IS_NULL) return KERN_INVALID_TASK; if (right >= MACH_PORT_RIGHT_NUMBER) return KERN_INVALID_VALUE; if (!MACH_PORT_VALID(name)) { if (right == MACH_PORT_RIGHT_SEND || right == MACH_PORT_RIGHT_SEND_ONCE) { *urefsp = 1; return KERN_SUCCESS; } return KERN_INVALID_NAME; } kr = ipc_right_lookup_write(space, name, &entry); if (kr != KERN_SUCCESS) return kr; /* space is write-locked and active */ kr = ipc_right_info(space, name, entry, &type, &urefs); /* unlocks */ if (kr != KERN_SUCCESS) return kr; /* space is unlocked */ is_write_unlock(space); if (type & MACH_PORT_TYPE(right)) switch (right) { case MACH_PORT_RIGHT_SEND_ONCE: assert(urefs == 1); /* fall-through */ case MACH_PORT_RIGHT_PORT_SET: case MACH_PORT_RIGHT_RECEIVE: *urefsp = 1; break; case MACH_PORT_RIGHT_DEAD_NAME: case MACH_PORT_RIGHT_SEND: assert(urefs > 0); *urefsp = urefs; break; default: panic("mach_port_get_refs: strange rights"); } else *urefsp = 0; return kr; }
kern_return_t mach_port_request_notification( ipc_space_t space, mach_port_name_t name, mach_msg_id_t id, mach_port_mscount_t sync, ipc_port_t notify, ipc_port_t *previousp) { kern_return_t kr; ipc_entry_t entry; ipc_port_t port; if (space == IS_NULL) return KERN_INVALID_TASK; if (notify == IP_DEAD) return KERN_INVALID_CAPABILITY; #if NOTYET /* * Requesting notifications on RPC ports is an error. */ kr = ipc_right_lookup_write(space, name, &entry); if (kr != KERN_SUCCESS) return kr; port = (ipc_port_t) entry->ie_object; if (port->ip_subsystem != NULL) { is_write_unlock(space); panic("mach_port_request_notification: on RPC port!!"); return KERN_INVALID_CAPABILITY; } is_write_unlock(space); #endif /* NOTYET */ switch (id) { case MACH_NOTIFY_PORT_DESTROYED: { ipc_port_t port, previous; if (sync != 0) return KERN_INVALID_VALUE; 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 */ ipc_port_pdrequest(port, notify, &previous); /* port is unlocked */ *previousp = previous; break; } case MACH_NOTIFY_NO_SENDERS: { ipc_port_t port; 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 */ ipc_port_nsrequest(port, sync, notify, previousp); /* port is unlocked */ break; } case MACH_NOTIFY_DEAD_NAME: if (!MACH_PORT_VALID(name)) { /* * Already dead. * Should do immediate delivery check - * will do that in the near future. */ return KERN_INVALID_ARGUMENT; } kr = ipc_right_dnrequest(space, name, sync != 0, notify, previousp); if (kr != KERN_SUCCESS) return kr; break; default: return KERN_INVALID_VALUE; } return KERN_SUCCESS; }