IPC rights and reply-port copyin checks

osfmk/ipc/ipc_right.c · 2793 lines · browse source

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