X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/2d21ac55c334faf3a56e5634905ed6987fc787d4..e2d2fc5c71f7d145cba7267989251af45e3bb5ba:/bsd/kern/uipc_syscalls.c diff --git a/bsd/kern/uipc_syscalls.c b/bsd/kern/uipc_syscalls.c index 1126e7955..8a6356d5a 100644 --- a/bsd/kern/uipc_syscalls.c +++ b/bsd/kern/uipc_syscalls.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2007 Apple Inc. All rights reserved. + * Copyright (c) 2000-2010 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -86,8 +86,9 @@ #include #include #include +#include -#include +#include #include #include @@ -133,13 +134,13 @@ static pid_t last_pid_4056224 = 0; int falloc_locked(proc_t, struct fileproc **, int *, vfs_context_t, int); static int sendit(struct proc *, int, struct user_msghdr *, uio_t, int, - register_t *); + int32_t *); static int recvit(struct proc *, int, struct user_msghdr *, uio_t, user_addr_t, - register_t *); + int32_t *); static int getsockaddr(struct socket *, struct sockaddr **, user_addr_t, - size_t); + size_t, boolean_t); static int getsockaddr_s(struct socket *, struct sockaddr_storage *, - user_addr_t, size_t); + user_addr_t, size_t, boolean_t); #if SENDFILE static void alloc_sendpkt(int, size_t, unsigned int *, struct mbuf **, boolean_t); @@ -166,7 +167,7 @@ extern struct fileops socketops; * socreate:??? [other protocol families, IPSEC] */ int -socket(struct proc *p, struct socket_args *uap, register_t *retval) +socket(struct proc *p, struct socket_args *uap, int32_t *retval) { struct socket *so; struct fileproc *fp; @@ -198,7 +199,12 @@ socket(struct proc *p, struct socket_args *uap, register_t *retval) ut = get_bsdthread_info(thread); /* if this is a backgrounded thread then throttle all new sockets */ - if ( (ut->uu_flag & UT_BACKGROUND) != 0 ) { +#if !CONFIG_EMBEDDED + if (proc_get_selfthread_isbackground() != 0) +#else /* !CONFIG_EMBEDDED */ + if ( (ut->uu_flag & UT_BACKGROUND) != 0 ) +#endif /* !CONFIG_EMBEDDED */ + { so->so_traffic_mgt_flags |= TRAFFIC_MGT_SO_BACKGROUND; so->so_background_thread = thread; } @@ -230,7 +236,7 @@ socket(struct proc *p, struct socket_args *uap, register_t *retval) */ /* ARGSUSED */ int -bind(__unused proc_t p, struct bind_args *uap, __unused register_t *retval) +bind(__unused proc_t p, struct bind_args *uap, __unused int32_t *retval) { struct sockaddr_storage ss; struct sockaddr *sa = NULL; @@ -251,9 +257,9 @@ bind(__unused proc_t p, struct bind_args *uap, __unused register_t *retval) goto out; } if (uap->namelen > sizeof (ss)) { - error = getsockaddr(so, &sa, uap->name, uap->namelen); + error = getsockaddr(so, &sa, uap->name, uap->namelen, TRUE); } else { - error = getsockaddr_s(so, &ss, uap->name, uap->namelen); + error = getsockaddr_s(so, &ss, uap->name, uap->namelen, TRUE); if (error == 0) { sa = (struct sockaddr *)&ss; want_free = FALSE; @@ -287,7 +293,7 @@ out: */ int listen(__unused struct proc *p, struct listen_args *uap, - __unused register_t *retval) + __unused int32_t *retval) { int error; struct socket *so; @@ -332,7 +338,7 @@ listen(__unused struct proc *p, struct listen_args *uap, */ int accept_nocancel(struct proc *p, struct accept_nocancel_args *uap, - register_t *retval) + int32_t *retval) { struct fileproc *fp; struct sockaddr *sa = NULL; @@ -498,8 +504,6 @@ accept_nocancel(struct proc *p, struct accept_nocancel_args *uap, namelen = 0; if (uap->name) goto gotnoname; - if (dosocklock) - socket_unlock(so, 1); error = 0; goto releasefd; } @@ -521,23 +525,19 @@ gotnoname: } FREE(sa, M_SONAME); +releasefd: /* - * If the socket has been marked as inactive by soacceptfilter(), - * disallow further operations on it. We explicitly call shutdown - * on both data directions to ensure that SS_CANT{RCV,SEND}MORE - * states are set for the socket. This would also flush out data - * hanging off the receive list of this socket. + * If the socket has been marked as inactive by sosetdefunct(), + * disallow further operations on it. */ if (so->so_flags & SOF_DEFUNCT) { - (void) soshutdownlock(so, SHUT_RD); - (void) soshutdownlock(so, SHUT_WR); - (void) sodisconnectlocked(so); + sodefunct(current_proc(), so, + SHUTDOWN_SOCKET_LEVEL_DISCONNECT_INTERNAL); } if (dosocklock) socket_unlock(so, 1); -releasefd: proc_fdlock(p); procfdtbl_releasefd(p, newfd, NULL); fp_drop(p, newfd, fp, 1); @@ -549,7 +549,7 @@ out: } int -accept(struct proc *p, struct accept_args *uap, register_t *retval) +accept(struct proc *p, struct accept_args *uap, int32_t *retval) { __pthread_testcancel(1); return(accept_nocancel(p, (struct accept_nocancel_args *)uap, retval)); @@ -579,14 +579,14 @@ accept(struct proc *p, struct accept_args *uap, register_t *retval) */ /* ARGSUSED */ int -connect(struct proc *p, struct connect_args *uap, register_t *retval) +connect(struct proc *p, struct connect_args *uap, int32_t *retval) { __pthread_testcancel(1); return(connect_nocancel(p, (struct connect_nocancel_args *)uap, retval)); } int -connect_nocancel(__unused proc_t p, struct connect_nocancel_args *uap, __unused register_t *retval) +connect_nocancel(__unused proc_t p, struct connect_nocancel_args *uap, __unused int32_t *retval) { struct socket *so; struct sockaddr_storage ss; @@ -595,6 +595,7 @@ connect_nocancel(__unused proc_t p, struct connect_nocancel_args *uap, __unused boolean_t want_free = TRUE; int error; int fd = uap->s; + boolean_t dgram; AUDIT_ARG(fd, uap->s); error = file_socket(fd, &so); @@ -605,11 +606,17 @@ connect_nocancel(__unused proc_t p, struct connect_nocancel_args *uap, __unused goto out; } + /* + * Ask getsockaddr{_s} to not translate AF_UNSPEC to AF_INET + * if this is a datagram socket; translate for other types. + */ + dgram = (so->so_type == SOCK_DGRAM); + /* Get socket address now before we obtain socket lock */ if (uap->namelen > sizeof (ss)) { - error = getsockaddr(so, &sa, uap->name, uap->namelen); + error = getsockaddr(so, &sa, uap->name, uap->namelen, !dgram); } else { - error = getsockaddr_s(so, &ss, uap->name, uap->namelen); + error = getsockaddr_s(so, &ss, uap->name, uap->namelen, !dgram); if (error == 0) { sa = (struct sockaddr *)&ss; want_free = FALSE; @@ -693,7 +700,7 @@ out: */ int socketpair(struct proc *p, struct socketpair_args *uap, - __unused register_t *retval) + __unused int32_t *retval) { struct fileproc *fp1, *fp2; struct socket *so1, *so2; @@ -741,6 +748,9 @@ socketpair(struct proc *p, struct socketpair_args *uap, } } + if ((error = copyout(sv, uap->rsv, 2 * sizeof (int))) != 0) + goto free4; + proc_fdlock(p); procfdtbl_releasefd(p, sv[0], NULL); procfdtbl_releasefd(p, sv[1], NULL); @@ -748,8 +758,7 @@ socketpair(struct proc *p, struct socketpair_args *uap, fp_drop(p, sv[1], fp2, 1); proc_fdunlock(p); - error = copyout((caddr_t)sv, uap->rsv, 2 * sizeof (int)); - return (error); + return (0); free4: fp_free(p, sv[1], fp2); free3: @@ -803,7 +812,7 @@ free1: */ static int sendit(struct proc *p, int s, struct user_msghdr *mp, uio_t uiop, - int flags, register_t *retval) + int flags, int32_t *retval) { struct mbuf *control = NULL; struct sockaddr_storage ss; @@ -827,10 +836,10 @@ sendit(struct proc *p, int s, struct user_msghdr *mp, uio_t uiop, if (mp->msg_name != USER_ADDR_NULL) { if (mp->msg_namelen > sizeof (ss)) { error = getsockaddr(so, &to, mp->msg_name, - mp->msg_namelen); + mp->msg_namelen, TRUE); } else { error = getsockaddr_s(so, &ss, mp->msg_name, - mp->msg_namelen); + mp->msg_namelen, TRUE); if (error == 0) { to = (struct sockaddr *)&ss; want_free = FALSE; @@ -891,14 +900,14 @@ out: * write:??? [4056224: applicable for pipes] */ int -sendto(struct proc *p, struct sendto_args *uap, register_t *retval) +sendto(struct proc *p, struct sendto_args *uap, int32_t *retval) { __pthread_testcancel(1); return(sendto_nocancel(p, (struct sendto_nocancel_args *)uap, retval)); } int -sendto_nocancel(struct proc *p, struct sendto_nocancel_args *uap, register_t *retval) +sendto_nocancel(struct proc *p, struct sendto_nocancel_args *uap, int32_t *retval) { struct user_msghdr msg; int error; @@ -977,34 +986,32 @@ sendto_nocancel(struct proc *p, struct sendto_nocancel_args *uap, register_t *re * sendit:??? [see sendit definition in this file] */ int -sendmsg(struct proc *p, struct sendmsg_args *uap, register_t *retval) +sendmsg(struct proc *p, struct sendmsg_args *uap, int32_t *retval) { __pthread_testcancel(1); return(sendmsg_nocancel(p, (struct sendmsg_nocancel_args *)uap, retval)); } int -sendmsg_nocancel(struct proc *p, struct sendmsg_nocancel_args *uap, register_t *retval) +sendmsg_nocancel(struct proc *p, struct sendmsg_nocancel_args *uap, int32_t *retval) { - struct msghdr msg; + struct user32_msghdr msg32; + struct user64_msghdr msg64; struct user_msghdr user_msg; caddr_t msghdrp; int size_of_msghdr; int error; - int size_of_iovec; uio_t auio = NULL; struct user_iovec *iovp; KERNEL_DEBUG(DBG_FNC_SENDMSG | DBG_FUNC_START, 0, 0, 0, 0, 0); AUDIT_ARG(fd, uap->s); if (IS_64BIT_PROCESS(p)) { - msghdrp = (caddr_t)&user_msg; - size_of_msghdr = sizeof (user_msg); - size_of_iovec = sizeof (struct user_iovec); + msghdrp = (caddr_t)&msg64; + size_of_msghdr = sizeof (msg64); } else { - msghdrp = (caddr_t)&msg; - size_of_msghdr = sizeof (msg); - size_of_iovec = sizeof (struct iovec); + msghdrp = (caddr_t)&msg32; + size_of_msghdr = sizeof (msg32); } error = copyin(uap->msg, msghdrp, size_of_msghdr); if (error) { @@ -1012,15 +1019,22 @@ sendmsg_nocancel(struct proc *p, struct sendmsg_nocancel_args *uap, register_t * return (error); } - /* only need to copy if user process is not 64-bit */ - if (!IS_64BIT_PROCESS(p)) { - user_msg.msg_flags = msg.msg_flags; - user_msg.msg_controllen = msg.msg_controllen; - user_msg.msg_control = CAST_USER_ADDR_T(msg.msg_control); - user_msg.msg_iovlen = msg.msg_iovlen; - user_msg.msg_iov = CAST_USER_ADDR_T(msg.msg_iov); - user_msg.msg_namelen = msg.msg_namelen; - user_msg.msg_name = CAST_USER_ADDR_T(msg.msg_name); + if (IS_64BIT_PROCESS(p)) { + user_msg.msg_flags = msg64.msg_flags; + user_msg.msg_controllen = msg64.msg_controllen; + user_msg.msg_control = msg64.msg_control; + user_msg.msg_iovlen = msg64.msg_iovlen; + user_msg.msg_iov = msg64.msg_iov; + user_msg.msg_namelen = msg64.msg_namelen; + user_msg.msg_name = msg64.msg_name; + } else { + user_msg.msg_flags = msg32.msg_flags; + user_msg.msg_controllen = msg32.msg_controllen; + user_msg.msg_control = msg32.msg_control; + user_msg.msg_iovlen = msg32.msg_iovlen; + user_msg.msg_iov = msg32.msg_iov; + user_msg.msg_namelen = msg32.msg_namelen; + user_msg.msg_name = msg32.msg_name; } if (user_msg.msg_iovlen <= 0 || user_msg.msg_iovlen > UIO_MAXIOV) { @@ -1048,8 +1062,9 @@ sendmsg_nocancel(struct proc *p, struct sendmsg_nocancel_args *uap, register_t * error = ENOBUFS; goto done; } - error = copyin(user_msg.msg_iov, (caddr_t)iovp, - (user_msg.msg_iovlen * size_of_iovec)); + error = copyin_user_iovec_array(user_msg.msg_iov, + IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32, + user_msg.msg_iovlen, iovp); if (error) goto done; user_msg.msg_iov = CAST_USER_ADDR_T(iovp); @@ -1097,7 +1112,7 @@ done: */ static int recvit(struct proc *p, int s, struct user_msghdr *mp, uio_t uiop, - user_addr_t namelenp, register_t *retval) + user_addr_t namelenp, int32_t *retval) { int len, error; struct mbuf *m, *control = 0; @@ -1148,7 +1163,9 @@ recvit(struct proc *p, int s, struct user_msghdr *mp, uio_t uiop, error = so->so_proto->pr_usrreqs->pru_soreceive(so, &fromsa, uiop, (struct mbuf **)0, mp->msg_control ? &control : (struct mbuf **)0, &mp->msg_flags); - AUDIT_ARG(sockaddr, vfs_context_cwd(vfs_context_current()), fromsa); + if (fromsa) + AUDIT_ARG(sockaddr, vfs_context_cwd(vfs_context_current()), + fromsa); if (error) { if (uio_resid(uiop) != len && (error == ERESTART || error == EINTR || error == EWOULDBLOCK)) @@ -1191,21 +1208,80 @@ recvit(struct proc *p, int s, struct user_msghdr *mp, uio_t uiop, while (m && len > 0) { unsigned int tocopy; - - if (len >= m->m_len) { - tocopy = m->m_len; - } else { - mp->msg_flags |= MSG_CTRUNC; - tocopy = len; + struct cmsghdr *cp = mtod(m, struct cmsghdr *); + int cp_size = CMSG_ALIGN(cp->cmsg_len); + int buflen = m->m_len; + + while (buflen > 0 && len > 0) { + + /* + SCM_TIMESTAMP hack because struct timeval has a + * different size for 32 bits and 64 bits processes + */ + if (cp->cmsg_level == SOL_SOCKET && cp->cmsg_type == SCM_TIMESTAMP) { + unsigned char tmp_buffer[CMSG_SPACE(sizeof(struct user64_timeval))]; + struct cmsghdr *tmp_cp = (struct cmsghdr *)tmp_buffer; + int tmp_space; + struct timeval *tv = (struct timeval *)CMSG_DATA(cp); + + tmp_cp->cmsg_level = SOL_SOCKET; + tmp_cp->cmsg_type = SCM_TIMESTAMP; + + if (proc_is64bit(p)) { + struct user64_timeval *tv64 = (struct user64_timeval *)CMSG_DATA(tmp_cp); + + tv64->tv_sec = tv->tv_sec; + tv64->tv_usec = tv->tv_usec; + + tmp_cp->cmsg_len = CMSG_LEN(sizeof(struct user64_timeval)); + tmp_space = CMSG_SPACE(sizeof(struct user64_timeval)); + } else { + struct user32_timeval *tv32 = (struct user32_timeval *)CMSG_DATA(tmp_cp); + + tv32->tv_sec = tv->tv_sec; + tv32->tv_usec = tv->tv_usec; + + tmp_cp->cmsg_len = CMSG_LEN(sizeof(struct user32_timeval)); + tmp_space = CMSG_SPACE(sizeof(struct user32_timeval)); + } + if (len >= tmp_space) { + tocopy = tmp_space; + } else { + mp->msg_flags |= MSG_CTRUNC; + tocopy = len; + } + error = copyout(tmp_buffer, ctlbuf, tocopy); + if (error) + goto out; + + } else { + + if (cp_size > buflen) { + panic("cp_size > buflen, something wrong with alignment!"); + } + + if (len >= cp_size) { + tocopy = cp_size; + } else { + mp->msg_flags |= MSG_CTRUNC; + tocopy = len; + } + + error = copyout((caddr_t) cp, ctlbuf, + tocopy); + if (error) + goto out; + } + + + ctlbuf += tocopy; + len -= tocopy; + + buflen -= cp_size; + cp = (struct cmsghdr *) ((unsigned char *) cp + cp_size); + cp_size = CMSG_ALIGN(cp->cmsg_len); } - - error = copyout((caddr_t)mtod(m, caddr_t), ctlbuf, - tocopy); - if (error) - goto out; - - ctlbuf += tocopy; - len -= tocopy; + m = m->m_next; } mp->msg_controllen = ctlbuf - mp->msg_control; @@ -1221,7 +1297,6 @@ out1: return (error); } - /* * Returns: 0 Success * ENOMEM @@ -1238,14 +1313,14 @@ out1: * the block header for the recvit function. */ int -recvfrom(struct proc *p, struct recvfrom_args *uap, register_t *retval) +recvfrom(struct proc *p, struct recvfrom_args *uap, int32_t *retval) { __pthread_testcancel(1); return(recvfrom_nocancel(p, (struct recvfrom_nocancel_args *)uap, retval)); } int -recvfrom_nocancel(struct proc *p, struct recvfrom_nocancel_args *uap, register_t *retval) +recvfrom_nocancel(struct proc *p, struct recvfrom_nocancel_args *uap, int32_t *retval) { struct user_msghdr msg; int error; @@ -1335,35 +1410,33 @@ recvfrom_nocancel(struct proc *p, struct recvfrom_nocancel_args *uap, register_t * the block header for the recvit function. */ int -recvmsg(struct proc *p, struct recvmsg_args *uap, register_t *retval) +recvmsg(struct proc *p, struct recvmsg_args *uap, int32_t *retval) { __pthread_testcancel(1); return(recvmsg_nocancel(p, (struct recvmsg_nocancel_args *)uap, retval)); } int -recvmsg_nocancel(struct proc *p, struct recvmsg_nocancel_args *uap, register_t *retval) +recvmsg_nocancel(struct proc *p, struct recvmsg_nocancel_args *uap, int32_t *retval) { - struct msghdr msg; + struct user32_msghdr msg32; + struct user64_msghdr msg64; struct user_msghdr user_msg; caddr_t msghdrp; int size_of_msghdr; user_addr_t uiov; int error; - int size_of_iovec; uio_t auio = NULL; struct user_iovec *iovp; KERNEL_DEBUG(DBG_FNC_RECVMSG | DBG_FUNC_START, 0, 0, 0, 0, 0); AUDIT_ARG(fd, uap->s); if (IS_64BIT_PROCESS(p)) { - msghdrp = (caddr_t)&user_msg; - size_of_msghdr = sizeof (user_msg); - size_of_iovec = sizeof (struct user_iovec); + msghdrp = (caddr_t)&msg64; + size_of_msghdr = sizeof (msg64); } else { - msghdrp = (caddr_t)&msg; - size_of_msghdr = sizeof (msg); - size_of_iovec = sizeof (struct iovec); + msghdrp = (caddr_t)&msg32; + size_of_msghdr = sizeof (msg32); } error = copyin(uap->msg, msghdrp, size_of_msghdr); if (error) { @@ -1372,14 +1445,22 @@ recvmsg_nocancel(struct proc *p, struct recvmsg_nocancel_args *uap, register_t * } /* only need to copy if user process is not 64-bit */ - if (!IS_64BIT_PROCESS(p)) { - user_msg.msg_flags = msg.msg_flags; - user_msg.msg_controllen = msg.msg_controllen; - user_msg.msg_control = CAST_USER_ADDR_T(msg.msg_control); - user_msg.msg_iovlen = msg.msg_iovlen; - user_msg.msg_iov = CAST_USER_ADDR_T(msg.msg_iov); - user_msg.msg_namelen = msg.msg_namelen; - user_msg.msg_name = CAST_USER_ADDR_T(msg.msg_name); + if (IS_64BIT_PROCESS(p)) { + user_msg.msg_flags = msg64.msg_flags; + user_msg.msg_controllen = msg64.msg_controllen; + user_msg.msg_control = msg64.msg_control; + user_msg.msg_iovlen = msg64.msg_iovlen; + user_msg.msg_iov = msg64.msg_iov; + user_msg.msg_namelen = msg64.msg_namelen; + user_msg.msg_name = msg64.msg_name; + } else { + user_msg.msg_flags = msg32.msg_flags; + user_msg.msg_controllen = msg32.msg_controllen; + user_msg.msg_control = msg32.msg_control; + user_msg.msg_iovlen = msg32.msg_iovlen; + user_msg.msg_iov = msg32.msg_iov; + user_msg.msg_namelen = msg32.msg_namelen; + user_msg.msg_name = msg32.msg_name; } if (user_msg.msg_iovlen <= 0 || user_msg.msg_iovlen > UIO_MAXIOV) { @@ -1410,8 +1491,9 @@ recvmsg_nocancel(struct proc *p, struct recvmsg_nocancel_args *uap, register_t * } uiov = user_msg.msg_iov; user_msg.msg_iov = CAST_USER_ADDR_T(iovp); - error = copyin(uiov, (caddr_t)iovp, - (user_msg.msg_iovlen * size_of_iovec)); + error = copyin_user_iovec_array(uiov, + IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32, + user_msg.msg_iovlen, iovp); if (error) goto done; @@ -1421,18 +1503,22 @@ recvmsg_nocancel(struct proc *p, struct recvmsg_nocancel_args *uap, register_t * error = recvit(p, uap->s, &user_msg, auio, 0, retval); if (!error) { user_msg.msg_iov = uiov; - /* only need to copy if user process is not 64-bit */ - if (!IS_64BIT_PROCESS(p)) { - // LP64todo - do all these change? if not, then no need to copy all of them! - msg.msg_flags = user_msg.msg_flags; - msg.msg_controllen = user_msg.msg_controllen; - msg.msg_control = - CAST_DOWN(caddr_t, user_msg.msg_control); - msg.msg_iovlen = user_msg.msg_iovlen; - msg.msg_iov = (struct iovec *) - CAST_DOWN(caddr_t, user_msg.msg_iov); - msg.msg_namelen = user_msg.msg_namelen; - msg.msg_name = CAST_DOWN(caddr_t, user_msg.msg_name); + if (IS_64BIT_PROCESS(p)) { + msg64.msg_flags = user_msg.msg_flags; + msg64.msg_controllen = user_msg.msg_controllen; + msg64.msg_control = user_msg.msg_control; + msg64.msg_iovlen = user_msg.msg_iovlen; + msg64.msg_iov = user_msg.msg_iov; + msg64.msg_namelen = user_msg.msg_namelen; + msg64.msg_name = user_msg.msg_name; + } else { + msg32.msg_flags = user_msg.msg_flags; + msg32.msg_controllen = user_msg.msg_controllen; + msg32.msg_control = user_msg.msg_control; + msg32.msg_iovlen = user_msg.msg_iovlen; + msg32.msg_iov = user_msg.msg_iov; + msg32.msg_namelen = user_msg.msg_namelen; + msg32.msg_name = user_msg.msg_name; } error = copyout(msghdrp, uap->msg, size_of_msghdr); } @@ -1467,7 +1553,7 @@ done: /* ARGSUSED */ int shutdown(__unused struct proc *p, struct shutdown_args *uap, - __unused register_t *retval) + __unused int32_t *retval) { struct socket *so; int error; @@ -1504,7 +1590,7 @@ out: /* ARGSUSED */ int setsockopt(struct proc *p, struct setsockopt_args *uap, - __unused register_t *retval) + __unused int32_t *retval) { struct socket *so; struct sockopt sopt; @@ -1556,7 +1642,7 @@ out: */ int getsockopt(struct proc *p, struct getsockopt_args *uap, - __unused register_t *retval) + __unused int32_t *retval) { int error; socklen_t valsize; @@ -1620,7 +1706,7 @@ out: /* ARGSUSED */ int getsockname(__unused struct proc *p, struct getsockname_args *uap, - __unused register_t *retval) + __unused int32_t *retval) { struct socket *so; struct sockaddr *sa; @@ -1642,28 +1728,9 @@ getsockname(__unused struct proc *p, struct getsockname_args *uap, socket_lock(so, 1); error = (*so->so_proto->pr_usrreqs->pru_sockaddr)(so, &sa); if (error == 0) { - struct socket_filter_entry *filter; - int filtered = 0; - for (filter = so->so_filt; filter && error == 0; - filter = filter->sfe_next_onsocket) { - if (filter->sfe_filter->sf_filter.sf_getsockname) { - if (!filtered) { - filtered = 1; - sflt_use(so); - socket_unlock(so, 0); - } - error = filter->sfe_filter->sf_filter. - sf_getsockname(filter->sfe_cookie, so, &sa); - } - } - + error = sflt_getsockname(so, &sa); if (error == EJUSTRETURN) error = 0; - - if (filtered) { - socket_lock(so, 0); - sflt_unuse(so); - } } socket_unlock(so, 1); if (error) @@ -1707,7 +1774,7 @@ out: /* ARGSUSED */ int getpeername(__unused struct proc *p, struct getpeername_args *uap, - __unused register_t *retval) + __unused int32_t *retval) { struct socket *so; struct sockaddr *sa; @@ -1746,28 +1813,9 @@ getpeername(__unused struct proc *p, struct getpeername_args *uap, sa = 0; error = (*so->so_proto->pr_usrreqs->pru_peeraddr)(so, &sa); if (error == 0) { - struct socket_filter_entry *filter; - int filtered = 0; - for (filter = so->so_filt; filter && error == 0; - filter = filter->sfe_next_onsocket) { - if (filter->sfe_filter->sf_filter.sf_getpeername) { - if (!filtered) { - filtered = 1; - sflt_use(so); - socket_unlock(so, 0); - } - error = filter->sfe_filter->sf_filter. - sf_getpeername(filter->sfe_cookie, so, &sa); - } - } - + error = sflt_getpeername(so, &sa); if (error == EJUSTRETURN) error = 0; - - if (filtered) { - socket_lock(so, 0); - sflt_unuse(so); - } } socket_unlock(so, 1); if (error) @@ -1799,22 +1847,34 @@ sockargs(struct mbuf **mp, user_addr_t data, int buflen, int type) struct mbuf *m; int error; - if ((u_int)buflen > MLEN) { - if (type == MT_SONAME && (u_int)buflen <= 112) - buflen = MLEN; /* unix domain compat. hack */ - else if ((u_int)buflen > MCLBYTES) + size_t alloc_buflen = (size_t)buflen; + + if(alloc_buflen > INT_MAX/2) + return (EINVAL); +#ifdef __LP64__ + /* The fd's in the buffer must expand to be pointers, thus we need twice as much space */ + if(type == MT_CONTROL) + alloc_buflen = ((buflen - sizeof(struct cmsghdr))*2) + sizeof(struct cmsghdr); +#endif + if (alloc_buflen > MLEN) { + if (type == MT_SONAME && alloc_buflen <= 112) + alloc_buflen = MLEN; /* unix domain compat. hack */ + else if (alloc_buflen > MCLBYTES) return (EINVAL); } m = m_get(M_WAIT, type); if (m == NULL) return (ENOBUFS); - if ((u_int)buflen > MLEN) { + if (alloc_buflen > MLEN) { MCLGET(m, M_WAIT); if ((m->m_flags & M_EXT) == 0) { m_free(m); return (ENOBUFS); } } + /* K64: We still copyin the original buflen because it gets expanded later + * and we lie about the size of the mbuf because it only affects unp_* functions + */ m->m_len = buflen; error = copyin(data, mtod(m, caddr_t), (u_int)buflen); if (error) { @@ -1840,7 +1900,7 @@ sockargs(struct mbuf **mp, user_addr_t data, int buflen, int type) */ static int getsockaddr(struct socket *so, struct sockaddr **namp, user_addr_t uaddr, - size_t len) + size_t len, boolean_t translate_unspec) { struct sockaddr *sa; int error; @@ -1865,7 +1925,7 @@ getsockaddr(struct socket *so, struct sockaddr **namp, user_addr_t uaddr, * sockets we leave it unchanged and let the lower layer * handle it. */ - if (sa->sa_family == AF_UNSPEC && + if (translate_unspec && sa->sa_family == AF_UNSPEC && INP_CHECK_SOCKAF(so, AF_INET) && len == sizeof (struct sockaddr_in)) sa->sa_family = AF_INET; @@ -1878,7 +1938,7 @@ getsockaddr(struct socket *so, struct sockaddr **namp, user_addr_t uaddr, static int getsockaddr_s(struct socket *so, struct sockaddr_storage *ss, - user_addr_t uaddr, size_t len) + user_addr_t uaddr, size_t len, boolean_t translate_unspec) { int error; @@ -1902,7 +1962,7 @@ getsockaddr_s(struct socket *so, struct sockaddr_storage *ss, * sockets we leave it unchanged and let the lower layer * handle it. */ - if (ss->ss_family == AF_UNSPEC && + if (translate_unspec && ss->ss_family == AF_UNSPEC && INP_CHECK_SOCKAF(so, AF_INET) && len == sizeof (struct sockaddr_in)) ss->ss_family = AF_INET; @@ -1918,7 +1978,7 @@ SYSCTL_DECL(_kern_ipc); #define SFUIOBUFS 64 static int sendfileuiobufs = SFUIOBUFS; -SYSCTL_INT(_kern_ipc, OID_AUTO, sendfileuiobufs, CTLFLAG_RW, &sendfileuiobufs, +SYSCTL_INT(_kern_ipc, OID_AUTO, sendfileuiobufs, CTLFLAG_RW | CTLFLAG_LOCKED, &sendfileuiobufs, 0, ""); /* Macros to compute the number of mbufs needed depending on cluster size */ @@ -1961,13 +2021,13 @@ alloc_sendpkt(int how, size_t pktlen, unsigned int *maxchunks, * use mbuf_allocpacket(). The logic below is similar to sosend(). */ *m = NULL; - if (pktlen > NBPG && jumbocl) { + if (pktlen > MBIGCLBYTES && jumbocl) { needed = MIN(SENDFILE_MAX_16K, HOWMANY_16K(pktlen)); *m = m_getpackets_internal(&needed, 1, how, 0, M16KCLBYTES); } if (*m == NULL) { needed = MIN(SENDFILE_MAX_4K, HOWMANY_4K(pktlen)); - *m = m_getpackets_internal(&needed, 1, how, 0, NBPG); + *m = m_getpackets_internal(&needed, 1, how, 0, MBIGCLBYTES); } /* @@ -1978,7 +2038,7 @@ alloc_sendpkt(int how, size_t pktlen, unsigned int *maxchunks, */ if (*m == NULL) { needed = 1; - *m = m_getpackets_internal(&needed, 1, M_WAIT, 1, NBPG); + *m = m_getpackets_internal(&needed, 1, M_WAIT, 1, MBIGCLBYTES); } if (*m == NULL) panic("%s: blocking allocation returned NULL\n", __func__); @@ -2004,18 +2064,22 @@ sendfile(struct proc *p, struct sendfile_args *uap, __unused int *retval) struct socket *so; struct writev_nocancel_args nuap; user_ssize_t writev_retval; - struct sf_hdtr hdtr; struct user_sf_hdtr user_hdtr; + struct user32_sf_hdtr user32_hdtr; + struct user64_sf_hdtr user64_hdtr; off_t off, xfsize; off_t nbytes = 0, sbytes = 0; int error = 0; size_t sizeof_hdtr; - size_t size_of_iovec; off_t file_size; struct vfs_context context = *vfs_context_current(); KERNEL_DEBUG_CONSTANT((DBG_FNC_SENDFILE | DBG_FUNC_START), uap->s, 0, 0, 0, 0); + + AUDIT_ARG(fd, uap->fd); + AUDIT_ARG(value32, uap->s); + /* * Do argument checking. Must be a regular file in, stream * type and connected socket out, positive offset. @@ -2085,23 +2149,25 @@ sendfile(struct proc *p, struct sendfile_args *uap, __unused int *retval) bzero(&user_hdtr, sizeof (user_hdtr)); if (IS_64BIT_PROCESS(p)) { - hdtrp = (caddr_t)&user_hdtr; - sizeof_hdtr = sizeof (user_hdtr); - size_of_iovec = sizeof (struct user_iovec); + hdtrp = (caddr_t)&user64_hdtr; + sizeof_hdtr = sizeof (user64_hdtr); } else { - hdtrp = (caddr_t)&hdtr; - sizeof_hdtr = sizeof (hdtr); - size_of_iovec = sizeof (struct iovec); + hdtrp = (caddr_t)&user32_hdtr; + sizeof_hdtr = sizeof (user32_hdtr); } error = copyin(uap->hdtr, hdtrp, sizeof_hdtr); if (error) goto done2; - /* need to copy if user process is not 64-bit */ - if (!IS_64BIT_PROCESS(p)) { - user_hdtr.headers = CAST_USER_ADDR_T(hdtr.headers); - user_hdtr.hdr_cnt = hdtr.hdr_cnt; - user_hdtr.trailers = CAST_USER_ADDR_T(hdtr.trailers); - user_hdtr.trl_cnt = hdtr.trl_cnt; + if (IS_64BIT_PROCESS(p)) { + user_hdtr.headers = user64_hdtr.headers; + user_hdtr.hdr_cnt = user64_hdtr.hdr_cnt; + user_hdtr.trailers = user64_hdtr.trailers; + user_hdtr.trl_cnt = user64_hdtr.trl_cnt; + } else { + user_hdtr.headers = user32_hdtr.headers; + user_hdtr.hdr_cnt = user32_hdtr.hdr_cnt; + user_hdtr.trailers = user32_hdtr.trailers; + user_hdtr.trl_cnt = user32_hdtr.trl_cnt; } /* @@ -2196,7 +2262,7 @@ sendfile(struct proc *p, struct sendfile_args *uap, __unused int *retval) socket_unlock(so, 0); alloc_sendpkt(M_WAIT, xfsize, &nbufs, &m0, jumbocl); pktlen = mbuf_pkt_maxlen(m0); - if (pktlen < xfsize) + if (pktlen < (size_t)xfsize) xfsize = pktlen; auio = uio_createwithbuffer(nbufs, off, UIO_SYSSPACE, @@ -2210,11 +2276,11 @@ sendfile(struct proc *p, struct sendfile_args *uap, __unused int *retval) } for (i = 0, m = m0, uiolen = 0; - i < nbufs && m != NULL && uiolen < xfsize; + i < nbufs && m != NULL && uiolen < (size_t)xfsize; i++, m = mbuf_next(m)) { size_t mlen = mbuf_maxlen(m); - if (mlen + uiolen > xfsize) + if (mlen + uiolen > (size_t)xfsize) mlen = xfsize - uiolen; mbuf_setlen(m, mlen); uio_addiov(auio, CAST_USER_ADDR_T(mbuf_datastart(m)), @@ -2224,7 +2290,7 @@ sendfile(struct proc *p, struct sendfile_args *uap, __unused int *retval) if (xfsize != uio_resid(auio)) printf("sendfile: xfsize: %lld != uio_resid(auio): " - "%lld\n", xfsize, uio_resid(auio)); + "%lld\n", xfsize, (long long)uio_resid(auio)); KERNEL_DEBUG_CONSTANT((DBG_FNC_SENDFILE_READ | DBG_FUNC_START), uap->s, (unsigned int)((xfsize >> 32) & 0x0ffffffff), @@ -2257,7 +2323,7 @@ sendfile(struct proc *p, struct sendfile_args *uap, __unused int *retval) i++, m = mbuf_next(m)) { size_t mlen = mbuf_maxlen(m); - if (rlen + mlen > xfsize) + if (rlen + mlen > (size_t)xfsize) mlen = xfsize - rlen; mbuf_setlen(m, mlen); @@ -2314,53 +2380,20 @@ retry_space: } goto retry_space; } + + struct mbuf *control = NULL; { /* * Socket filter processing */ - struct socket_filter_entry *filter; - int filtered = 0; - struct mbuf *control = NULL; - boolean_t recursive = (so->so_send_filt_thread != NULL); - error = 0; - for (filter = so->so_filt; filter && (error == 0); - filter = filter->sfe_next_onsocket) { - if (filter->sfe_filter->sf_filter.sf_data_out) { - if (filtered == 0) { - filtered = 1; - so->so_send_filt_thread = - current_thread(); - sflt_use(so); - socket_unlock(so, 0); - } - error = filter->sfe_filter->sf_filter. - sf_data_out(filter->sfe_cookie, so, - NULL, &m0, &control, 0); - } - } - - if (filtered) { - /* - * At this point, we've run at least one filter. - * The socket is unlocked as is the socket - * buffer. Clear the recorded filter thread - * only when we are outside of a filter's - * context. This allows for a filter to issue - * multiple inject calls from its sf_data_out - * callback routine. - */ - socket_lock(so, 0); - sflt_unuse(so); - if (!recursive) - so->so_send_filt_thread = 0; - if (error) { - if (error == EJUSTRETURN) { - error = 0; - continue; - } - goto done3; + error = sflt_data_out(so, NULL, &m0, &control, 0); + if (error) { + if (error == EJUSTRETURN) { + error = 0; + continue; } + goto done3; } /* * End Socket filter processing @@ -2369,7 +2402,7 @@ retry_space: KERNEL_DEBUG_CONSTANT((DBG_FNC_SENDFILE_SEND | DBG_FUNC_START), uap->s, 0, 0, 0, 0); error = (*so->so_proto->pr_usrreqs->pru_send)(so, 0, m0, - 0, 0, p); + 0, control, p); KERNEL_DEBUG_CONSTANT((DBG_FNC_SENDFILE_SEND | DBG_FUNC_START), uap->s, 0, 0, 0, 0); if (error) {