/*
- * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2010 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#include <sys/kernel.h>
#include <sys/uio_internal.h>
#include <sys/kauth.h>
+#include <kern/task.h>
-#include <bsm/audit_kernel.h>
+#include <security/audit/audit.h>
#include <sys/kdebug.h>
#include <sys/sysproto.h>
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);
* 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;
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;
}
*/
/* 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;
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;
*/
int
listen(__unused struct proc *p, struct listen_args *uap,
- __unused register_t *retval)
+ __unused int32_t *retval)
{
int error;
struct socket *so;
*/
int
accept_nocancel(struct proc *p, struct accept_nocancel_args *uap,
- register_t *retval)
+ int32_t *retval)
{
struct fileproc *fp;
struct sockaddr *sa = NULL;
namelen = 0;
if (uap->name)
goto gotnoname;
- if (dosocklock)
- socket_unlock(so, 1);
error = 0;
goto releasefd;
}
}
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);
}
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));
*/
/* 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;
boolean_t want_free = TRUE;
int error;
int fd = uap->s;
+ boolean_t dgram;
AUDIT_ARG(fd, uap->s);
error = file_socket(fd, &so);
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;
*/
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;
}
}
+ 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);
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:
*/
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;
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;
* 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;
* 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) {
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) {
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);
*/
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;
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))
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;
return (error);
}
-
/*
* Returns: 0 Success
* ENOMEM
* 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;
* 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) {
}
/* 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) {
}
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;
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);
}
/* ARGSUSED */
int
shutdown(__unused struct proc *p, struct shutdown_args *uap,
- __unused register_t *retval)
+ __unused int32_t *retval)
{
struct socket *so;
int error;
/* ARGSUSED */
int
setsockopt(struct proc *p, struct setsockopt_args *uap,
- __unused register_t *retval)
+ __unused int32_t *retval)
{
struct socket *so;
struct sockopt sopt;
*/
int
getsockopt(struct proc *p, struct getsockopt_args *uap,
- __unused register_t *retval)
+ __unused int32_t *retval)
{
int error;
socklen_t valsize;
/* 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;
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)
/* 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;
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)
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)
+ int alloc_buflen = buflen;
+#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 ((u_int)alloc_buflen > MLEN) {
+ if (type == MT_SONAME && (u_int)alloc_buflen <= 112)
+ alloc_buflen = MLEN; /* unix domain compat. hack */
+ else if ((u_int)alloc_buflen > MCLBYTES)
return (EINVAL);
}
m = m_get(M_WAIT, type);
if (m == NULL)
return (ENOBUFS);
- if ((u_int)buflen > MLEN) {
+ if ((u_int)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) {
*/
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;
* 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;
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;
* 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;
#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 */
* 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);
}
/*
*/
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__);
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.
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;
}
/*
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,
}
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)),
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),
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);
}
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
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) {