]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/ipc/ipc_right.c
xnu-6153.11.26.tar.gz
[apple/xnu.git] / osfmk / ipc / ipc_right.c
index 08a79c30033b94cab239c5349871a21d3d5be93b..00a256e177fa5ddd57bbb21b392495cbe90e0eb1 100644 (file)
@@ -204,7 +204,7 @@ ipc_right_reverse(
        assert(is_active(space));
        assert(io_otype(object) == IOT_PORT);
 
-       port = (ipc_port_t) object;
+       port = ip_object_to_port(object);
 
        ip_lock(port);
        if (!ip_active(port)) {
@@ -221,17 +221,17 @@ ipc_right_reverse(
 
                assert(entry != IE_NULL);
                assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
-               assert(port == (ipc_port_t) entry->ie_object);
+               assert(port == ip_object_to_port(entry->ie_object));
 
                *namep = name;
                *entryp = entry;
                return TRUE;
        }
 
-       if (ipc_hash_lookup(space, (ipc_object_t) port, namep, entryp)) {
+       if (ipc_hash_lookup(space, ip_to_object(port), namep, entryp)) {
                assert((entry = *entryp) != IE_NULL);
                assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_SEND);
-               assert(port == (ipc_port_t) entry->ie_object);
+               assert(port == ip_object_to_port(entry->ie_object));
 
                return TRUE;
        }
@@ -301,7 +301,7 @@ ipc_right_request_alloc(
                if (entry->ie_bits & MACH_PORT_TYPE_PORT_RIGHTS) {
                        ipc_port_request_index_t new_request;
 
-                       port = (ipc_port_t) entry->ie_object;
+                       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)) {
@@ -448,8 +448,8 @@ ipc_right_request_cancel(
 {
        ipc_port_t previous;
 
-       assert(ip_active(port));
-       assert(port == (ipc_port_t) entry->ie_object);
+       require_ip_active(port);
+       assert(port == ip_object_to_port(entry->ie_object));
 
        if (entry->ie_request == IE_REQ_NONE) {
                return IP_NULL;
@@ -511,7 +511,7 @@ ipc_right_check(
        ipc_entry_bits_t bits;
 
        assert(is_active(space));
-       assert(port == (ipc_port_t) entry->ie_object);
+       assert(port == ip_object_to_port(entry->ie_object));
 
        ip_lock(port);
        if (ip_active(port) ||
@@ -545,7 +545,7 @@ ipc_right_check(
         */
 
        if ((bits & MACH_PORT_TYPE_SEND) != 0) {
-               ipc_hash_delete(space, (ipc_object_t)port, name, entry);
+               ipc_hash_delete(space, ip_to_object(port), name, entry);
        }
 
        /* convert entry to dead name */
@@ -622,7 +622,7 @@ ipc_right_terminate(
                break;
 
        case MACH_PORT_TYPE_PORT_SET: {
-               ipc_pset_t pset = (ipc_pset_t) entry->ie_object;
+               ipc_pset_t pset = ips_object_to_pset(entry->ie_object);
 
                assert(entry->ie_request == IE_REQ_NONE);
                assert(pset != IPS_NULL);
@@ -637,7 +637,7 @@ ipc_right_terminate(
        case MACH_PORT_TYPE_RECEIVE:
        case MACH_PORT_TYPE_SEND_RECEIVE:
        case MACH_PORT_TYPE_SEND_ONCE: {
-               ipc_port_t port = (ipc_port_t) entry->ie_object;
+               ipc_port_t port = ip_object_to_port(entry->ie_object);
                ipc_port_t request;
                ipc_port_t nsrequest = IP_NULL;
                mach_port_mscount_t mscount = 0;
@@ -673,6 +673,7 @@ ipc_right_terminate(
                        ipc_port_destroy(port); /* clears receiver, consumes our ref, unlocks */
                } else if (type & MACH_PORT_TYPE_SEND_ONCE) {
                        assert(port->ip_sorights > 0);
+                       port->ip_reply_context = 0;
                        ip_unlock(port);
 
                        ipc_notify_send_once(port); /* consumes our ref */
@@ -736,7 +737,7 @@ ipc_right_destroy(
                break;
 
        case MACH_PORT_TYPE_PORT_SET: {
-               ipc_pset_t pset = (ipc_pset_t) entry->ie_object;
+               ipc_pset_t pset = ips_object_to_pset(entry->ie_object);
 
                assert(entry->ie_request == IE_REQ_NONE);
                assert(pset != IPS_NULL);
@@ -756,7 +757,7 @@ ipc_right_destroy(
        case MACH_PORT_TYPE_RECEIVE:
        case MACH_PORT_TYPE_SEND_RECEIVE:
        case MACH_PORT_TYPE_SEND_ONCE: {
-               ipc_port_t port = (ipc_port_t) entry->ie_object;
+               ipc_port_t port = ip_object_to_port(entry->ie_object);
                ipc_port_t nsrequest = IP_NULL;
                mach_port_mscount_t mscount = 0;
                ipc_port_t request;
@@ -764,8 +765,7 @@ ipc_right_destroy(
                assert(port != IP_NULL);
 
                if (type == MACH_PORT_TYPE_SEND) {
-                       ipc_hash_delete(space, (ipc_object_t) port,
-                           name, entry);
+                       ipc_hash_delete(space, ip_to_object(port), name, entry);
                }
 
                ip_lock(port);
@@ -813,12 +813,13 @@ ipc_right_destroy(
                }
 
                if (type & MACH_PORT_TYPE_RECEIVE) {
-                       assert(ip_active(port));
+                       require_ip_active(port);
                        assert(port->ip_receiver == space);
 
                        ipc_port_destroy(port); /* clears receiver, consumes our ref, unlocks */
                } else if (type & MACH_PORT_TYPE_SEND_ONCE) {
                        assert(port->ip_sorights > 0);
+                       port->ip_reply_context = 0;
                        ip_unlock(port);
 
                        ipc_notify_send_once(port); /* consumes our ref */
@@ -885,7 +886,7 @@ ipc_right_dealloc(
                assert(IE_BITS_UREFS(bits) == 0);
                assert(entry->ie_request == IE_REQ_NONE);
 
-               pset = (ipc_pset_t) entry->ie_object;
+               pset = ips_object_to_pset(entry->ie_object);
                assert(pset != IPS_NULL);
 
                entry->ie_object = IO_NULL;
@@ -929,7 +930,7 @@ dead_name:
 
                assert(IE_BITS_UREFS(bits) == 1);
 
-               port = (ipc_port_t) entry->ie_object;
+               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)) {
@@ -941,6 +942,13 @@ dead_name:
 
                assert(port->ip_sorights > 0);
 
+               /*
+                * clear any reply context:
+                * no one will be sending the response b/c we are destroying
+                * the single, outstanding send once right.
+                */
+               port->ip_reply_context = 0;
+
                request = ipc_right_request_cancel_macro(space, port, name, entry);
                ip_unlock(port);
 
@@ -965,7 +973,7 @@ dead_name:
 
                assert(IE_BITS_UREFS(bits) > 0);
 
-               port = (ipc_port_t) entry->ie_object;
+               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)) {
@@ -988,8 +996,7 @@ dead_name:
 
                        request = ipc_right_request_cancel_macro(space, port,
                            name, entry);
-                       ipc_hash_delete(space, (ipc_object_t) port,
-                           name, entry);
+                       ipc_hash_delete(space, ip_to_object(port), name, entry);
 
                        ip_unlock(port);
                        entry->ie_object = IO_NULL;
@@ -1022,11 +1029,11 @@ dead_name:
 
                assert(IE_BITS_UREFS(bits) > 0);
 
-               port = (ipc_port_t) entry->ie_object;
+               port = ip_object_to_port(entry->ie_object);
                assert(port != IP_NULL);
 
                ip_lock(port);
-               assert(ip_active(port));
+               require_ip_active(port);
                assert(port->ip_receiver_name == name);
                assert(port->ip_receiver == space);
                assert(port->ip_srights > 0);
@@ -1129,7 +1136,7 @@ ipc_right_delta(
                        goto invalid_value;
                }
 
-               pset = (ipc_pset_t) entry->ie_object;
+               pset = ips_object_to_pset(entry->ie_object);
                assert(pset != IPS_NULL);
 
                entry->ie_object = IO_NULL;
@@ -1147,7 +1154,9 @@ ipc_right_delta(
                ipc_port_t request = IP_NULL;
 
                if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) {
-                       mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_RIGHT);
+                       if ((bits & MACH_PORT_TYPE_EX_RECEIVE) == 0) {
+                               mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_RIGHT);
+                       }
                        goto invalid_right;
                }
 
@@ -1159,7 +1168,7 @@ ipc_right_delta(
                        goto invalid_value;
                }
 
-               port = (ipc_port_t) entry->ie_object;
+               port = ip_object_to_port(entry->ie_object);
                assert(port != IP_NULL);
 
                /*
@@ -1169,7 +1178,7 @@ ipc_right_delta(
                 */
 
                ip_lock(port);
-               assert(ip_active(port));
+               require_ip_active(port);
                assert(port->ip_receiver_name == name);
                assert(port->ip_receiver == space);
 
@@ -1202,7 +1211,8 @@ ipc_right_delta(
                                 */
                                ipc_entry_modified(space, name, entry);
                                entry->ie_bits &= ~MACH_PORT_TYPE_RECEIVE;
-                               ipc_hash_insert(space, (ipc_object_t) port,
+                               entry->ie_bits |= MACH_PORT_TYPE_EX_RECEIVE;
+                               ipc_hash_insert(space, ip_to_object(port),
                                    name, entry);
                                ip_reference(port);
                        } else {
@@ -1214,7 +1224,7 @@ ipc_right_delta(
                                 *      port is destroyed "first".
                                 */
                                bits &= ~IE_BITS_TYPE_MASK;
-                               bits |= MACH_PORT_TYPE_DEAD_NAME;
+                               bits |= (MACH_PORT_TYPE_DEAD_NAME | MACH_PORT_TYPE_EX_RECEIVE);
                                if (entry->ie_request) {
                                        entry->ie_request = IE_REQ_NONE;
                                        /* if urefs are pegged due to overflow, leave them pegged */
@@ -1255,7 +1265,7 @@ ipc_right_delta(
                assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
                assert(IE_BITS_UREFS(bits) == 1);
 
-               port = (ipc_port_t) entry->ie_object;
+               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)) {
@@ -1277,6 +1287,13 @@ ipc_right_delta(
                        goto success;
                }
 
+               /*
+                * clear any reply context:
+                * no one will be sending the response b/c we are destroying
+                * the single, outstanding send once right.
+                */
+               port->ip_reply_context = 0;
+
                request = ipc_right_request_cancel_macro(space, port, name, entry);
                ip_unlock(port);
 
@@ -1298,7 +1315,7 @@ ipc_right_delta(
                mach_port_urefs_t urefs;
 
                if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
-                       port = (ipc_port_t) entry->ie_object;
+                       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)) {
@@ -1372,7 +1389,15 @@ ipc_right_delta(
 
                if ((bits & MACH_PORT_TYPE_SEND) == 0) {
                        /* invalid right exception only when not live/dead confusion */
-                       if ((bits & MACH_PORT_TYPE_DEAD_NAME) == 0) {
+                       if ((bits & MACH_PORT_TYPE_DEAD_NAME) == 0
+#if !defined(AE_MAKESENDRIGHT_FIXED)
+                           /*
+                            * AE tries to add single send right without knowing if it already owns one.
+                            * But if it doesn't, it should own the receive right and delta should be 1.
+                            */
+                           && (((bits & MACH_PORT_TYPE_RECEIVE) == 0) || (delta != 1))
+#endif
+                           ) {
                                mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_RIGHT);
                        }
                        goto invalid_right;
@@ -1380,7 +1405,7 @@ ipc_right_delta(
 
                /* maximum urefs for send is MACH_PORT_UREFS_MAX */
 
-               port = (ipc_port_t) entry->ie_object;
+               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)) {
@@ -1444,7 +1469,7 @@ ipc_right_delta(
 
                                request = ipc_right_request_cancel_macro(space, port,
                                    name, entry);
-                               ipc_hash_delete(space, (ipc_object_t) port,
+                               ipc_hash_delete(space, ip_to_object(port),
                                    name, entry);
 
                                ip_unlock(port);
@@ -1541,8 +1566,17 @@ ipc_right_destruct(
 
        assert(is_active(space));
 
-       if (((bits & MACH_PORT_TYPE_RECEIVE) == 0) ||
-           (srdelta && ((bits & MACH_PORT_TYPE_SEND) == 0))) {
+       if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) {
+               is_write_unlock(space);
+
+               /* No exception if we used to have receive and held entry since */
+               if ((bits & MACH_PORT_TYPE_EX_RECEIVE) == 0) {
+                       mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_RIGHT);
+               }
+               return KERN_INVALID_RIGHT;
+       }
+
+       if (srdelta && (bits & MACH_PORT_TYPE_SEND) == 0) {
                is_write_unlock(space);
                mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_RIGHT);
                return KERN_INVALID_RIGHT;
@@ -1552,11 +1586,11 @@ ipc_right_destruct(
                goto invalid_value;
        }
 
-       port = (ipc_port_t) entry->ie_object;
+       port = ip_object_to_port(entry->ie_object);
        assert(port != IP_NULL);
 
        ip_lock(port);
-       assert(ip_active(port));
+       require_ip_active(port);
        assert(port->ip_receiver_name == name);
        assert(port->ip_receiver == space);
 
@@ -1639,7 +1673,8 @@ ipc_right_destruct(
                         */
                        ipc_entry_modified(space, name, entry);
                        entry->ie_bits &= ~MACH_PORT_TYPE_RECEIVE;
-                       ipc_hash_insert(space, (ipc_object_t) port,
+                       entry->ie_bits |= MACH_PORT_TYPE_EX_RECEIVE;
+                       ipc_hash_insert(space, ip_to_object(port),
                            name, entry);
                        ip_reference(port);
                } else {
@@ -1651,7 +1686,7 @@ ipc_right_destruct(
                         *      port is destroyed "first".
                         */
                        bits &= ~IE_BITS_TYPE_MASK;
-                       bits |= MACH_PORT_TYPE_DEAD_NAME;
+                       bits |= (MACH_PORT_TYPE_DEAD_NAME | MACH_PORT_TYPE_EX_RECEIVE);
                        if (entry->ie_request) {
                                entry->ie_request = IE_REQ_NONE;
                                if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
@@ -1719,14 +1754,14 @@ ipc_right_info(
 
        bits = entry->ie_bits;
        request = entry->ie_request;
-       port = (ipc_port_t) entry->ie_object;
+       port = ip_object_to_port(entry->ie_object);
 
        if (bits & MACH_PORT_TYPE_RECEIVE) {
                assert(IP_VALID(port));
 
                if (request != IE_REQ_NONE) {
                        ip_lock(port);
-                       assert(ip_active(port));
+                       require_ip_active(port);
                        type |= ipc_port_request_type(port, name, request);
                        ip_unlock(port);
                }
@@ -1761,27 +1796,29 @@ ipc_right_info(
 }
 
 /*
- *     Routine:        ipc_right_copyin_check
+ *     Routine:        ipc_right_copyin_check_reply
  *     Purpose:
- *             Check if a subsequent ipc_right_copyin would succeed.
+ *             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.
  */
 
 boolean_t
-ipc_right_copyin_check(
+ipc_right_copyin_check_reply(
        __assert_only ipc_space_t       space,
-       __unused mach_port_name_t       name,
-       ipc_entry_t                     entry,
-       mach_msg_type_name_t            msgt_name)
+       mach_port_name_t                reply_name,
+       ipc_entry_t                     reply_entry,
+       mach_msg_type_name_t            reply_type)
 {
        ipc_entry_bits_t bits;
-       ipc_port_t port;
+       ipc_port_t reply_port;
 
-       bits = entry->ie_bits;
+       bits = reply_entry->ie_bits;
        assert(is_active(space));
 
-       switch (msgt_name) {
+       switch (reply_type) {
        case MACH_MSG_TYPE_MAKE_SEND:
                if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) {
                        return FALSE;
@@ -1795,17 +1832,8 @@ ipc_right_copyin_check(
                break;
 
        case MACH_MSG_TYPE_MOVE_RECEIVE:
-               if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) {
-                       return FALSE;
-               }
-               if (io_kotype(entry->ie_object) != IKOT_NONE) {
-                       return FALSE;
-               }
-               port = (ipc_port_t) entry->ie_object;
-               if (port->ip_specialreply) {
-                       return FALSE;
-               }
-               break;
+               /* ipc_kmsg_copyin_header already filters it out */
+               return FALSE;
 
        case MACH_MSG_TYPE_COPY_SEND:
        case MACH_MSG_TYPE_MOVE_SEND:
@@ -1818,19 +1846,29 @@ ipc_right_copyin_check(
                        return FALSE;
                }
 
-               port = (ipc_port_t) entry->ie_object;
-               assert(port != IP_NULL);
+               reply_port = ip_object_to_port(reply_entry->ie_object);
+               assert(reply_port != IP_NULL);
 
                /*
                 * active status peek to avoid checks that will be skipped
                 * on copyin for dead ports.  Lock not held, so will not be
                 * atomic (but once dead, there's no going back).
                 */
-               if (!ip_active(port)) {
+               if (!ip_active(reply_port)) {
                        break;
                }
 
-               if (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE) {
+               /*
+                * Can't copyin a send right that is marked immovable. This bit
+                * is set only during port creation and never unset. So it can
+                * 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 (reply_type == MACH_MSG_TYPE_MOVE_SEND_ONCE) {
                        if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0) {
                                return FALSE;
                        }
@@ -1850,6 +1888,40 @@ ipc_right_copyin_check(
        return TRUE;
 }
 
+/*
+ *     Routine:        ipc_right_copyin_check_guard_locked
+ *     Purpose:
+ *             Check if the port is guarded and the guard
+ *             value matches the one passed in the arguments.
+ *             If MACH_MSG_GUARD_FLAGS_UNGUARDED_ON_SEND is set,
+ *             check if the port is unguarded.
+ *     Conditions:
+ *             The port is locked.
+ *     Returns:
+ *             KERN_SUCCESS            Port is either unguarded
+ *                                     or guarded with expected value
+ *             KERN_INVALID_ARGUMENT   Port is either unguarded already or guard mismatch.
+ *                                     This also raises a EXC_GUARD exception.
+ */
+static kern_return_t
+ipc_right_copyin_check_guard_locked(
+       mach_port_name_t name,
+       ipc_port_t port,
+       mach_port_context_t context,
+       mach_msg_guard_flags_t *guard_flags)
+{
+       mach_msg_guard_flags_t flags = *guard_flags;
+       if ((flags & MACH_MSG_GUARD_FLAGS_UNGUARDED_ON_SEND) && !port->ip_guarded && !context) {
+               return KERN_SUCCESS;
+       } else if (port->ip_guarded && (port->ip_context == context)) {
+               return KERN_SUCCESS;
+       }
+
+       /* Incorrect guard; Raise exception */
+       mach_port_guard_exception(name, context, port->ip_context, kGUARD_EXC_INCORRECT_GUARD);
+       return KERN_INVALID_ARGUMENT;
+}
+
 /*
  *     Routine:        ipc_right_copyin
  *     Purpose:
@@ -1871,26 +1943,32 @@ ipc_right_copyin_check(
  *     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_ARGUMENT   Port is unguarded or guard mismatch
  */
 
 kern_return_t
 ipc_right_copyin(
-       ipc_space_t              space,
-       mach_port_name_t         name,
-       ipc_entry_t              entry,
-       mach_msg_type_name_t     msgt_name,
-       ipc_right_copyin_flags_t flags,
-       ipc_object_t             *objectp,
-       ipc_port_t               *sorightp,
-       ipc_port_t               *releasep,
-       int                      *assertcntp)
+       ipc_space_t                space,
+       mach_port_name_t           name,
+       ipc_entry_t                entry,
+       mach_msg_type_name_t       msgt_name,
+       ipc_right_copyin_flags_t   flags,
+       ipc_object_t               *objectp,
+       ipc_port_t                 *sorightp,
+       ipc_port_t                 *releasep,
+       int                        *assertcntp,
+       mach_port_context_t        context,
+       mach_msg_guard_flags_t     *guard_flags)
 {
        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;
 
        *releasep = IP_NULL;
        *assertcntp = 0;
-       boolean_t deadok = (flags & IPC_RIGHT_COPYIN_FLAGS_DEADOK) ? TRUE : FALSE;
 
        bits = entry->ie_bits;
 
@@ -1902,20 +1980,17 @@ ipc_right_copyin(
                        goto invalid_right;
                }
 
-               port = (ipc_port_t) entry->ie_object;
+               port = ip_object_to_port(entry->ie_object);
                assert(port != IP_NULL);
 
                ip_lock(port);
-               assert(ip_active(port));
                assert(port->ip_receiver_name == name);
                assert(port->ip_receiver == space);
 
-               port->ip_mscount++;
-               port->ip_srights++;
-               ip_reference(port);
+               ipc_port_make_send_locked(port);
                ip_unlock(port);
 
-               *objectp = (ipc_object_t) port;
+               *objectp = ip_to_object(port);
                *sorightp = IP_NULL;
                break;
        }
@@ -1925,19 +2000,18 @@ ipc_right_copyin(
                        goto invalid_right;
                }
 
-               port = (ipc_port_t) entry->ie_object;
+               port = ip_object_to_port(entry->ie_object);
                assert(port != IP_NULL);
 
                ip_lock(port);
-               assert(ip_active(port));
+               require_ip_active(port);
                assert(port->ip_receiver_name == name);
                assert(port->ip_receiver == space);
 
-               port->ip_sorights++;
-               ip_reference(port);
+               ipc_port_make_sonce_locked(port);
                ip_unlock(port);
 
-               *objectp = (ipc_object_t) port;
+               *objectp = ip_to_object(port);
                *sorightp = IP_NULL;
                break;
        }
@@ -1963,24 +2037,41 @@ ipc_right_copyin(
                         * situation which is, "This is a valid receive right,
                         * but it's also a kobject and you can't move it."
                         */
+                       mach_port_guard_exception(name, 0, 0, kGUARD_EXC_IMMOVABLE);
                        return KERN_INVALID_CAPABILITY;
                }
 
-               port = (ipc_port_t) entry->ie_object;
+               port = ip_object_to_port(entry->ie_object);
                assert(port != IP_NULL);
 
                ip_lock(port);
-               assert(ip_active(port));
+               require_ip_active(port);
                assert(port->ip_receiver_name == name);
                assert(port->ip_receiver == space);
 
+               if (port->ip_immovable_receive) {
+                       assert(port->ip_receiver != ipc_space_kernel);
+                       ip_unlock(port);
+                       assert(current_task() != kernel_task);
+                       mach_port_guard_exception(name, 0, 0, kGUARD_EXC_IMMOVABLE);
+                       return KERN_INVALID_CAPABILITY;
+               }
+
+               if (guard_flags != NULL) {
+                       kr = ipc_right_copyin_check_guard_locked(name, port, context, guard_flags);
+                       if (kr != KERN_SUCCESS) {
+                               ip_unlock(port);
+                               return kr;
+                       }
+               }
+
                if (bits & MACH_PORT_TYPE_SEND) {
                        assert(IE_BITS_TYPE(bits) ==
                            MACH_PORT_TYPE_SEND_RECEIVE);
                        assert(IE_BITS_UREFS(bits) > 0);
                        assert(port->ip_srights > 0);
 
-                       ipc_hash_insert(space, (ipc_object_t) port,
+                       ipc_hash_insert(space, ip_to_object(port),
                            name, entry);
                        ip_reference(port);
                } else {
@@ -1992,9 +2083,15 @@ ipc_right_copyin(
                        entry->ie_object = IO_NULL;
                }
                entry->ie_bits = bits & ~MACH_PORT_TYPE_RECEIVE;
+               entry->ie_bits |= MACH_PORT_TYPE_EX_RECEIVE;
                ipc_entry_modified(space, name, entry);
 
+               /* ipc_port_clear_receiver unguards the port and clears the ip_immovable_receive bit */
                (void)ipc_port_clear_receiver(port, FALSE); /* don't destroy the port/mqueue */
+               if (guard_flags != NULL) {
+                       /* this flag will be cleared during copyout */
+                       *guard_flags = *guard_flags | MACH_MSG_GUARD_FLAGS_UNGUARDED_ON_SEND;
+               }
 
 #if IMPORTANCE_INHERITANCE
                /*
@@ -2017,7 +2114,7 @@ ipc_right_copyin(
 
                ip_unlock(port);
 
-               *objectp = (ipc_object_t) port;
+               *objectp = ip_to_object(port);
                *sorightp = request;
                break;
        }
@@ -2035,7 +2132,7 @@ ipc_right_copyin(
 
                assert(IE_BITS_UREFS(bits) > 0);
 
-               port = (ipc_port_t) entry->ie_object;
+               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)) {
@@ -2053,13 +2150,16 @@ ipc_right_copyin(
                        goto invalid_right;
                }
 
-               assert(port->ip_srights > 0);
+               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;
+               }
 
-               port->ip_srights++;
-               ip_reference(port);
+               ipc_port_copy_send_locked(port);
                ip_unlock(port);
 
-               *objectp = (ipc_object_t) port;
+               *objectp = ip_to_object(port);
                *sorightp = IP_NULL;
                break;
        }
@@ -2079,7 +2179,7 @@ ipc_right_copyin(
 
                assert(IE_BITS_UREFS(bits) > 0);
 
-               port = (ipc_port_t) entry->ie_object;
+               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)) {
@@ -2097,9 +2197,14 @@ ipc_right_copyin(
                        goto invalid_right;
                }
 
-               assert(port->ip_srights > 0);
+               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 (IE_BITS_UREFS(bits) == 1) {
+                       assert(port->ip_srights > 0);
                        if (bits & MACH_PORT_TYPE_RECEIVE) {
                                assert(port->ip_receiver_name == name);
                                assert(port->ip_receiver == space);
@@ -2113,7 +2218,7 @@ ipc_right_copyin(
 
                                request = ipc_right_request_cancel_macro(space, port,
                                    name, entry);
-                               ipc_hash_delete(space, (ipc_object_t) port,
+                               ipc_hash_delete(space, ip_to_object(port),
                                    name, entry);
                                entry->ie_object = IO_NULL;
                                /* transfer entry's reference to caller */
@@ -2121,8 +2226,7 @@ ipc_right_copyin(
                        entry->ie_bits = bits & ~
                            (IE_BITS_UREFS_MASK | MACH_PORT_TYPE_SEND);
                } else {
-                       port->ip_srights++;
-                       ip_reference(port);
+                       ipc_port_copy_send_locked(port);
                        /* if urefs are pegged due to overflow, leave them pegged */
                        if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
                                entry->ie_bits = bits - 1; /* decrement urefs */
@@ -2132,7 +2236,7 @@ ipc_right_copyin(
                ipc_entry_modified(space, name, entry);
                ip_unlock(port);
 
-               *objectp = (ipc_object_t) port;
+               *objectp = ip_to_object(port);
                *sorightp = request;
                break;
        }
@@ -2152,7 +2256,7 @@ ipc_right_copyin(
 
                assert(IE_BITS_UREFS(bits) > 0);
 
-               port = (ipc_port_t) entry->ie_object;
+               port = ip_object_to_port(entry->ie_object);
                assert(port != IP_NULL);
 
                if (ipc_right_check(space, port, name, entry, flags)) {
@@ -2175,6 +2279,12 @@ ipc_right_copyin(
                        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;
+               }
+
                assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
                assert(IE_BITS_UREFS(bits) == 1);
                assert(port->ip_sorights > 0);
@@ -2186,7 +2296,7 @@ ipc_right_copyin(
                entry->ie_bits = bits & ~
                    (IE_BITS_UREFS_MASK | MACH_PORT_TYPE_SEND_ONCE);
                ipc_entry_modified(space, name, entry);
-               *objectp = (ipc_object_t) port;
+               *objectp = ip_to_object(port);
                *sorightp = request;
                break;
        }
@@ -2235,93 +2345,6 @@ move_dead:
        return KERN_SUCCESS;
 }
 
-/*
- *     Routine:        ipc_right_copyin_undo
- *     Purpose:
- *             Undoes the effects of an ipc_right_copyin
- *             of a send/send-once right that is dead.
- *             (Object is either IO_DEAD or a dead port.)
- *     Conditions:
- *             The space is write-locked and active.
- */
-
-void
-ipc_right_copyin_undo(
-       ipc_space_t             space,
-       mach_port_name_t        name,
-       ipc_entry_t             entry,
-       mach_msg_type_name_t    msgt_name,
-       ipc_object_t            object,
-       ipc_port_t              soright)
-{
-       ipc_entry_bits_t bits;
-
-       bits = entry->ie_bits;
-
-       assert(is_active(space));
-
-       assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
-           (msgt_name == MACH_MSG_TYPE_COPY_SEND) ||
-           (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
-
-       if (soright != IP_NULL) {
-               assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
-                   (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
-               assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
-               assert(object != IO_DEAD);
-
-               entry->ie_bits = ((bits & ~IE_BITS_RIGHT_MASK) |
-                   MACH_PORT_TYPE_DEAD_NAME | 2);
-       } else if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE) {
-               assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
-                   (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
-
-               entry->ie_bits = ((bits & ~IE_BITS_RIGHT_MASK) |
-                   MACH_PORT_TYPE_DEAD_NAME | 1);
-       } else if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME) {
-               assert(object == IO_DEAD);
-               assert(IE_BITS_UREFS(bits) > 0);
-
-               if (msgt_name != MACH_MSG_TYPE_COPY_SEND) {
-                       assert(IE_BITS_UREFS(bits) <= MACH_PORT_UREFS_MAX);
-                       /* if urefs are pegged due to overflow, leave them pegged */
-                       if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
-                               entry->ie_bits = bits + 1; /* increment urefs */
-                       }
-               }
-       } else {
-               assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
-                   (msgt_name == MACH_MSG_TYPE_COPY_SEND));
-               assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
-               assert(object != IO_DEAD);
-               assert(entry->ie_object == object);
-               assert(IE_BITS_UREFS(bits) > 0);
-
-               if (msgt_name != MACH_MSG_TYPE_COPY_SEND) {
-                       assert(IE_BITS_UREFS(bits) <= MACH_PORT_UREFS_MAX);
-                       /* if urefs are pegged due to overflow, leave them pegged */
-                       if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
-                               entry->ie_bits = bits + 1; /* increment urefs */
-                       }
-               }
-
-               /*
-                *      May as well convert the entry to a dead name.
-                *      (Or if it is a compat entry, destroy it.)
-                */
-
-               (void) ipc_right_check(space, (ipc_port_t) object,
-                   name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE);
-               /* object is dead so it is not locked */
-       }
-       ipc_entry_modified(space, name, entry);
-       /* release the reference acquired by copyin */
-
-       if (object != IO_DEAD) {
-               io_release(object);
-       }
-}
-
 /*
  *     Routine:        ipc_right_copyin_two_move_sends
  *     Purpose:
@@ -2365,7 +2388,7 @@ ipc_right_copyin_two_move_sends(
                goto invalid_right;
        }
 
-       port = (ipc_port_t) entry->ie_object;
+       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)) {
@@ -2374,45 +2397,57 @@ ipc_right_copyin_two_move_sends(
        }
        /* port is locked and active */
 
-       assert(port->ip_srights > 0);
+       if (urefs > 2) {
+               /*
+                * We are moving 2 urefs as naked send rights, which is decomposed as:
+                * - two copy sends (which doesn't affect the make send count)
+                * - decrementing the local urefs twice.
+                */
+               ipc_port_copy_send_locked(port);
+               ipc_port_copy_send_locked(port);
+               /* if urefs are pegged due to overflow, leave them pegged */
+               if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
+                       entry->ie_bits = bits - 2; /* decrement urefs */
+               }
+       } else {
+               /*
+                * We have exactly 2 send rights for this port in this space,
+                * which means that we will liberate the naked send right held
+                * by this entry.
+                *
+                * However refcounting rules around entries are that naked send rights
+                * on behalf of spaces do not have an associated port reference,
+                * so we need to donate one ...
+                */
+               ipc_port_copy_send_locked(port);
 
-       if (urefs == 2) {
                if (bits & MACH_PORT_TYPE_RECEIVE) {
                        assert(port->ip_receiver_name == name);
                        assert(port->ip_receiver == space);
                        assert(IE_BITS_TYPE(bits) ==
                            MACH_PORT_TYPE_SEND_RECEIVE);
 
-                       port->ip_srights++;
-                       ip_reference(port);
+                       /* ... that we inject manually when the entry stays alive */
                        ip_reference(port);
                } else {
                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
 
+                       /* ... that we steal from the entry when it dies */
                        request = ipc_right_request_cancel_macro(space, port,
                            name, entry);
 
-                       port->ip_srights++;
-                       ip_reference(port);
-                       ipc_hash_delete(space, (ipc_object_t) port,
+                       ipc_hash_delete(space, ip_to_object(port),
                            name, entry);
                        entry->ie_object = IO_NULL;
                }
+
                entry->ie_bits = bits & ~(IE_BITS_UREFS_MASK | MACH_PORT_TYPE_SEND);
-       } else {
-               port->ip_srights += 2;
-               ip_reference(port);
-               ip_reference(port);
-               /* if urefs are pegged due to overflow, leave them pegged */
-               if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
-                       entry->ie_bits = bits - 2; /* decrement urefs */
-               }
        }
        ipc_entry_modified(space, name, entry);
 
        ip_unlock(port);
 
-       *objectp = (ipc_object_t) port;
+       *objectp = ip_to_object(port);
        *sorightp = request;
        return KERN_SUCCESS;
 
@@ -2430,6 +2465,7 @@ invalid_right:
  *     Conditions:
  *             The space is write-locked and active.
  *             The object is returned with two refs/rights.
+ *             Msgt_one refers to the dest_type
  *     Returns:
  *             KERN_SUCCESS            Acquired an object.
  *             KERN_INVALID_RIGHT      Name doesn't denote correct right(s).
@@ -2437,14 +2473,14 @@ invalid_right:
  */
 kern_return_t
 ipc_right_copyin_two(
-       ipc_space_t             space,
-       mach_port_name_t        name,
-       ipc_entry_t             entry,
-       mach_msg_type_name_t    msgt_one,
-       mach_msg_type_name_t    msgt_two,
-       ipc_object_t            *objectp,
-       ipc_port_t              *sorightp,
-       ipc_port_t              *releasep)
+       ipc_space_t               space,
+       mach_port_name_t          name,
+       ipc_entry_t               entry,
+       mach_msg_type_name_t      msgt_one,
+       mach_msg_type_name_t      msgt_two,
+       ipc_object_t              *objectp,
+       ipc_port_t                *sorightp,
+       ipc_port_t                *releasep)
 {
        kern_return_t kr;
        int assertcnt = 0;
@@ -2452,14 +2488,6 @@ ipc_right_copyin_two(
        assert(MACH_MSG_TYPE_PORT_ANY_SEND(msgt_one));
        assert(MACH_MSG_TYPE_PORT_ANY_SEND(msgt_two));
 
-
-       /*
-        * Pre-validate the second disposition is possible all by itself.
-        */
-       if (!ipc_right_copyin_check(space, name, entry, msgt_two)) {
-               return KERN_INVALID_CAPABILITY;
-       }
-
        /*
         *      This is a little tedious to make atomic, because
         *      there are 25 combinations of valid dispositions.
@@ -2491,9 +2519,9 @@ ipc_right_copyin_two(
                ipc_object_t object_two;
 
                kr = ipc_right_copyin(space, name, entry,
-                   msgt_one, IPC_RIGHT_COPYIN_FLAGS_NONE,
+                   msgt_one, IPC_RIGHT_COPYIN_FLAGS_ALLOW_IMMOVABLE_SEND,
                    objectp, sorightp, releasep,
-                   &assertcnt);
+                   &assertcnt, 0, NULL);
                assert(assertcnt == 0);
                if (kr != KERN_SUCCESS) {
                        return kr;
@@ -2512,7 +2540,7 @@ ipc_right_copyin_two(
                kr = ipc_right_copyin(space, name, entry,
                    msgt_two, IPC_RIGHT_COPYIN_FLAGS_NONE,
                    &object_two, sorightp, releasep,
-                   &assertcnt);
+                   &assertcnt, 0, NULL);
                assert(assertcnt == 0);
                assert(kr == KERN_SUCCESS);
                assert(*sorightp == IP_NULL);
@@ -2550,9 +2578,9 @@ ipc_right_copyin_two(
                }
 
                kr = ipc_right_copyin(space, name, entry,
-                   msgt_name, IPC_RIGHT_COPYIN_FLAGS_NONE,
+                   msgt_name, IPC_RIGHT_COPYIN_FLAGS_ALLOW_IMMOVABLE_SEND,
                    objectp, sorightp, releasep,
-                   &assertcnt);
+                   &assertcnt, 0, NULL);
                assert(assertcnt == 0);
                if (kr != KERN_SUCCESS) {
                        return kr;
@@ -2563,7 +2591,7 @@ ipc_right_copyin_two(
                 *      that's OK.  Neither right will be usable to send
                 *      a message anyway.
                 */
-               (void)ipc_port_copy_send((ipc_port_t)*objectp);
+               (void)ipc_port_copy_send(ip_object_to_port(*objectp));
        }
 
        return KERN_SUCCESS;
@@ -2580,9 +2608,9 @@ ipc_right_copyin_two(
  *             because user-reference overflow isn't a possibility.
  *
  *             If copying out the object would cause the user-reference
- *             count in the entry to overflow, and overflow is TRUE,
- *             then instead the user-reference count is left pegged
- *             to its maximum value and the copyout succeeds anyway.
+ *             count in the entry to overflow, then the user-reference
+ *             count is left pegged to its maximum value and the copyout
+ *             succeeds anyway.
  *     Conditions:
  *             The space is write-locked and active.
  *             The object is locked and active.
@@ -2597,7 +2625,8 @@ ipc_right_copyout(
        mach_port_name_t        name,
        ipc_entry_t             entry,
        mach_msg_type_name_t    msgt_name,
-       __unused boolean_t      overflow,
+       mach_port_context_t     *context,
+       mach_msg_guard_flags_t  *guard_flags,
        ipc_object_t            object)
 {
        ipc_entry_bits_t bits;
@@ -2610,7 +2639,7 @@ ipc_right_copyout(
        assert(io_active(object));
        assert(entry->ie_object == object);
 
-       port = (ipc_port_t) object;
+       port = ip_object_to_port(object);
 
        switch (msgt_name) {
        case MACH_MSG_TYPE_PORT_SEND_ONCE:
@@ -2673,8 +2702,7 @@ ipc_right_copyout(
 
                        /* entry is locked holding ref, so can use port */
 
-                       ipc_hash_insert(space, (ipc_object_t) port,
-                           name, entry);
+                       ipc_hash_insert(space, ip_to_object(port), name, entry);
                }
 
                entry->ie_bits = (bits | MACH_PORT_TYPE_SEND) + 1; /* increment urefs */
@@ -2683,9 +2711,6 @@ ipc_right_copyout(
 
        case MACH_MSG_TYPE_PORT_RECEIVE: {
                ipc_port_t dest;
-               turnstile_inheritor_t inheritor = TURNSTILE_INHERITOR_NULL;
-               struct turnstile *ts = TURNSTILE_NULL;
-
 #if IMPORTANCE_INHERITANCE
                natural_t assertcnt = port->ip_impcount;
 #endif /* IMPORTANCE_INHERITANCE */
@@ -2699,50 +2724,49 @@ ipc_right_copyout(
                port->ip_receiver_name = name;
                port->ip_receiver = space;
 
-               assert((bits & MACH_PORT_TYPE_RECEIVE) == 0);
+               struct knote *kn = current_thread()->ith_knote;
 
-               /* Update the port's turnstile linkage to WL turnstile */
-               ts = port_send_turnstile(port);
-               if (ts) {
-                       struct knote *kn = current_thread()->ith_knote;
-                       if (ITH_KNOTE_VALID(kn, MACH_MSG_TYPE_PORT_RECEIVE)) {
-                               inheritor = filt_machport_stash_port(kn, port, NULL);
-                               if (inheritor) {
-                                       turnstile_reference(inheritor);
-                                       IMQ_SET_INHERITOR(&port->ip_messages, inheritor);
-                               }
+               if ((guard_flags != NULL) && ((*guard_flags & MACH_MSG_GUARD_FLAGS_IMMOVABLE_RECEIVE) != 0)) {
+                       assert(port->ip_immovable_receive == 0);
+                       port->ip_guarded = 1;
+                       port->ip_strict_guard = 0;
+                       /* pseudo receive shouldn't set the receive right as immovable in the sender's space */
+                       if (kn != ITH_KNOTE_PSEUDO) {
+                               port->ip_immovable_receive = 1;
                        }
-                       turnstile_reference(ts);
-                       turnstile_update_inheritor(ts, inheritor,
-                           (TURNSTILE_IMMEDIATE_UPDATE | TURNSTILE_INHERITOR_TURNSTILE));
+                       port->ip_context = current_thread()->ith_msg_addr;
+                       *context = port->ip_context;
+                       *guard_flags = *guard_flags & ~MACH_MSG_GUARD_FLAGS_UNGUARDED_ON_SEND;
                }
 
-               imq_unlock(&port->ip_messages);
-
+               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_unlock(port);
-                       ip_release(port);
-
-                       /* entry is locked holding ref, so can use port */
-                       ipc_hash_delete(space, (ipc_object_t) port, name, entry);
                } else {
                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
                        assert(IE_BITS_UREFS(bits) == 0);
+               }
 
-                       /* transfer ref to entry */
-                       ip_unlock(port);
+               boolean_t sync_bootstrap_checkin = FALSE;
+               if (kn != ITH_KNOTE_PSEUDO && port->ip_sync_bootstrap_checkin) {
+                       sync_bootstrap_checkin = TRUE;
                }
-               entry->ie_bits = bits | MACH_PORT_TYPE_RECEIVE;
-               ipc_entry_modified(space, name, entry);
+               if (!ITH_KNOTE_VALID(kn, MACH_MSG_TYPE_PORT_RECEIVE)) {
+                       kn = NULL;
+               }
+               ipc_port_adjust_port_locked(port, kn, sync_bootstrap_checkin);
+               /* port & message queue are unlocked */
 
-               if (ts) {
-                       turnstile_update_inheritor_complete(ts, TURNSTILE_INTERLOCK_NOT_HELD);
-                       turnstile_deallocate_safe(ts);
+               if (bits & MACH_PORT_TYPE_SEND) {
+                       ip_release(port);
+
+                       /* entry is locked holding ref, so can use port */
+                       ipc_hash_delete(space, ip_to_object(port), name, entry);
                }
+               entry->ie_bits = bits | MACH_PORT_TYPE_RECEIVE;
+               ipc_entry_modified(space, name, entry);
 
                if (dest != IP_NULL) {
 #if IMPORTANCE_INHERITANCE
@@ -2769,137 +2793,3 @@ ipc_right_copyout(
        }
        return KERN_SUCCESS;
 }
-
-/*
- *     Routine:        ipc_right_rename
- *     Purpose:
- *             Transfer an entry from one name to another.
- *             The old entry is deallocated.
- *     Conditions:
- *             The space is write-locked and active.
- *             The new entry is unused.  Upon return,
- *             the space is unlocked.
- *     Returns:
- *             KERN_SUCCESS            Moved entry to new name.
- */
-
-kern_return_t
-ipc_right_rename(
-       ipc_space_t             space,
-       mach_port_name_t        oname,
-       ipc_entry_t             oentry,
-       mach_port_name_t        nname,
-       ipc_entry_t             nentry)
-{
-       ipc_port_request_index_t request = oentry->ie_request;
-       ipc_entry_bits_t bits = oentry->ie_bits;
-       ipc_object_t object = oentry->ie_object;
-       ipc_port_t release_port = IP_NULL;
-
-       assert(is_active(space));
-       assert(oname != nname);
-
-       /*
-        *      If IE_BITS_COMPAT, we can't allow the entry to be renamed
-        *      if the port is dead.  (This would foil ipc_port_destroy.)
-        *      Instead we should fail because oentry shouldn't exist.
-        *      Note IE_BITS_COMPAT implies ie_request != 0.
-        */
-
-       if (request != IE_REQ_NONE) {
-               ipc_port_t port;
-
-               assert(bits & MACH_PORT_TYPE_PORT_RIGHTS);
-               port = (ipc_port_t) object;
-               assert(port != IP_NULL);
-
-               if (ipc_right_check(space, port, oname, oentry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
-                       request = IE_REQ_NONE;
-                       object = IO_NULL;
-                       bits = oentry->ie_bits;
-                       release_port = port;
-                       assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
-                       assert(oentry->ie_request == IE_REQ_NONE);
-               } else {
-                       /* port is locked and active */
-
-                       ipc_port_request_rename(port, request, oname, nname);
-                       ip_unlock(port);
-                       oentry->ie_request = IE_REQ_NONE;
-               }
-       }
-
-       /* initialize nentry before letting ipc_hash_insert see it */
-
-       assert((nentry->ie_bits & IE_BITS_RIGHT_MASK) == 0);
-       nentry->ie_bits |= bits & IE_BITS_RIGHT_MASK;
-       nentry->ie_request = request;
-       nentry->ie_object = object;
-
-       switch (IE_BITS_TYPE(bits)) {
-       case MACH_PORT_TYPE_SEND: {
-               ipc_port_t port;
-
-               port = (ipc_port_t) object;
-               assert(port != IP_NULL);
-
-               /* remember, there are no other share entries possible */
-               /* or we can't do the rename.  Therefore we do not need */
-               /* to check the other subspaces */
-               ipc_hash_delete(space, (ipc_object_t) port, oname, oentry);
-               ipc_hash_insert(space, (ipc_object_t) port, nname, nentry);
-               break;
-       }
-
-       case MACH_PORT_TYPE_RECEIVE:
-       case MACH_PORT_TYPE_SEND_RECEIVE: {
-               ipc_port_t port;
-
-               port = (ipc_port_t) object;
-               assert(port != IP_NULL);
-
-               ip_lock(port);
-               imq_lock(&port->ip_messages);
-               assert(ip_active(port));
-               assert(port->ip_receiver_name == oname);
-               assert(port->ip_receiver == space);
-
-               port->ip_receiver_name = nname;
-               imq_unlock(&port->ip_messages);
-               ip_unlock(port);
-               break;
-       }
-
-       case MACH_PORT_TYPE_PORT_SET: {
-               ipc_pset_t pset;
-
-               pset = (ipc_pset_t) object;
-               assert(pset != IPS_NULL);
-
-               ips_lock(pset);
-               assert(ips_active(pset));
-
-               ips_unlock(pset);
-               break;
-       }
-
-       case MACH_PORT_TYPE_SEND_ONCE:
-       case MACH_PORT_TYPE_DEAD_NAME:
-               break;
-
-       default:
-               panic("ipc_right_rename: strange rights");
-       }
-
-       assert(oentry->ie_request == IE_REQ_NONE);
-       oentry->ie_object = IO_NULL;
-       ipc_entry_dealloc(space, oname, oentry);
-       ipc_entry_modified(space, nname, nentry);
-       is_write_unlock(space);
-
-       if (release_port != IP_NULL) {
-               ip_release(release_port);
-       }
-
-       return KERN_SUCCESS;
-}