]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/ipc/ipc_kmsg.c
xnu-2422.115.4.tar.gz
[apple/xnu.git] / osfmk / ipc / ipc_kmsg.c
index 9adfe5b832f90296e4b60148459a118620099a51..70ae8f7ef616e97ede25c38a7343f778977ab38d 100644 (file)
@@ -70,7 +70,6 @@
  *     Operations on kernel messages.
  */
 
-#include <norma_vm.h>
 
 #include <mach/mach_types.h>
 #include <mach/boolean.h>
 #define DEBUG_MSGS_K64 1
 #endif
 
+#include <sys/kdebug.h>
+#include <libkern/OSAtomic.h>
+
 #pragma pack(4)
 
 typedef        struct 
@@ -484,7 +486,9 @@ ipc_msg_print_untyped64(
 #endif  /* !DEBUG_MSGS_K64 */
 
 extern vm_map_t                ipc_kernel_copy_map;
+extern vm_size_t       ipc_kmsg_max_space;
 extern vm_size_t       ipc_kmsg_max_vm_space;
+extern vm_size_t       ipc_kmsg_max_body_space;
 extern vm_size_t       msg_ool_size_small;
 
 #define MSG_OOL_SIZE_SMALL     msg_ool_size_small
@@ -591,20 +595,25 @@ ipc_kmsg_alloc(
         * data backwards.
         */
        mach_msg_size_t size = msg_and_trailer_size - MAX_TRAILER_SIZE;
+
+       /* compare against implementation upper limit for the body */
+       if (size > ipc_kmsg_max_body_space)
+               return IKM_NULL;
+
        if (size > sizeof(mach_msg_base_t)) {
                mach_msg_size_t max_desc = (mach_msg_size_t)(((size - sizeof(mach_msg_base_t)) /
                                           sizeof(mach_msg_ool_descriptor32_t)) *
                                           DESC_SIZE_ADJUSTMENT);
-               if (msg_and_trailer_size >= MACH_MSG_SIZE_MAX - max_desc)
+
+               /* make sure expansion won't cause wrap */
+               if (msg_and_trailer_size > MACH_MSG_SIZE_MAX - max_desc)
                        return IKM_NULL;
 
                max_expanded_size = msg_and_trailer_size + max_desc;
        } else
                max_expanded_size = msg_and_trailer_size;
 
-       if (max_expanded_size > ikm_less_overhead(MACH_MSG_SIZE_MAX))
-               return IKM_NULL;
-       else if (max_expanded_size < IKM_SAVED_MSG_SIZE)
+       if (max_expanded_size < IKM_SAVED_MSG_SIZE)
                max_expanded_size = IKM_SAVED_MSG_SIZE;         /* round up for ikm_cache */
 
        if (max_expanded_size == IKM_SAVED_MSG_SIZE) {
@@ -617,12 +626,9 @@ ipc_kmsg_alloc(
                        assert(i <= IKM_STASH);
                        kmsg = cache->entries[--i];
                        cache->avail = i;
-                       ikm_check_init(kmsg, max_expanded_size);
                        enable_preemption();
-                       kmsg->ikm_header = (mach_msg_header_t *)
-                                          ((vm_offset_t)(kmsg + 1) +
-                                           max_expanded_size -
-                                           msg_and_trailer_size);
+                       ikm_check_init(kmsg, max_expanded_size);
+                       ikm_set_header(kmsg, msg_and_trailer_size);
                        return (kmsg);
                }
                enable_preemption();
@@ -633,10 +639,7 @@ ipc_kmsg_alloc(
 
        if (kmsg != IKM_NULL) {
                ikm_init(kmsg, max_expanded_size);
-               kmsg->ikm_header = (mach_msg_header_t *)
-                                  ((vm_offset_t)(kmsg + 1) +
-                                   max_expanded_size -
-                                   msg_and_trailer_size);
+               ikm_set_header(kmsg, msg_and_trailer_size);
        }
 
        return(kmsg);
@@ -680,9 +683,11 @@ ipc_kmsg_free(
                if (ip_active(port) && (port->ip_premsg == kmsg)) {
                        assert(IP_PREALLOC(port));
                        ip_unlock(port);
+                       ip_release(port);
                        return;
                }
-               ip_check_unlock(port);  /* May be last reference */
+                ip_unlock(port);
+               ip_release(port); /* May be last reference */
        }
 
        /*
@@ -814,51 +819,59 @@ void
 ipc_kmsg_destroy(
        ipc_kmsg_t      kmsg)
 {
-       ipc_kmsg_queue_t queue;
-       boolean_t empty;
-
        /*
-        *      ipc_kmsg_clean can cause more messages to be destroyed.
-        *      Curtail recursion by queueing messages.  If a message
-        *      is already queued, then this is a recursive call.
+        *      Destroying a message can cause more messages to be destroyed.
+        *      Curtail recursion by putting messages on the deferred
+        *      destruction queue.  If this was the first message on the
+        *      queue, this instance must process the full queue.
         */
+       if (ipc_kmsg_delayed_destroy(kmsg))
+               ipc_kmsg_reap_delayed();
+}
 
-       queue = &(current_thread()->ith_messages);
-       empty = ipc_kmsg_queue_empty(queue);
-       ipc_kmsg_enqueue(queue, kmsg);
+/*
+ *     Routine:        ipc_kmsg_delayed_destroy
+ *     Purpose:
+ *             Enqueues a kernel message for deferred destruction.
+ *     Returns:
+ *             Boolean indicator that the caller is responsible to reap
+ *             deferred messages.
+ */
 
-       if (empty) {
-               /* must leave kmsg in queue while cleaning it */
+boolean_t ipc_kmsg_delayed_destroy(
+       ipc_kmsg_t kmsg)
+{
+       ipc_kmsg_queue_t queue = &(current_thread()->ith_messages);
+       boolean_t first = ipc_kmsg_queue_empty(queue);
 
-               while ((kmsg = ipc_kmsg_queue_first(queue)) != IKM_NULL) {
-                       ipc_kmsg_clean(kmsg);
-                       ipc_kmsg_rmqueue(queue, kmsg);
-                       ipc_kmsg_free(kmsg);
-               }
-       }
+       ipc_kmsg_enqueue(queue, kmsg);
+       return first;
 }
 
 /*
- *     Routine:        ipc_kmsg_destroy_dest
+ *     Routine:        ipc_kmsg_destroy_queue
  *     Purpose:
- *             Destroys a kernel message.  Releases all rights,
- *             references, and memory held by the message (including
- *             the destination port reference.
- *             Frees the message.
+ *             Destroys messages from the per-thread
+ *             deferred reaping queue.
  *     Conditions:
  *             No locks held.
  */
+
 void
-ipc_kmsg_destroy_dest(
-       ipc_kmsg_t kmsg)
+ipc_kmsg_reap_delayed(void)
 {
-    ipc_port_t port;
-       
-    port = kmsg->ikm_header->msgh_remote_port;
+       ipc_kmsg_queue_t queue = &(current_thread()->ith_messages);
+       ipc_kmsg_t kmsg;
 
-    ipc_port_release(port);
-    kmsg->ikm_header->msgh_remote_port = MACH_PORT_NULL;
-    ipc_kmsg_destroy(kmsg);
+       /*
+        * must leave kmsg in queue while cleaning it to assure
+        * no nested calls recurse into here.
+        */
+       while ((kmsg = ipc_kmsg_queue_first(queue)) != IKM_NULL) {
+               ipc_kmsg_clean(kmsg);
+               ipc_kmsg_rmqueue(queue, kmsg);
+               ipc_kmsg_free(kmsg);
+       }
 }
 
 /*
@@ -870,7 +883,7 @@ ipc_kmsg_destroy_dest(
  *     Conditions:
  *             No locks held.
  */
-
+static unsigned int _ipc_kmsg_clean_invalid_desc = 0;
 void
 ipc_kmsg_clean_body(
        __unused ipc_kmsg_t     kmsg,
@@ -949,7 +962,7 @@ ipc_kmsg_clean_body(
                break;
            }
            default : {
-               printf("cleanup: don't understand this type of descriptor\n");
+                   _ipc_kmsg_clean_invalid_desc++; /* don't understand this type of descriptor */
            }
        }
     }
@@ -981,7 +994,7 @@ ipc_kmsg_clean_partial(
 
        object = (ipc_object_t) kmsg->ikm_header->msgh_remote_port;
        assert(IO_VALID(object));
-       ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits));
+       ipc_object_destroy_dest(object, MACH_MSGH_BITS_REMOTE(mbits));
 
        object = (ipc_object_t) kmsg->ikm_header->msgh_local_port;
        if (IO_VALID(object))
@@ -1013,7 +1026,7 @@ ipc_kmsg_clean(
        mbits = kmsg->ikm_header->msgh_bits;
        object = (ipc_object_t) kmsg->ikm_header->msgh_remote_port;
        if (IO_VALID(object))
-               ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits));
+               ipc_object_destroy_dest(object, MACH_MSGH_BITS_REMOTE(mbits));
 
        object = (ipc_object_t) kmsg->ikm_header->msgh_local_port;
        if (IO_VALID(object))
@@ -1072,6 +1085,23 @@ ipc_kmsg_clear_prealloc(
        IP_CLEAR_PREALLOC(port, kmsg);
 }
 
+/*
+ *     Routine:        ipc_kmsg_prealloc
+ *     Purpose:
+ *             Wraper to ipc_kmsg_alloc() to account for
+ *             header expansion requirements.
+ */
+ipc_kmsg_t
+ipc_kmsg_prealloc(mach_msg_size_t size)
+{
+#if defined(__LP64__)
+       if (size > MACH_MSG_SIZE_MAX - LEGACY_HEADER_SIZE_DELTA)
+               return IKM_NULL;
+
+       size += LEGACY_HEADER_SIZE_DELTA;
+#endif
+       return ipc_kmsg_alloc(size);
+}
 
 
 /*
@@ -1085,6 +1115,7 @@ ipc_kmsg_clear_prealloc(
  *             MACH_MSG_SUCCESS        Acquired a message buffer.
  *             MACH_SEND_MSG_TOO_SMALL Message smaller than a header.
  *             MACH_SEND_MSG_TOO_SMALL Message size not long-word multiple.
+ *             MACH_SEND_TOO_LARGE     Message too large to ever be sent.
  *             MACH_SEND_NO_BUFFER     Couldn't allocate a message buffer.
  *             MACH_SEND_INVALID_DATA  Couldn't copy message data.
  */
@@ -1105,7 +1136,7 @@ ipc_kmsg_get(
        if ((size < sizeof(mach_msg_legacy_header_t)) || (size & 3))
                return MACH_SEND_MSG_TOO_SMALL;
 
-       if (size > MACH_MSG_SIZE_MAX - MAX_TRAILER_SIZE)
+       if (size > ipc_kmsg_max_body_space)
                return MACH_SEND_TOO_LARGE;
 
        if(size == sizeof(mach_msg_legacy_header_t))
@@ -1231,9 +1262,8 @@ ipc_kmsg_get_from_kernel(
        ipc_port_t      dest_port;
 
        assert(size >= sizeof(mach_msg_header_t));
-//     assert((size & 3) == 0);
+       assert((size & 3) == 0);
 
-       assert(IP_VALID((ipc_port_t) msg->msgh_remote_port));
        dest_port = (ipc_port_t)msg->msgh_remote_port;
 
        msg_and_trailer_size = size + MAX_TRAILER_SIZE;
@@ -1243,10 +1273,9 @@ ipc_kmsg_get_from_kernel(
         * clients.  These are set up for those kernel clients
         * which cannot afford to wait.
         */
-#ifndef __LP64__
-       /* LP64todo - does the prealloc kmsg need ikm_header padding?
-        */
-       if (IP_PREALLOC(dest_port)) {
+       if (IP_VALID(dest_port) && IP_PREALLOC(dest_port)) {
+               mach_msg_size_t max_desc = 0;
+
                ip_lock(dest_port);
                if (!ip_active(dest_port)) {
                        ip_unlock(dest_port);
@@ -1254,19 +1283,26 @@ ipc_kmsg_get_from_kernel(
                }
                assert(IP_PREALLOC(dest_port));
                kmsg = dest_port->ip_premsg;
-               if (msg_and_trailer_size > kmsg->ikm_size) {
-                       ip_unlock(dest_port);
-                       return MACH_SEND_TOO_LARGE;
-               }
                if (ikm_prealloc_inuse(kmsg)) {
                        ip_unlock(dest_port);
                        return MACH_SEND_NO_BUFFER;
                }
+#if !defined(__LP64__)
+               if (msg->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
+                       assert(size > sizeof(mach_msg_base_t));
+                       max_desc = ((mach_msg_base_t *)msg)->body.msgh_descriptor_count *
+                               DESC_SIZE_ADJUSTMENT;
+               }
+#endif
+               if (msg_and_trailer_size > kmsg->ikm_size - max_desc) {
+                       ip_unlock(dest_port);
+                       return MACH_SEND_TOO_LARGE;
+               }
                ikm_prealloc_set_inuse(kmsg, dest_port);
+               ikm_set_header(kmsg, msg_and_trailer_size);
                ip_unlock(dest_port);
        }
        else
-#endif /* !__LP64__ */
        {
                kmsg = ipc_kmsg_alloc(msg_and_trailer_size);
                if (kmsg == IKM_NULL)
@@ -1315,7 +1351,10 @@ ipc_kmsg_get_from_kernel(
  *             MACH_MSG_SUCCESS        The message was accepted.
  *             MACH_SEND_TIMED_OUT     Caller still has message.
  *             MACH_SEND_INTERRUPTED   Caller still has message.
+ *             MACH_SEND_INVALID_DEST  Caller still has message.
  */
+
+
 mach_msg_return_t
 ipc_kmsg_send(
        ipc_kmsg_t              kmsg,
@@ -1326,12 +1365,22 @@ ipc_kmsg_send(
        mach_msg_return_t error = MACH_MSG_SUCCESS;
        spl_t s;
 
-       port = (ipc_port_t) kmsg->ikm_header->msgh_remote_port;
-       assert(IP_VALID(port));
+#if IMPORTANCE_INHERITANCE
+       boolean_t did_importance = FALSE;
+#if IMPORTANCE_DEBUG
+       mach_msg_id_t imp_msgh_id = -1;
+       int           sender_pid  = -1;
+#endif /* IMPORTANCE_DEBUG */
+#endif /* IMPORTANCE_INHERITANCE */
 
-       if ((option & ~(MACH_SEND_TIMEOUT|MACH_SEND_ALWAYS)) != 0)
-               printf("ipc_kmsg_send: bad option 0x%x\n", option);
+       /* don't allow the creation of a circular loop */
+       if (kmsg->ikm_header->msgh_bits & MACH_MSGH_BITS_CIRCULAR) {
+               ipc_kmsg_destroy(kmsg);
+               return MACH_MSG_SUCCESS;
+       }
 
+       port = (ipc_port_t) kmsg->ikm_header->msgh_remote_port;
+       assert(IP_VALID(port));
        ip_lock(port);
 
        if (port->ip_receiver == ipc_space_kernel) {
@@ -1361,6 +1410,10 @@ ipc_kmsg_send(
                /* fall thru with reply - same options */
        }
 
+#if IMPORTANCE_INHERITANCE
+ retry:
+#endif /* IMPORTANCE_INHERITANCE */
+
        /*
         *      Can't deliver to a dead port.
         *      However, we can pretend it got sent
@@ -1373,22 +1426,46 @@ ipc_kmsg_send(
                 *      in an infinite loop trying to deliver
                 *      a send-once notification.
                 */
-
+               ip_unlock(port);
                ip_release(port);
-               ip_check_unlock(port);
                kmsg->ikm_header->msgh_remote_port = MACH_PORT_NULL;
                ipc_kmsg_destroy(kmsg);
                return MACH_MSG_SUCCESS;
        }
 
-       if (kmsg->ikm_header->msgh_bits & MACH_MSGH_BITS_CIRCULAR) {
-               ip_unlock(port);
-
-               /* don't allow the creation of a circular loop */
+#if IMPORTANCE_INHERITANCE
+       /*
+        * Need to see if this message needs importance donation and/or
+        * propagation.  That routine can drop the port lock.  If it does
+        * we'll have to revalidate the destination.
+        */
+       if ((did_importance == FALSE) &&
+           (port->ip_impdonation != 0) &&
+           ((option & MACH_SEND_NOIMPORTANCE) == 0) &&
+           (((option & MACH_SEND_IMPORTANCE) != 0) ||
+            (task_is_importance_donor(current_task())))) {
+
+               did_importance = TRUE;
+               kmsg->ikm_header->msgh_bits |= MACH_MSGH_BITS_RAISEIMP;
+                               
+#if IMPORTANCE_DEBUG
+               if (kdebug_enable) {
+                       mach_msg_max_trailer_t *dbgtrailer = (mach_msg_max_trailer_t *)
+                               ((vm_offset_t)kmsg->ikm_header + round_msg(kmsg->ikm_header->msgh_size));
+                       sender_pid = dbgtrailer->msgh_audit.val[5];
+                       imp_msgh_id = kmsg->ikm_header->msgh_id;
+
+                       KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, (IMPORTANCE_CODE(IMP_MSG, IMP_MSG_SEND)) | DBG_FUNC_START,
+                                                  audit_token_pid_from_task(current_task()), sender_pid, imp_msgh_id, 0, 0);
+               }
+#endif /* IMPORTANCE_DEBUG */
 
-               ipc_kmsg_destroy(kmsg);
-               return MACH_MSG_SUCCESS;
+               if (ipc_port_importance_delta(port, 1) == TRUE) {
+                       ip_lock(port);
+                       goto retry;
+               }
        }
+#endif /* IMPORTANCE_INHERITANCE */
 
        /*
         * We have a valid message and a valid reference on the port.
@@ -1398,9 +1475,59 @@ ipc_kmsg_send(
        s = splsched();
        imq_lock(&port->ip_messages);
        ip_unlock(port);
+
        error = ipc_mqueue_send(&port->ip_messages, kmsg, option, 
                        send_timeout, s);
 
+#if IMPORTANCE_INHERITANCE
+       if (did_importance == TRUE) {
+               __unused int importance_cleared = 0;
+               switch (error) {
+                       case MACH_SEND_TIMED_OUT:
+                       case MACH_SEND_NO_BUFFER:
+                       case MACH_SEND_INTERRUPTED:
+                               /*
+                                * We still have the kmsg and its
+                                * reference on the port.  But we
+                                * have to back out the importance
+                                * boost.
+                                *
+                                * The port could have changed hands,
+                                * be inflight to another destination,
+                                * etc...  But in those cases our
+                                * back-out will find the new owner
+                                * (and all the operations that
+                                * transferred the right should have
+                                * applied their own boost adjustments
+                                * to the old owner(s)).
+                                */
+                               importance_cleared = 1;
+                               ip_lock(port);
+                               if (ipc_port_importance_delta(port, -1) == FALSE)
+                                       ip_unlock(port);
+                               break;
+
+                       case MACH_SEND_INVALID_DEST:
+                               /*
+                                * In the case that the receive right has
+                                * gone away, the assertion count for the
+                                * message we were trying to enqueue was
+                                * already subtracted from the destination
+                                * task (as part of port destruction).
+                                */
+                               break;
+
+                       case MACH_MSG_SUCCESS:
+                       default:
+                               break;
+               }
+#if IMPORTANCE_DEBUG
+               KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, (IMPORTANCE_CODE(IMP_MSG, IMP_MSG_SEND)) | DBG_FUNC_END,
+                                         audit_token_pid_from_task(current_task()), sender_pid, imp_msgh_id, importance_cleared, 0);
+#endif /* IMPORTANCE_DEBUG */
+       }
+#endif /* IMPORTANCE_INHERITANCE */
+
        /*
         * If the port has been destroyed while we wait, treat the message
         * as a successful delivery (like we do for an inactive port).
@@ -1526,16 +1653,6 @@ ipc_kmsg_put_to_kernel(
  *             and the bits field is updated.  The destination port
  *             will be a valid port pointer.
  *
- *             The notify argument implements the MACH_SEND_CANCEL option.
- *             If it is not MACH_PORT_NULL, it should name a receive right.
- *             If the processing of the destination port would generate
- *             a port-deleted notification (because the right for the
- *             destination port is destroyed and it had a request for
- *             a dead-name notification registered), and the port-deleted
- *             notification would be sent to the named receive right,
- *             then it isn't sent and the send-once right for the notify
- *             port is quietly destroyed.
- *
  *     Conditions:
  *             Nothing locked.
  *     Returns:
@@ -1543,9 +1660,6 @@ ipc_kmsg_put_to_kernel(
  *             MACH_SEND_INVALID_HEADER
  *                     Illegal value in the message header bits.
  *             MACH_SEND_INVALID_DEST  The space is dead.
- *             MACH_SEND_INVALID_NOTIFY
- *                     Notify is non-null and doesn't name a receive right.
- *                     (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
  *             MACH_SEND_INVALID_DEST  Can't copyin destination port.
  *                     (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
  *             MACH_SEND_INVALID_REPLY Can't copyin reply port.
@@ -1556,7 +1670,7 @@ mach_msg_return_t
 ipc_kmsg_copyin_header(
        mach_msg_header_t       *msg,
        ipc_space_t             space,
-       mach_port_name_t        notify)
+       mach_msg_option_t       *optionp)
 {
        mach_msg_bits_t mbits = msg->msgh_bits & MACH_MSGH_BITS_USER;
        mach_port_name_t dest_name = CAST_MACH_PORT_TO_NAME(msg->msgh_remote_port);
@@ -1566,9 +1680,20 @@ ipc_kmsg_copyin_header(
        mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
        mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
        ipc_object_t dest_port, reply_port;
+       ipc_entry_t dest_entry, reply_entry;
        ipc_port_t dest_soright, reply_soright;
-       ipc_port_t notify_port;
-       ipc_entry_t entry;
+       ipc_port_t release_port = IP_NULL;
+
+#if IMPORTANCE_INHERITANCE
+       int assertcnt = 0;
+       boolean_t needboost = FALSE;
+#endif /* IMPORTANCE_INHERITANCE */
+
+       queue_head_t links_data;
+       queue_t links = &links_data;
+       wait_queue_link_t wql;
+
+       queue_init(links);
 
        if ((mbits != msg->msgh_bits) ||
            (!MACH_MSG_TYPE_PORT_ANY_SEND(dest_type)) ||
@@ -1580,7 +1705,7 @@ ipc_kmsg_copyin_header(
        reply_soright = IP_NULL; /* in case we go to invalid dest early */
 
        is_write_lock(space);
-       if (!space->is_active)
+       if (!is_active(space))
                goto invalid_dest;
 
        if (!MACH_PORT_VALID(dest_name))
@@ -1592,10 +1717,10 @@ ipc_kmsg_copyin_header(
         * because copying the header involves copying the port rights too
         * and we need to do the send check before anything is actually copied.
         */
-       entry = ipc_entry_lookup(space, dest_name);
-       if (entry != IE_NULL) {
+       dest_entry = ipc_entry_lookup(space, dest_name);
+       if (dest_entry != IE_NULL) {
                int error = 0;
-               ipc_port_t port = (ipc_port_t) entry->ie_object;
+               ipc_port_t port = (ipc_port_t) dest_entry->ie_object;
                if (port == IP_NULL)
                        goto invalid_dest;
                ip_lock(port);
@@ -1612,20 +1737,6 @@ ipc_kmsg_copyin_header(
        }
 #endif
 
-       if (notify != MACH_PORT_NULL) {
-               if ((entry = ipc_entry_lookup(space, notify)) == IE_NULL) {
-                       is_write_unlock(space);
-                       return MACH_SEND_INVALID_NOTIFY;
-               }
-               if((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0) {
-                       is_write_unlock(space);
-                       return MACH_SEND_INVALID_NOTIFY;
-               }
-
-               notify_port = (ipc_port_t) entry->ie_object;
-       } else
-               notify_port = IP_NULL;
-
        if (dest_name == reply_name) {
                mach_port_name_t name = dest_name;
 
@@ -1641,13 +1752,14 @@ ipc_kmsg_copyin_header(
                 *      copy-send and make-send.
                 */
 
-               entry = ipc_entry_lookup(space, name);
-               if (entry == IE_NULL)
+               dest_entry = ipc_entry_lookup(space, name);
+               if (dest_entry == IE_NULL)
                        goto invalid_dest;
 
+               reply_entry = dest_entry;
                assert(reply_type != 0); /* because name not null */
 
-               if (!ipc_right_copyin_check(space, name, entry, reply_type))
+               if (!ipc_right_copyin_check(space, name, reply_entry, reply_type))
                        goto invalid_reply;
 
                if ((dest_type == MACH_MSG_TYPE_MOVE_SEND_ONCE) ||
@@ -1668,9 +1780,23 @@ ipc_kmsg_copyin_header(
                           (dest_type == MACH_MSG_TYPE_MAKE_SEND_ONCE) ||
                           (reply_type == MACH_MSG_TYPE_MAKE_SEND) ||
                           (reply_type == MACH_MSG_TYPE_MAKE_SEND_ONCE)) {
-                       kr = ipc_right_copyin(space, name, entry,
+
+#if IMPORTANCE_INHERITANCE
+                       kr = ipc_right_copyin(space, name, dest_entry,
+                                             dest_type, FALSE,
+                                             &dest_port, &dest_soright,
+                                             &release_port,
+                                             &assertcnt,
+                                             links);
+                       assert(assertcnt == 0);
+#else
+                       kr = ipc_right_copyin(space, name, dest_entry,
                                              dest_type, FALSE,
-                                             &dest_port, &dest_soright);
+                                             &dest_port, &dest_soright,
+                                             &release_port,
+                                             links);
+#endif /* IMPORTANCE_INHERITANCE */
+
                        if (kr != KERN_SUCCESS)
                                goto invalid_dest;
 
@@ -1685,16 +1811,27 @@ ipc_kmsg_copyin_header(
                         */
 
                        assert(IO_VALID(dest_port));
-                       assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
                        assert(dest_soright == IP_NULL);
 
-                       kr = ipc_right_copyin(space, name, entry,
+#if IMPORTANCE_INHERITANCE
+                       kr = ipc_right_copyin(space, name, reply_entry,
                                              reply_type, TRUE,
-                                             &reply_port, &reply_soright);
+                                             &reply_port, &reply_soright,
+                                             &release_port,
+                                             &assertcnt,
+                                             links);
+                       assert(assertcnt == 0);
+#else
+                       kr = ipc_right_copyin(space, name, reply_entry,
+                                             reply_type, TRUE,
+                                             &reply_port, &reply_soright,
+                                             &release_port,
+                                             links);
+#endif /* IMPORTANCE_INHERITANCE */
 
                        assert(kr == KERN_SUCCESS);
                        assert(reply_port == dest_port);
-                       assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
+                       assert(reply_entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
                        assert(reply_soright == IP_NULL);
                } else if ((dest_type == MACH_MSG_TYPE_COPY_SEND) &&
                           (reply_type == MACH_MSG_TYPE_COPY_SEND)) {
@@ -1703,13 +1840,26 @@ ipc_kmsg_copyin_header(
                         *      and dup the send right we get out.
                         */
 
-                       kr = ipc_right_copyin(space, name, entry,
+#if IMPORTANCE_INHERITANCE
+                       kr = ipc_right_copyin(space, name, dest_entry,
                                              dest_type, FALSE,
-                                             &dest_port, &dest_soright);
+                                             &dest_port, &dest_soright,
+                                             &release_port,
+                                             &assertcnt,
+                                             links);
+                       assert(assertcnt == 0);
+#else
+                       kr = ipc_right_copyin(space, name, dest_entry,
+                                             dest_type, FALSE,
+                                             &dest_port, &dest_soright,
+                                             &release_port,
+                                             links);
+#endif /* IMPORTANCE_INHERITANCE */
+
                        if (kr != KERN_SUCCESS)
                                goto invalid_dest;
 
-                       assert(entry->ie_bits & MACH_PORT_TYPE_SEND);
+                       assert(dest_entry->ie_bits & MACH_PORT_TYPE_SEND);
                        assert(dest_soright == IP_NULL);
 
                        /*
@@ -1729,14 +1879,17 @@ ipc_kmsg_copyin_header(
                         *      to get two send rights for the price of one.
                         */
 
-                       kr = ipc_right_copyin_two(space, name, entry,
-                                                 &dest_port, &dest_soright);
+                       kr = ipc_right_copyin_two(space, name, dest_entry,
+                                                 &dest_port, &dest_soright,
+                                                 &release_port);
                        if (kr != KERN_SUCCESS)
                                goto invalid_dest;
 
                        /* the entry might need to be deallocated */
-                       if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
-                               ipc_entry_dealloc(space, name, entry);
+                       if (IE_BITS_TYPE(dest_entry->ie_bits) == MACH_PORT_TYPE_NONE) {
+                               ipc_entry_dealloc(space, name, dest_entry);
+                               dest_entry = IE_NULL;
+                       }
 
                        reply_port = dest_port;
                        reply_soright = IP_NULL;
@@ -1753,16 +1906,31 @@ ipc_kmsg_copyin_header(
                         *      and dup the send right we get out.
                         */
 
-                       kr = ipc_right_copyin(space, name, entry,
+#if IMPORTANCE_INHERITANCE
+                       kr = ipc_right_copyin(space, name, dest_entry,
                                              MACH_MSG_TYPE_MOVE_SEND, FALSE,
-                                             &dest_port, &soright);
+                                             &dest_port, &soright,
+                                             &release_port,
+                                             &assertcnt,
+                                             links);
+                       assert(assertcnt == 0);
+#else
+                       kr = ipc_right_copyin(space, name, dest_entry,
+                                             MACH_MSG_TYPE_MOVE_SEND, FALSE,
+                                             &dest_port, &soright,
+                                             &release_port,
+                                             links);
+#endif /* IMPORTANCE_INHERITANCE */
+
                        if (kr != KERN_SUCCESS)
                                goto invalid_dest;
 
                        /* the entry might need to be deallocated */
 
-                       if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
-                               ipc_entry_dealloc(space, name, entry);
+                       if (IE_BITS_TYPE(dest_entry->ie_bits) == MACH_PORT_TYPE_NONE) {
+                               ipc_entry_dealloc(space, name, dest_entry);
+                               dest_entry = IE_NULL;
+                       }
 
                        /*
                         *      It's OK if the port we got is dead now,
@@ -1787,26 +1955,38 @@ ipc_kmsg_copyin_header(
                 *      to make atomic.  Just copyin the destination.
                 */
 
-               entry = ipc_entry_lookup(space, dest_name);
-               if (entry == IE_NULL)
+               dest_entry = ipc_entry_lookup(space, dest_name);
+               if (dest_entry == IE_NULL)
                        goto invalid_dest;
 
-               kr = ipc_right_copyin(space, dest_name, entry,
+#if IMPORTANCE_INHERITANCE
+               kr = ipc_right_copyin(space, dest_name, dest_entry,
+                                     dest_type, FALSE,
+                                     &dest_port, &dest_soright,
+                                     &release_port,
+                                     &assertcnt,
+                                     links);
+               assert(assertcnt == 0);
+#else
+               kr = ipc_right_copyin(space, dest_name, dest_entry,
                                      dest_type, FALSE,
-                                     &dest_port, &dest_soright);
+                                     &dest_port, &dest_soright,
+                                     &release_port,
+                                     links);
+#endif /* IMPORTANCE_INHERITANCE */
+
                if (kr != KERN_SUCCESS)
                        goto invalid_dest;
 
                /* the entry might need to be deallocated */
-
-               if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
-                       ipc_entry_dealloc(space, dest_name, entry);
+               if (IE_BITS_TYPE(dest_entry->ie_bits) == MACH_PORT_TYPE_NONE) {
+                       ipc_entry_dealloc(space, dest_name, dest_entry);
+                       dest_entry = IE_NULL;
+               }
 
                reply_port = (ipc_object_t)CAST_MACH_NAME_TO_PORT(reply_name);
                reply_soright = IP_NULL;
        } else {
-               ipc_entry_t dest_entry, reply_entry;
-
                /*
                 *      This is the tough case to make atomic.
                 *      The difficult problem is serializing with port death.
@@ -1839,7 +2019,7 @@ ipc_kmsg_copyin_header(
                 * JMM - The code to handle this was too expensive and, anyway,
                 * we intend to separate the dest lookup from the reply copyin
                 * by a wide margin, so the user will have to learn to deal!
-                * I will be making the change soon!
+                * I will be making the change soon in rdar://problem/6275821.
                 */
 
                dest_entry = ipc_entry_lookup(space, dest_name);
@@ -1857,73 +2037,162 @@ ipc_kmsg_copyin_header(
                                            reply_type))
                        goto invalid_reply;
 
+#if IMPORTANCE_INHERITANCE
+               kr = ipc_right_copyin(space, dest_name, dest_entry,
+                                     dest_type, FALSE,
+                                     &dest_port, &dest_soright,
+                                     &release_port,
+                                     &assertcnt,
+                                     links);
+               assert(assertcnt == 0);
+#else
                kr = ipc_right_copyin(space, dest_name, dest_entry,
                                      dest_type, FALSE,
-                                     &dest_port, &dest_soright);
+                                     &dest_port, &dest_soright,
+                                     &release_port,
+                                     links);
+#endif /* IMPORTANCE_INHERITANCE */
+
                if (kr != KERN_SUCCESS)
                        goto invalid_dest;
 
                assert(IO_VALID(dest_port));
 
+#if IMPORTANCE_INHERITANCE
                kr = ipc_right_copyin(space, reply_name, reply_entry,
                                      reply_type, TRUE,
-                                     &reply_port, &reply_soright);
+                                     &reply_port, &reply_soright,
+                                     &release_port,
+                                     &assertcnt,
+                                     links);
+               assert(assertcnt == 0);
+#else
+               kr = ipc_right_copyin(space, reply_name, reply_entry,
+                                     reply_type, TRUE,
+                                     &reply_port, &reply_soright,
+                                     &release_port,
+                                     links);
+#endif /* IMPORTANCE_INHERITANCE */
 
                assert(kr == KERN_SUCCESS);
 
                /* the entries might need to be deallocated */
 
-               if (IE_BITS_TYPE(reply_entry->ie_bits) == MACH_PORT_TYPE_NONE)
+               if (IE_BITS_TYPE(reply_entry->ie_bits) == MACH_PORT_TYPE_NONE) {
                        ipc_entry_dealloc(space, reply_name, reply_entry);
+                       reply_entry = IE_NULL;
+               }
 
-               if (IE_BITS_TYPE(dest_entry->ie_bits) == MACH_PORT_TYPE_NONE)
+               if (IE_BITS_TYPE(dest_entry->ie_bits) == MACH_PORT_TYPE_NONE) {
                        ipc_entry_dealloc(space, dest_name, dest_entry);
+                       dest_entry = IE_NULL;
+               }
        }
 
+       dest_type = ipc_object_copyin_type(dest_type);
+       reply_type = ipc_object_copyin_type(reply_type);
+
        /*
-        *      At this point, dest_port, reply_port,
-        *      dest_soright, reply_soright are all initialized.
-        *      Any defunct entries have been deallocated.
-        *      The space is still write-locked, and we need to
-        *      make the MACH_SEND_CANCEL check.  The notify_port pointer
-        *      is still usable, because the copyin code above won't ever
-        *      deallocate a receive right, so its entry still exists
-        *      and holds a ref.  Note notify_port might even equal
-        *      dest_port or reply_port.
+        * JMM - Without rdar://problem/6275821, this is the last place we can
+        * re-arm the send-possible notifications.  It may trigger unexpectedly
+        * early (send may NOT have failed), but better than missing.  We assure
+        * we won't miss by forcing MACH_SEND_ALWAYS if we got past arming.
         */
+       if (((*optionp & MACH_SEND_NOTIFY) != 0) && 
+           dest_type != MACH_MSG_TYPE_PORT_SEND_ONCE &&
+           dest_entry != IE_NULL && dest_entry->ie_request != IE_REQ_NONE) {
+               ipc_port_t dport = (ipc_port_t)dest_port;
+
+               assert(dport != IP_NULL);
+               ip_lock(dport);
+               if (ip_active(dport) && dport->ip_receiver != ipc_space_kernel) {
+                       if (ip_full(dport)) {
+#if IMPORTANCE_INHERITANCE
+                               needboost = ipc_port_request_sparm(dport, dest_name, 
+                                                       dest_entry->ie_request,
+                                                       (*optionp & MACH_SEND_NOIMPORTANCE));
+                               if (needboost == FALSE)
+                                       ip_unlock(dport);
+#else
 
-       if ((notify != MACH_PORT_NULL) &&
-           (dest_soright == notify_port)) {
-               ipc_port_release_sonce(dest_soright);
-               dest_soright = IP_NULL;
+                               ipc_port_request_sparm(dport, dest_name, dest_entry->ie_request);
+                               ip_unlock(dport);
+#endif /* IMPORTANCE_INHERITANCE */
+                       } else {
+                               *optionp |= MACH_SEND_ALWAYS;
+                               ip_unlock(dport);
+                       }
+               } else {
+                       ip_unlock(dport);
+               }
        }
 
        is_write_unlock(space);
 
+#if IMPORTANCE_INHERITANCE
+       /* 
+        * If our request is the first boosting send-possible
+        * notification this cycle, push the boost down the
+        * destination port.
+        */
+       if (needboost == TRUE) {
+               ipc_port_t dport = (ipc_port_t)dest_port;
+
+               /* dport still locked from above */
+               if (ipc_port_importance_delta(dport, 1) == FALSE)
+                       ip_unlock(dport);
+       }
+#endif /* IMPORTANCE_INHERITANCE */
+
        if (dest_soright != IP_NULL)
                ipc_notify_port_deleted(dest_soright, dest_name);
 
        if (reply_soright != IP_NULL)
                ipc_notify_port_deleted(reply_soright, reply_name);
 
-       dest_type = ipc_object_copyin_type(dest_type);
-       reply_type = ipc_object_copyin_type(reply_type);
-
        msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
                          MACH_MSGH_BITS(dest_type, reply_type));
        msg->msgh_remote_port = (ipc_port_t)dest_port;
        msg->msgh_local_port = (ipc_port_t)reply_port;
 
+       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);
+
+
        return MACH_MSG_SUCCESS;
 
 invalid_reply:
        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);
+
        return MACH_SEND_INVALID_REPLY;
 
 invalid_dest:
        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 (reply_soright != IP_NULL)
                ipc_notify_port_deleted(reply_soright, reply_name);
+
        return MACH_SEND_INVALID_DEST;
 }
 
@@ -2351,6 +2620,13 @@ ipc_kmsg_copyin_body(
                 * Out-of-line memory descriptor, accumulate kernel
                 * memory requirements
                 */
+               if (space_needed + round_page(size) <= space_needed) {
+                   /* Overflow dectected */
+                   ipc_kmsg_clean_partial(kmsg, 0, NULL, 0, 0);
+                   mr = MACH_MSG_VM_KERNEL;
+                   goto out;
+               }                   
+                   
                space_needed += round_page(size);
                if (space_needed > ipc_kmsg_max_vm_space) {
                    
@@ -2455,7 +2731,6 @@ ipc_kmsg_copyin_body(
  *             MACH_MSG_SUCCESS        Successful copyin.
  *             MACH_SEND_INVALID_HEADER
  *                     Illegal value in the message header bits.
- *             MACH_SEND_INVALID_NOTIFY        Bad notify port.
  *             MACH_SEND_INVALID_DEST  Can't copyin destination port.
  *             MACH_SEND_INVALID_REPLY Can't copyin reply port.
  *             MACH_SEND_INVALID_MEMORY        Can't grab out-of-line memory.
@@ -2469,11 +2744,14 @@ ipc_kmsg_copyin(
        ipc_kmsg_t              kmsg,
        ipc_space_t             space,
        vm_map_t                map,
-       mach_port_name_t        notify)
+       mach_msg_option_t       *optionp)
 {
     mach_msg_return_t          mr;
-    
-    mr = ipc_kmsg_copyin_header(kmsg->ikm_header, space, notify);
+
+    kmsg->ikm_header->msgh_bits &= MACH_MSGH_BITS_USER;
+
+    mr = ipc_kmsg_copyin_header(kmsg->ikm_header, space, optionp);
+
     if (mr != MACH_MSG_SUCCESS)
        return mr;
     
@@ -2499,6 +2777,7 @@ ipc_kmsg_copyin(
                        kprintf("%.4x\n",((uint32_t *)(kmsg->ikm_header + 1))[i]);
                }
        }
+
        return mr;
 }
 
@@ -2511,14 +2790,11 @@ ipc_kmsg_copyin(
  *             Because the message comes from the kernel,
  *             the implementation assumes there are no errors
  *             or peculiarities in the message.
- *
- *             Returns TRUE if queueing the message
- *             would result in a circularity.
  *     Conditions:
  *             Nothing locked.
  */
 
-void
+mach_msg_return_t
 ipc_kmsg_copyin_from_kernel(
        ipc_kmsg_t      kmsg)
 {
@@ -2529,6 +2805,8 @@ ipc_kmsg_copyin_from_kernel(
        ipc_object_t local = (ipc_object_t) kmsg->ikm_header->msgh_local_port;
 
        /* translate the destination and reply ports */
+       if (!IO_VALID(remote))
+               return MACH_SEND_INVALID_DEST;
 
        ipc_object_copyin_from_kernel(remote, rname);
        if (IO_VALID(local))
@@ -2552,7 +2830,7 @@ ipc_kmsg_copyin_from_kernel(
 
                kmsg->ikm_header->msgh_bits = bits;
                if ((bits & MACH_MSGH_BITS_COMPLEX) == 0)
-                       return;
+                       return MACH_MSG_SUCCESS;
        }
     {
        mach_msg_descriptor_t   *saddr;
@@ -2646,10 +2924,11 @@ ipc_kmsg_copyin_from_kernel(
            }
        }
     }
+    return MACH_MSG_SUCCESS;
 }
 
 #if IKM_SUPPORT_LEGACY
-void
+mach_msg_return_t
 ipc_kmsg_copyin_from_kernel_legacy(
        ipc_kmsg_t      kmsg)
 {
@@ -2660,6 +2939,8 @@ ipc_kmsg_copyin_from_kernel_legacy(
        ipc_object_t local = (ipc_object_t) kmsg->ikm_header->msgh_local_port;
 
        /* translate the destination and reply ports */
+       if (!IO_VALID(remote))
+               return MACH_SEND_INVALID_DEST;
 
        ipc_object_copyin_from_kernel(remote, rname);
        if (IO_VALID(local))
@@ -2683,7 +2964,7 @@ ipc_kmsg_copyin_from_kernel_legacy(
 
                kmsg->ikm_header->msgh_bits = bits;
                if ((bits & MACH_MSGH_BITS_COMPLEX) == 0)
-                       return;
+                       return MACH_MSG_SUCCESS;
        }
     {
        mach_msg_legacy_descriptor_t    *saddr;
@@ -2816,6 +3097,7 @@ ipc_kmsg_copyin_from_kernel_legacy(
            }
        }
     }
+    return MACH_MSG_SUCCESS;
 }
 #endif /* IKM_SUPPORT_LEGACY */
 
@@ -2828,13 +3110,6 @@ ipc_kmsg_copyin_from_kernel_legacy(
  *             If it does succeed the remote/local port fields
  *             contain port names instead of object pointers,
  *             and the bits field is updated.
- *
- *             The notify argument implements the MACH_RCV_NOTIFY option.
- *             If it is not MACH_PORT_NULL, it should name a receive right.
- *             If the process of receiving the reply port creates a
- *             new right in the receiving task, then the new right is
- *             automatically registered for a dead-name notification,
- *             with the notify port supplying the send-once right.
  *     Conditions:
  *             Nothing locked.
  *     Returns:
@@ -2855,79 +3130,49 @@ ipc_kmsg_copyin_from_kernel_legacy(
 mach_msg_return_t
 ipc_kmsg_copyout_header(
        mach_msg_header_t       *msg,
-       ipc_space_t             space,
-       mach_port_name_t        notify)
+       ipc_space_t             space)
 {
        mach_msg_bits_t mbits = msg->msgh_bits;
        ipc_port_t dest = (ipc_port_t) msg->msgh_remote_port;
 
        assert(IP_VALID(dest));
 
+       /*
+        * While we still hold a reference on the received-from port,
+        * process all send-possible notfications we received along with
+        * the message.
+        */
+       ipc_port_spnotify(dest);
+
     {
        mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
        mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
        ipc_port_t reply = (ipc_port_t) msg->msgh_local_port;
+       ipc_port_t release_port = IP_NULL;
        mach_port_name_t dest_name, reply_name;
 
        if (IP_VALID(reply)) {
-               ipc_port_t notify_port;
                ipc_entry_t entry;
                kern_return_t kr;
 
                /*
-                *      Handling notify (for MACH_RCV_NOTIFY) is tricky.
-                *      The problem is atomically making a send-once right
-                *      from the notify port and installing it for a
-                *      dead-name request in the new entry, because this
-                *      requires two port locks (on the notify port and
-                *      the reply port).  However, we can safely make
-                *      and consume send-once rights for the notify port
-                *      as long as we hold the space locked.  This isn't
-                *      an atomicity problem, because the only way
-                *      to detect that a send-once right has been created
-                *      and then consumed if it wasn't needed is by getting
-                *      at the receive right to look at ip_sorights, and
-                *      because the space is write-locked status calls can't
-                *      lookup the notify port receive right.  When we make
-                *      the send-once right, we lock the notify port,
-                *      so any status calls in progress will be done.
+                *      Get reply port entry (if none, skip to dest port
+                *      copyout).  This may require growing the space.
                 */
 
                is_write_lock(space);
 
                for (;;) {
-                       ipc_port_request_index_t request;
-
-                       if (!space->is_active) {
+                       if (!is_active(space)) {
                                is_write_unlock(space);
                                return (MACH_RCV_HEADER_ERROR|
                                        MACH_MSG_IPC_SPACE);
                        }
 
-                       if (notify != MACH_PORT_NULL) {
-                               notify_port = ipc_port_lookup_notify(space,
-                                                                    notify);
-                               if (notify_port == IP_NULL) {
-                                       printf("ipc_kmsg_copyout_header: no notify port\n");
-                                       is_write_unlock(space);
-                                       return MACH_RCV_INVALID_NOTIFY;
-                               }
-                       } else
-                               notify_port = IP_NULL;
-
                        if ((reply_type != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
                            ipc_right_reverse(space, (ipc_object_t) reply,
                                              &reply_name, &entry)) {
                                /* reply port is locked and active */
-
-                               /*
-                                *      We don't need the notify_port
-                                *      send-once right, but we can't release
-                                *      it here because reply port is locked.
-                                *      Wait until after the copyout to
-                                *      release the notify port right.
-                                */
-
                                assert(entry->ie_bits &
                                       MACH_PORT_TYPE_SEND_RECEIVE);
                                break;
@@ -2935,15 +3180,11 @@ ipc_kmsg_copyout_header(
 
                        ip_lock(reply);
                        if (!ip_active(reply)) {
-                               ip_release(reply);
-                               ip_check_unlock(reply);
-
-                               if (notify_port != IP_NULL)
-                                       ipc_port_release_sonce(notify_port);
-
+                               ip_unlock(reply);
                                ip_lock(dest);
                                is_write_unlock(space);
 
+                               release_port = reply;
                                reply = IP_DEAD;
                                reply_name = MACH_PORT_DEAD;
                                goto copyout_dest;
@@ -2954,24 +3195,12 @@ ipc_kmsg_copyout_header(
                        if (kr != KERN_SUCCESS) {
                                ip_unlock(reply);
 
-                               if (notify_port != IP_NULL)
-                                       ipc_port_release_sonce(notify_port);
-
                                /* space is locked */
                                kr = ipc_entry_grow_table(space,
                                                          ITS_SIZE_NONE);
                                if (kr != KERN_SUCCESS) {
-                                       /* space is unlocked */
-
-                                       if (kr == KERN_RESOURCE_SHORTAGE) {
-                                               printf("ipc_kmsg_copyout_header: can't grow kernel ipc space\n");
-                                               return (MACH_RCV_HEADER_ERROR|
-                                                       MACH_MSG_IPC_KERNEL);
-                                       } else {
-                                               printf("ipc_kmsg_copyout_header: can't grow user ipc space\n");
-                                               return (MACH_RCV_HEADER_ERROR|
-                                                       MACH_MSG_IPC_SPACE);
-                                       }
+                                       return (MACH_RCV_HEADER_ERROR|
+                                               MACH_MSG_IPC_SPACE);
                                }
                                /* space is locked again; start over */
 
@@ -2981,48 +3210,7 @@ ipc_kmsg_copyout_header(
                               MACH_PORT_TYPE_NONE);
                        assert(entry->ie_object == IO_NULL); 
 
-                       if (notify_port == IP_NULL) {
-                               /* not making a dead-name request */
-
-                               entry->ie_object = (ipc_object_t) reply;
-                               break;
-                       }
-
-                       kr = ipc_port_dnrequest(reply, reply_name,
-                                               notify_port, &request);
-                       if (kr != KERN_SUCCESS) {
-                               ip_unlock(reply);
-
-                               ipc_port_release_sonce(notify_port);
-
-                               ipc_entry_dealloc(space, reply_name, entry);
-                               is_write_unlock(space);
-
-                               ip_lock(reply);
-                               if (!ip_active(reply)) {
-                                       /* will fail next time around loop */
-
-                                       ip_unlock(reply);
-                                       is_write_lock(space);
-                                       continue;
-                               }
-
-                               kr = ipc_port_dngrow(reply, ITS_SIZE_NONE);
-                               /* port is unlocked */
-                               if (kr != KERN_SUCCESS) {
-                                       printf("ipc_kmsg_copyout_header: can't grow kernel ipc space2\n");
-                                       return (MACH_RCV_HEADER_ERROR|
-                                               MACH_MSG_IPC_KERNEL);
-                               }
-
-                               is_write_lock(space);
-                               continue;
-                       }
-
-                       notify_port = IP_NULL; /* don't release right below */
-
                        entry->ie_object = (ipc_object_t) reply;
-                       entry->ie_request = request;
                        break;
                }
 
@@ -3032,46 +3220,26 @@ ipc_kmsg_copyout_header(
 
                kr = ipc_right_copyout(space, reply_name, entry,
                                       reply_type, TRUE, (ipc_object_t) reply);
+
                /* reply port is unlocked */
                assert(kr == KERN_SUCCESS);
 
-               if (notify_port != IP_NULL)
-                       ipc_port_release_sonce(notify_port);
-
                ip_lock(dest);
                is_write_unlock(space);
+
        } else {
                /*
                 *      No reply port!  This is an easy case.
                 *      We only need to have the space locked
-                *      when checking notify and when locking
-                *      the destination (to ensure atomicity).
+                *      when locking the destination.
                 */
 
                is_read_lock(space);
-               if (!space->is_active) {
+               if (!is_active(space)) {
                        is_read_unlock(space);
                        return MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE;
                }
 
-               if (notify != MACH_PORT_NULL) {
-                       ipc_entry_t entry;
-
-                       /* must check notify even though it won't be used */
-
-                       if ((entry = ipc_entry_lookup(space, notify)) == IE_NULL) {
-                               printf("ipc_kmsg_copyout_header: ipc_entry_lookup failed\n");
-                               is_read_unlock(space);
-                               return MACH_RCV_INVALID_NOTIFY;
-                       }
-       
-                       if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0) {
-                               printf("ipc_kmsg_copyout_header: MACH_PORT_TYPE_RECEIVE not set!\n");
-                               is_read_unlock(space);
-                               return MACH_RCV_INVALID_NOTIFY;
-                       }
-               }
-
                ip_lock(dest);
                is_read_unlock(space);
 
@@ -3131,12 +3299,13 @@ ipc_kmsg_copyout_header(
                ipc_object_copyout_dest(space, (ipc_object_t) dest,
                                        dest_type, &dest_name);
                /* dest is unlocked */
+
        } else {
                ipc_port_timestamp_t timestamp;
 
                timestamp = dest->ip_timestamp;
+               ip_unlock(dest);
                ip_release(dest);
-               ip_check_unlock(dest);
 
                if (IP_VALID(reply)) {
                        ip_lock(reply);
@@ -3152,7 +3321,10 @@ ipc_kmsg_copyout_header(
        }
 
        if (IP_VALID(reply))
-               ipc_port_release(reply);
+               ip_release(reply);
+
+       if (IP_VALID(release_port))
+               ip_release(release_port);
 
        msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
                          MACH_MSGH_BITS(reply_type, dest_type));
@@ -3263,7 +3435,7 @@ mach_msg_descriptor_t *
 ipc_kmsg_copyout_ool_descriptor(mach_msg_ool_descriptor_t *dsc, mach_msg_descriptor_t *user_dsc, int is_64bit, vm_map_t map, mach_msg_return_t *mr)
 {
     vm_map_copy_t                      copy;
-    mach_vm_offset_t           rcv_addr;
+    vm_map_address_t                   rcv_addr;
     mach_msg_copy_options_t            copy_options;
     mach_msg_size_t                    size;
     mach_msg_descriptor_type_t dsc_type;
@@ -3402,7 +3574,7 @@ ipc_kmsg_copyout_ool_ports_descriptor(mach_msg_ool_ports_descriptor_t *dsc,
         ipc_kmsg_t kmsg,
         mach_msg_return_t *mr)
 {
-    mach_vm_offset_t           rcv_addr;
+    mach_vm_offset_t           rcv_addr = 0;
     mach_msg_type_name_t               disp;
     mach_msg_type_number_t             count, i;
     vm_size_t                          ports_length, names_length;
@@ -3687,8 +3859,6 @@ ipc_kmsg_copyout_size(
  *             Nothing locked.
  *     Returns:
  *             MACH_MSG_SUCCESS        Copied out all rights and memory.
- *             MACH_RCV_INVALID_NOTIFY Bad notify port.
- *                     Rights and memory in the message are intact.
  *             MACH_RCV_HEADER_ERROR + special bits
  *                     Rights and memory in the message are intact.
  *             MACH_RCV_BODY_ERROR + special bits
@@ -3701,12 +3871,11 @@ ipc_kmsg_copyout(
        ipc_kmsg_t              kmsg,
        ipc_space_t             space,
        vm_map_t                map,
-       mach_port_name_t        notify,
        mach_msg_body_t         *slist)
 {
        mach_msg_return_t mr;
 
-       mr = ipc_kmsg_copyout_header(kmsg->ikm_header, space, notify);
+       mr = ipc_kmsg_copyout_header(kmsg->ikm_header, space);
        if (mr != MACH_MSG_SUCCESS) {
                return mr;
        }
@@ -3761,7 +3930,7 @@ ipc_kmsg_copyout_pseudo(
        mr = (ipc_kmsg_copyout_object(space, dest, dest_type, &dest_name) |
              ipc_kmsg_copyout_object(space, reply, reply_type, &reply_name));
 
-       kmsg->ikm_header->msgh_bits = mbits &~ MACH_MSGH_BITS_CIRCULAR;
+       kmsg->ikm_header->msgh_bits = mbits & MACH_MSGH_BITS_USER;
        kmsg->ikm_header->msgh_remote_port = CAST_MACH_NAME_TO_PORT(dest_name);
        kmsg->ikm_header->msgh_local_port = CAST_MACH_NAME_TO_PORT(reply_name);
 
@@ -3806,8 +3975,8 @@ ipc_kmsg_copyout_dest(
                ipc_object_copyout_dest(space, dest, dest_type, &dest_name);
                /* dest is unlocked */
        } else {
+               io_unlock(dest);
                io_release(dest);
-               io_check_unlock(dest);
                dest_name = MACH_PORT_DEAD;
        }
 
@@ -4024,8 +4193,8 @@ ipc_kmsg_copyout_to_kernel(
                ipc_object_copyout_dest(space, dest, dest_type, &dest_name);
                /* dest is unlocked */
        } else {
+               io_unlock(dest);
                io_release(dest);
-               io_check_unlock(dest);
                dest_name = MACH_PORT_DEAD;
        }
 
@@ -4062,8 +4231,8 @@ ipc_kmsg_copyout_to_kernel_legacy(
                ipc_object_copyout_dest(space, dest, dest_type, &dest_name);
                /* dest is unlocked */
        } else {
+               io_unlock(dest);
                io_release(dest);
-               io_check_unlock(dest);
                dest_name = MACH_PORT_DEAD;
        }
 
@@ -4157,272 +4326,82 @@ ipc_kmsg_copyout_to_kernel_legacy(
 }
 #endif /* IKM_SUPPORT_LEGACY */
 
-
-#include <mach_kdb.h>
-#if    MACH_KDB
-
-#include <ddb/db_output.h>
-#include <ipc/ipc_print.h>
-/*
- * Forward declarations
- */
-void ipc_msg_print_untyped(
-       mach_msg_body_t         *body);
-
-const char * ipc_type_name(
-       int             type_name,
-       boolean_t       received);
-
-const char *
-msgh_bit_decode(
-       mach_msg_bits_t bit);
-
-const char *
-mm_copy_options_string(
-       mach_msg_copy_options_t option);
-
-void db_print_msg_uid(mach_msg_header_t *);
-
-
-const char *
-ipc_type_name(
-       int             type_name,
-       boolean_t       received)
+mach_msg_trailer_size_t
+ipc_kmsg_add_trailer(ipc_kmsg_t kmsg, ipc_space_t space, 
+               mach_msg_option_t option, thread_t thread, 
+               mach_port_seqno_t seqno, boolean_t minimal_trailer,
+               mach_vm_offset_t context)
 {
-       switch (type_name) {
-               case MACH_MSG_TYPE_PORT_NAME:
-               return "port_name";
-               
-               case MACH_MSG_TYPE_MOVE_RECEIVE:
-               if (received) {
-                       return "port_receive";
-               } else {
-                       return "move_receive";
-               }
-               
-               case MACH_MSG_TYPE_MOVE_SEND:
-               if (received) {
-                       return "port_send";
-               } else {
-                       return "move_send";
-               }
-               
-               case MACH_MSG_TYPE_MOVE_SEND_ONCE:
-               if (received) {
-                       return "port_send_once";
-               } else {
-                       return "move_send_once";
-               }
-               
-               case MACH_MSG_TYPE_COPY_SEND:
-               return "copy_send";
-               
-               case MACH_MSG_TYPE_MAKE_SEND:
-               return "make_send";
-               
-               case MACH_MSG_TYPE_MAKE_SEND_ONCE:
-               return "make_send_once";
-               
-               default:
-               return (char *) 0;
-       }
-}
-               
-void
-ipc_print_type_name(
-       int     type_name)
-{
-       const char *name = ipc_type_name(type_name, TRUE);
-       if (name) {
-               printf("%s", name);
-       } else {
-               printf("type%d", type_name);
-       }
-}
+       mach_msg_max_trailer_t *trailer;
 
-/*
- * ipc_kmsg_print      [ debug ]
- */
-void
-ipc_kmsg_print(
-       ipc_kmsg_t      kmsg)
-{
-       iprintf("kmsg=0x%x\n", kmsg);
-       iprintf("ikm_next=0x%x, prev=0x%x, size=%d",
-               kmsg->ikm_next,
-               kmsg->ikm_prev,
-               kmsg->ikm_size);
-       printf("\n");
-       ipc_msg_print(kmsg->ikm_header);
-}
+       (void)thread;
+       trailer = (mach_msg_max_trailer_t *)
+               ((vm_offset_t)kmsg->ikm_header +
+                round_msg(kmsg->ikm_header->msgh_size));
 
-const char *
-msgh_bit_decode(
-       mach_msg_bits_t bit)
-{
-       switch (bit) {
-           case MACH_MSGH_BITS_COMPLEX:        return "complex";
-           case MACH_MSGH_BITS_CIRCULAR:       return "circular";
-           default:                            return (char *) 0;
+       if (!(option & MACH_RCV_TRAILER_MASK)) {
+               return trailer->msgh_trailer_size;
        }
-}
 
-/*
- * ipc_msg_print       [ debug ]
- */
-void
-ipc_msg_print(
-       mach_msg_header_t       *msgh)
-{
-       mach_msg_bits_t mbits;
-       unsigned int    bit, i;
-       const char      *bit_name;
-       int             needs_comma;
-
-       mbits = msgh->msgh_bits;
-       iprintf("msgh_bits=0x%x:  l=0x%x,r=0x%x\n",
-               mbits,
-               MACH_MSGH_BITS_LOCAL(msgh->msgh_bits),
-               MACH_MSGH_BITS_REMOTE(msgh->msgh_bits));
+       trailer->msgh_seqno = seqno;
+       trailer->msgh_context = context;
+       trailer->msgh_trailer_size = REQUESTED_TRAILER_SIZE(thread_is_64bit(thread), option);
 
-       mbits = MACH_MSGH_BITS_OTHER(mbits) & MACH_MSGH_BITS_USED;
-       db_indent += 2;
-       if (mbits)
-               iprintf("decoded bits:  ");
-       needs_comma = 0;
-       for (i = 0, bit = 1; i < sizeof(mbits) * 8; ++i, bit <<= 1) {
-               if ((mbits & bit) == 0)
-                       continue;
-               bit_name = msgh_bit_decode((mach_msg_bits_t)bit);
-               if (bit_name)
-                       printf("%s%s", needs_comma ? "," : "", bit_name);
-               else
-                       printf("%sunknown(0x%x),", needs_comma ? "," : "", bit);
-               ++needs_comma;
-       }
-       if (msgh->msgh_bits & ~MACH_MSGH_BITS_USED) {
-               printf("%sunused=0x%x,", needs_comma ? "," : "",
-                      msgh->msgh_bits & ~MACH_MSGH_BITS_USED);
+       if (minimal_trailer) { 
+               goto done;
        }
-       printf("\n");
-       db_indent -= 2;
 
-       needs_comma = 1;
-       if (msgh->msgh_remote_port) {
-               iprintf("remote=0x%x(", msgh->msgh_remote_port);
-               ipc_print_type_name(MACH_MSGH_BITS_REMOTE(msgh->msgh_bits));
-               printf(")");
-       } else {
-               iprintf("remote=null");
-       }
-
-       if (msgh->msgh_local_port) {
-               printf("%slocal=%p(", needs_comma ? "," : "",
-                      msgh->msgh_local_port);
-               ipc_print_type_name(MACH_MSGH_BITS_LOCAL(msgh->msgh_bits));
-               printf(")\n");
-       } else {
-               printf("local=null\n");
-       }
-
-       iprintf("msgh_id=%d, size=%d\n",
-               msgh->msgh_id,
-               msgh->msgh_size);
-
-       if (mbits & MACH_MSGH_BITS_COMPLEX) {   
-               ipc_msg_print_untyped((mach_msg_body_t *) (msgh + 1));
+       if (MACH_RCV_TRAILER_ELEMENTS(option) >= 
+                       MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AV)){
+#if CONFIG_MACF_MACH
+               if (kmsg->ikm_sender != NULL &&
+                               IP_VALID(kmsg->ikm_header->msgh_remote_port) &&
+                               mac_port_check_method(kmsg->ikm_sender,
+                                       &kmsg->ikm_sender->maclabel,
+                                       &kmsg->ikm_header->msgh_remote_port->ip_label,
+                                       kmsg->ikm_header->msgh_id) == 0)
+                       trailer->msgh_ad = 1;
+               else
+#endif
+                       trailer->msgh_ad = 0;
        }
-}
 
+       /*
+        * The ipc_kmsg_t holds a reference to the label of a label
+        * handle, not the port. We must get a reference to the port
+        * and a send right to copyout to the receiver.
+        */
 
-const char *
-mm_copy_options_string(
-       mach_msg_copy_options_t option)
-{
-       const char      *name;
-
-       switch (option) {
-           case MACH_MSG_PHYSICAL_COPY:
-               name = "PHYSICAL";
-               break;
-           case MACH_MSG_VIRTUAL_COPY:
-               name = "VIRTUAL";
-               break;
-           case MACH_MSG_OVERWRITE:
-               name = "OVERWRITE";
-               break;
-           case MACH_MSG_ALLOCATE:
-               name = "ALLOCATE";
-               break;
-           case MACH_MSG_KALLOC_COPY_T:
-               name = "KALLOC_COPY_T";
-               break;
-           default:
-               name = "unknown";
-               break;
+       if (option & MACH_RCV_TRAILER_ELEMENTS (MACH_RCV_TRAILER_LABELS)) {
+#if CONFIG_MACF_MACH
+               if (kmsg->ikm_sender != NULL) {
+                       ipc_labelh_t  lh = kmsg->ikm_sender->label;
+                       kern_return_t kr;
+
+                       ip_lock(lh->lh_port);
+                       lh->lh_port->ip_mscount++;
+                       lh->lh_port->ip_srights++;
+                       ip_reference(lh->lh_port);
+                       ip_unlock(lh->lh_port);
+
+                       kr = ipc_object_copyout(space, (ipc_object_t)lh->lh_port,
+                                       MACH_MSG_TYPE_PORT_SEND, 0,
+                                       &trailer->msgh_labels.sender);
+                       if (kr != KERN_SUCCESS) {
+                               ip_release(lh->lh_port);
+                               trailer->msgh_labels.sender = 0;
+                       }
+               } else {
+                       trailer->msgh_labels.sender = 0;
+               }
+#else
+               (void)space;
+               trailer->msgh_labels.sender = 0;
+#endif
        }
-       return name;
-}
-
-void
-ipc_msg_print_untyped(
-       mach_msg_body_t         *body)
-{
-    mach_msg_descriptor_t      *saddr, *send;
-    mach_msg_descriptor_type_t type;
-
-    iprintf("%d descriptors %d: \n", body->msgh_descriptor_count);
-
-    saddr = (mach_msg_descriptor_t *) (body + 1);
-    send = saddr + body->msgh_descriptor_count;
-
-    for ( ; saddr < send; saddr++ ) {
-       
-       type = saddr->type.type;
-
-       switch (type) {
-           
-           case MACH_MSG_PORT_DESCRIPTOR: {
-               mach_msg_port_descriptor_t *dsc;
 
-               dsc = &saddr->port;
-               iprintf("-- PORT name = 0x%x disp = ", dsc->name);
-               ipc_print_type_name(dsc->disposition);
-               printf("\n");
-               break;
-           }
-           case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
-           case MACH_MSG_OOL_DESCRIPTOR: {
-               mach_msg_ool_descriptor_t *dsc;
-               
-               dsc = &saddr->out_of_line;
-               iprintf("-- OOL%s addr = 0x%x size = 0x%x copy = %s %s\n",
-                       type == MACH_MSG_OOL_DESCRIPTOR ? "" : " VOLATILE",
-                       dsc->address, dsc->size,
-                       mm_copy_options_string(dsc->copy),
-                       dsc->deallocate ? "DEALLOC" : "");
-               break;
-           } 
-           case MACH_MSG_OOL_PORTS_DESCRIPTOR : {
-               mach_msg_ool_ports_descriptor_t *dsc;
 
-               dsc = &saddr->ool_ports;
+done:
 
-               iprintf("-- OOL_PORTS addr = 0x%x count = 0x%x ",
-                         dsc->address, dsc->count);
-               printf("disp = ");
-               ipc_print_type_name(dsc->disposition);
-               printf(" copy = %s %s\n",
-                      mm_copy_options_string(dsc->copy),
-                      dsc->deallocate ? "DEALLOC" : "");
-               break;
-           }
-
-           default: {
-               iprintf("-- UNKNOWN DESCRIPTOR 0x%x\n", type);
-               break;
-           }
-       }
-    }
+       return trailer->msgh_trailer_size;
 }
-#endif /* MACH_KDB */