* Translate (space, object) -> (name, entry).
* Only finds send/receive rights.
* Returns TRUE if an entry is found; if so,
- * the object is locked and active.
+ * the object active.
* Conditions:
* The space must be locked (read or write) and active.
- * Nothing else locked.
+ * The port is locked and active
*/
-boolean_t
+bool
ipc_right_reverse(
ipc_space_t space,
ipc_object_t object,
assert(io_otype(object) == IOT_PORT);
port = ip_object_to_port(object);
+ require_ip_active(port);
- ip_lock(port);
- if (!ip_active(port)) {
- ip_unlock(port);
-
- return FALSE;
- }
+ ip_lock_held(port);
if (port->ip_receiver == space) {
name = port->ip_receiver_name;
*namep = name;
*entryp = entry;
- return TRUE;
+ return true;
}
if (ipc_hash_lookup(space, ip_to_object(port), namep, entryp)) {
assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_SEND);
assert(port == ip_object_to_port(entry->ie_object));
- return TRUE;
+ return true;
}
- ip_unlock(port);
- return FALSE;
+ return false;
}
/*
port = ip_object_to_port(entry->ie_object);
assert(port != IP_NULL);
- if (!ipc_right_check(space, port, name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
+ if (!ipc_right_check(space, port, name, entry, IPC_OBJECT_COPYIN_FLAGS_NONE)) {
/* port is locked and active */
/* if no new request, just cancel previous */
* Returns TRUE if it is.
* Conditions:
* The space is write-locked and active.
- * It is unlocked if the entry is inuse.
*/
-boolean_t
+bool
ipc_right_inuse(
- ipc_space_t space,
- __unused mach_port_name_t name,
- ipc_entry_t entry)
+ ipc_entry_t entry)
{
- if (IE_BITS_TYPE(entry->ie_bits) != MACH_PORT_TYPE_NONE) {
- is_write_unlock(space);
- return TRUE;
- }
- return FALSE;
+ return IE_BITS_TYPE(entry->ie_bits) != MACH_PORT_TYPE_NONE;
}
/*
* Routine: ipc_right_check
* Purpose:
* Check if the port has died. If it has,
- * and IPC_RIGHT_COPYIN_FLAGS_ALLOW_DEAD_SEND_ONCE is not
+ * and IPC_OBJECT_COPYIN_FLAGS_ALLOW_DEAD_SEND_ONCE is not
* passed and it is not a send once right then
* clean up the entry and return TRUE.
* Conditions:
ipc_port_t port,
mach_port_name_t name,
ipc_entry_t entry,
- ipc_right_copyin_flags_t flags)
+ ipc_object_copyin_flags_t flags)
{
ipc_entry_bits_t bits;
ip_lock(port);
if (ip_active(port) ||
- ((flags & IPC_RIGHT_COPYIN_FLAGS_ALLOW_DEAD_SEND_ONCE) &&
+ ((flags & IPC_OBJECT_COPYIN_FLAGS_ALLOW_DEAD_SEND_ONCE) &&
entry->ie_request == IE_REQ_NONE &&
(entry->ie_bits & MACH_PORT_TYPE_SEND_ONCE))) {
return FALSE;
* Returns:
* KERN_SUCCESS A user ref was released.
* KERN_INVALID_RIGHT Entry has wrong type.
+ * KERN_INVALID_CAPABILITY Deallocating a pinned right.
*/
kern_return_t
port = ip_object_to_port(entry->ie_object);
assert(port != IP_NULL);
- if (ipc_right_check(space, port, name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
+ if (ipc_right_check(space, port, name, entry, IPC_OBJECT_COPYIN_FLAGS_NONE)) {
bits = entry->ie_bits;
assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
goto dead_name; /* it will release port */
port = ip_object_to_port(entry->ie_object);
assert(port != IP_NULL);
- if (ipc_right_check(space, port, name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
+ if (ipc_right_check(space, port, name, entry, IPC_OBJECT_COPYIN_FLAGS_NONE)) {
bits = entry->ie_bits;
assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
goto dead_name; /* it will release port */
assert(port->ip_srights > 0);
if (IE_BITS_UREFS(bits) == 1) {
+ if (pinned_control_port_enabled && port->ip_pinned != 0) {
+ ip_unlock(port);
+ is_write_unlock(space);
+ mach_port_guard_exception(name, 0, MPG_FLAGS_MOD_REFS_PINNED_DEALLOC,
+ ipc_control_port_options & IPC_CONTROL_PORT_OPTIONS_PINNED_HARD ?
+ kGUARD_EXC_MOD_REFS : kGUARD_EXC_MOD_REFS_NON_FATAL);
+ return KERN_INVALID_CAPABILITY;
+ }
if (--port->ip_srights == 0) {
nsrequest = port->ip_nsrequest;
if (nsrequest != IP_NULL) {
* KERN_SUCCESS Count was modified.
* KERN_INVALID_RIGHT Entry has wrong type.
* KERN_INVALID_VALUE Bad delta for the right.
+ * KERN_INVALID_CAPABILITY Deallocating a pinned right.
*/
kern_return_t
port = ip_object_to_port(entry->ie_object);
assert(port != IP_NULL);
- if (ipc_right_check(space, port, name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
+ if (ipc_right_check(space, port, name, entry, IPC_OBJECT_COPYIN_FLAGS_NONE)) {
assert(!(entry->ie_bits & MACH_PORT_TYPE_SEND_ONCE));
mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_RIGHT);
goto invalid_right;
port = ip_object_to_port(entry->ie_object);
assert(port != IP_NULL);
- if (!ipc_right_check(space, port, name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
+ if (!ipc_right_check(space, port, name, entry, IPC_OBJECT_COPYIN_FLAGS_NONE)) {
/* port is locked and active */
ip_unlock(port);
port = IP_NULL;
port = ip_object_to_port(entry->ie_object);
assert(port != IP_NULL);
- if (ipc_right_check(space, port, name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
+ if (ipc_right_check(space, port, name, entry, IPC_OBJECT_COPYIN_FLAGS_NONE)) {
assert((entry->ie_bits & MACH_PORT_TYPE_SEND) == 0);
goto invalid_right;
}
}
if ((urefs + delta) == 0) {
+ if (pinned_control_port_enabled && port->ip_pinned != 0) {
+ ip_unlock(port);
+ goto pinned_right;
+ }
+
if (--port->ip_srights == 0) {
nsrequest = port->ip_nsrequest;
if (nsrequest != IP_NULL) {
}
return KERN_INVALID_RIGHT;
+pinned_right:
+ assert(pinned_control_port_enabled);
+
+ is_write_unlock(space);
+ mach_port_guard_exception(name, 0, MPG_FLAGS_MOD_REFS_PINNED_DEALLOC,
+ ipc_control_port_options & IPC_CONTROL_PORT_OPTIONS_PINNED_HARD ?
+ kGUARD_EXC_MOD_REFS : kGUARD_EXC_MOD_REFS_NON_FATAL);
+ return KERN_INVALID_CAPABILITY;
+
invalid_value:
is_write_unlock(space);
mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_VALUE);
* types while we still have it locked. Otherwise,
* recapture the (now dead) bits.
*/
- if (!ipc_right_check(space, port, name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
+ if (!ipc_right_check(space, port, name, entry, IPC_OBJECT_COPYIN_FLAGS_NONE)) {
if (request != IE_REQ_NONE) {
type |= ipc_port_request_type(port, name, request);
}
* be read without a lock.
*/
if (reply_port->ip_immovable_send) {
- mach_port_guard_exception(reply_name, 0, 0, kGUARD_EXC_IMMOVABLE);
- return FALSE;
+ if (!ip_is_control(reply_port) || immovable_control_port_enabled) {
+ mach_port_guard_exception_immovable(reply_name, reply_port, MPG_FLAGS_NONE);
+ return FALSE;
+ }
}
if (reply_type == MACH_MSG_TYPE_MOVE_SEND_ONCE) {
* Returns:
* KERN_SUCCESS Acquired an object, possibly IO_DEAD.
* KERN_INVALID_RIGHT Name doesn't denote correct right.
- * KERN_INVALID_CAPABILITY Trying to move an kobject port or an immovable right
+ * KERN_INVALID_CAPABILITY Trying to move an kobject port or an immovable right,
+ * or moving the last ref of pinned right
* KERN_INVALID_ARGUMENT Port is unguarded or guard mismatch
*/
mach_port_name_t name,
ipc_entry_t entry,
mach_msg_type_name_t msgt_name,
- ipc_right_copyin_flags_t flags,
+ ipc_object_copyin_flags_t flags,
ipc_object_t *objectp,
ipc_port_t *sorightp,
ipc_port_t *releasep,
ipc_entry_bits_t bits;
ipc_port_t port;
kern_return_t kr;
- boolean_t deadok = flags & IPC_RIGHT_COPYIN_FLAGS_DEADOK? TRUE : FALSE;
- boolean_t allow_imm_send = flags & IPC_RIGHT_COPYIN_FLAGS_ALLOW_IMMOVABLE_SEND? TRUE : FALSE;
+ boolean_t deadok = !!(flags & IPC_OBJECT_COPYIN_FLAGS_DEADOK);
+ boolean_t allow_imm_send = !!(flags & IPC_OBJECT_COPYIN_FLAGS_ALLOW_IMMOVABLE_SEND);
+ boolean_t soft_fail_imm_send = !!(flags & IPC_OBJECT_COPYIN_FLAGS_SOFT_FAIL_IMMOVABLE_SEND);
*releasep = IP_NULL;
*assertcntp = 0;
port = ip_object_to_port(entry->ie_object);
assert(port != IP_NULL);
- if (ipc_right_check(space, port, name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
+ if (ipc_right_check(space, port, name, entry, IPC_OBJECT_COPYIN_FLAGS_NONE)) {
bits = entry->ie_bits;
*releasep = port;
goto copy_dead;
}
if (!allow_imm_send && port->ip_immovable_send) {
- ip_unlock(port);
- mach_port_guard_exception(name, 0, 0, kGUARD_EXC_IMMOVABLE);
- return KERN_INVALID_CAPABILITY;
+ if (!ip_is_control(port) || immovable_control_port_enabled) {
+ ip_unlock(port);
+ if (!soft_fail_imm_send) {
+ mach_port_guard_exception_immovable(name, port, MPG_FLAGS_NONE);
+ }
+ return KERN_INVALID_CAPABILITY;
+ }
}
ipc_port_copy_send_locked(port);
port = ip_object_to_port(entry->ie_object);
assert(port != IP_NULL);
- if (ipc_right_check(space, port, name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
+ if (ipc_right_check(space, port, name, entry, IPC_OBJECT_COPYIN_FLAGS_NONE)) {
bits = entry->ie_bits;
*releasep = port;
goto move_dead;
if ((bits & MACH_PORT_TYPE_SEND) == 0) {
assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
assert(port->ip_sorights > 0);
-
ip_unlock(port);
goto invalid_right;
}
if (!allow_imm_send && port->ip_immovable_send) {
- ip_unlock(port);
- mach_port_guard_exception(name, 0, 0, kGUARD_EXC_IMMOVABLE);
- return KERN_INVALID_CAPABILITY;
+ if (!ip_is_control(port) || immovable_control_port_enabled) {
+ ip_unlock(port);
+ if (!soft_fail_imm_send) {
+ mach_port_guard_exception_immovable(name, port, MPG_FLAGS_NONE);
+ }
+ return KERN_INVALID_CAPABILITY;
+ }
}
if (IE_BITS_UREFS(bits) == 1) {
assert(port->ip_receiver == space);
assert(IE_BITS_TYPE(bits) ==
MACH_PORT_TYPE_SEND_RECEIVE);
+ assert(port->ip_pinned == 0);
ip_reference(port);
} else {
}
if (!allow_imm_send && port->ip_immovable_send) {
- ip_unlock(port);
- mach_port_guard_exception(name, 0, 0, kGUARD_EXC_IMMOVABLE);
- return KERN_INVALID_CAPABILITY;
+ if (!ip_is_control(port) || immovable_control_port_enabled) {
+ ip_unlock(port);
+ if (!soft_fail_imm_send) {
+ mach_port_guard_exception_immovable(name, port, MPG_FLAGS_NONE);
+ }
+ return KERN_INVALID_CAPABILITY;
+ }
}
assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
port = ip_object_to_port(entry->ie_object);
assert(port != IP_NULL);
- if (ipc_right_check(space, port, name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
+ if (ipc_right_check(space, port, name, entry, IPC_OBJECT_COPYIN_FLAGS_NONE)) {
*releasep = port;
goto invalid_right;
}
ipc_object_t object_two;
kr = ipc_right_copyin(space, name, entry,
- msgt_one, IPC_RIGHT_COPYIN_FLAGS_ALLOW_IMMOVABLE_SEND,
+ msgt_one, IPC_OBJECT_COPYIN_FLAGS_ALLOW_IMMOVABLE_SEND,
objectp, sorightp, releasep,
&assertcnt, 0, NULL);
assert(assertcnt == 0);
* receive right.
*/
kr = ipc_right_copyin(space, name, entry,
- msgt_two, IPC_RIGHT_COPYIN_FLAGS_NONE,
+ msgt_two, IPC_OBJECT_COPYIN_FLAGS_NONE,
&object_two, sorightp, releasep,
&assertcnt, 0, NULL);
assert(assertcnt == 0);
}
kr = ipc_right_copyin(space, name, entry,
- msgt_name, IPC_RIGHT_COPYIN_FLAGS_ALLOW_IMMOVABLE_SEND,
+ msgt_name, IPC_OBJECT_COPYIN_FLAGS_ALLOW_IMMOVABLE_SEND,
objectp, sorightp, releasep,
&assertcnt, 0, NULL);
assert(assertcnt == 0);
mach_port_name_t name,
ipc_entry_t entry,
mach_msg_type_name_t msgt_name,
+ ipc_object_copyout_flags_t flags,
mach_port_context_t *context,
mach_msg_guard_flags_t *guard_flags,
ipc_object_t object)
port = ip_object_to_port(object);
+ if (pinned_control_port_enabled && (flags & IPC_OBJECT_COPYOUT_FLAGS_PINNED)) {
+ assert(!port->ip_pinned);
+ assert(port->ip_immovable_send);
+ port->ip_pinned = 1;
+ }
+
switch (msgt_name) {
case MACH_MSG_TYPE_PORT_SEND_ONCE: