]> 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 c64053a2c55e24a77da818d956335d54db12c8e6..a01ac5eb24fd6adc1ea561e2a2aadc2c46dd5f7b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2010 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
@@ -672,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:
@@ -699,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;
@@ -709,6 +763,7 @@ uipc_ctloutput(struct socket *so, struct sockopt *sopt)
                error = EOPNOTSUPP;
                break;
        }
+
        return (error);
 }
 
@@ -821,6 +876,8 @@ unp_detach(struct unpcb *unp)
 
        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;
@@ -1122,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);
@@ -1455,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;
@@ -1563,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.
@@ -1607,7 +1678,6 @@ 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
@@ -1687,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;
@@ -1750,7 +1824,6 @@ 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)
@@ -1831,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);
@@ -1915,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);
@@ -2029,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;
@@ -2150,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);
@@ -2327,9 +2404,8 @@ unp_unlock(struct socket *so, int refcount, void * lr)
                
                lck_mtx_unlock(mutex_held);
 
-               unp->unp_gencnt = ++unp_gencnt;
+               lck_mtx_destroy(&unp->unp_mtx, unp_mtx_grp);
                zfree(unp_zone, unp);
-               --unp_count;
 
                unp_gc();
        } else {