Print this page
5880 Increase IOV_MAX to at least 1024
Portions contributed by: Jerry Jelinek <jerry.jelinek@joyent.com>

*** 19,32 **** * CDDL HEADER END */ /* * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. ! */ ! ! /* Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved. */ ! /* * Copyright 2015 Nexenta Systems, Inc. All rights reserved. */ #include <sys/types.h> #include <sys/t_lock.h> --- 19,30 ---- * CDDL HEADER END */ /* * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. ! * Copyright 2015, Joyent, Inc. All rights reserved. ! * Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved. * Copyright 2015 Nexenta Systems, Inc. All rights reserved. */ #include <sys/types.h> #include <sys/t_lock.h>
*** 52,61 **** --- 50,60 ---- #include <sys/flock.h> #include <sys/modctl.h> #include <sys/cmn_err.h> #include <sys/vmsystm.h> #include <sys/policy.h> + #include <sys/limits.h> #include <sys/socket.h> #include <sys/socketvar.h> #include <sys/isa_defs.h>
*** 84,99 **** extern void nl7c_init(void); extern int sockfs_defer_nl7c_init; /* - * Note: DEF_IOV_MAX is defined and used as it is in "fs/vncalls.c" - * as there isn't a formal definition of IOV_MAX ??? - */ - #define MSG_MAXIOVLEN 16 - - /* * Kernel component of socket creation. * * The socket library determines which version number to use. * First the library calls this with a NULL devpath. If this fails * to find a transport (using solookup) the library will look in /etc/netconfig --- 83,92 ----
*** 1019,1031 **** { STRUCT_DECL(nmsghdr, u_lmsg); STRUCT_HANDLE(nmsghdr, umsgptr); struct nmsghdr lmsg; struct uio auio; ! struct iovec aiov[MSG_MAXIOVLEN]; int iovcnt; ! ssize_t len; int i; int *flagsp; model_t model; dprint(1, ("recvmsg(%d, %p, %d)\n", --- 1012,1025 ---- { STRUCT_DECL(nmsghdr, u_lmsg); STRUCT_HANDLE(nmsghdr, umsgptr); struct nmsghdr lmsg; struct uio auio; ! struct iovec buf[IOV_MAX_STACK], *aiov = buf; ! ssize_t iovsize = 0; int iovcnt; ! ssize_t len, rval; int i; int *flagsp; model_t model; dprint(1, ("recvmsg(%d, %p, %d)\n",
*** 1064,1112 **** lmsg.msg_controllen = STRUCT_FGET(u_lmsg, msg_controllen); lmsg.msg_flags = STRUCT_FGET(u_lmsg, msg_flags); iovcnt = lmsg.msg_iovlen; ! if (iovcnt <= 0 || iovcnt > MSG_MAXIOVLEN) { return (set_errno(EMSGSIZE)); } #ifdef _SYSCALL32_IMPL /* * 32-bit callers need to have their iovec expanded, while ensuring * that they can't move more than 2Gbytes of data in a single call. */ if (model == DATAMODEL_ILP32) { ! struct iovec32 aiov32[MSG_MAXIOVLEN]; ssize32_t count32; ! if (copyin((struct iovec32 *)lmsg.msg_iov, aiov32, ! iovcnt * sizeof (struct iovec32))) return (set_errno(EFAULT)); count32 = 0; for (i = 0; i < iovcnt; i++) { ssize32_t iovlen32; iovlen32 = aiov32[i].iov_len; count32 += iovlen32; ! if (iovlen32 < 0 || count32 < 0) return (set_errno(EINVAL)); aiov[i].iov_len = iovlen32; aiov[i].iov_base = (caddr_t)(uintptr_t)aiov32[i].iov_base; } } else #endif /* _SYSCALL32_IMPL */ if (copyin(lmsg.msg_iov, aiov, iovcnt * sizeof (struct iovec))) { return (set_errno(EFAULT)); } len = 0; for (i = 0; i < iovcnt; i++) { ssize_t iovlen = aiov[i].iov_len; len += iovlen; if (iovlen < 0 || len < 0) { return (set_errno(EINVAL)); } } auio.uio_loffset = 0; auio.uio_iov = aiov; --- 1058,1137 ---- lmsg.msg_controllen = STRUCT_FGET(u_lmsg, msg_controllen); lmsg.msg_flags = STRUCT_FGET(u_lmsg, msg_flags); iovcnt = lmsg.msg_iovlen; ! if (iovcnt <= 0 || iovcnt > IOV_MAX) { return (set_errno(EMSGSIZE)); } + if (iovcnt > IOV_MAX_STACK) { + iovsize = iovcnt * sizeof (struct iovec); + aiov = kmem_alloc(iovsize, KM_SLEEP); + } + #ifdef _SYSCALL32_IMPL /* * 32-bit callers need to have their iovec expanded, while ensuring * that they can't move more than 2Gbytes of data in a single call. */ if (model == DATAMODEL_ILP32) { ! struct iovec32 buf32[IOV_MAX_STACK], *aiov32 = buf32; ! ssize_t iov32size; ssize32_t count32; ! iov32size = iovcnt * sizeof (struct iovec32); ! if (iovsize != 0) ! aiov32 = kmem_alloc(iov32size, KM_SLEEP); ! ! if (copyin((struct iovec32 *)lmsg.msg_iov, aiov32, iov32size)) { ! if (iovsize != 0) { ! kmem_free(aiov32, iov32size); ! kmem_free(aiov, iovsize); ! } ! return (set_errno(EFAULT)); + } count32 = 0; for (i = 0; i < iovcnt; i++) { ssize32_t iovlen32; iovlen32 = aiov32[i].iov_len; count32 += iovlen32; ! if (iovlen32 < 0 || count32 < 0) { ! if (iovsize != 0) { ! kmem_free(aiov32, iov32size); ! kmem_free(aiov, iovsize); ! } ! return (set_errno(EINVAL)); + } + aiov[i].iov_len = iovlen32; aiov[i].iov_base = (caddr_t)(uintptr_t)aiov32[i].iov_base; } + + if (iovsize != 0) + kmem_free(aiov32, iov32size); } else #endif /* _SYSCALL32_IMPL */ if (copyin(lmsg.msg_iov, aiov, iovcnt * sizeof (struct iovec))) { + if (iovsize != 0) + kmem_free(aiov, iovsize); + return (set_errno(EFAULT)); } len = 0; for (i = 0; i < iovcnt; i++) { ssize_t iovlen = aiov[i].iov_len; len += iovlen; if (iovlen < 0 || len < 0) { + if (iovsize != 0) + kmem_free(aiov, iovsize); + return (set_errno(EINVAL)); } } auio.uio_loffset = 0; auio.uio_iov = aiov;
*** 1117,1132 **** if (lmsg.msg_control != NULL && (do_useracc == 0 || useracc(lmsg.msg_control, lmsg.msg_controllen, B_WRITE) != 0)) { return (set_errno(EFAULT)); } ! return (recvit(sock, &lmsg, &auio, flags, STRUCT_FADDR(umsgptr, msg_namelen), ! STRUCT_FADDR(umsgptr, msg_controllen), flagsp)); } /* * Common send function. */ --- 1142,1165 ---- if (lmsg.msg_control != NULL && (do_useracc == 0 || useracc(lmsg.msg_control, lmsg.msg_controllen, B_WRITE) != 0)) { + if (iovsize != 0) + kmem_free(aiov, iovsize); + return (set_errno(EFAULT)); } ! rval = recvit(sock, &lmsg, &auio, flags, STRUCT_FADDR(umsgptr, msg_namelen), ! STRUCT_FADDR(umsgptr, msg_controllen), flagsp); ! ! if (iovsize != 0) ! kmem_free(aiov, iovsize); ! ! return (rval); } /* * Common send function. */
*** 1260,1272 **** sendmsg(int sock, struct nmsghdr *msg, int flags) { struct nmsghdr lmsg; STRUCT_DECL(nmsghdr, u_lmsg); struct uio auio; ! struct iovec aiov[MSG_MAXIOVLEN]; int iovcnt; ! ssize_t len; int i; model_t model; dprint(1, ("sendmsg(%d, %p, %d)\n", sock, (void *)msg, flags)); --- 1293,1306 ---- sendmsg(int sock, struct nmsghdr *msg, int flags) { struct nmsghdr lmsg; STRUCT_DECL(nmsghdr, u_lmsg); struct uio auio; ! struct iovec buf[IOV_MAX_STACK], *aiov = buf; ! ssize_t iovsize = 0; int iovcnt; ! ssize_t len, rval; int i; model_t model; dprint(1, ("sendmsg(%d, %p, %d)\n", sock, (void *)msg, flags));
*** 1305,1361 **** lmsg.msg_controllen = STRUCT_FGET(u_lmsg, msg_controllen); lmsg.msg_flags = STRUCT_FGET(u_lmsg, msg_flags); iovcnt = lmsg.msg_iovlen; ! if (iovcnt <= 0 || iovcnt > MSG_MAXIOVLEN) { /* * Unless this is XPG 4.2 we allow iovcnt == 0 to * be compatible with SunOS 4.X and 4.4BSD. */ if (iovcnt != 0 || (flags & MSG_XPG4_2)) return (set_errno(EMSGSIZE)); } #ifdef _SYSCALL32_IMPL /* * 32-bit callers need to have their iovec expanded, while ensuring * that they can't move more than 2Gbytes of data in a single call. */ if (model == DATAMODEL_ILP32) { ! struct iovec32 aiov32[MSG_MAXIOVLEN]; ssize32_t count32; if (iovcnt != 0 && ! copyin((struct iovec32 *)lmsg.msg_iov, aiov32, ! iovcnt * sizeof (struct iovec32))) return (set_errno(EFAULT)); count32 = 0; for (i = 0; i < iovcnt; i++) { ssize32_t iovlen32; iovlen32 = aiov32[i].iov_len; count32 += iovlen32; ! if (iovlen32 < 0 || count32 < 0) return (set_errno(EINVAL)); aiov[i].iov_len = iovlen32; aiov[i].iov_base = (caddr_t)(uintptr_t)aiov32[i].iov_base; } } else #endif /* _SYSCALL32_IMPL */ if (iovcnt != 0 && copyin(lmsg.msg_iov, aiov, (unsigned)iovcnt * sizeof (struct iovec))) { return (set_errno(EFAULT)); } len = 0; for (i = 0; i < iovcnt; i++) { ssize_t iovlen = aiov[i].iov_len; len += iovlen; if (iovlen < 0 || len < 0) { return (set_errno(EINVAL)); } } auio.uio_loffset = 0; auio.uio_iov = aiov; --- 1339,1426 ---- lmsg.msg_controllen = STRUCT_FGET(u_lmsg, msg_controllen); lmsg.msg_flags = STRUCT_FGET(u_lmsg, msg_flags); iovcnt = lmsg.msg_iovlen; ! if (iovcnt <= 0 || iovcnt > IOV_MAX) { /* * Unless this is XPG 4.2 we allow iovcnt == 0 to * be compatible with SunOS 4.X and 4.4BSD. */ if (iovcnt != 0 || (flags & MSG_XPG4_2)) return (set_errno(EMSGSIZE)); } + if (iovcnt > IOV_MAX_STACK) { + iovsize = iovcnt * sizeof (struct iovec); + aiov = kmem_alloc(iovsize, KM_SLEEP); + } + #ifdef _SYSCALL32_IMPL /* * 32-bit callers need to have their iovec expanded, while ensuring * that they can't move more than 2Gbytes of data in a single call. */ if (model == DATAMODEL_ILP32) { ! struct iovec32 buf32[IOV_MAX_STACK], *aiov32 = buf32; ! ssize_t iov32size; ssize32_t count32; + iov32size = iovcnt * sizeof (struct iovec32); + if (iovsize != 0) + aiov32 = kmem_alloc(iov32size, KM_SLEEP); + if (iovcnt != 0 && ! copyin((struct iovec32 *)lmsg.msg_iov, aiov32, iov32size)) { ! if (iovsize != 0) { ! kmem_free(aiov32, iov32size); ! kmem_free(aiov, iovsize); ! } ! return (set_errno(EFAULT)); + } count32 = 0; for (i = 0; i < iovcnt; i++) { ssize32_t iovlen32; iovlen32 = aiov32[i].iov_len; count32 += iovlen32; ! if (iovlen32 < 0 || count32 < 0) { ! if (iovsize != 0) { ! kmem_free(aiov32, iov32size); ! kmem_free(aiov, iovsize); ! } ! return (set_errno(EINVAL)); + } + aiov[i].iov_len = iovlen32; aiov[i].iov_base = (caddr_t)(uintptr_t)aiov32[i].iov_base; } + + if (iovsize != 0) + kmem_free(aiov32, iov32size); } else #endif /* _SYSCALL32_IMPL */ if (iovcnt != 0 && copyin(lmsg.msg_iov, aiov, (unsigned)iovcnt * sizeof (struct iovec))) { + if (iovsize != 0) + kmem_free(aiov, iovsize); + return (set_errno(EFAULT)); } len = 0; for (i = 0; i < iovcnt; i++) { ssize_t iovlen = aiov[i].iov_len; len += iovlen; if (iovlen < 0 || len < 0) { + if (iovsize != 0) + kmem_free(aiov, iovsize); + return (set_errno(EINVAL)); } } auio.uio_loffset = 0; auio.uio_iov = aiov;
*** 1362,1372 **** auio.uio_iovcnt = iovcnt; auio.uio_resid = len; auio.uio_segflg = UIO_USERSPACE; auio.uio_limit = 0; ! return (sendit(sock, &lmsg, &auio, flags)); } ssize_t sendto(int sock, void *buffer, size_t len, int flags, struct sockaddr *name, socklen_t namelen) --- 1427,1442 ---- auio.uio_iovcnt = iovcnt; auio.uio_resid = len; auio.uio_segflg = UIO_USERSPACE; auio.uio_limit = 0; ! rval = sendit(sock, &lmsg, &auio, flags); ! ! if (iovsize != 0) ! kmem_free(aiov, iovsize); ! ! return (rval); } ssize_t sendto(int sock, void *buffer, size_t len, int flags, struct sockaddr *name, socklen_t namelen)