]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/kern/ipc_mig.c
xnu-6153.101.6.tar.gz
[apple/xnu.git] / osfmk / kern / ipc_mig.c
index 63227588385c00541add842c658e3792d02f2af1..6896e3793bf934969f94070948cce0d6bc702b48 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * unlawful or unlicensed copies of an Apple operating system, or to
  * circumvent, violate, or enable the circumvention or violation of, any
  * terms of an Apple operating system software license agreement.
- * 
+ *
  * Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this file.
- * 
+ *
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  * Please see the License for the specific language governing rights and
  * limitations under the License.
- * 
+ *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
 /*
  * @OSF_COPYRIGHT@
  */
-/* 
+/*
  * Mach Operating System
  * Copyright (c) 1991,1990 Carnegie Mellon University
  * All Rights Reserved.
- * 
+ *
  * Permission to use, copy, modify and distribute this software and its
  * documentation is hereby granted, provided that both the copyright
  * notice and this permission notice appear in all copies of the
  * software, derivative works or modified versions, and any portions
  * thereof, and that both notices appear in supporting documentation.
- * 
+ *
  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- * 
+ *
  * Carnegie Mellon requests users of this software to return to
- * 
+ *
  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
  *  School of Computer Science
  *  Carnegie Mellon University
  *  Pittsburgh PA 15213-3890
- * 
+ *
  * any improvements or extensions that they make and grant Carnegie Mellon
  * the rights to redistribute these changes.
  */
@@ -84,6 +84,9 @@
 
 #include <libkern/OSAtomic.h>
 
+void
+mach_msg_receive_results_complete(ipc_object_t object);
+
 /*
  *     Routine:        mach_msg_send_from_kernel
  *     Purpose:
 
 #undef mach_msg_send_from_kernel
 mach_msg_return_t mach_msg_send_from_kernel(
-       mach_msg_header_t       *msg,
-       mach_msg_size_t         send_size);
+       mach_msg_header_t       *msg,
+       mach_msg_size_t         send_size);
 
 mach_msg_return_t
 mach_msg_send_from_kernel(
-       mach_msg_header_t       *msg,
-       mach_msg_size_t         send_size)
+       mach_msg_header_t       *msg,
+       mach_msg_size_t         send_size)
 {
        ipc_kmsg_t kmsg;
        mach_msg_return_t mr;
 
+       KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_START);
+
        mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg);
-       if (mr != MACH_MSG_SUCCESS)
+       if (mr != MACH_MSG_SUCCESS) {
+               KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
                return mr;
+       }
 
        mr = ipc_kmsg_copyin_from_kernel_legacy(kmsg);
        if (mr != MACH_MSG_SUCCESS) {
                ipc_kmsg_free(kmsg);
+               KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
                return mr;
-       }               
+       }
+
+       /*
+        * respect the thread's SEND_IMPORTANCE option to allow importance
+        * donation from the kernel-side of user threads
+        * (11938665 & 23925818)
+        */
+       mach_msg_option_t option = MACH_SEND_KERNEL_DEFAULT;
+       if (current_thread()->options & TH_OPT_SEND_IMPORTANCE) {
+               option &= ~MACH_SEND_NOIMPORTANCE;
+       }
 
-       mr = ipc_kmsg_send(kmsg, 
-                          MACH_SEND_KERNEL_DEFAULT,
-                          MACH_MSG_TIMEOUT_NONE);
+       mr = ipc_kmsg_send(kmsg, option, MACH_MSG_TIMEOUT_NONE);
        if (mr != MACH_MSG_SUCCESS) {
                ipc_kmsg_destroy(kmsg);
+               KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
        }
 
        return mr;
@@ -140,27 +157,41 @@ mach_msg_send_from_kernel(
 
 mach_msg_return_t
 mach_msg_send_from_kernel_proper(
-       mach_msg_header_t       *msg,
-       mach_msg_size_t         send_size)
+       mach_msg_header_t       *msg,
+       mach_msg_size_t         send_size)
 {
        ipc_kmsg_t kmsg;
        mach_msg_return_t mr;
 
+       KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_START);
+
        mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg);
-       if (mr != MACH_MSG_SUCCESS)
+       if (mr != MACH_MSG_SUCCESS) {
+               KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
                return mr;
+       }
 
        mr = ipc_kmsg_copyin_from_kernel(kmsg);
        if (mr != MACH_MSG_SUCCESS) {
                ipc_kmsg_free(kmsg);
+               KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
                return mr;
        }
 
-       mr = ipc_kmsg_send(kmsg, 
-                          MACH_SEND_KERNEL_DEFAULT,
-                          MACH_MSG_TIMEOUT_NONE);
+       /*
+        * respect the thread's SEND_IMPORTANCE option to force importance
+        * donation from the kernel-side of user threads
+        * (11938665 & 23925818)
+        */
+       mach_msg_option_t option = MACH_SEND_KERNEL_DEFAULT;
+       if (current_thread()->options & TH_OPT_SEND_IMPORTANCE) {
+               option &= ~MACH_SEND_NOIMPORTANCE;
+       }
+
+       mr = ipc_kmsg_send(kmsg, option, MACH_MSG_TIMEOUT_NONE);
        if (mr != MACH_MSG_SUCCESS) {
                ipc_kmsg_destroy(kmsg);
+               KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
        }
 
        return mr;
@@ -168,40 +199,69 @@ mach_msg_send_from_kernel_proper(
 
 mach_msg_return_t
 mach_msg_send_from_kernel_with_options(
-       mach_msg_header_t       *msg,
-       mach_msg_size_t         send_size,
-       mach_msg_option_t       option,
-       mach_msg_timeout_t      timeout_val)
+       mach_msg_header_t       *msg,
+       mach_msg_size_t         send_size,
+       mach_msg_option_t       option,
+       mach_msg_timeout_t      timeout_val)
+{
+       return kernel_mach_msg_send(msg, send_size, option, timeout_val, NULL);
+}
+
+mach_msg_return_t
+kernel_mach_msg_send(
+       mach_msg_header_t       *msg,
+       mach_msg_size_t         send_size,
+       mach_msg_option_t       option,
+       mach_msg_timeout_t      timeout_val,
+       boolean_t               *message_moved)
 {
        ipc_kmsg_t kmsg;
        mach_msg_return_t mr;
 
+       KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_START);
+
+       if (message_moved) {
+               *message_moved = FALSE;
+       }
+
        mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg);
-       if (mr != MACH_MSG_SUCCESS)
+       if (mr != MACH_MSG_SUCCESS) {
+               KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
                return mr;
+       }
 
        mr = ipc_kmsg_copyin_from_kernel(kmsg);
        if (mr != MACH_MSG_SUCCESS) {
                ipc_kmsg_free(kmsg);
+               KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
                return mr;
        }
 
-#if 11938665
+       if (message_moved) {
+               *message_moved = TRUE;
+       }
+
        /*
         * Until we are sure of its effects, we are disabling
         * importance donation from the kernel-side of user
         * threads in importance-donating tasks - unless the
-        * option to force importance donation is passed in.
+        * option to force importance donation is passed in,
+        * or the thread's SEND_IMPORTANCE option has been set.
+        * (11938665 & 23925818)
         */
-       if ((option & MACH_SEND_IMPORTANCE) == 0)
+       if (current_thread()->options & TH_OPT_SEND_IMPORTANCE) {
+               option &= ~MACH_SEND_NOIMPORTANCE;
+       } else if ((option & MACH_SEND_IMPORTANCE) == 0) {
                option |= MACH_SEND_NOIMPORTANCE;
-#endif
+       }
+
        mr = ipc_kmsg_send(kmsg, option, timeout_val);
 
        if (mr != MACH_MSG_SUCCESS) {
                ipc_kmsg_destroy(kmsg);
+               KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
        }
-       
+
        return mr;
 }
 
@@ -210,38 +270,48 @@ mach_msg_send_from_kernel_with_options(
 
 mach_msg_return_t
 mach_msg_send_from_kernel_with_options_legacy(
-       mach_msg_header_t       *msg,
-       mach_msg_size_t         send_size,
-       mach_msg_option_t       option,
-       mach_msg_timeout_t      timeout_val)
+       mach_msg_header_t       *msg,
+       mach_msg_size_t         send_size,
+       mach_msg_option_t       option,
+       mach_msg_timeout_t      timeout_val)
 {
        ipc_kmsg_t kmsg;
        mach_msg_return_t mr;
 
+       KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_START);
+
        mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg);
-       if (mr != MACH_MSG_SUCCESS)
+       if (mr != MACH_MSG_SUCCESS) {
+               KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
                return mr;
+       }
 
        mr = ipc_kmsg_copyin_from_kernel_legacy(kmsg);
        if (mr != MACH_MSG_SUCCESS) {
                ipc_kmsg_free(kmsg);
+               KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
                return mr;
        }
 
-#if 11938665
        /*
         * Until we are sure of its effects, we are disabling
         * importance donation from the kernel-side of user
         * threads in importance-donating tasks.
+        * (11938665 & 23925818)
         */
-       option |= MACH_SEND_NOIMPORTANCE;
-#endif
+       if (current_thread()->options & TH_OPT_SEND_IMPORTANCE) {
+               option &= ~MACH_SEND_NOIMPORTANCE;
+       } else {
+               option |= MACH_SEND_NOIMPORTANCE;
+       }
+
        mr = ipc_kmsg_send(kmsg, option, timeout_val);
 
        if (mr != MACH_MSG_SUCCESS) {
                ipc_kmsg_destroy(kmsg);
+               KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
        }
-       
+
        return mr;
 }
 
@@ -262,47 +332,44 @@ mach_msg_send_from_kernel_with_options_legacy(
  *             MACH_RCV_PORT_DIED      The reply port was deallocated.
  */
 
-mach_msg_return_t mach_msg_rpc_from_kernel_body(mach_msg_header_t *msg, 
-        mach_msg_size_t send_size, mach_msg_size_t rcv_size, boolean_t legacy);
-
 #if IKM_SUPPORT_LEGACY
 
 #undef mach_msg_rpc_from_kernel
 mach_msg_return_t
 mach_msg_rpc_from_kernel(
-       mach_msg_header_t       *msg,
-       mach_msg_size_t         send_size,
-       mach_msg_size_t         rcv_size);
+       mach_msg_header_t       *msg,
+       mach_msg_size_t         send_size,
+       mach_msg_size_t         rcv_size);
 
 mach_msg_return_t
 mach_msg_rpc_from_kernel(
-       mach_msg_header_t       *msg,
-       mach_msg_size_t         send_size,
-       mach_msg_size_t         rcv_size)
+       mach_msg_header_t       *msg,
+       mach_msg_size_t         send_size,
+       mach_msg_size_t         rcv_size)
 {
-    return mach_msg_rpc_from_kernel_body(msg, send_size, rcv_size, TRUE);
+       return kernel_mach_msg_rpc(msg, send_size, rcv_size, TRUE, NULL);
 }
-
 #endif /* IKM_SUPPORT_LEGACY */
 
 mach_msg_return_t
 mach_msg_rpc_from_kernel_proper(
-       mach_msg_header_t       *msg,
-       mach_msg_size_t         send_size,
-       mach_msg_size_t         rcv_size)
+       mach_msg_header_t       *msg,
+       mach_msg_size_t         send_size,
+       mach_msg_size_t         rcv_size)
 {
-    return mach_msg_rpc_from_kernel_body(msg, send_size, rcv_size, FALSE);
+       return kernel_mach_msg_rpc(msg, send_size, rcv_size, FALSE, NULL);
 }
 
 mach_msg_return_t
-mach_msg_rpc_from_kernel_body(
-       mach_msg_header_t       *msg,
-       mach_msg_size_t         send_size,
-       mach_msg_size_t         rcv_size,
+kernel_mach_msg_rpc(
+       mach_msg_header_t       *msg,
+       mach_msg_size_t         send_size,
+       mach_msg_size_t         rcv_size,
 #if !IKM_SUPPORT_LEGACY
        __unused
 #endif
-    boolean_t           legacy)
+       boolean_t           legacy,
+       boolean_t           *message_moved)
 {
        thread_t self = current_thread();
        ipc_port_t reply;
@@ -312,52 +379,77 @@ mach_msg_rpc_from_kernel_body(
 
        assert(msg->msgh_local_port == MACH_PORT_NULL);
 
+       KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_START);
+
+       if (message_moved) {
+               *message_moved = FALSE;
+       }
+
        mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg);
-       if (mr != MACH_MSG_SUCCESS)
+       if (mr != MACH_MSG_SUCCESS) {
+               KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
                return mr;
+       }
 
        reply = self->ith_rpc_reply;
        if (reply == IP_NULL) {
                reply = ipc_port_alloc_reply();
                if ((reply == IP_NULL) ||
-                   (self->ith_rpc_reply != IP_NULL))
+                   (self->ith_rpc_reply != IP_NULL)) {
                        panic("mach_msg_rpc_from_kernel");
+               }
                self->ith_rpc_reply = reply;
        }
 
        /* insert send-once right for the reply port */
        kmsg->ikm_header->msgh_local_port = reply;
        kmsg->ikm_header->msgh_bits |=
-               MACH_MSGH_BITS(0, MACH_MSG_TYPE_MAKE_SEND_ONCE);
+           MACH_MSGH_BITS(0, MACH_MSG_TYPE_MAKE_SEND_ONCE);
 
 #if IKM_SUPPORT_LEGACY
-    if(legacy)
-        mr = ipc_kmsg_copyin_from_kernel_legacy(kmsg);
-    else
-        mr = ipc_kmsg_copyin_from_kernel(kmsg);
+       if (legacy) {
+               mr = ipc_kmsg_copyin_from_kernel_legacy(kmsg);
+       } else {
+               mr = ipc_kmsg_copyin_from_kernel(kmsg);
+       }
 #else
-    mr = ipc_kmsg_copyin_from_kernel(kmsg);
+       mr = ipc_kmsg_copyin_from_kernel(kmsg);
 #endif
-    if (mr != MACH_MSG_SUCCESS) {
-           ipc_kmsg_free(kmsg);
-           return mr;
-    }
-       mr = ipc_kmsg_send(kmsg, 
-                          MACH_SEND_KERNEL_DEFAULT,
-                          MACH_MSG_TIMEOUT_NONE);
+       if (mr != MACH_MSG_SUCCESS) {
+               ipc_kmsg_free(kmsg);
+               KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
+               return mr;
+       }
+
+       if (message_moved) {
+               *message_moved = TRUE;
+       }
+
+       /*
+        * respect the thread's SEND_IMPORTANCE option to force importance
+        * donation from the kernel-side of user threads
+        * (11938665 & 23925818)
+        */
+       mach_msg_option_t option = MACH_SEND_KERNEL_DEFAULT;
+       if (current_thread()->options & TH_OPT_SEND_IMPORTANCE) {
+               option &= ~MACH_SEND_NOIMPORTANCE;
+       }
+
+       mr = ipc_kmsg_send(kmsg, option, MACH_MSG_TIMEOUT_NONE);
        if (mr != MACH_MSG_SUCCESS) {
                ipc_kmsg_destroy(kmsg);
+               KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
                return mr;
        }
 
        for (;;) {
                ipc_mqueue_t mqueue;
 
-               assert(reply->ip_pset_count == 0);
-               assert(ip_active(reply));
+               assert(reply->ip_in_pset == 0);
+               require_ip_active(reply);
 
                /* JMM - why this check? */
-               if (!self->active) {
+               if (!self->active && !self->inspection) {
                        ipc_port_dealloc_reply(reply);
                        self->ith_rpc_reply = IP_NULL;
                        return MACH_RCV_INTERRUPTED;
@@ -367,46 +459,46 @@ mach_msg_rpc_from_kernel_body(
 
                mqueue = &reply->ip_messages;
                ipc_mqueue_receive(mqueue,
-                                  MACH_MSG_OPTION_NONE,
-                                  MACH_MSG_SIZE_MAX,
-                                  MACH_MSG_TIMEOUT_NONE,
-                                  THREAD_INTERRUPTIBLE);
+                   MACH_MSG_OPTION_NONE,
+                   MACH_MSG_SIZE_MAX,
+                   MACH_MSG_TIMEOUT_NONE,
+                   THREAD_INTERRUPTIBLE);
 
                mr = self->ith_state;
                kmsg = self->ith_kmsg;
                seqno = self->ith_seqno;
 
-               if (mr == MACH_MSG_SUCCESS)
-                 {
+               mach_msg_receive_results_complete(ip_to_object(reply));
+
+               if (mr == MACH_MSG_SUCCESS) {
                        break;
-                 }
+               }
 
                assert(mr == MACH_RCV_INTERRUPTED);
 
                assert(reply == self->ith_rpc_reply);
 
-               if (self->handlers) {
+               if (self->ast & AST_APC) {
                        ipc_port_dealloc_reply(reply);
                        self->ith_rpc_reply = IP_NULL;
-                       return(mr);
+                       return mr;
                }
        }
 
-       /* 
+       /*
         * Check to see how much of the message/trailer can be received.
         * We chose the maximum trailer that will fit, since we don't
         * have options telling us which trailer elements the caller needed.
         */
        if (rcv_size >= kmsg->ikm_header->msgh_size) {
                mach_msg_format_0_trailer_t *trailer =  (mach_msg_format_0_trailer_t *)
-                       ((vm_offset_t)kmsg->ikm_header + kmsg->ikm_header->msgh_size);
+                   ((vm_offset_t)kmsg->ikm_header + kmsg->ikm_header->msgh_size);
 
                if (rcv_size >= kmsg->ikm_header->msgh_size + MAX_TRAILER_SIZE) {
                        /* Enough room for a maximum trailer */
                        trailer->msgh_trailer_size = MAX_TRAILER_SIZE;
-               } 
-               else if (rcv_size < kmsg->ikm_header->msgh_size + 
-                          trailer->msgh_trailer_size) {
+               } else if (rcv_size < kmsg->ikm_header->msgh_size +
+                   trailer->msgh_trailer_size) {
                        /* no room for even the basic (default) trailer */
                        trailer->msgh_trailer_size = 0;
                }
@@ -424,17 +516,110 @@ mach_msg_rpc_from_kernel_body(
         *      as they are.
         */
 #if IKM_SUPPORT_LEGACY
-    if(legacy)
-        ipc_kmsg_copyout_to_kernel_legacy(kmsg, ipc_space_reply);
-    else
-        ipc_kmsg_copyout_to_kernel(kmsg, ipc_space_reply);
+       if (legacy) {
+               ipc_kmsg_copyout_to_kernel_legacy(kmsg, ipc_space_reply);
+       } else {
+               ipc_kmsg_copyout_to_kernel(kmsg, ipc_space_reply);
+       }
 #else
-    ipc_kmsg_copyout_to_kernel(kmsg, ipc_space_reply);
+       ipc_kmsg_copyout_to_kernel(kmsg, ipc_space_reply);
 #endif
        ipc_kmsg_put_to_kernel(msg, kmsg, rcv_size);
        return mr;
 }
 
+/*
+ *     Routine:        mach_msg_destroy_from_kernel_proper
+ *     Purpose:
+ *             mach_msg_destroy_from_kernel_proper is used to destroy
+ *             an unwanted/unexpected reply message from a MIG
+ *             kernel-specific user-side stub. It is like ipc_kmsg_destroy(),
+ *             except we no longer have the kmsg - just the contents.
+ */
+void
+mach_msg_destroy_from_kernel_proper(mach_msg_header_t *msg)
+{
+       mach_msg_bits_t mbits = msg->msgh_bits;
+       ipc_object_t object;
+
+       object = (ipc_object_t) msg->msgh_remote_port;
+       if (IO_VALID(object)) {
+               ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits));
+       }
+
+       /*
+        * The destination (now in msg->msgh_local_port via
+        * ipc_kmsg_copyout_to_kernel) has been consumed with
+        * ipc_object_copyout_dest.
+        */
+
+       /* MIG kernel users don't receive vouchers */
+       assert(!MACH_MSGH_BITS_VOUCHER(mbits));
+
+       /* For simple messages, we're done */
+       if ((mbits & MACH_MSGH_BITS_COMPLEX) == 0) {
+               return;
+       }
+
+       /* Discard descriptor contents */
+       mach_msg_body_t *body = (mach_msg_body_t *)(msg + 1);
+       mach_msg_descriptor_t *daddr = (mach_msg_descriptor_t *)(body + 1);
+       mach_msg_size_t i;
+
+       for (i = 0; i < body->msgh_descriptor_count; i++, daddr++) {
+               switch (daddr->type.type) {
+               case MACH_MSG_PORT_DESCRIPTOR: {
+                       mach_msg_port_descriptor_t *dsc = &daddr->port;
+                       if (IO_VALID((ipc_object_t) dsc->name)) {
+                               ipc_object_destroy((ipc_object_t) dsc->name, dsc->disposition);
+                       }
+                       break;
+               }
+               case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
+               case MACH_MSG_OOL_DESCRIPTOR: {
+                       mach_msg_ool_descriptor_t *dsc =
+                           (mach_msg_ool_descriptor_t *)&daddr->out_of_line;
+
+                       if (dsc->size > 0) {
+                               vm_map_copy_discard((vm_map_copy_t) dsc->address);
+                       } else {
+                               assert(dsc->address == (void *) 0);
+                       }
+                       break;
+               }
+               case MACH_MSG_OOL_PORTS_DESCRIPTOR: {
+                       ipc_object_t                    *objects;
+                       mach_msg_type_number_t          j;
+                       mach_msg_ool_ports_descriptor_t *dsc;
+
+                       dsc = (mach_msg_ool_ports_descriptor_t  *)&daddr->ool_ports;
+                       objects = (ipc_object_t *) dsc->address;
+
+                       if (dsc->count == 0) {
+                               break;
+                       }
+                       assert(objects != 0);
+                       for (j = 0; j < dsc->count; j++) {
+                               object = objects[j];
+                               if (IO_VALID(object)) {
+                                       ipc_object_destroy(object, dsc->disposition);
+                               }
+                       }
+                       kfree(dsc->address, (vm_size_t) dsc->count * sizeof(mach_port_t));
+                       break;
+               }
+               case MACH_MSG_GUARDED_PORT_DESCRIPTOR: {
+                       mach_msg_guarded_port_descriptor_t *dsc = (mach_msg_guarded_port_descriptor_t *)&daddr->guarded_port;
+                       if (IO_VALID((ipc_object_t) dsc->name)) {
+                               ipc_object_destroy((ipc_object_t) dsc->name, dsc->disposition);
+                       }
+                       break;
+               }
+               default:
+                       break;
+               }
+       }
+}
 
 /************** These Calls are set up for kernel-loaded tasks/threads **************/
 
@@ -454,15 +639,15 @@ mach_msg_rpc_from_kernel_body(
 
 mach_msg_return_t
 mach_msg_overwrite(
-       mach_msg_header_t               *msg,
-       mach_msg_option_t               option,
-       mach_msg_size_t         send_size,
-       mach_msg_size_t         rcv_size,
-       mach_port_name_t                rcv_name,
-       __unused mach_msg_timeout_t     msg_timeout,
-       __unused mach_port_name_t       notify,
-       __unused mach_msg_header_t      *rcv_msg,
-       __unused mach_msg_size_t        rcv_msg_size)
+       mach_msg_header_t               *msg,
+       mach_msg_option_t               option,
+       mach_msg_size_t         send_size,
+       mach_msg_size_t         rcv_size,
+       mach_port_name_t                rcv_name,
+       __unused mach_msg_timeout_t     msg_timeout,
+       mach_msg_priority_t     override,
+       __unused mach_msg_header_t      *rcv_msg,
+       __unused mach_msg_size_t rcv_msg_size)
 {
        ipc_space_t space = current_space();
        vm_map_t map = current_map();
@@ -472,26 +657,39 @@ mach_msg_overwrite(
        mach_msg_trailer_size_t trailer_size;
 
        if (option & MACH_SEND_MSG) {
-               mach_msg_size_t msg_and_trailer_size;
-               mach_msg_max_trailer_t  *max_trailer;
+               mach_msg_size_t msg_and_trailer_size;
+               mach_msg_max_trailer_t  *max_trailer;
 
-               if ((send_size < sizeof(mach_msg_header_t)) || (send_size & 3))
+               if ((send_size & 3) ||
+                   send_size < sizeof(mach_msg_header_t) ||
+                   (send_size < sizeof(mach_msg_base_t) && (msg->msgh_bits & MACH_MSGH_BITS_COMPLEX))) {
                        return MACH_SEND_MSG_TOO_SMALL;
+               }
 
-               if (send_size > MACH_MSG_SIZE_MAX - MAX_TRAILER_SIZE)
+               if (send_size > MACH_MSG_SIZE_MAX - MAX_TRAILER_SIZE) {
                        return MACH_SEND_TOO_LARGE;
+               }
+
+               KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_START);
 
                msg_and_trailer_size = send_size + MAX_TRAILER_SIZE;
                kmsg = ipc_kmsg_alloc(msg_and_trailer_size);
 
-               if (kmsg == IKM_NULL)
+               if (kmsg == IKM_NULL) {
+                       KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, MACH_SEND_NO_BUFFER);
                        return MACH_SEND_NO_BUFFER;
+               }
 
+               KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_LINK) | DBG_FUNC_NONE,
+                   (uintptr_t)0,                   /* this should only be called from the kernel! */
+                   VM_KERNEL_ADDRPERM((uintptr_t)kmsg),
+                   0, 0,
+                   0);
                (void) memcpy((void *) kmsg->ikm_header, (const void *) msg, send_size);
 
                kmsg->ikm_header->msgh_size = send_size;
 
-               /* 
+               /*
                 * Reserve for the trailer the largest space (MAX_TRAILER_SIZE)
                 * However, the internal size field of the trailer (msgh_trailer_size)
                 * is initialized to the minimum (sizeof(mach_msg_trailer_t)), to optimize
@@ -503,16 +701,17 @@ mach_msg_overwrite(
                max_trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
                max_trailer->msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE;
 
-               mr = ipc_kmsg_copyin(kmsg, space, map, &option);
+               mr = ipc_kmsg_copyin(kmsg, space, map, override, &option);
 
                if (mr != MACH_MSG_SUCCESS) {
                        ipc_kmsg_free(kmsg);
+                       KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
                        return mr;
                }
 
                do {
                        mr = ipc_kmsg_send(kmsg, MACH_MSG_OPTION_NONE, MACH_MSG_TIMEOUT_NONE);
-                } while (mr == MACH_SEND_INTERRUPTED);
+               } while (mr == MACH_SEND_INTERRUPTED);
 
                assert(mr == MACH_MSG_SUCCESS);
        }
@@ -525,30 +724,33 @@ mach_msg_overwrite(
                        ipc_mqueue_t mqueue;
 
                        mr = ipc_mqueue_copyin(space, rcv_name,
-                                              &mqueue, &object);
-                       if (mr != MACH_MSG_SUCCESS)
+                           &mqueue, &object);
+                       if (mr != MACH_MSG_SUCCESS) {
                                return mr;
+                       }
+
                        /* hold ref for object */
 
                        self->ith_continuation = (void (*)(mach_msg_return_t))0;
                        ipc_mqueue_receive(mqueue,
-                                          MACH_MSG_OPTION_NONE,
-                                          MACH_MSG_SIZE_MAX,
-                                          MACH_MSG_TIMEOUT_NONE,
-                                          THREAD_ABORTSAFE);
+                           MACH_MSG_OPTION_NONE,
+                           MACH_MSG_SIZE_MAX,
+                           MACH_MSG_TIMEOUT_NONE,
+                           THREAD_ABORTSAFE);
                        mr = self->ith_state;
                        kmsg = self->ith_kmsg;
                        seqno = self->ith_seqno;
 
+                       mach_msg_receive_results_complete(object);
                        io_release(object);
-
                } while (mr == MACH_RCV_INTERRUPTED);
-               if (mr != MACH_MSG_SUCCESS)
-                       return mr;
 
+               if (mr != MACH_MSG_SUCCESS) {
+                       return mr;
+               }
 
                trailer_size = ipc_kmsg_add_trailer(kmsg, space, option, current_thread(), seqno, TRUE,
-                               kmsg->ikm_header->msgh_remote_port->ip_context);
+                   kmsg->ikm_header->msgh_remote_port->ip_context);
 
                if (rcv_size < (kmsg->ikm_header->msgh_size + trailer_size)) {
                        ipc_kmsg_copyout_dest(kmsg, space);
@@ -557,11 +759,11 @@ mach_msg_overwrite(
                        return MACH_RCV_TOO_LARGE;
                }
 
-               mr = ipc_kmsg_copyout(kmsg, space, map, MACH_MSG_BODY_NULL);
+               mr = ipc_kmsg_copyout(kmsg, space, map, MACH_MSG_BODY_NULL, option);
                if (mr != MACH_MSG_SUCCESS) {
-                       if ((mr &MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) {
+                       if ((mr & ~MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) {
                                ipc_kmsg_put_to_kernel(msg, kmsg,
-                                               kmsg->ikm_header->msgh_size + trailer_size);
+                                   kmsg->ikm_header->msgh_size + trailer_size);
                        } else {
                                ipc_kmsg_copyout_dest(kmsg, space);
                                (void) memcpy((void *) msg, (const void *) kmsg->ikm_header, sizeof *msg);
@@ -572,7 +774,7 @@ mach_msg_overwrite(
                }
 
                (void) memcpy((void *) msg, (const void *) kmsg->ikm_header,
-                             kmsg->ikm_header->msgh_size + trailer_size);
+                   kmsg->ikm_header->msgh_size + trailer_size);
                ipc_kmsg_free(kmsg);
        }
 
@@ -588,7 +790,7 @@ mach_msg_overwrite(
 mach_port_t
 mig_get_reply_port(void)
 {
-       return (MACH_PORT_NULL);
+       return MACH_PORT_NULL;
 }
 
 /*
@@ -606,7 +808,7 @@ mig_dealloc_reply_port(
 /*
  *     Routine:        mig_put_reply_port
  *     Purpose:
- *             Called by client side interfaces after each RPC to 
+ *             Called by client side interfaces after each RPC to
  *             let the client recycle the reply port if it wishes.
  */
 void
@@ -619,48 +821,105 @@ mig_put_reply_port(
  * mig_strncpy.c - by Joshua Block
  *
  * mig_strncp -- Bounded string copy.  Does what the library routine strncpy
- * OUGHT to do:  Copies the (null terminated) string in src into dest, a 
+ * OUGHT to do:  Copies the (null terminated) string in src into dest, a
  * buffer of length len.  Assures that the copy is still null terminated
  * and doesn't overflow the buffer, truncating the copy if necessary.
  *
  * Parameters:
- * 
+ *
  *     dest - Pointer to destination buffer.
- * 
+ *
  *     src - Pointer to source string.
- * 
+ *
  *     len - Length of destination buffer.
  */
-int 
+int
 mig_strncpy(
-       char            *dest,
-       const char      *src,
-       int             len)
+       char            *dest,
+       const char      *src,
+       int             len)
+{
+       int i = 0;
+
+       if (len > 0) {
+               if (dest != NULL) {
+                       if (src != NULL) {
+                               for (i = 1; i < len; i++) {
+                                       if (!(*dest++ = *src++)) {
+                                               return i;
+                                       }
+                               }
+                       }
+                       *dest = '\0';
+               }
+       }
+       return i;
+}
+
+/*
+ * mig_strncpy_zerofill -- Bounded string copy.  Does what the
+ * library routine strncpy OUGHT to do:  Copies the (null terminated)
+ * string in src into dest, a buffer of length len.  Assures that
+ * the copy is still null terminated and doesn't overflow the buffer,
+ * truncating the copy if necessary. If the string in src is smaller
+ * than given length len, it will zero fill the remaining bytes in dest.
+ *
+ * Parameters:
+ *
+ *     dest - Pointer to destination buffer.
+ *
+ *     src - Pointer to source string.
+ *
+ *     len - Length of destination buffer.
+ */
+int
+mig_strncpy_zerofill(
+       char            *dest,
+       const char      *src,
+       int             len)
 {
-    int i = 0;
+       int i = 0;
+       boolean_t terminated = FALSE;
+       int retval = 0;
 
-    if (len > 0)
-       if (dest != NULL) {
-           if (src != NULL)
-                  for (i=1; i<len; i++)
-                       if (! (*dest++ = *src++))
-                           return i;
-               *dest = '\0';
+       if (len <= 0 || dest == NULL) {
+               return 0;
        }
-    return i;
+
+       if (src == NULL) {
+               terminated = TRUE;
+       }
+
+       for (i = 1; i < len; i++) {
+               if (!terminated) {
+                       if (!(*dest++ = *src++)) {
+                               retval = i;
+                               terminated = TRUE;
+                       }
+               } else {
+                       *dest++ = '\0';
+               }
+       }
+
+       *dest = '\0';
+       if (!terminated) {
+               retval = i;
+       }
+
+       return retval;
 }
 
-char *
+void *
 mig_user_allocate(
-       vm_size_t       size)
+       vm_size_t       size)
 {
        return (char *)kalloc(size);
 }
 
 void
 mig_user_deallocate(
-       char            *data,
-       vm_size_t       size)
+       char            *data,
+       vm_size_t       size)
 {
        kfree(data, size);
 }
@@ -673,11 +932,12 @@ mig_user_deallocate(
  */
 kern_return_t
 mig_object_init(
-       mig_object_t            mig_object,
-       const IMIGObject        *interface)
+       mig_object_t            mig_object,
+       const IMIGObject        *interface)
 {
-       if (mig_object == MIG_OBJECT_NULL)
+       if (mig_object == MIG_OBJECT_NULL) {
                return KERN_INVALID_ARGUMENT;
+       }
        mig_object->pVtbl = (const IMIGObjectVtbl *)interface;
        mig_object->port = MACH_PORT_NULL;
        return KERN_SUCCESS;
@@ -696,7 +956,7 @@ mig_object_init(
  */
 void
 mig_object_destroy(
-       __assert_only mig_object_t      mig_object)
+       __assert_only mig_object_t      mig_object)
 {
        assert(mig_object->port == MACH_PORT_NULL);
        return;
@@ -712,7 +972,7 @@ mig_object_destroy(
  */
 void
 mig_object_reference(
-       mig_object_t    mig_object)
+       mig_object_t    mig_object)
 {
        assert(mig_object != MIG_OBJECT_NULL);
        mig_object->pVtbl->AddRef((IMIGObject *)mig_object);
@@ -728,10 +988,16 @@ mig_object_reference(
  */
 void
 mig_object_deallocate(
-       mig_object_t    mig_object)
+       mig_object_t    mig_object)
 {
        assert(mig_object != MIG_OBJECT_NULL);
-       mig_object->pVtbl->Release((IMIGObject *)mig_object);
+       ipc_port_t port = mig_object->port;
+       if (mig_object->pVtbl->Release((IMIGObject *)mig_object) == 0) {
+               if (IP_VALID(port)) {
+                       assert(!port->ip_srights);
+                       ipc_port_dealloc_kernel(port);
+               }
+       }
 }
 
 /*
@@ -748,56 +1014,22 @@ mig_object_deallocate(
  */
 ipc_port_t
 convert_mig_object_to_port(
-       mig_object_t    mig_object)
+       mig_object_t    mig_object)
 {
-       ipc_port_t      port;
-       boolean_t       deallocate = TRUE;
-
-       if (mig_object == MIG_OBJECT_NULL)
+       if (mig_object == MIG_OBJECT_NULL) {
                return IP_NULL;
-
-       port = mig_object->port;
-       while ((port == IP_NULL) ||
-              ((port = ipc_port_make_send(port)) == IP_NULL)) {
-               ipc_port_t      previous;
-
-               /*
-                * Either the port was never set up, or it was just
-                * deallocated out from under us by the no-senders
-                * processing.  In either case, we must:
-                *      Attempt to make one
-                *      Arrange for no senders
-                *      Try to atomically register it with the object
-                *              Destroy it if we are raced.
-                */
-               port = ipc_port_alloc_kernel();
-               ip_lock(port);
-               ipc_kobject_set_atomically(port,
-                                          (ipc_kobject_t) mig_object,
-                                          IKOT_MIG);
-
-               /* make a sonce right for the notification */
-               port->ip_sorights++;
-               ip_reference(port);
-
-               ipc_port_nsrequest(port, 1, port, &previous);
-               /* port unlocked */
-
-               assert(previous == IP_NULL);
-
-               if (OSCompareAndSwapPtr((void *)IP_NULL, (void *)port,
-                                                                                       (void * volatile *)&mig_object->port)) {
-                       deallocate = FALSE;
-               } else {
-                       ipc_port_dealloc_kernel(port);
-                       port = mig_object->port;
-               }
        }
 
-       if (deallocate)
-               mig_object->pVtbl->Release((IMIGObject *)mig_object);
+       /*
+        * make a send right and donate our reference for mig_object_no_senders
+        * if this is the first send right
+        */
+       if (!ipc_kobject_make_send_lazy_alloc_port(&mig_object->port,
+           (ipc_kobject_t) mig_object, IKOT_MIG)) {
+               mig_object_deallocate(mig_object);
+       }
 
-       return (port);
+       return mig_object->port;
 }
 
 
@@ -816,14 +1048,15 @@ convert_mig_object_to_port(
  */
 mig_object_t
 convert_port_to_mig_object(
-       ipc_port_t      port,
-       const MIGIID    *iid)
+       ipc_port_t      port,
+       const MIGIID    *iid)
 {
-       mig_object_t    mig_object;
-       void            *ppv;
+       mig_object_t    mig_object;
+       void            *ppv;
 
-       if (!IP_VALID(port))
+       if (!IP_VALID(port)) {
                return NULL;
+       }
 
        ip_lock(port);
        if (!ip_active(port) || (ip_kotype(port) != IKOT_MIG)) {
@@ -836,7 +1069,7 @@ convert_port_to_mig_object(
         * query it to get a reference to the desired interface.
         */
        ppv = NULL;
-       mig_object = (mig_object_t)port->ip_kobject;
+       mig_object = (mig_object_t) ip_get_kobject(port);
        mig_object->pVtbl->QueryInterface((IMIGObject *)mig_object, iid, &ppv);
        ip_unlock(port);
        return (mig_object_t)ppv;
@@ -848,60 +1081,19 @@ convert_port_to_mig_object(
  *             Base implementation of a no-senders notification handler
  *             for MIG objects. If there truly are no more senders, must
  *             destroy the port and drop its reference on the object.
- *     Returns:
- *             TRUE  - port deallocate and reference dropped
- *             FALSE - more senders arrived, re-registered for notification
  *     Conditions:
  *             Nothing locked.
  */
-
-boolean_t
+void
 mig_object_no_senders(
-       ipc_port_t              port,
-       mach_port_mscount_t     mscount)
+       ipc_port_t              port)
 {
-       mig_object_t            mig_object;
-
-       ip_lock(port);
-       if (port->ip_mscount > mscount) {
-               ipc_port_t      previous;
-
-               /*
-                * Somebody created new send rights while the
-                * notification was in-flight.  Just create a
-                * new send-once right and re-register with 
-                * the new (higher) mscount threshold.
-                */
-               /* make a sonce right for the notification */
-               port->ip_sorights++;
-               ip_reference(port);
-               ipc_port_nsrequest(port, mscount, port, &previous);
-               /* port unlocked */
-
-               assert(previous == IP_NULL);
-               return (FALSE);
-       }
-
-       /*
-        * Clear the port pointer while we have it locked.
-        */
-       mig_object = (mig_object_t)port->ip_kobject;
-       mig_object->port = IP_NULL;
+       require_ip_active(port);
+       assert(IKOT_MIG == ip_kotype(port));
 
-       /*
-        * Bring the sequence number and mscount in
-        * line with ipc_port_destroy assertion.
-        */
-       port->ip_mscount = 0;
-       port->ip_messages.imq_seqno = 0;
-       ipc_port_destroy(port); /* releases lock */
-       
-       /*
-        * Release the port's reference on the object.
-        */
-       mig_object->pVtbl->Release((IMIGObject *)mig_object);
-       return (TRUE);
-}      
+       /* consume the reference donated by convert_mig_object_to_port */
+       mig_object_deallocate((mig_object_t) ip_get_kobject(port));
+}
 
 /*
  * Kernel implementation of the notification chain for MIG object