IPC rights and reply-port copyin checks
Selected IPC copyin checks from the pinned XNU source. ipc_right_copyin_check_reply validates header reply rights; ipc_right_copyin restricts the use of reply-port send-once rights to a message destination and enforces immovable rights. Relevant when relaying a debugger exception to a previous handler.
ipc_right_copyin_check_reply source
Routine: ipc_right_copyin_check_reply
Purpose:
Check if a subsequent ipc_right_copyin would succeed. Used only
by ipc_kmsg_copyin_header to check if reply_port can be copied in.
If the reply port is an immovable send right, it errors out.
Conditions:
The space is locked (read or write) and active.
bool ipc_right_copyin_check_reply( __assert_only ipc_space_t space, mach_port_name_t reply_name, ipc_entry_t reply_entry, mach_msg_type_name_t reply_type) { ipc_entry_bits_t reply_bits = reply_entry->ie_bits; ipc_port_t reply_port = reply_entry->ie_port; assert(is_active(space)); if (ip_is_reply_port(reply_port) && !MACH_MSG_TYPE_PORT_ANY_SEND_ONCE(reply_type)) { return false; } switch (reply_type) { case MACH_MSG_TYPE_MAKE_SEND: if ((reply_bits & MACH_PORT_TYPE_RECEIVE) == 0) { return false; } break; case MACH_MSG_TYPE_MAKE_SEND_ONCE: if ((reply_bits & MACH_PORT_TYPE_RECEIVE) == 0) { return false; } break; … more in source
ipc_right_copyin source
Routine: ipc_right_copyin
Purpose:
Copyin a capability from a space.
If successful, the caller gets a ref
for the resulting port, unless it is IP_DEAD,
and possibly a send-once right which should
be used in a port-deleted notification.
If deadok is not TRUE, the copyin operation
will fail instead of producing IO_DEAD.
The entry is deallocated if the entry type becomes
MACH_PORT_TYPE_NONE.
Conditions:
The space is write-locked and active.
Returns:
KERN_SUCCESS Acquired a port, possibly IP_DEAD.
KERN_INVALID_RIGHT Name doesn't denote correct right.
KERN_INVALID_CAPABILITY Trying to move a kobject port,
an immovable right or
the last ref of a pinned right
KERN_INVALID_ARGUMENT Port is unguarded or guard mismatch
kern_return_t ipc_right_copyin( ipc_space_t space, mach_port_name_t name, mach_msg_type_name_t msgt_name, ipc_object_copyin_flags_t flags, ipc_copyin_op_t copyin_reason, ipc_entry_t entry, ipc_port_t *portp, ipc_copyin_cleanup_t *icc, ipc_copyin_rcleanup_t *icrc) { ipc_entry_bits_t bits = entry->ie_bits; ipc_port_t port = entry->ie_port; ipc_object_label_t label; kern_return_t kr; uint32_t moves = (flags & IPC_OBJECT_COPYIN_FLAGS_DEST_EXTRA_MOVE) ? 2 : 1; bool deadok = !!(flags & IPC_OBJECT_COPYIN_FLAGS_DEADOK); bool allow_imm_send = !!(flags & IPC_OBJECT_COPYIN_FLAGS_ALLOW_IMMOVABLE_SEND); if (flags & IPC_OBJECT_COPYIN_FLAGS_DEST_EXTRA_MOVE) { assert((flags & IPC_OBJECT_COPYIN_FLAGS_DEST_EXTRA_COPY) == 0); assert(msgt_name == MACH_MSG_TYPE_MOVE_SEND); } if (flags & IPC_OBJECT_COPYIN_FLAGS_DEST_EXTRA_COPY) { assert(msgt_name == MACH_MSG_TYPE_MOVE_SEND || msgt_name == MACH_MSG_TYPE_COPY_SEND); } … more in source