]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/ipc/ipc_right.c
xnu-1699.32.7.tar.gz
[apple/xnu.git] / osfmk / ipc / ipc_right.c
index f94bcc903047891a3930503a03aa975856c6a6e8..d3db278b84362eb964dab7afe0864ef69644c97b 100644 (file)
@@ -1,23 +1,29 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License").  You may not use this file except in compliance with the
- * License.  Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
+ * 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
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * 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.
  * 
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * 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,
  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
- * License for the specific language governing rights and limitations
- * under the License.
+ * 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_LICENSE_HEADER_END@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
 /*
  * @OSF_FREE_COPYRIGHT@
  * any improvements or extensions that they make and grant Carnegie Mellon
  * the rights to redistribute these changes.
  */
+/*
+ * NOTICE: This file was modified by McAfee Research in 2004 to introduce
+ * support for mandatory and extensible security protections.  This notice
+ * is included in support of clause 2.2 (b) of the Apple Public License,
+ * Version 2.0.
+ * Copyright (c) 2005-2006 SPARTA, Inc.
+ */
 /*
  */
 /*
@@ -63,7 +76,6 @@
 #include <mach/message.h>
 #include <kern/assert.h>
 #include <kern/misc_protos.h>
-#include <kern/ipc_subsystem.h>
 #include <ipc/port.h>
 #include <ipc/ipc_entry.h>
 #include <ipc/ipc_space.h>
@@ -74,6 +86,7 @@
 #include <ipc/ipc_right.h>
 #include <ipc/ipc_notify.h>
 #include <ipc/ipc_table.h>
+#include <security/mac_mach_internal.h>
 
 /*
  *     Routine:        ipc_right_lookup_write
@@ -230,12 +243,6 @@ ipc_right_reverse(
  *             registered send-once right.  If notify is IP_NULL,
  *             just cancels the previously registered request.
  *
- *             This interacts with the IE_BITS_COMPAT, because they
- *             both use ie_request.  If this is a compat entry, then
- *             previous always gets IP_NULL.  If notify is IP_NULL,
- *             then the entry remains a compat entry.  Otherwise
- *             the real dead-name request is registered and the entry
- *             is no longer a compat entry.
  *     Conditions:
  *             Nothing locked.  May allocate memory.
  *             Only consumes/returns refs if successful.
@@ -252,28 +259,39 @@ ipc_right_reverse(
  */
 
 kern_return_t
-ipc_right_dnrequest(
+ipc_right_request_alloc(
        ipc_space_t             space,
        mach_port_name_t        name,
        boolean_t               immediate,
+       boolean_t               send_possible,
        ipc_port_t              notify,
        ipc_port_t              *previousp)
 {
-       ipc_port_t previous;
+       ipc_port_request_index_t prev_request;
+       ipc_port_t previous = IP_NULL;
+       ipc_entry_t entry;
+       kern_return_t kr;
 
        for (;;) {
-               ipc_entry_t entry;
-               ipc_entry_bits_t bits;
-               kern_return_t kr;
-
                kr = ipc_right_lookup_write(space, name, &entry);
                if (kr != KERN_SUCCESS)
                        return kr;
+
                /* space is write-locked and active */
-               bits = entry->ie_bits;
-               if (bits & MACH_PORT_TYPE_PORT_RIGHTS) {
+               
+               prev_request = entry->ie_request;
+
+               /* if nothing to do or undo, we're done */
+               if (notify == IP_NULL && prev_request == IE_REQ_NONE) {
+                       is_write_unlock(space);
+                       *previousp = IP_NULL;
+                       return KERN_SUCCESS;
+               }
+
+               /* see if the entry is of proper type for requests */
+               if (entry->ie_bits & MACH_PORT_TYPE_PORT_RIGHTS) {
+                       ipc_port_request_index_t new_request;
                        ipc_port_t port;
-                       ipc_port_request_index_t request;
 
                        port = (ipc_port_t) entry->ie_object;
                        assert(port != IP_NULL);
@@ -281,70 +299,71 @@ ipc_right_dnrequest(
                        if (!ipc_right_check(space, port, name, entry)) {
                                /* port is locked and active */
 
+                               /* if no new request, just cancel previous */
                                if (notify == IP_NULL) {
-                                       previous = ipc_right_dncancel_macro(
-                                                  space, port, name, entry);
-
+                                       if (prev_request != IE_REQ_NONE)
+                                               previous = ipc_port_request_cancel(port, name, prev_request);
                                        ip_unlock(port);
+                                       entry->ie_request = IE_REQ_NONE;
                                        is_write_unlock(space);
                                        break;
                                }
 
                                /*
-                                *      If a registered soright exists,
-                                *      want to atomically switch with it.
-                                *      If ipc_port_dncancel finds us a
-                                *      soright, then the following
-                                *      ipc_port_dnrequest will reuse
-                                *      that slot, so we are guaranteed
-                                *      not to unlock and retry.
+                                * send-once rights, kernel objects, and non-full other queues
+                                * fire immediately (if immediate specified).
                                 */
+                               if (send_possible && immediate &&
+                                   ((entry->ie_bits & MACH_PORT_TYPE_SEND_ONCE) ||
+                                    port->ip_receiver == ipc_space_kernel || !ip_full(port))) {
+                                       if (prev_request != IE_REQ_NONE)
+                                               previous = ipc_port_request_cancel(port, name, prev_request);
+                                       ip_unlock(port);
+                                       entry->ie_request = IE_REQ_NONE;
+                                       is_write_unlock(space);
+
+                                       ipc_notify_send_possible(notify, name);
+                                       break;
+                               }
 
-                               previous = ipc_right_dncancel_macro(space,
-                                               port, name, entry);
+                               /*
+                                * If there is a previous request, free it.  Any subsequent
+                                * allocation cannot fail, thus assuring an atomic swap.
+                                */
+                               if (prev_request != IE_REQ_NONE)
+                                       previous = ipc_port_request_cancel(port, name, prev_request);
 
-                               kr = ipc_port_dnrequest(port, name, notify,
-                                                       &request);
+                               kr = ipc_port_request_alloc(port, name, notify,
+                                                           send_possible, immediate,
+                                                           &new_request);
                                if (kr != KERN_SUCCESS) {
                                        assert(previous == IP_NULL);
                                        is_write_unlock(space);
 
-                                       kr = ipc_port_dngrow(port,
-                                                            ITS_SIZE_NONE);
+                                       kr = ipc_port_request_grow(port, ITS_SIZE_NONE);
                                        /* port is unlocked */
+
                                        if (kr != KERN_SUCCESS)
                                                return kr;
 
                                        continue;
                                }
 
-                               assert(request != 0);
+                               assert(new_request != IE_REQ_NONE);
                                ip_unlock(port);
-
-                               entry->ie_request = request;
+                               entry->ie_request = new_request;
                                is_write_unlock(space);
                                break;
-                       } else {
-
-                         /*
-                          * Our capability bits were changed by ipc_right_check
-                          * because it found an inactive port and removed our
-                          * references to it (converting our entry into a dead
-                          * one).  Reload the bits (and obviously we can't use
-                          * the port name anymore).
-                          */
-                         bits = entry->ie_bits;
-
                        }
+                       /* entry may have changed to dead-name by ipc_right_check() */
 
-                       assert(bits & MACH_PORT_TYPE_DEAD_NAME);
                }
 
-               if ((bits & MACH_PORT_TYPE_DEAD_NAME) &&
-                   immediate && (notify != IP_NULL)) {
-                       mach_port_urefs_t urefs = IE_BITS_UREFS(bits);
+               /* treat send_possible requests as immediate w.r.t. dead-name */
+               if ((send_possible || immediate) && notify != IP_NULL &&
+                   (entry->ie_bits & MACH_PORT_TYPE_DEAD_NAME)) {
+                       mach_port_urefs_t urefs = IE_BITS_UREFS(entry->ie_bits);
 
-                       assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
                        assert(urefs > 0);
 
                        if (MACH_PORT_UREFS_OVERFLOW(urefs, 1)) {
@@ -361,7 +380,7 @@ ipc_right_dnrequest(
                }
 
                is_write_unlock(space);
-               if (bits & MACH_PORT_TYPE_PORT_OR_DEAD)
+               if (entry->ie_bits & MACH_PORT_TYPE_PORT_OR_DEAD)
                        return KERN_INVALID_ARGUMENT;
                else
                        return KERN_INVALID_RIGHT;
@@ -372,9 +391,9 @@ ipc_right_dnrequest(
 }
 
 /*
- *     Routine:        ipc_right_dncancel
+ *     Routine:        ipc_right_request_cancel
  *     Purpose:
- *             Cancel a dead-name request and return the send-once right.
+ *             Cancel a notification request and return the send-once right.
  *             Afterwards, entry->ie_request == 0.
  *     Conditions:
  *             The space must be write-locked; the port must be locked.
@@ -382,21 +401,23 @@ ipc_right_dnrequest(
  */
 
 ipc_port_t
-ipc_right_dncancel(
-       ipc_space_t             space,
-       ipc_port_t              port,
-       mach_port_name_t        name,
-       ipc_entry_t             entry)
+ipc_right_request_cancel(
+       __unused ipc_space_t            space,
+       ipc_port_t                      port,
+       mach_port_name_t                name,
+       ipc_entry_t                     entry)
 {
-       ipc_port_t dnrequest;
+       ipc_port_t previous;
 
        assert(ip_active(port));
        assert(port == (ipc_port_t) entry->ie_object);
 
-       dnrequest = ipc_port_dncancel(port, name, entry->ie_request);
-       entry->ie_request = 0;
+       if (entry->ie_request == IE_REQ_NONE)
+               return IP_NULL;
 
-       return dnrequest;
+       previous = ipc_port_request_cancel(port, name, entry->ie_request);
+       entry->ie_request = IE_REQ_NONE;
+       return previous;
 }
 
 /*
@@ -411,9 +432,9 @@ ipc_right_dncancel(
 
 boolean_t
 ipc_right_inuse(
-       ipc_space_t             space,
-       mach_port_name_t        name,
-       ipc_entry_t             entry)
+       ipc_space_t                     space,
+       __unused mach_port_name_t       name,
+       ipc_entry_t                     entry)
 {
        if (IE_BITS_TYPE(entry->ie_bits) != MACH_PORT_TYPE_NONE) {
                is_write_unlock(space);
@@ -465,8 +486,6 @@ ipc_right_check(
         }
 
 
-       ipc_port_release(port);
-
        /* convert entry to dead name */
 
        if ((bits & MACH_PORT_TYPE_SEND) && !(bits & MACH_PORT_TYPE_RECEIVE))
@@ -476,27 +495,32 @@ ipc_right_check(
        
        /*
         * If there was a notification request outstanding on this
-        * name, and since the port went dead, that notification
-        * must already be on its way up from the port layer. We
-        * don't need the index of the notification port anymore.
+        * name, and the port went dead, that notification
+        * must already be on its way up from the port layer. 
         *
-        * JMM - We also add a reference to the entry since the
-        * notification only carries the name and NOT a reference
-        * (or right). This makes for pretty loose reference
-        * counting, since it is only happenstance that we
-        * detected the notification in progress like this.
-        * But most (all?) calls that try to deal with this entry
-        * will also come through here, so the reference gets added
-        * before the entry gets used eventually (I would rather it
-        * be explicit in the notification generation, though)
+        * Add the reference that the notification carries. It
+        * is done here, and not in the notification delivery,
+        * because the latter doesn't have a space reference and
+        * trying to actually move a send-right reference would
+        * get short-circuited into a MACH_PORT_DEAD by IPC. Since
+        * all calls that deal with the right eventually come
+        * through here, it has the same result.
+        *
+        * Once done, clear the request index so we only account
+        * for it once.
         */
-       if (entry->ie_request != 0) {
-               assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX);
-               entry->ie_request = 0; 
-               bits++; 
+       if (entry->ie_request != IE_REQ_NONE) {
+               if (ipc_port_request_type(port, name, entry->ie_request) != 0) {
+                       assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX);
+                       bits++; 
+               }
+               entry->ie_request = IE_REQ_NONE; 
        }
        entry->ie_bits = bits;
        entry->ie_object = IO_NULL;
+
+       ipc_port_release(port);
+
        return TRUE;
 }
 
@@ -535,14 +559,14 @@ ipc_right_clean(
 
        switch (type) {
            case MACH_PORT_TYPE_DEAD_NAME:
-               assert(entry->ie_request == 0);
+               assert(entry->ie_request == IE_REQ_NONE);
                assert(entry->ie_object == IO_NULL);
                break;
 
            case MACH_PORT_TYPE_PORT_SET: {
                ipc_pset_t pset = (ipc_pset_t) entry->ie_object;
 
-               assert(entry->ie_request == 0);
+               assert(entry->ie_request == IE_REQ_NONE);
                assert(pset != IPS_NULL);
 
                ips_lock(pset);
@@ -557,9 +581,9 @@ ipc_right_clean(
            case MACH_PORT_TYPE_SEND_RECEIVE:
            case MACH_PORT_TYPE_SEND_ONCE: {
                ipc_port_t port = (ipc_port_t) entry->ie_object;
-               ipc_port_t dnrequest;
+               ipc_port_t request;
                ipc_port_t nsrequest = IP_NULL;
-               mach_port_mscount_t mscount;
+               mach_port_mscount_t mscount = 0;
 
                assert(port != IP_NULL);
                ip_lock(port);
@@ -570,7 +594,7 @@ ipc_right_clean(
                        break;
                }
 
-               dnrequest = ipc_right_dncancel_macro(space, port, 
+               request = ipc_right_request_cancel_macro(space, port, 
                                        name, entry);
 
                if (type & MACH_PORT_TYPE_SEND) {
@@ -606,13 +630,13 @@ ipc_right_clean(
                if (nsrequest != IP_NULL)
                        ipc_notify_no_senders(nsrequest, mscount);
 
-               if (dnrequest != IP_NULL)
-                       ipc_notify_port_deleted(dnrequest, name);
+               if (request != IP_NULL)
+                       ipc_notify_port_deleted(request, name);
                break;
            }
 
            default:
-               panic("ipc_right_clean: strange type");
+               panic("ipc_right_clean: strange type - 0x%x", type);
        }
 }
 
@@ -644,7 +668,7 @@ ipc_right_destroy(
 
        switch (type) {
            case MACH_PORT_TYPE_DEAD_NAME:
-               assert(entry->ie_request == 0);
+               assert(entry->ie_request == IE_REQ_NONE);
                assert(entry->ie_object == IO_NULL);
 
                ipc_entry_dealloc(space, name, entry);
@@ -653,12 +677,10 @@ ipc_right_destroy(
            case MACH_PORT_TYPE_PORT_SET: {
                ipc_pset_t pset = (ipc_pset_t) entry->ie_object;
 
-               assert(entry->ie_request == 0);
+               assert(entry->ie_request == IE_REQ_NONE);
                assert(pset != IPS_NULL);
 
                entry->ie_object = IO_NULL;
-               /* port sets are not sharable entries on a subspace basis */
-               /* so there is no need to check the subspace array here   */
                ipc_entry_dealloc(space, name, entry);
 
                ips_lock(pset);
@@ -674,8 +696,8 @@ ipc_right_destroy(
            case MACH_PORT_TYPE_SEND_ONCE: {
                ipc_port_t port = (ipc_port_t) entry->ie_object;
                ipc_port_t nsrequest = IP_NULL;
-               mach_port_mscount_t mscount;
-               ipc_port_t dnrequest;
+               mach_port_mscount_t mscount = 0;
+               ipc_port_t request;
 
                assert(port != IP_NULL);
 
@@ -690,14 +712,14 @@ ipc_right_destroy(
                        ip_release(port);
                        ip_check_unlock(port);
 
-                       entry->ie_request = 0;
+                       entry->ie_request = IE_REQ_NONE;
                        entry->ie_object = IO_NULL;
                        ipc_entry_dealloc(space, name, entry);
 
                        break;
                }
 
-               dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
+               request = ipc_right_request_cancel_macro(space, port, name, entry);
 
                entry->ie_object = IO_NULL;
                ipc_entry_dealloc(space, name, entry);
@@ -717,9 +739,6 @@ ipc_right_destroy(
                        assert(ip_active(port));
                        assert(port->ip_receiver == space);
 
-                       if (port->ip_subsystem)
-                               subsystem_deallocate(
-                                       port->ip_subsystem->subsystem);
                        ipc_port_clear_receiver(port);
                        ipc_port_destroy(port); /* consumes our ref, unlocks */
                } else if (type & MACH_PORT_TYPE_SEND_ONCE) {
@@ -737,8 +756,8 @@ ipc_right_destroy(
                if (nsrequest != IP_NULL)
                        ipc_notify_no_senders(nsrequest, mscount);
 
-               if (dnrequest != IP_NULL)
-                       ipc_notify_port_deleted(dnrequest, name);
+               if (request != IP_NULL)
+                       ipc_notify_port_deleted(request, name);
                break;
            }
 
@@ -784,7 +803,7 @@ ipc_right_dealloc(
            dead_name:
 
                assert(IE_BITS_UREFS(bits) > 0);
-               assert(entry->ie_request == 0);
+               assert(entry->ie_request == IE_REQ_NONE);
                assert(entry->ie_object == IO_NULL);
 
                if (IE_BITS_UREFS(bits) == 1) {
@@ -798,7 +817,7 @@ ipc_right_dealloc(
            }
 
            case MACH_PORT_TYPE_SEND_ONCE: {
-               ipc_port_t port, dnrequest;
+               ipc_port_t port, request;
 
                assert(IE_BITS_UREFS(bits) == 1);
 
@@ -815,7 +834,7 @@ ipc_right_dealloc(
 
                assert(port->ip_sorights > 0);
 
-               dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
+               request = ipc_right_request_cancel_macro(space, port, name, entry);
                ip_unlock(port);
 
                entry->ie_object = IO_NULL;
@@ -825,16 +844,16 @@ ipc_right_dealloc(
 
                ipc_notify_send_once(port);
 
-               if (dnrequest != IP_NULL)
-                       ipc_notify_port_deleted(dnrequest, name);
+               if (request != IP_NULL)
+                       ipc_notify_port_deleted(request, name);
                break;
            }
 
            case MACH_PORT_TYPE_SEND: {
                ipc_port_t port;
-               ipc_port_t dnrequest = IP_NULL;
+               ipc_port_t request = IP_NULL;
                ipc_port_t nsrequest = IP_NULL;
-               mach_port_mscount_t mscount;
+               mach_port_mscount_t mscount =  0;
 
 
                assert(IE_BITS_UREFS(bits) > 0);
@@ -860,7 +879,7 @@ ipc_right_dealloc(
                                }
                        }
 
-                       dnrequest = ipc_right_dncancel_macro(space, port,
+                       request = ipc_right_request_cancel_macro(space, port,
                                                             name, entry);
                        ipc_hash_delete(space, (ipc_object_t) port,
                                        name, entry);
@@ -879,15 +898,15 @@ ipc_right_dealloc(
                if (nsrequest != IP_NULL)
                        ipc_notify_no_senders(nsrequest, mscount);
 
-               if (dnrequest != IP_NULL)
-                       ipc_notify_port_deleted(dnrequest, name);
+               if (request != IP_NULL)
+                       ipc_notify_port_deleted(request, name);
                break;
            }
 
            case MACH_PORT_TYPE_SEND_RECEIVE: {
                ipc_port_t port;
                ipc_port_t nsrequest = IP_NULL;
-               mach_port_mscount_t mscount;
+               mach_port_mscount_t mscount = 0;
 
                assert(IE_BITS_UREFS(bits) > 0);
 
@@ -980,7 +999,7 @@ ipc_right_delta(
 
                assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_PORT_SET);
                assert(IE_BITS_UREFS(bits) == 0);
-               assert(entry->ie_request == 0);
+               assert(entry->ie_request == IE_REQ_NONE);
 
                if (delta == 0)
                        goto success;
@@ -1007,7 +1026,7 @@ ipc_right_delta(
 
            case MACH_PORT_RIGHT_RECEIVE: {
                ipc_port_t port;
-               ipc_port_t dnrequest = IP_NULL;
+               ipc_port_t request = IP_NULL;
 
                if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
                        goto invalid_right;
@@ -1039,26 +1058,43 @@ ipc_right_delta(
                        assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX);
                        assert(port->ip_srights > 0);
 
-                       /*
-                        *      The remaining send right turns into a
-                        *      dead name.  Notice we don't decrement
-                        *      ip_srights, generate a no-senders notif,
-                        *      or use ipc_right_dncancel, because the
-                        *      port is destroyed "first".
-                        */
-                       bits &= ~IE_BITS_TYPE_MASK;
-                       bits |= MACH_PORT_TYPE_DEAD_NAME;
-                       if (entry->ie_request) {
-                               entry->ie_request = 0;
-                               bits++;
+                       if (port->ip_pdrequest != NULL) {
+                               /*
+                                * Since another task has requested a
+                                * destroy notification for this port, it
+                                * isn't actually being destroyed - the receive
+                                * right is just being moved to another task.
+                                * Since we still have one or more send rights,
+                                * we need to record the loss of the receive
+                                * right and enter the remaining send right
+                                * into the hash table.
+                                */
+                               entry->ie_bits &= ~MACH_PORT_TYPE_RECEIVE;
+                               ipc_hash_insert(space, (ipc_object_t) port,
+                                   name, entry);
+                               ip_reference(port);
+                       } else {
+                               /*
+                                *      The remaining send right turns into a
+                                *      dead name.  Notice we don't decrement
+                                *      ip_srights, generate a no-senders notif,
+                                *      or use ipc_right_dncancel, because the
+                                *      port is destroyed "first".
+                                */
+                               bits &= ~IE_BITS_TYPE_MASK;
+                               bits |= MACH_PORT_TYPE_DEAD_NAME;
+                               if (entry->ie_request) {
+                                       entry->ie_request = IE_REQ_NONE;
+                                       bits++;
+                               }
+                               entry->ie_bits = bits;
+                               entry->ie_object = IO_NULL;
                        }
-                       entry->ie_bits = bits;
-                       entry->ie_object = IO_NULL;
                } else {
                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
                        assert(IE_BITS_UREFS(bits) == 0);
 
-                       dnrequest = ipc_right_dncancel_macro(space, port,
+                       request = ipc_right_request_cancel_macro(space, port,
                                                             name, entry);
                        entry->ie_object = IO_NULL;
                        ipc_entry_dealloc(space, name, entry);
@@ -1068,13 +1104,13 @@ ipc_right_delta(
                ipc_port_clear_receiver(port);
                ipc_port_destroy(port); /* consumes ref, unlocks */
 
-               if (dnrequest != IP_NULL)
-                       ipc_notify_port_deleted(dnrequest, name);
+               if (request != IP_NULL)
+                       ipc_notify_port_deleted(request, name);
                break;
            }
 
            case MACH_PORT_RIGHT_SEND_ONCE: {
-               ipc_port_t port, dnrequest;
+               ipc_port_t port, request;
 
                if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0)
                        goto invalid_right;
@@ -1103,7 +1139,7 @@ ipc_right_delta(
                        goto success;
                }
 
-               dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
+               request = ipc_right_request_cancel_macro(space, port, name, entry);
                ip_unlock(port);
 
                entry->ie_object = IO_NULL;
@@ -1113,8 +1149,8 @@ ipc_right_delta(
 
                ipc_notify_send_once(port);
 
-               if (dnrequest != IP_NULL)
-                       ipc_notify_port_deleted(dnrequest, name);
+               if (request != IP_NULL)
+                       ipc_notify_port_deleted(request, name);
                break;
            }
 
@@ -1139,7 +1175,7 @@ ipc_right_delta(
                assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
                assert(IE_BITS_UREFS(bits) > 0);
                assert(entry->ie_object == IO_NULL);
-               assert(entry->ie_request == 0);
+               assert(entry->ie_request == IE_REQ_NONE);
 
                urefs = IE_BITS_UREFS(bits);
                if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta))
@@ -1161,9 +1197,9 @@ ipc_right_delta(
            case MACH_PORT_RIGHT_SEND: {
                mach_port_urefs_t urefs;
                ipc_port_t port;
-               ipc_port_t dnrequest = IP_NULL;
+               ipc_port_t request = IP_NULL;
                ipc_port_t nsrequest = IP_NULL;
-               mach_port_mscount_t mscount;
+               mach_port_mscount_t mscount = 0;
 
                if ((bits & MACH_PORT_TYPE_SEND) == 0)
                        goto invalid_right;
@@ -1212,7 +1248,7 @@ ipc_right_delta(
                                assert(IE_BITS_TYPE(bits) ==
                                                MACH_PORT_TYPE_SEND);
 
-                               dnrequest = ipc_right_dncancel_macro(space, port,
+                               request = ipc_right_request_cancel_macro(space, port,
                                                                     name, entry);
                                ipc_hash_delete(space, (ipc_object_t) port,
                                                name, entry);
@@ -1232,8 +1268,8 @@ ipc_right_delta(
                if (nsrequest != IP_NULL)
                        ipc_notify_no_senders(nsrequest, mscount);
 
-               if (dnrequest != IP_NULL)
-                       ipc_notify_port_deleted(dnrequest, name);
+               if (request != IP_NULL)
+                       ipc_notify_port_deleted(request, name);
                break;
            }
 
@@ -1279,27 +1315,42 @@ ipc_right_info(
        mach_port_type_t        *typep,
        mach_port_urefs_t       *urefsp)
 {
+       ipc_port_t port;
        ipc_entry_bits_t bits;
-       mach_port_type_t type;
+       mach_port_type_t type = 0;
        ipc_port_request_index_t request;
 
        bits = entry->ie_bits;
+       request = entry->ie_request;
+       port = (ipc_port_t) entry->ie_object;
 
-       if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
-               ipc_port_t port = (ipc_port_t) entry->ie_object;
+       if (bits & MACH_PORT_TYPE_RECEIVE) {
+               assert(IP_VALID(port));
 
-               if (ipc_right_check(space, port, name, entry)) {
+               if (request != IE_REQ_NONE) {
+                       ip_lock(port);
+                       assert(ip_active(port));
+                       type |= ipc_port_request_type(port, name, request);
+                       ip_unlock(port);
+               }
+
+       } else if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
+               /*
+                * validate port is still alive - if so, get request
+                * types while we still have it locked.  Otherwise,
+                * recapture the (now dead) bits.
+                */
+               if (!ipc_right_check(space, port, name, entry)) {
+                       if (request != IE_REQ_NONE)
+                               type |= ipc_port_request_type(port, name, request);
+                       ip_unlock(port);
+               } else {
                        bits = entry->ie_bits;
                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
-               } else
-                       ip_unlock(port);
+               }
        }
 
-       type = IE_BITS_TYPE(bits);
-       request = entry->ie_request;
-
-       if (request != 0)
-               type |= MACH_PORT_TYPE_DNREQUEST;
+       type |= IE_BITS_TYPE(bits);
 
        *typep = type;
        *urefsp = IE_BITS_UREFS(bits);
@@ -1316,29 +1367,72 @@ ipc_right_info(
 
 boolean_t
 ipc_right_copyin_check(
-       ipc_space_t             space,
-       mach_port_name_t        name,
-       ipc_entry_t             entry,
-       mach_msg_type_name_t    msgt_name)
+       __assert_only ipc_space_t       space,
+       __unused mach_port_name_t       name,
+       ipc_entry_t                     entry,
+       mach_msg_type_name_t            msgt_name)
 {
        ipc_entry_bits_t bits;
+       ipc_port_t port;
+#if CONFIG_MACF_MACH
+       task_t self = current_task();
+       int rc = 0;
+#endif
 
        bits= entry->ie_bits;
        assert(space->is_active);
 
        switch (msgt_name) {
            case MACH_MSG_TYPE_MAKE_SEND:
+               if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
+                       return FALSE;
+
+#if CONFIG_MACF_MACH
+               port = (ipc_port_t) entry->ie_object;
+               ip_lock(port);
+               tasklabel_lock(self);
+               rc = mac_port_check_make_send(&self->maclabel, &port->ip_label);                tasklabel_unlock(self);
+               ip_unlock(port);
+               if (rc)
+                       return FALSE;
+#endif
+               break;
+
            case MACH_MSG_TYPE_MAKE_SEND_ONCE:
+               if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
+                       return FALSE;
+
+#if CONFIG_MACF_MACH
+               port = (ipc_port_t) entry->ie_object;
+               ip_lock(port);
+               tasklabel_lock(self);
+               rc = mac_port_check_make_send_once(&self->maclabel, &port->ip_label);
+               tasklabel_unlock(self);
+               ip_unlock(port);
+               if (rc)
+                       return FALSE;
+#endif
+               break;
+
            case MACH_MSG_TYPE_MOVE_RECEIVE:
                if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
                        return FALSE;
 
+#if CONFIG_MACF_MACH
+               port = (ipc_port_t) entry->ie_object;
+               ip_lock(port);
+               tasklabel_lock(self);
+               rc = mac_port_check_move_receive(&self->maclabel, &port->ip_label);
+               tasklabel_unlock(self);
+               ip_unlock(port);
+               if (rc)
+                        return FALSE;
+#endif
                break;
 
            case MACH_MSG_TYPE_COPY_SEND:
            case MACH_MSG_TYPE_MOVE_SEND:
            case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
-               ipc_port_t port;
                boolean_t active;
 
                if (bits & MACH_PORT_TYPE_DEAD_NAME)
@@ -1352,6 +1446,30 @@ ipc_right_copyin_check(
 
                ip_lock(port);
                active = ip_active(port);
+#if CONFIG_MACF_MACH
+               tasklabel_lock(self);
+               switch (msgt_name) {
+               case MACH_MSG_TYPE_COPY_SEND:
+                       rc = mac_port_check_copy_send(&self->maclabel,
+                           &port->ip_label);
+                       break;
+               case MACH_MSG_TYPE_MOVE_SEND:
+                       rc = mac_port_check_move_send(&self->maclabel,
+                           &port->ip_label);
+                       break;
+               case MACH_MSG_TYPE_MOVE_SEND_ONCE:
+                       rc = mac_port_check_move_send_once(&self->maclabel,
+                           &port->ip_label);
+                       break;
+               default:
+                       panic("ipc_right_copyin_check: strange rights");
+               }
+               tasklabel_unlock(self);
+               if (rc) {
+                       ip_unlock(port);
+                       return FALSE;
+               }
+#endif
                ip_unlock(port);
 
                if (!active) {
@@ -1410,6 +1528,10 @@ ipc_right_copyin(
        ipc_port_t              *sorightp)
 {
        ipc_entry_bits_t bits;
+#if CONFIG_MACF_MACH
+       task_t self = current_task();
+       int    rc;
+#endif
        
        bits = entry->ie_bits;
 
@@ -1430,6 +1552,16 @@ ipc_right_copyin(
                assert(port->ip_receiver_name == name);
                assert(port->ip_receiver == space);
 
+#if CONFIG_MACF_MACH
+               tasklabel_lock(self);
+               rc = mac_port_check_make_send(&self->maclabel, &port->ip_label);
+               tasklabel_unlock(self);
+               if (rc) {
+                       ip_unlock(port);
+                       return KERN_NO_ACCESS;
+               }
+#endif
+
                port->ip_mscount++;
                port->ip_srights++;
                ip_reference(port);
@@ -1454,6 +1586,16 @@ ipc_right_copyin(
                assert(port->ip_receiver_name == name);
                assert(port->ip_receiver == space);
 
+#if CONFIG_MACF_MACH
+               tasklabel_lock(self);
+               rc = mac_port_check_make_send_once(&self->maclabel, &port->ip_label);
+               tasklabel_unlock(self);
+               if (rc) {
+                       ip_unlock(port);
+                       return KERN_NO_ACCESS;
+               }
+#endif
+
                port->ip_sorights++;
                ip_reference(port);
                ip_unlock(port);
@@ -1465,7 +1607,7 @@ ipc_right_copyin(
 
            case MACH_MSG_TYPE_MOVE_RECEIVE: {
                ipc_port_t port;
-               ipc_port_t dnrequest = IP_NULL;
+               ipc_port_t request = IP_NULL;
 
                if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
                        goto invalid_right;
@@ -1478,6 +1620,17 @@ ipc_right_copyin(
                assert(port->ip_receiver_name == name);
                assert(port->ip_receiver == space);
 
+#if CONFIG_MACF_MACH
+               tasklabel_lock(self);
+               rc = mac_port_check_move_receive(&self->maclabel,
+                                                &port->ip_label);
+               tasklabel_unlock(self);
+               if (rc) {
+                       ip_unlock(port);
+                       return KERN_NO_ACCESS;
+               }
+#endif
+
                if (bits & MACH_PORT_TYPE_SEND) {
                        assert(IE_BITS_TYPE(bits) ==
                                        MACH_PORT_TYPE_SEND_RECEIVE);
@@ -1491,7 +1644,7 @@ ipc_right_copyin(
                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
                        assert(IE_BITS_UREFS(bits) == 0);
 
-                       dnrequest = ipc_right_dncancel_macro(space, port,
+                       request = ipc_right_request_cancel_macro(space, port,
                                                             name, entry);
                        entry->ie_object = IO_NULL;
                }
@@ -1504,7 +1657,7 @@ ipc_right_copyin(
                ip_unlock(port);
 
                *objectp = (ipc_object_t) port;
-               *sorightp = dnrequest;
+               *sorightp = request;
                break;
            }
 
@@ -1530,6 +1683,16 @@ ipc_right_copyin(
                }
                /* port is locked and active */
 
+#if CONFIG_MACF_MACH
+               tasklabel_lock(self);
+               rc = mac_port_check_copy_send(&self->maclabel, &port->ip_label);
+               tasklabel_unlock(self);
+               if (rc) {
+                       ip_unlock(port);
+                       return KERN_NO_ACCESS;
+               }
+#endif
+
                if ((bits & MACH_PORT_TYPE_SEND) == 0) {
                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
                        assert(port->ip_sorights > 0);
@@ -1551,7 +1714,7 @@ ipc_right_copyin(
 
            case MACH_MSG_TYPE_MOVE_SEND: {
                ipc_port_t port;
-               ipc_port_t dnrequest = IP_NULL;
+               ipc_port_t request = IP_NULL;
 
                if (bits & MACH_PORT_TYPE_DEAD_NAME)
                        goto move_dead;
@@ -1572,6 +1735,17 @@ ipc_right_copyin(
                }
                /* port is locked and active */
 
+#if CONFIG_MACF_MACH
+               tasklabel_lock (self);
+               rc = mac_port_check_copy_send (&self->maclabel, &port->ip_label);
+               tasklabel_unlock (self);
+               if (rc)
+                 {
+                   ip_unlock (port);
+                   return KERN_NO_ACCESS;
+                 }
+#endif
+
                if ((bits & MACH_PORT_TYPE_SEND) == 0) {
                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
                        assert(port->ip_sorights > 0);
@@ -1594,7 +1768,7 @@ ipc_right_copyin(
                                assert(IE_BITS_TYPE(bits) ==
                                                MACH_PORT_TYPE_SEND);
 
-                               dnrequest = ipc_right_dncancel_macro(space, port,
+                               request = ipc_right_request_cancel_macro(space, port,
                                                                     name, entry);
                                ipc_hash_delete(space, (ipc_object_t) port,
                                                name, entry);
@@ -1611,13 +1785,13 @@ ipc_right_copyin(
                ip_unlock(port);
 
                *objectp = (ipc_object_t) port;
-               *sorightp = dnrequest;
+               *sorightp = request;
                break;
            }
 
            case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
                ipc_port_t port;
-               ipc_port_t dnrequest;
+               ipc_port_t request;
 
                if (bits & MACH_PORT_TYPE_DEAD_NAME)
                        goto move_dead;
@@ -1638,6 +1812,17 @@ ipc_right_copyin(
                }
                /* port is locked and active */
 
+#if CONFIG_MACF_MACH
+               tasklabel_lock (self);
+               rc = mac_port_check_copy_send (&self->maclabel, &port->ip_label);
+               tasklabel_unlock (self);
+               if (rc)
+                 {
+                   ip_unlock (port);
+                   return KERN_NO_ACCESS;
+                 }
+#endif
+
                if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0) {
                        assert(bits & MACH_PORT_TYPE_SEND);
                        assert(port->ip_srights > 0);
@@ -1650,7 +1835,7 @@ ipc_right_copyin(
                assert(IE_BITS_UREFS(bits) == 1);
                assert(port->ip_sorights > 0);
 
-               dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
+               request = ipc_right_request_cancel_macro(space, port, name, entry);
                ip_unlock(port);
 
                entry->ie_object = IO_NULL;
@@ -1658,7 +1843,7 @@ ipc_right_copyin(
                        (IE_BITS_UREFS_MASK | MACH_PORT_TYPE_SEND_ONCE);
 
                *objectp = (ipc_object_t) port;
-               *sorightp = dnrequest;
+               *sorightp = request;
                break;
            }
 
@@ -1672,7 +1857,7 @@ ipc_right_copyin(
     copy_dead:
        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
        assert(IE_BITS_UREFS(bits) > 0);
-       assert(entry->ie_request == 0);
+       assert(entry->ie_request == IE_REQ_NONE);
        assert(entry->ie_object == 0);
 
        if (!deadok)
@@ -1685,7 +1870,7 @@ ipc_right_copyin(
     move_dead:
        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
        assert(IE_BITS_UREFS(bits) > 0);
-       assert(entry->ie_request == 0);
+       assert(entry->ie_request == IE_REQ_NONE);
        assert(entry->ie_object == 0);
 
        if (!deadok)
@@ -1808,7 +1993,11 @@ ipc_right_copyin_two(
        ipc_entry_bits_t bits;
        mach_port_urefs_t urefs;
        ipc_port_t port;
-       ipc_port_t dnrequest = IP_NULL;
+       ipc_port_t request = IP_NULL;
+#if CONFIG_MACF_MACH
+       task_t self = current_task();
+       int    rc;
+#endif
 
        assert(space->is_active);
 
@@ -1829,6 +2018,16 @@ ipc_right_copyin_two(
        }
        /* port is locked and active */
 
+#if CONFIG_MACF_MACH
+       tasklabel_lock(self);
+       rc = mac_port_check_copy_send(&self->maclabel, &port->ip_label);
+       tasklabel_unlock(self);
+       if (rc) {
+               ip_unlock(port);
+               return KERN_NO_ACCESS;
+       }
+#endif
+
        assert(port->ip_srights > 0);
 
        if (urefs == 2) {
@@ -1844,7 +2043,7 @@ ipc_right_copyin_two(
                } else {
                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
 
-                       dnrequest = ipc_right_dncancel_macro(space, port,
+                       request = ipc_right_request_cancel_macro(space, port,
                                                             name, entry);
 
                        port->ip_srights++;
@@ -1863,7 +2062,7 @@ ipc_right_copyin_two(
        ip_unlock(port);
 
        *objectp = (ipc_object_t) port;
-       *sorightp = dnrequest;
+       *sorightp = request;
        return KERN_SUCCESS;
 
     invalid_right:
@@ -1905,6 +2104,9 @@ ipc_right_copyout(
 {
        ipc_entry_bits_t bits;
        ipc_port_t port;
+#if CONFIG_MACF_MACH
+       int rc;
+#endif
 
        bits = entry->ie_bits;
 
@@ -1921,6 +2123,19 @@ ipc_right_copyout(
                assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
                assert(port->ip_sorights > 0);
 
+#if CONFIG_MACF_MACH
+               if (space->is_task) {
+                       tasklabel_lock(space->is_task);
+                       rc = mac_port_check_hold_send_once(&space->is_task->maclabel,
+                                                          &port->ip_label);
+                       tasklabel_unlock(space->is_task);
+
+                       if (rc) {
+                               ip_unlock(port);
+                               return KERN_NO_ACCESS;
+                       }
+               }
+#endif
                /* transfer send-once right and ref to entry */
                ip_unlock(port);
 
@@ -1930,6 +2145,20 @@ ipc_right_copyout(
            case MACH_MSG_TYPE_PORT_SEND:
                assert(port->ip_srights > 0);
 
+#if CONFIG_MACF_MACH
+               if (space->is_task) {
+                       tasklabel_lock(space->is_task);
+                       rc = mac_port_check_hold_send(&space->is_task->maclabel,
+                                                     &port->ip_label);
+                       tasklabel_unlock(space->is_task);
+
+                       if (rc) {
+                               ip_unlock(port);
+                               return KERN_NO_ACCESS;
+                       }
+               }
+#endif
+
                if (bits & MACH_PORT_TYPE_SEND) {
                        mach_port_urefs_t urefs = IE_BITS_UREFS(bits);
 
@@ -1984,6 +2213,20 @@ ipc_right_copyout(
                assert(port->ip_receiver_name == MACH_PORT_NULL);
                dest = port->ip_destination;
 
+#if CONFIG_MACF_MACH
+               if (space->is_task) {
+                       tasklabel_lock(space->is_task);
+                       rc = mac_port_check_hold_receive(&space->is_task->maclabel,
+                                                        &port->ip_label);
+                       tasklabel_unlock(space->is_task);
+
+                       if (rc) {
+                               ip_unlock(port);
+                               return KERN_NO_ACCESS;
+                       }
+               }
+#endif
+
                port->ip_receiver_name = name;
                port->ip_receiver = space;
 
@@ -2057,7 +2300,7 @@ ipc_right_rename(
         *      Note IE_BITS_COMPAT implies ie_request != 0.
         */
 
-       if (request != 0) {
+       if (request != IE_REQ_NONE) {
                ipc_port_t port;
 
                assert(bits & MACH_PORT_TYPE_PORT_RIGHTS);
@@ -2065,17 +2308,17 @@ ipc_right_rename(
                assert(port != IP_NULL);
 
                if (ipc_right_check(space, port, oname, oentry)) {
-                       request = 0;
+                       request = IE_REQ_NONE;
                        object = IO_NULL;
                        bits = oentry->ie_bits;
                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
-                       assert(oentry->ie_request == 0);
+                       assert(oentry->ie_request == IE_REQ_NONE);
                } else {
                        /* port is locked and active */
 
-                       ipc_port_dnrename(port, request, oname, nname);
+                       ipc_port_request_rename(port, request, oname, nname);
                        ip_unlock(port);
-                       oentry->ie_request = 0;
+                       oentry->ie_request = IE_REQ_NONE;
                }
        }
 
@@ -2141,7 +2384,7 @@ ipc_right_rename(
                panic("ipc_right_rename: strange rights");
        }
 
-       assert(oentry->ie_request == 0);
+       assert(oentry->ie_request == IE_REQ_NONE);
        oentry->ie_object = IO_NULL;
        ipc_entry_dealloc(space, oname, oentry);
        is_write_unlock(space);