]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/kern/uipc_syscalls.c
xnu-517.3.7.tar.gz
[apple/xnu.git] / bsd / kern / uipc_syscalls.c
index f27ada4639c87b8130ad56eed8e579db6316e2ed..e2902e519555e3f3652121b38ba7f26c40a00f34 100644 (file)
@@ -1,21 +1,24 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_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.
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
  * 
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * 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. 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@
  */
@@ -74,6 +77,7 @@
 #include <sys/ktrace.h>
 #endif
 #include <sys/kernel.h>
+#include <sys/kern_audit.h>
 
 #include <sys/kdebug.h>
 
 #endif
 
 struct getsockname_args  {
-    int        fdes;
+    int                fdes;
     caddr_t    asa;
-    int        *alen;
+    socklen_t  *alen;
 };
 
 struct getsockopt_args  {
-    int        s;
-    int        level;
-    int        name;
+    int                s;
+    int                level;
+    int                name;
     caddr_t    val;
-    int        *avalsize;
+    socklen_t  *avalsize;
 } ;
 
 struct accept_args {
-       int     s;
-       caddr_t name;
-       int     *anamelen;
+       int             s;
+       caddr_t         name;
+       socklen_t       *anamelen;
 };
 
 struct getpeername_args {
-       int     fdes;
-       caddr_t asa;
-       int     *alen;
+       int             fdes;
+       caddr_t         asa;
+       socklen_t       *alen;
 };
 
 
@@ -169,6 +173,7 @@ socket(p, uap, retval)
        struct file *fp;
        int fd, error;
 
+       AUDIT_ARG(socket, uap->domain, uap->type, uap->protocol);
        thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
        error = falloc(p, &fp, &fd);
        thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
@@ -193,9 +198,9 @@ socket(p, uap, retval)
 }
 
 struct bind_args {
-       int     s;
-       caddr_t name;
-       int     namelen;
+       int             s;
+       caddr_t         name;
+       socklen_t       namelen;
 };
 
 /* ARGSUSED */
@@ -209,13 +214,18 @@ bind(p, uap, retval)
        struct sockaddr *sa;
        int error;
 
+       AUDIT_ARG(fd, uap->s);
        error = getsock(p->p_fd, uap->s, &fp);
        if (error)
                return (error);
        error = getsockaddr(&sa, uap->name, uap->namelen);
        if (error)
                return (error);
-       error = sobind((struct socket *)fp->f_data, sa);
+       AUDIT_ARG(sockaddr, p, sa);
+       if (fp->f_data != NULL) 
+               error = sobind((struct socket *)fp->f_data, sa);
+       else
+               error = EBADF;
        FREE(sa, M_SONAME);
        return (error);
 }
@@ -236,10 +246,14 @@ listen(p, uap, retval)
        struct file *fp;
        int error;
 
+       AUDIT_ARG(fd, uap->s);
        error = getsock(p->p_fd, uap->s, &fp);
        if (error)
                return (error);
-       return (solisten((struct socket *)fp->f_data, uap->backlog));
+       if (fp->f_data != NULL)
+               return (solisten((struct socket *)fp->f_data, uap->backlog));
+       else
+               return (EBADF);
 }
 
 #ifndef COMPAT_OLDSOCK
@@ -264,6 +278,7 @@ accept1(p, uap, retval, compat)
        short fflag;            /* type must match fp->f_flag */
        int tmpfd;
 
+       AUDIT_ARG(fd, uap->s);
        if (uap->name) {
                error = copyin((caddr_t)uap->anamelen, (caddr_t)&namelen,
                        sizeof (namelen));
@@ -275,6 +290,10 @@ accept1(p, uap, retval, compat)
                return (error);
        s = splnet();
        head = (struct socket *)fp->f_data;
+       if (head == NULL) {
+               splx(s);
+               return (EBADF);
+       }
        if ((head->so_options & SO_ACCEPTCONN) == 0) {
                splx(s);
                return (EINVAL);
@@ -283,7 +302,7 @@ accept1(p, uap, retval, compat)
                splx(s);
                return (EWOULDBLOCK);
        }
-       while (head->so_comp.tqh_first == NULL && head->so_error == 0) {
+        while (TAILQ_EMPTY(&head->so_comp) && head->so_error == 0) {
                if (head->so_state & SS_CANTRCVMORE) {
                        head->so_error = ECONNABORTED;
                        break;
@@ -310,7 +329,7 @@ accept1(p, uap, retval, compat)
         * block allowing another process to accept the connection
         * instead.
         */
-       so = head->so_comp.tqh_first;
+       so = TAILQ_FIRST(&head->so_comp);
        TAILQ_REMOVE(&head->so_comp, so, so_list);
        head->so_qlen--;
 
@@ -349,6 +368,7 @@ accept1(p, uap, retval, compat)
                        goto gotnoname;
                return 0;
        }
+       AUDIT_ARG(sockaddr, p, sa);
        if (uap->name) {
                /* check sa_len before it is destroyed */
                if (namelen > sa->sa_len)
@@ -392,9 +412,9 @@ oaccept(p, uap, retval)
 #endif /* COMPAT_OLDSOCK */
 
 struct connect_args {
-       int s;
-       caddr_t name;
-       int     namelen;
+       int             s;
+       caddr_t         name;
+       socklen_t       namelen;
 };
 /* ARGSUSED */
 int
@@ -408,15 +428,19 @@ connect(p, uap, retval)
        struct sockaddr *sa;
        int error, s;
 
+       AUDIT_ARG(fd, uap->s);
        error = getsock(p->p_fd, uap->s, &fp);
        if (error)
                return (error);
        so = (struct socket *)fp->f_data;
+       if (so == NULL)
+               return (EBADF);
        if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING))
                return (EALREADY);
        error = getsockaddr(&sa, uap->name, uap->namelen);
        if (error)
                return (error);
+       AUDIT_ARG(sockaddr, p, sa);
        error = soconnect(so, sa);
        if (error)
                goto bad;
@@ -461,6 +485,7 @@ socketpair(p, uap, retval)
        struct socket *so1, *so2;
        int fd, error, sv[2];
 
+       AUDIT_ARG(socket, uap->domain, uap->type, uap->protocol);
        error = socreate(uap->domain, &so1, uap->type, uap->protocol);
        if (error)
                return (error);
@@ -542,6 +567,7 @@ sendit(p, s, mp, flags, retsize)
        struct socket *so;
 #if KTRACE
        struct iovec *ktriov = NULL;
+       struct uio ktruio;
 #endif
        
        KERNEL_DEBUG(DBG_FNC_SENDIT | DBG_FUNC_START, 0,0,0,0,0);
@@ -579,6 +605,7 @@ sendit(p, s, mp, flags, retsize)
                    KERNEL_DEBUG(DBG_FNC_SENDIT | DBG_FUNC_END, error,0,0,0,0);
                    return (error);
                }
+               AUDIT_ARG(sockaddr, p, to);
        } else
                to = 0;
        if (mp->msg_control) {
@@ -613,24 +640,39 @@ sendit(p, s, mp, flags, retsize)
        } else
                control = 0;
 
+#if KTRACE    
+    if (KTRPOINT(p, KTR_GENIO)) {
+        int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
+
+        MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
+        bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
+        ktruio = auio;
+    }   
+#endif
        len = auio.uio_resid;
        so = (struct socket *)fp->f_data;
-       error = so->so_proto->pr_usrreqs->pru_sosend(so, to, &auio, 0, control,
-                                                    flags);
+       if (so == NULL)
+               error = EBADF;
+       else
+               error = so->so_proto->pr_usrreqs->pru_sosend(so, to, &auio, 0, control,
+                                                            flags);
        if (error) {
                if (auio.uio_resid != len && (error == ERESTART ||
                    error == EINTR || error == EWOULDBLOCK))
                        error = 0;
-               if (error == EPIPE)
+                /* Generation of SIGPIPE can be controlled per socket */
+               if (error == EPIPE && !(so->so_flags & SOF_NOSIGPIPE))
                        psignal(p, SIGPIPE);
        }
        if (error == 0)
                *retsize = len - auio.uio_resid;
 #if KTRACE
        if (ktriov != NULL) {
-               if (error == 0)
-                       ktrgenio(p->p_tracep, s, UIO_WRITE,
-                               ktriov, *retsize, error);
+               if (error == 0) {
+                       ktruio.uio_iov = ktriov;
+                       ktruio.uio_resid = retsize[0];
+                       ktrgenio(p->p_tracep, s, UIO_WRITE, &ktruio, error, -1);
+               }
                FREE(ktriov, M_TEMP);
        }
 #endif
@@ -670,6 +712,7 @@ sendto(p, uap, retval)
        int stat;
 
        KERNEL_DEBUG(DBG_FNC_SENDTO | DBG_FUNC_START, 0,0,0,0,0);
+       AUDIT_ARG(fd, uap->s);
 
        msg.msg_name = uap->to;
        msg.msg_namelen = uap->tolen;
@@ -782,6 +825,7 @@ sendmsg(p, uap, retval)
        int error;
 
        KERNEL_DEBUG(DBG_FNC_SENDMSG | DBG_FUNC_START, 0,0,0,0,0);
+       AUDIT_ARG(fd, uap->s);
        if (error = copyin(uap->msg, (caddr_t)&msg, sizeof (msg)))
        {
            KERNEL_DEBUG(DBG_FNC_SENDMSG | DBG_FUNC_END, error,0,0,0,0);
@@ -833,6 +877,7 @@ recvit(p, s, mp, namelenp, retval)
        struct sockaddr *fromsa = 0;
 #if KTRACE
        struct iovec *ktriov = NULL;
+       struct uio ktruio;
 #endif
 
        KERNEL_DEBUG(DBG_FNC_RECVIT | DBG_FUNC_START, 0,0,0,0,0);
@@ -862,13 +907,18 @@ recvit(p, s, mp, namelenp, retval)
 
                MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
                bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
+               ktruio = auio;
        }
 #endif
        len = auio.uio_resid;
        so = (struct socket *)fp->f_data;
-       error = so->so_proto->pr_usrreqs->pru_soreceive(so, &fromsa, &auio,
-           (struct mbuf **)0, mp->msg_control ? &control : (struct mbuf **)0,
-           &mp->msg_flags);
+       if (so == NULL)
+               error = EBADF;
+       else
+               error = so->so_proto->pr_usrreqs->pru_soreceive(so, &fromsa, &auio,
+                       (struct mbuf **)0, mp->msg_control ? &control : (struct mbuf **)0,
+                       &mp->msg_flags);
+       AUDIT_ARG(sockaddr, p, fromsa);
        if (error) {
                if (auio.uio_resid != len && (error == ERESTART ||
                    error == EINTR || error == EWOULDBLOCK))
@@ -876,9 +926,11 @@ recvit(p, s, mp, namelenp, retval)
        }
 #if KTRACE
        if (ktriov != NULL) {
-               if (error == 0)
-                       ktrgenio(p->p_tracep, s, UIO_WRITE,
-                               ktriov, len - auio.uio_resid, error);
+               if (error == 0) {
+                       ktruio.uio_iov = ktriov;
+                       ktruio.uio_resid = len - auio.uio_resid;
+                       ktrgenio(p->p_tracep, s, UIO_WRITE, &ktruio, error, -1);
+               }
                FREE(ktriov, M_TEMP);
        }
 #endif
@@ -999,6 +1051,7 @@ recvfrom(p, uap, retval)
        int error;
 
        KERNEL_DEBUG(DBG_FNC_RECVFROM | DBG_FUNC_START, 0,0,0,0,0);
+       AUDIT_ARG(fd, uap->s);
 
        if (uap->fromlenaddr) {
                error = copyin((caddr_t)uap->fromlenaddr,
@@ -1027,21 +1080,23 @@ orecvfrom(p, uap, retval)
 {
 
        uap->flags |= MSG_COMPAT;
-       return (recvfrom(p, uap));
+       return (recvfrom(p, uap, retval));
 }
 #endif
 
 
 #ifdef COMPAT_OLDSOCK
+struct orecv_args {
+       int     s;
+       caddr_t buf;
+       int     len;
+       int     flags;
+};
+
 int
 orecv(p, uap, retval)
        struct proc *p;
-       register struct orecv_args  {
-               int     s;
-               caddr_t buf;
-               int     len;
-               int     flags;
-       }  *uap;
+       struct  orecv_args      *uap;
        register_t *retval;
 {
        struct msghdr msg;
@@ -1063,14 +1118,16 @@ orecv(p, uap, retval)
  * overlays the new one, missing only the flags, and with the (old) access
  * rights where the control fields are now.
  */
+struct orecvmsg_args  {
+       int     s;
+       struct  omsghdr *msg;
+       int     flags;
+};
+
 int
 orecvmsg(p, uap, retval)
        struct proc *p;
-       register struct orecvmsg_args  {
-               int     s;
-               struct  omsghdr *msg;
-               int     flags;
-       }  *uap;
+       struct orecvmsg_args *uap;
        register_t *retval;
 {
        struct msghdr msg;
@@ -1107,14 +1164,16 @@ done:
 }
 #endif
 
+struct recvmsg_args  {
+       int     s;
+       struct  msghdr *msg;
+       int     flags;
+};
+
 int
 recvmsg(p, uap, retval)
        struct proc *p;
-       register struct recvmsg_args  {
-               int     s;
-               struct  msghdr *msg;
-               int     flags;
-       }  *uap;
+       struct recvmsg_args *uap;
        register_t *retval;
 {
        struct msghdr msg;
@@ -1122,6 +1181,7 @@ recvmsg(p, uap, retval)
        register int error;
 
        KERNEL_DEBUG(DBG_FNC_RECVMSG | DBG_FUNC_START, 0,0,0,0,0);
+       AUDIT_ARG(fd, uap->s);
        if (error = copyin((caddr_t)uap->msg, (caddr_t)&msg,
            sizeof (msg)))
        {
@@ -1163,21 +1223,26 @@ done:
 }
 
 /* ARGSUSED */
+struct shutdown_args  {
+       int     s;
+       int     how;
+};
+
 int
 shutdown(p, uap, retval)
        struct proc *p;
-       register struct shutdown_args  {
-               int     s;
-               int     how;
-       }  *uap;
+       struct shutdown_args *uap;
        register_t *retval;
 {
        struct file *fp;
        int error;
 
+       AUDIT_ARG(fd, uap->s);
        error = getsock(p->p_fd, uap->s, &fp);
        if (error)
                return (error);
+       if (fp->f_data == NULL)
+               return (EBADF);
        return (soshutdown((struct socket *)fp->f_data, uap->how));
 }
 
@@ -1186,22 +1251,25 @@ shutdown(p, uap, retval)
 
 
 /* ARGSUSED */
+struct setsockopt_args  {
+       int             s;
+       int             level;
+       int             name;
+       caddr_t         val;
+       socklen_t       valsize;
+};
+
 int
 setsockopt(p, uap, retval)
        struct proc *p;
-       register struct setsockopt_args  {
-               int     s;
-               int     level;
-               int     name;
-               caddr_t val;
-               int     valsize;
-       }  *uap;
+       struct setsockopt_args *uap;
        register_t *retval;
 {
        struct file *fp;
        struct sockopt sopt;
        int error;
 
+       AUDIT_ARG(fd, uap->s);
        if (uap->val == 0 && uap->valsize != 0)
                return (EFAULT);
        if (uap->valsize < 0)
@@ -1218,6 +1286,8 @@ setsockopt(p, uap, retval)
        sopt.sopt_valsize = uap->valsize;
        sopt.sopt_p = p;
 
+       if (fp->f_data == NULL)
+               return (EBADF);
        return (sosetopt((struct socket *)fp->f_data, &sopt));
 }
 
@@ -1253,6 +1323,8 @@ getsockopt(p, uap, retval)
        sopt.sopt_valsize = (size_t)valsize; /* checked non-negative above */
        sopt.sopt_p = p;
 
+        if (fp->f_data == NULL)
+                return (EBADF);
        error = sogetopt((struct socket *)fp->f_data, &sopt);
        if (error == 0) {
                valsize = sopt.sopt_valsize;
@@ -1352,6 +1424,8 @@ getsockname1(p, uap, retval, compat)
        if (error)
                return (error);
        so = (struct socket *)fp->f_data;
+       if (so == NULL)
+               return (EBADF);
        sa = 0;
        error = (*so->so_proto->pr_usrreqs->pru_sockaddr)(so, &sa);
        if (error)
@@ -1420,6 +1494,8 @@ getpeername1(p, uap, retval, compat)
        if (error)
                return (error);
        so = (struct socket *)fp->f_data;
+       if (so == NULL)
+               return (EBADF);
        if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0)
                return (ENOTCONN);
        error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len));
@@ -1705,6 +1781,10 @@ sendfile(struct proc *p, struct sendfile_args *uap)
        if (error)
                goto done;
        so = (struct socket *)fp->f_data;
+       if (so == NULL) {
+               error = EBADF;
+               goto done;
+       }
        if (so->so_type != SOCK_STREAM) {
                error = EINVAL;
                goto done;