]> 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 167d42145944b075292e94151d7ec23c50ec7d6a..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,10 +595,17 @@ 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);
+
+               /* make sure expansion won't cause wrap */
                if (msg_and_trailer_size > MACH_MSG_SIZE_MAX - max_desc)
                        return IKM_NULL;
 
@@ -602,9 +613,7 @@ ipc_kmsg_alloc(
        } 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) {
@@ -674,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 */
        }
 
        /*
@@ -1104,6 +1115,7 @@ ipc_kmsg_prealloc(mach_msg_size_t size)
  *             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.
  */
@@ -1124,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))
@@ -1250,7 +1262,7 @@ 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);
 
        dest_port = (ipc_port_t)msg->msgh_remote_port;
 
@@ -1341,6 +1353,8 @@ ipc_kmsg_get_from_kernel(
  *             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,
@@ -1351,9 +1365,22 @@ ipc_kmsg_send(
        mach_msg_return_t error = MACH_MSG_SUCCESS;
        spl_t s;
 
+#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 */
+
+       /* 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) {
@@ -1383,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
@@ -1395,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.
@@ -1420,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).
@@ -1565,7 +1670,7 @@ mach_msg_return_t
 ipc_kmsg_copyin_header(
        mach_msg_header_t       *msg,
        ipc_space_t             space,
-       boolean_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);
@@ -1575,8 +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_port_t dest_soright, reply_soright;
        ipc_entry_t dest_entry, reply_entry;
+       ipc_port_t dest_soright, reply_soright;
+       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)) ||
@@ -1588,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))
@@ -1663,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)) {
+
+#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;
 
@@ -1682,9 +1813,21 @@ ipc_kmsg_copyin_header(
                        assert(IO_VALID(dest_port));
                        assert(dest_soright == IP_NULL);
 
+#if IMPORTANCE_INHERITANCE
+                       kr = ipc_right_copyin(space, name, reply_entry,
+                                             reply_type, TRUE,
+                                             &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);
+                                             &reply_port, &reply_soright,
+                                             &release_port,
+                                             links);
+#endif /* IMPORTANCE_INHERITANCE */
 
                        assert(kr == KERN_SUCCESS);
                        assert(reply_port == dest_port);
@@ -1697,9 +1840,22 @@ ipc_kmsg_copyin_header(
                         *      and dup the send right we get out.
                         */
 
+#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;
 
@@ -1724,7 +1880,8 @@ ipc_kmsg_copyin_header(
                         */
 
                        kr = ipc_right_copyin_two(space, name, dest_entry,
-                                                 &dest_port, &dest_soright);
+                                                 &dest_port, &dest_soright,
+                                                 &release_port);
                        if (kr != KERN_SUCCESS)
                                goto invalid_dest;
 
@@ -1749,9 +1906,22 @@ ipc_kmsg_copyin_header(
                         *      and dup the send right we get out.
                         */
 
+#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;
 
@@ -1789,9 +1959,22 @@ ipc_kmsg_copyin_header(
                if (dest_entry == IE_NULL)
                        goto invalid_dest;
 
+#if IMPORTANCE_INHERITANCE
                kr = ipc_right_copyin(space, dest_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, dest_name, dest_entry,
+                                     dest_type, FALSE,
+                                     &dest_port, &dest_soright,
+                                     &release_port,
+                                     links);
+#endif /* IMPORTANCE_INHERITANCE */
+
                if (kr != KERN_SUCCESS)
                        goto invalid_dest;
 
@@ -1854,17 +2037,42 @@ 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);
+                                     &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,
+                                     &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,
+                                     &release_port,
+                                     &assertcnt,
+                                     links);
+               assert(assertcnt == 0);
+#else
                kr = ipc_right_copyin(space, reply_name, reply_entry,
                                      reply_type, TRUE,
-                                     &reply_port, &reply_soright);
+                                     &reply_port, &reply_soright,
+                                     &release_port,
+                                     links);
+#endif /* IMPORTANCE_INHERITANCE */
 
                assert(kr == KERN_SUCCESS);
 
@@ -1887,23 +2095,55 @@ ipc_kmsg_copyin_header(
        /*
         * 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.
+        * 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 (notify && dest_type != MACH_MSG_TYPE_PORT_SEND_ONCE &&
+       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 && ip_full(dport)) {
-                       ipc_port_request_sparm(dport, dest_name, dest_entry->ie_request);
+               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
+
+                               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);
                }
-               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);
 
@@ -1915,16 +2155,44 @@ ipc_kmsg_copyin_header(
        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;
 }
 
@@ -2352,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) {
                    
@@ -2469,11 +2744,14 @@ ipc_kmsg_copyin(
        ipc_kmsg_t              kmsg,
        ipc_space_t             space,
        vm_map_t                map,
-       boolean_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,9 +2790,6 @@ 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.
  */
@@ -2872,6 +3148,7 @@ ipc_kmsg_copyout_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_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)) {
@@ -2886,7 +3163,7 @@ ipc_kmsg_copyout_header(
                is_write_lock(space);
 
                for (;;) {
-                       if (!space->is_active) {
+                       if (!is_active(space)) {
                                is_write_unlock(space);
                                return (MACH_RCV_HEADER_ERROR|
                                        MACH_MSG_IPC_SPACE);
@@ -2903,12 +3180,11 @@ ipc_kmsg_copyout_header(
 
                        ip_lock(reply);
                        if (!ip_active(reply)) {
-                               ip_release(reply);
-                               ip_check_unlock(reply);
-
+                               ip_unlock(reply);
                                ip_lock(dest);
                                is_write_unlock(space);
 
+                               release_port = reply;
                                reply = IP_DEAD;
                                reply_name = MACH_PORT_DEAD;
                                goto copyout_dest;
@@ -2944,11 +3220,13 @@ 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);
 
                ip_lock(dest);
                is_write_unlock(space);
+
        } else {
                /*
                 *      No reply port!  This is an easy case.
@@ -2957,7 +3235,7 @@ ipc_kmsg_copyout_header(
                 */
 
                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;
                }
@@ -3021,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);
@@ -3042,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));
@@ -3153,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;
@@ -3292,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;
@@ -3648,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);
 
@@ -3693,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;
        }
 
@@ -3911,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;
        }
 
@@ -3949,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;
        }
 
@@ -4044,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);
-       }
-}
-
-/*
- * 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);
-}
-
-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;
-       }
-}
-
-/*
- * 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;
+       mach_msg_max_trailer_t *trailer;
 
-       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));
+       (void)thread;
+       trailer = (mach_msg_max_trailer_t *)
+               ((vm_offset_t)kmsg->ikm_header +
+                round_msg(kmsg->ikm_header->msgh_size));
 
-       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 (!(option & MACH_RCV_TRAILER_MASK)) {
+               return trailer->msgh_trailer_size;
        }
-       if (msgh->msgh_bits & ~MACH_MSGH_BITS_USED) {
-               printf("%sunused=0x%x,", needs_comma ? "," : "",
-                      msgh->msgh_bits & ~MACH_MSGH_BITS_USED);
-       }
-       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");
-       }
+       trailer->msgh_seqno = seqno;
+       trailer->msgh_context = context;
+       trailer->msgh_trailer_size = REQUESTED_TRAILER_SIZE(thread_is_64bit(thread), option);
 
-       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");
+       if (minimal_trailer) { 
+               goto done;
        }
 
-       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;
        }
-}
-
 
-const char *
-mm_copy_options_string(
-       mach_msg_copy_options_t option)
-{
-       const char      *name;
+       /*
+        * 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.
+        */
 
-       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;
+done:
 
-               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;
-
-               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 */