]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/kern/uipc_usrreq.c
xnu-2422.110.17.tar.gz
[apple/xnu.git] / bsd / kern / uipc_usrreq.c
index 26f38c8f5238edce4f38790a7bf02fbd551ed2b7..a01ac5eb24fd6adc1ea561e2a2aadc2c46dd5f7b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2012 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
@@ -73,6 +73,7 @@
 #include <sys/fcntl.h>
 #include <sys/malloc.h>                /* XXX must be before <sys/file.h> */
 #include <sys/file_internal.h>
+#include <sys/guarded.h>
 #include <sys/filedesc.h>
 #include <sys/lock.h>
 #include <sys/mbuf.h>
@@ -96,6 +97,8 @@
 #include <security/mac_framework.h>
 #endif /* CONFIG_MACF */
 
+#include <mach/vm_param.h>
+
 #define        f_msgcount f_fglob->fg_msgcount
 #define        f_cred f_fglob->fg_cred
 #define        f_ops f_fglob->fg_ops
@@ -117,6 +120,32 @@ static  u_int                   disconnect_in_progress;
 extern lck_mtx_t *uipc_lock;
 static struct unp_head unp_shead, unp_dhead;
 
+/*
+ * mDNSResponder tracing.  When enabled, endpoints connected to
+ * /var/run/mDNSResponder will be traced; during each send on
+ * the traced socket, we log the PID and process name of the
+ * sending process.  We also print out a bit of info related
+ * to the data itself; this assumes ipc_msg_hdr in dnssd_ipc.h
+ * of mDNSResponder stays the same.
+ */
+#define        MDNSRESPONDER_PATH      "/var/run/mDNSResponder"
+
+static int unpst_tracemdns;    /* enable tracing */
+
+#define        MDNS_IPC_MSG_HDR_VERSION_1      1
+
+struct mdns_ipc_msg_hdr {
+       uint32_t version;
+       uint32_t datalen;
+       uint32_t ipc_flags;
+       uint32_t op;
+       union {
+               void *context;
+               uint32_t u32[2];
+       } __attribute__((packed));
+       uint32_t reg_index;
+} __attribute__((packed));
+
 /*
  * Unix communications domain.
  *
@@ -271,7 +300,7 @@ uipc_detach(struct socket *so)
        if (unp == 0)
                return (EINVAL);
 
-       lck_mtx_assert(unp->unp_mtx, LCK_MTX_ASSERT_OWNED);
+       lck_mtx_assert(&unp->unp_mtx, LCK_MTX_ASSERT_OWNED);
        unp_detach(unp);
        return (0);
 }
@@ -428,7 +457,8 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
                }
 
                so2 = unp->unp_conn->unp_socket;
-               unp_get_locks_in_order(so, so2);
+               if (so != so2)
+                       unp_get_locks_in_order(so, so2);
 
                if (unp->unp_addr)
                        from = (struct sockaddr *)unp->unp_addr;
@@ -450,7 +480,8 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
                        control = NULL;
                }
 
-               socket_unlock(so2, 1);
+               if (so != so2) 
+                       socket_unlock(so2, 1);
 
                m = NULL;
                if (nam)
@@ -498,6 +529,16 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
                        break;
                }       
 
+               if (unp->unp_flags & UNP_TRACE_MDNS) {
+                       struct mdns_ipc_msg_hdr hdr;
+
+                       if (mbuf_copydata(m, 0, sizeof (hdr), &hdr) == 0 &&
+                           hdr.version  == ntohl(MDNS_IPC_MSG_HDR_VERSION_1)) {
+                               printf("%s[mDNSResponder] pid=%d (%s): op=0x%x\n",
+                                   __func__, p->p_pid, p->p_comm, ntohl(hdr.op));
+                       }
+               }
+
                /*
                 * Send to paired receive port, and then reduce send buffer
                 * hiwater marks to maintain backpressure.  Wake up readers.
@@ -634,18 +675,32 @@ uipc_sockaddr(struct socket *so, struct sockaddr **nam)
 }
 
 struct pr_usrreqs uipc_usrreqs = {
-       uipc_abort, uipc_accept, uipc_attach, uipc_bind, uipc_connect,
-       uipc_connect2, pru_control_notsupp, uipc_detach, uipc_disconnect,
-       uipc_listen, uipc_peeraddr, uipc_rcvd, pru_rcvoob_notsupp,
-       uipc_send, uipc_sense, uipc_shutdown, uipc_sockaddr,
-       sosend, soreceive, pru_sopoll_notsupp
+       .pru_abort =            uipc_abort,
+       .pru_accept =           uipc_accept,
+       .pru_attach =           uipc_attach,
+       .pru_bind =             uipc_bind,
+       .pru_connect =          uipc_connect,
+       .pru_connect2 =         uipc_connect2,
+       .pru_detach =           uipc_detach,
+       .pru_disconnect =       uipc_disconnect,
+       .pru_listen =           uipc_listen,
+       .pru_peeraddr =         uipc_peeraddr,
+       .pru_rcvd =             uipc_rcvd,
+       .pru_send =             uipc_send,
+       .pru_sense =            uipc_sense,
+       .pru_shutdown =         uipc_shutdown,
+       .pru_sockaddr =         uipc_sockaddr,
+       .pru_sosend =           sosend,
+       .pru_soreceive =        soreceive,
 };
 
 int
 uipc_ctloutput(struct socket *so, struct sockopt *sopt)
 {
        struct unpcb *unp = sotounpcb(so);
-       int error;
+       int error = 0;
+       pid_t peerpid;
+       struct socket *peerso;
 
        switch (sopt->sopt_dir) {
        case SOPT_GET:
@@ -661,6 +716,43 @@ uipc_ctloutput(struct socket *so, struct sockopt *sopt)
                                        error = EINVAL;
                        }
                        break;
+               case LOCAL_PEERPID:
+               case LOCAL_PEEREPID:
+                       if (unp->unp_conn == NULL) {
+                               error = ENOTCONN;
+                               break;
+                       }
+                       peerso = unp->unp_conn->unp_socket;
+                       if (peerso == NULL)
+                               panic("peer is connected but has no socket?");
+                       unp_get_locks_in_order(so, peerso);
+                       if (sopt->sopt_name == LOCAL_PEEREPID &&
+                           peerso->so_flags & SOF_DELEGATED)
+                               peerpid = peerso->e_pid;
+                       else
+                               peerpid = peerso->last_pid;
+                       socket_unlock(peerso, 1);
+                       error = sooptcopyout(sopt, &peerpid, sizeof (peerpid));
+                       break;
+               case LOCAL_PEERUUID:
+               case LOCAL_PEEREUUID:
+                       if (unp->unp_conn == NULL) {
+                               error = ENOTCONN;
+                               break;
+                       }
+                       peerso = unp->unp_conn->unp_socket;
+                       if (peerso == NULL)
+                               panic("peer is connected but has no socket?");
+                       unp_get_locks_in_order(so, peerso);
+                       if (sopt->sopt_name == LOCAL_PEEREUUID &&
+                           peerso->so_flags & SOF_DELEGATED)
+                               error = sooptcopyout(sopt, &peerso->e_uuid,
+                                   sizeof (peerso->e_uuid));
+                       else
+                               error = sooptcopyout(sopt, &peerso->last_uuid,
+                                   sizeof (peerso->last_uuid));
+                       socket_unlock(peerso, 1);
+                       break;
                default:
                        error = EOPNOTSUPP;
                        break;
@@ -671,6 +763,7 @@ uipc_ctloutput(struct socket *so, struct sockopt *sopt)
                error = EOPNOTSUPP;
                break;
        }
+
        return (error);
 }
 
@@ -694,17 +787,19 @@ static int        unp_rights;                     /* file descriptors in flight */
 static int     unp_disposed;                   /* discarded file descriptors */
 
 SYSCTL_DECL(_net_local_stream);
-SYSCTL_INT(_net_local_stream, OID_AUTO, sendspace, CTLFLAG_RW,
+SYSCTL_INT(_net_local_stream, OID_AUTO, sendspace, CTLFLAG_RW | CTLFLAG_LOCKED,
    &unpst_sendspace, 0, "");
-SYSCTL_INT(_net_local_stream, OID_AUTO, recvspace, CTLFLAG_RW,
+SYSCTL_INT(_net_local_stream, OID_AUTO, recvspace, CTLFLAG_RW | CTLFLAG_LOCKED,
    &unpst_recvspace, 0, "");
+SYSCTL_INT(_net_local_stream, OID_AUTO, tracemdns, CTLFLAG_RW | CTLFLAG_LOCKED,
+   &unpst_tracemdns, 0, "");
 SYSCTL_DECL(_net_local_dgram);
-SYSCTL_INT(_net_local_dgram, OID_AUTO, maxdgram, CTLFLAG_RW,
+SYSCTL_INT(_net_local_dgram, OID_AUTO, maxdgram, CTLFLAG_RW | CTLFLAG_LOCKED,
    &unpdg_sendspace, 0, "");
-SYSCTL_INT(_net_local_dgram, OID_AUTO, recvspace, CTLFLAG_RW,
+SYSCTL_INT(_net_local_dgram, OID_AUTO, recvspace, CTLFLAG_RW | CTLFLAG_LOCKED,
    &unpdg_recvspace, 0, "");
 SYSCTL_DECL(_net_local);
-SYSCTL_INT(_net_local, OID_AUTO, inflight, CTLFLAG_RD, &unp_rights, 0, "");
+SYSCTL_INT(_net_local, OID_AUTO, inflight, CTLFLAG_RD | CTLFLAG_LOCKED, &unp_rights, 0, "");
 
 /*
  * Returns:    0                       Success
@@ -739,11 +834,8 @@ unp_attach(struct socket *so)
                return (ENOBUFS);
        bzero(unp, sizeof (*unp));
 
-       unp->unp_mtx = lck_mtx_alloc_init(unp_mtx_grp, unp_mtx_attr);
-       if (unp->unp_mtx == NULL) {
-               zfree(unp_zone, unp);
-               return(ENOBUFS);
-       }
+       lck_mtx_init(&unp->unp_mtx, 
+               unp_mtx_grp, unp_mtx_attr);
 
        lck_rw_lock_exclusive(unp_list_mtx);
        LIST_INIT(&unp->unp_refs);
@@ -780,8 +872,12 @@ unp_attach(struct socket *so)
 static void
 unp_detach(struct unpcb *unp)
 {
+       int so_locked = 1;
+
        lck_rw_lock_exclusive(unp_list_mtx);
        LIST_REMOVE(unp, unp_link);
+       --unp_count; 
+       ++unp_gencnt;
        lck_rw_done(unp_list_mtx);
        if (unp->unp_vnode) {
                struct vnode *tvp = NULL;
@@ -805,13 +901,46 @@ unp_detach(struct unpcb *unp)
        if (unp->unp_conn)
                unp_disconnect(unp);
        while (unp->unp_refs.lh_first) {
-               struct unpcb *unp2 = unp->unp_refs.lh_first;
-               socket_unlock(unp->unp_socket, 0);
-               socket_lock(unp2->unp_socket, 1);
-               unp_drop(unp2, ECONNRESET);
-               socket_unlock(unp2->unp_socket, 1);
+               struct unpcb *unp2 = NULL;
+
+               /* This datagram socket is connected to one or more
+                * sockets. In order to avoid a race condition between removing
+                * this reference and closing the connected socket, we need 
+                * to check disconnect_in_progress
+                */
+               if (so_locked == 1) {
+                       socket_unlock(unp->unp_socket, 0);
+                       so_locked = 0;
+               }
+               lck_mtx_lock(unp_disconnect_lock);
+               while (disconnect_in_progress != 0) {
+                       (void)msleep((caddr_t)&disconnect_in_progress, unp_disconnect_lock,
+                               PSOCK, "disconnect", NULL);
+               }
+               disconnect_in_progress = 1;
+               lck_mtx_unlock(unp_disconnect_lock);
+
+               /* Now we are sure that any unpcb socket disconnect is not happening */
+               if (unp->unp_refs.lh_first != NULL) {
+                       unp2 = unp->unp_refs.lh_first;
+                       socket_lock(unp2->unp_socket, 1);
+               }
+               
+               lck_mtx_lock(unp_disconnect_lock);
+               disconnect_in_progress = 0;
+               wakeup(&disconnect_in_progress);
+               lck_mtx_unlock(unp_disconnect_lock);
+                       
+               if (unp2 != NULL) {
+                       /* We already locked this socket and have a reference on it */
+                       unp_drop(unp2, ECONNRESET);
+                       socket_unlock(unp2->unp_socket, 1);
+               }
+       }
+
+       if (so_locked == 0) {
                socket_lock(unp->unp_socket, 0);
+               so_locked = 1;
        }
        soisdisconnected(unp->unp_socket);
        /* makes sure we're getting dealloced */
@@ -857,7 +986,7 @@ unp_bind(
        socket_unlock(so, 0);
 
        strlcpy(buf, soun->sun_path, namelen+1);
-       NDINIT(&nd, CREATE, FOLLOW | LOCKPARENT, UIO_SYSSPACE,
+       NDINIT(&nd, CREATE, OP_MKFIFO, FOLLOW | LOCKPARENT, UIO_SYSSPACE,
            CAST_USER_ADDR_T(buf), ctx);
        /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
        error = namei(&nd);
@@ -903,7 +1032,7 @@ unp_bind(
 
        if (!error) {
                /* create the socket */
-               error = vn_create(dvp, &vp, &nd.ni_cnd, &va, 0, ctx);
+               error = vn_create(dvp, &vp, &nd, &va, 0, 0, NULL, ctx);
        }
 
        nameidone(&nd);
@@ -966,7 +1095,7 @@ unp_connect(struct socket *so, struct sockaddr *nam, __unused proc_t p)
        strlcpy(buf, soun->sun_path, len+1);
        socket_unlock(so, 0);
 
-       NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE,
+       NDINIT(&nd, LOOKUP, OP_LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE,
            CAST_USER_ADDR_T(buf), ctx);
        error = namei(&nd);
        if (error) {
@@ -1011,8 +1140,13 @@ unp_connect(struct socket *so, struct sockaddr *nam, __unused proc_t p)
 
        if (so2->so_pcb == NULL) {
                error = ECONNREFUSED;
-               socket_unlock(so2, 1);
-               socket_lock(so, 0);
+               if (so != so2) {
+                       socket_unlock(so2, 1);
+                       socket_lock(so, 0);
+               } else {
+                       /* Release the reference held for the listen socket */
+                       so2->so_usecount--;
+               }
                goto out;
        }
 
@@ -1020,7 +1154,7 @@ unp_connect(struct socket *so, struct sockaddr *nam, __unused proc_t p)
                socket_unlock(so2, 0);
                socket_lock(so, 0);
                socket_lock(so2, 0);
-       } else {
+       } else if (so > so2) {
                socket_lock(so, 0);
        }
        /*
@@ -1029,15 +1163,13 @@ unp_connect(struct socket *so, struct sockaddr *nam, __unused proc_t p)
         * XXX - probably shouldn't return an error for SOCK_DGRAM
         */
        if ((so->so_state & SS_ISCONNECTED) != 0) {
-               socket_unlock(so2, 1);
                error = EISCONN;
-               goto out;
+               goto decref_out;
        }
 
        if (so->so_type != so2->so_type) {
-               socket_unlock(so2, 1);
                error = EPROTOTYPE;
-               goto out;
+               goto decref_out;
        }
 
        if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
@@ -1047,8 +1179,16 @@ unp_connect(struct socket *so, struct sockaddr *nam, __unused proc_t p)
                if ((so2->so_options & SO_ACCEPTCONN) == 0 ||
                    (so3 = sonewconn(so2, 0, nam)) == 0) {
                        error = ECONNREFUSED;
-                       socket_unlock(so2, 1);
-                       socket_lock(so, 0);
+                       if (so != so2) {
+                               socket_unlock(so2, 1);
+                               socket_lock(so, 0);
+                       } else {
+                               socket_lock(so, 0);
+                               /* Release the reference held for
+                                * listen socket.
+                                */
+                               so2->so_usecount--;
+                       }
                        goto out;
                }
                unp2 = sotounpcb(so2);
@@ -1114,19 +1254,41 @@ unp_connect(struct socket *so, struct sockaddr *nam, __unused proc_t p)
                socket_lock(so3, 1);
                so2 = so3;
 
+               /*
+                * Enable tracing for mDNSResponder endpoints.  (The use
+                * of sizeof instead of strlen below takes the null
+                * terminating character into account.)
+                */
+               if (unpst_tracemdns &&
+                   !strncmp(soun->sun_path, MDNSRESPONDER_PATH,
+                   sizeof (MDNSRESPONDER_PATH))) {
+                       unp->unp_flags |= UNP_TRACE_MDNS;
+                       unp2->unp_flags |= UNP_TRACE_MDNS;
+               }
        }
        
        error = unp_connect2(so, so2);
+
+decref_out:
        if (so2 != NULL) {
-               socket_unlock(so2, 1);
+               if (so != so2) {
+                       socket_unlock(so2, 1);
+               } else {
+                       /* Release the extra reference held for the listen socket.
+                        * This is possible only for SOCK_DGRAM sockets. We refuse
+                        * connecting to the same socket for SOCK_STREAM sockets.
+                        */
+                       so2->so_usecount--;
+               }
        }
 
        if (list_so != NULL) {
                socket_lock(list_so, 0);
                socket_unlock(list_so, 1);
        }
+
 out:
-       lck_mtx_assert(unp->unp_mtx, LCK_MTX_ASSERT_OWNED);
+       lck_mtx_assert(&unp->unp_mtx, LCK_MTX_ASSERT_OWNED);
        vnode_put(vp);
        return (error);
 }
@@ -1147,8 +1309,8 @@ unp_connect2(struct socket *so, struct socket *so2)
 
        unp2 = sotounpcb(so2);
 
-       lck_mtx_assert(unp->unp_mtx, LCK_MTX_ASSERT_OWNED);
-       lck_mtx_assert(unp2->unp_mtx, LCK_MTX_ASSERT_OWNED);
+       lck_mtx_assert(&unp->unp_mtx, LCK_MTX_ASSERT_OWNED);
+       lck_mtx_assert(&unp2->unp_mtx, LCK_MTX_ASSERT_OWNED);
 
        /* Verify both sockets are still opened */
        if (unp == 0 || unp2 == 0)
@@ -1160,19 +1322,20 @@ unp_connect2(struct socket *so, struct socket *so2)
        switch (so->so_type) {
 
        case SOCK_DGRAM:
-               lck_rw_lock_exclusive(unp_list_mtx);
                LIST_INSERT_HEAD(&unp2->unp_refs, unp, unp_reflink);
-               lck_rw_done(unp_list_mtx);
 
-               
-               /* Avoid lock order reversals due to drop/acquire in soisconnected. */
-               /* Keep an extra reference on so2 that will be dropped
-                * soon after getting the locks in order 
-                */ 
-               socket_unlock(so2, 0);
-               soisconnected(so);
-               unp_get_locks_in_order(so, so2);
-               so2->so_usecount--;
+               if (so != so2) {        
+                       /* Avoid lock order reversals due to drop/acquire in soisconnected. */
+                       /* Keep an extra reference on so2 that will be dropped
+                        * soon after getting the locks in order 
+                        */ 
+                       socket_unlock(so2, 0);
+                       soisconnected(so);
+                       unp_get_locks_in_order(so, so2);
+                       so2->so_usecount--;
+               } else {
+                       soisconnected(so);
+               }
 
                break;
 
@@ -1209,8 +1372,8 @@ unp_connect2(struct socket *so, struct socket *so2)
        default:
                panic("unknown socket type %d in unp_connect2", so->so_type);
        }
-       lck_mtx_assert(unp->unp_mtx, LCK_MTX_ASSERT_OWNED);
-       lck_mtx_assert(unp2->unp_mtx, LCK_MTX_ASSERT_OWNED);
+       lck_mtx_assert(&unp->unp_mtx, LCK_MTX_ASSERT_OWNED);
+       lck_mtx_assert(&unp2->unp_mtx, LCK_MTX_ASSERT_OWNED);
        return (0);
 }
 
@@ -1251,7 +1414,12 @@ unp_disconnect(struct unpcb *unp)
        so2 = unp2->unp_socket;
 
 try_again:
-       if (so < so2) {
+       if (so == so2) {
+               if (so_locked == 0) {
+                       socket_lock(so, 0);
+               }
+               waitso = so;
+       } else if (so < so2) {
                if (so_locked == 0) {
                        socket_lock(so, 0);
                }
@@ -1265,19 +1433,22 @@ try_again:
                socket_lock(so, 0);
                waitso = so;
        }
+       so_locked = 1;
 
-       lck_mtx_assert(unp->unp_mtx, LCK_MTX_ASSERT_OWNED);
-       lck_mtx_assert(unp2->unp_mtx, LCK_MTX_ASSERT_OWNED);
+       lck_mtx_assert(&unp->unp_mtx, LCK_MTX_ASSERT_OWNED);
+       lck_mtx_assert(&unp2->unp_mtx, LCK_MTX_ASSERT_OWNED);
 
        /* Check for the UNP_DONTDISCONNECT flag, if it
         * is set, release both sockets and go to sleep
         */
        
        if ((((struct unpcb *)waitso->so_pcb)->unp_flags & UNP_DONTDISCONNECT) != 0) {
-               socket_unlock(so2, 1);
+               if (so != so2) {
+                       socket_unlock(so2, 1);
+               }
                so_locked = 0;
 
-               (void)msleep(waitso->so_pcb, unp->unp_mtx, 
+               (void)msleep(waitso->so_pcb, &unp->unp_mtx, 
                        PSOCK | PDROP, "unpdisconnect", NULL);
                goto try_again;
        }
@@ -1289,14 +1460,16 @@ try_again:
        unp->unp_conn = NULL;
        so2->so_usecount--;
 
+       if (unp->unp_flags & UNP_TRACE_MDNS)
+               unp->unp_flags &= ~UNP_TRACE_MDNS;
+
        switch (unp->unp_socket->so_type) {
 
        case SOCK_DGRAM:
-               lck_rw_lock_exclusive(unp_list_mtx);
                LIST_REMOVE(unp, unp_reflink);
-               lck_rw_done(unp_list_mtx);
                unp->unp_socket->so_state &= ~SS_ISCONNECTED;
-               socket_unlock(so2, 1);
+               if (so != so2)
+                       socket_unlock(so2, 1);
                break;
 
        case SOCK_STREAM:
@@ -1312,6 +1485,10 @@ try_again:
 
                unp2->unp_socket->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING);
                unp->unp_socket->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE|SS_ISDISCONNECTED);
+
+               if (unp2->unp_flags & UNP_TRACE_MDNS)
+                       unp2->unp_flags &= ~UNP_TRACE_MDNS;
+
                strdisconn = 1;
                break;
        default:
@@ -1331,7 +1508,7 @@ out:
                socket_lock(so,0);
                soisdisconnected(so);
        }
-       lck_mtx_assert(unp->unp_mtx, LCK_MTX_ASSERT_OWNED);
+       lck_mtx_assert(&unp->unp_mtx, LCK_MTX_ASSERT_OWNED);
        return;
 }
 
@@ -1343,31 +1520,37 @@ static void
 unpcb_to_compat(struct unpcb *up, struct unpcb_compat *cp)
 {
 #if defined(__LP64__)
-       cp->unp_link.le_next = (u_int32_t)(uintptr_t)up->unp_link.le_next;
-       cp->unp_link.le_prev = (u_int32_t)(uintptr_t)up->unp_link.le_prev;
+       cp->unp_link.le_next = (u_int32_t)
+           VM_KERNEL_ADDRPERM(up->unp_link.le_next);
+       cp->unp_link.le_prev = (u_int32_t)
+           VM_KERNEL_ADDRPERM(up->unp_link.le_prev);
 #else
-       cp->unp_link.le_next = (struct unpcb_compat *)up->unp_link.le_next;
-       cp->unp_link.le_prev = (struct unpcb_compat **)up->unp_link.le_prev;
+       cp->unp_link.le_next = (struct unpcb_compat *)
+           VM_KERNEL_ADDRPERM(up->unp_link.le_next);
+       cp->unp_link.le_prev = (struct unpcb_compat **)
+           VM_KERNEL_ADDRPERM(up->unp_link.le_prev);
 #endif
-       cp->unp_socket = (_UNPCB_PTR(struct socket *))(uintptr_t)up->unp_socket;
-       cp->unp_vnode = (_UNPCB_PTR(struct vnode *))(uintptr_t)up->unp_vnode;
+       cp->unp_socket = (_UNPCB_PTR(struct socket *))
+           VM_KERNEL_ADDRPERM(up->unp_socket);
+       cp->unp_vnode = (_UNPCB_PTR(struct vnode *))
+           VM_KERNEL_ADDRPERM(up->unp_vnode);
        cp->unp_ino = up->unp_ino;
        cp->unp_conn = (_UNPCB_PTR(struct unpcb_compat *))
-           (uintptr_t)up->unp_conn;
-       cp->unp_refs = (u_int32_t)(uintptr_t)up->unp_refs.lh_first;
+           VM_KERNEL_ADDRPERM(up->unp_conn);
+       cp->unp_refs = (u_int32_t)VM_KERNEL_ADDRPERM(up->unp_refs.lh_first);
 #if defined(__LP64__)
        cp->unp_reflink.le_next =
-           (u_int32_t)(uintptr_t)up->unp_reflink.le_next;
+           (u_int32_t)VM_KERNEL_ADDRPERM(up->unp_reflink.le_next);
        cp->unp_reflink.le_prev =
-           (u_int32_t)(uintptr_t)up->unp_reflink.le_prev;
+           (u_int32_t)VM_KERNEL_ADDRPERM(up->unp_reflink.le_prev);
 #else
        cp->unp_reflink.le_next =
-           (struct unpcb_compat *)up->unp_reflink.le_next;
+           (struct unpcb_compat *)VM_KERNEL_ADDRPERM(up->unp_reflink.le_next);
        cp->unp_reflink.le_prev =
-           (struct unpcb_compat **)up->unp_reflink.le_prev;
+           (struct unpcb_compat **)VM_KERNEL_ADDRPERM(up->unp_reflink.le_prev);
 #endif
        cp->unp_addr = (_UNPCB_PTR(struct sockaddr_un *))
-           (uintptr_t)up->unp_addr;
+           VM_KERNEL_ADDRPERM(up->unp_addr);
        cp->unp_cc = up->unp_cc;
        cp->unp_mbcnt = up->unp_mbcnt;
        cp->unp_gencnt = up->unp_gencnt;
@@ -1451,7 +1634,7 @@ unp_pcblist SYSCTL_HANDLER_ARGS
                        bzero(&xu, sizeof (xu));
                        xu.xu_len = sizeof (xu);
                        xu.xu_unpp = (_UNPCB_PTR(struct unpcb_compat *))
-                           (uintptr_t)unp;
+                           VM_KERNEL_ADDRPERM(unp);
                        /*
                         * XXX - need more locking here to protect against
                         * connect/disconnect races for SMP.
@@ -1488,14 +1671,13 @@ unp_pcblist SYSCTL_HANDLER_ARGS
        return (error);
 }
 
-SYSCTL_PROC(_net_local_dgram, OID_AUTO, pcblist, CTLFLAG_RD,
+SYSCTL_PROC(_net_local_dgram, OID_AUTO, pcblist, CTLFLAG_RD | CTLFLAG_LOCKED,
             (caddr_t)(long)SOCK_DGRAM, 0, unp_pcblist, "S,xunpcb",
             "List of active local datagram sockets");
-SYSCTL_PROC(_net_local_stream, OID_AUTO, pcblist, CTLFLAG_RD,
+SYSCTL_PROC(_net_local_stream, OID_AUTO, pcblist, CTLFLAG_RD | CTLFLAG_LOCKED,
             (caddr_t)(long)SOCK_STREAM, 0, unp_pcblist, "S,xunpcb",
             "List of active local stream sockets");
 
-#if !CONFIG_EMBEDDED
 
 static int
 unp_pcblist64 SYSCTL_HANDLER_ARGS
@@ -1575,20 +1757,24 @@ unp_pcblist64 SYSCTL_HANDLER_ARGS
 
                        bzero(&xu, xu_len);
                        xu.xu_len = xu_len;
-                       xu.xu_unpp = (u_int64_t)(uintptr_t)unp;
-                        xu.xunp_link.le_next =
-                                (u_int64_t)(uintptr_t)unp->unp_link.le_next;
-                        xu.xunp_link.le_prev =
-                                (u_int64_t)(uintptr_t)unp->unp_link.le_prev;
-                       xu.xunp_socket = (u_int64_t)(uintptr_t)unp->unp_socket;
-                       xu.xunp_vnode = (u_int64_t)(uintptr_t)unp->unp_vnode;
+                       xu.xu_unpp = (u_int64_t)VM_KERNEL_ADDRPERM(unp);
+                       xu.xunp_link.le_next = (u_int64_t)
+                           VM_KERNEL_ADDRPERM(unp->unp_link.le_next);
+                       xu.xunp_link.le_prev = (u_int64_t)
+                           VM_KERNEL_ADDRPERM(unp->unp_link.le_prev);
+                       xu.xunp_socket = (u_int64_t)
+                           VM_KERNEL_ADDRPERM(unp->unp_socket);
+                       xu.xunp_vnode = (u_int64_t)
+                           VM_KERNEL_ADDRPERM(unp->unp_vnode);
                        xu.xunp_ino = unp->unp_ino;
-                       xu.xunp_conn = (u_int64_t)(uintptr_t)unp->unp_conn;
-                       xu.xunp_refs = (u_int64_t)(uintptr_t)unp->unp_refs.lh_first;
-                       xu.xunp_reflink.le_next = 
-                               (u_int64_t)(uintptr_t)unp->unp_reflink.le_next;
-                        xu.xunp_reflink.le_prev = 
-                                (u_int64_t)(uintptr_t)unp->unp_reflink.le_prev;
+                       xu.xunp_conn = (u_int64_t)
+                           VM_KERNEL_ADDRPERM(unp->unp_conn);
+                       xu.xunp_refs = (u_int64_t)
+                           VM_KERNEL_ADDRPERM(unp->unp_refs.lh_first);
+                       xu.xunp_reflink.le_next = (u_int64_t)
+                           VM_KERNEL_ADDRPERM(unp->unp_reflink.le_next);
+                       xu.xunp_reflink.le_prev = (u_int64_t)
+                           VM_KERNEL_ADDRPERM(unp->unp_reflink.le_prev);
                        xu.xunp_cc = unp->unp_cc;
                        xu.xunp_mbcnt = unp->unp_mbcnt;
                        xu.xunp_gencnt = unp->unp_gencnt;
@@ -1631,14 +1817,13 @@ unp_pcblist64 SYSCTL_HANDLER_ARGS
        return (error);
 }
 
-SYSCTL_PROC(_net_local_dgram, OID_AUTO, pcblist64, CTLFLAG_RD,
+SYSCTL_PROC(_net_local_dgram, OID_AUTO, pcblist64, CTLFLAG_RD | CTLFLAG_LOCKED,
            (caddr_t)(long)SOCK_DGRAM, 0, unp_pcblist64, "S,xunpcb64",
            "List of active local datagram sockets 64 bit");
-SYSCTL_PROC(_net_local_stream, OID_AUTO, pcblist64, CTLFLAG_RD,
+SYSCTL_PROC(_net_local_stream, OID_AUTO, pcblist64, CTLFLAG_RD | CTLFLAG_LOCKED,
            (caddr_t)(long)SOCK_STREAM, 0, unp_pcblist64, "S,xunpcb64",
            "List of active local stream sockets 64 bit");
 
-#endif /* !CONFIG_EMBEDDED */
 
 static void
 unp_shutdown(struct unpcb *unp)
@@ -1719,11 +1904,9 @@ unp_externalize(struct mbuf *rights)
                if (fdalloc(p, 0, &f))
                        panic("unp_externalize:fdalloc");
                fg = rp[i];
-               MALLOC_ZONE(fp, struct fileproc *, sizeof (struct fileproc),
-                   M_FILEPROC, M_WAITOK);
+               fp = fileproc_alloc_init(NULL);
                if (fp == NULL)
                        panic("unp_externalize: MALLOC_ZONE");
-               bzero(fp, sizeof (struct fileproc));
                fp->f_iocount = 0;
                fp->f_fglob = fg;
                fg_removeuipc(fg);
@@ -1803,9 +1986,14 @@ unp_internalize(struct mbuf *control, proc_t p)
                if (((error = fdgetf_noref(p, fds[i], &tmpfp)) != 0)) {
                        proc_fdunlock(p);
                        return (error);
-               } else if (!filetype_issendable(tmpfp->f_fglob->fg_type)) {
+               } else if (!filetype_issendable(FILEGLOB_DTYPE(tmpfp->f_fglob))) {
                        proc_fdunlock(p);
                        return (EINVAL);
+               } else if (FP_ISGUARDED(tmpfp, GUARD_SOCKET_IPC)) {
+                       error = fp_guard_exception(p,
+                               fds[i], tmpfp, kGUARD_EXC_SOCKET_IPC);
+                       proc_fdunlock(p);
+                       return (error);
                }
        }
        rp = (struct fileglob **)(cm + 1);
@@ -1917,12 +2105,12 @@ unp_gc(void)
                         * accessible and not already marked so.
                         * Now check if it is possibly one of OUR sockets.
                         */
-                       if (fg->fg_type != DTYPE_SOCKET ||
+                       if (FILEGLOB_DTYPE(fg) != DTYPE_SOCKET ||
                            (so = (struct socket *)fg->fg_data) == 0) {
                                lck_mtx_unlock(&fg->fg_lock);
                                continue;
                        }
-                       if (so->so_proto->pr_domain != &localdomain ||
+                       if (so->so_proto->pr_domain != localdomain ||
                            (so->so_proto->pr_flags&PR_RIGHTS) == 0) {
                                lck_mtx_unlock(&fg->fg_lock);
                                continue;
@@ -2038,7 +2226,8 @@ unp_gc(void)
 
                tfg = *fpp;
 
-               if (tfg->fg_type == DTYPE_SOCKET && tfg->fg_data != NULL) {
+               if (FILEGLOB_DTYPE(tfg) == DTYPE_SOCKET &&
+                   tfg->fg_data != NULL) {
                        so = (struct socket *)(tfg->fg_data);
 
                        socket_lock(so, 0);
@@ -2164,7 +2353,7 @@ unp_lock(struct socket *so, int refcount, void * lr)
         else lr_saved = lr;
 
         if (so->so_pcb) {
-                lck_mtx_lock(((struct unpcb *)so->so_pcb)->unp_mtx);
+                lck_mtx_lock(&((struct unpcb *)so->so_pcb)->unp_mtx);
         } else  {
                 panic("unp_lock: so=%p NO PCB! lr=%p ref=0x%x\n", 
                        so, lr_saved, so->so_usecount);
@@ -2201,7 +2390,7 @@ unp_unlock(struct socket *so, int refcount, void * lr)
         if (so->so_pcb == NULL) {
                 panic("unp_unlock: so=%p NO PCB usecount=%x\n", so, so->so_usecount);
         } else {
-                mutex_held = ((struct unpcb *)so->so_pcb)->unp_mtx;
+                mutex_held = &((struct unpcb *)so->so_pcb)->unp_mtx;
         }
         lck_mtx_assert(mutex_held, LCK_MTX_ASSERT_OWNED);
         so->unlock_lr[so->next_unlock_lr] = lr_saved;
@@ -2214,12 +2403,9 @@ unp_unlock(struct socket *so, int refcount, void * lr)
                        FREE(unp->unp_addr, M_SONAME);
                
                lck_mtx_unlock(mutex_held);
-               if (unp->unp_mtx)
-                       lck_mtx_free(unp->unp_mtx, unp_mtx_grp);
 
-               unp->unp_gencnt = ++unp_gencnt;
+               lck_mtx_destroy(&unp->unp_mtx, unp_mtx_grp);
                zfree(unp_zone, unp);
-               --unp_count;
 
                unp_gc();
        } else {
@@ -2238,7 +2424,7 @@ unp_getlock(struct socket *so, __unused int locktype)
         if (so->so_pcb)  {
                 if (so->so_usecount < 0)
                         panic("unp_getlock: so=%p usecount=%x\n", so, so->so_usecount);
-                return(unp->unp_mtx);
+                return(&unp->unp_mtx);
         } else {
                 panic("unp_getlock: so=%p NULL so_pcb\n", so);
                 return (so->so_proto->pr_domain->dom_mtx);