diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 1998-07-28 19:47:15 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 1998-07-28 19:47:15 +0000 |
commit | 3287b64e077693dbe8e5b8138453f03f4060e739 (patch) | |
tree | 76b77e1d456db5a77e92b64b2a16746f94ea8ab6 /sys/kern/sys_generic.c | |
parent | 996b26293c9ed22d2a4601386081731cf9f5a238 (diff) |
For read, write, send, sendto, recv, recvfrom return EINVAL is size arg > SSIZE_MAX. For readv, writev, sendmsg, recvmsg return EINVAL if sum of the over iov_len values overflows an ssize_t. Based on what XPG 4.2 says (though XPG is not entirely consistent here). Basically since the return value is ssize_t allowing size > SSIZE_MAX is bad since people who (incorrectly mind you) check the return value for < 0 instead of == -1 will have bad things happen to them.
Diffstat (limited to 'sys/kern/sys_generic.c')
-rw-r--r-- | sys/kern/sys_generic.c | 34 |
1 files changed, 18 insertions, 16 deletions
diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c index fb6cf718aef..e7750e21900 100644 --- a/sys/kern/sys_generic.c +++ b/sys/kern/sys_generic.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sys_generic.c,v 1.13 1998/07/28 00:12:58 millert Exp $ */ +/* $OpenBSD: sys_generic.c,v 1.14 1998/07/28 19:47:07 millert Exp $ */ /* $NetBSD: sys_generic.c,v 1.24 1996/03/29 00:25:32 cgd Exp $ */ /* @@ -78,8 +78,8 @@ sys_read(p, v, retval) { register struct sys_read_args /* { syscallarg(int) fd; - syscallarg(char *) buf; - syscallarg(u_int) nbyte; + syscallarg(void *) buf; + syscallarg(size_t) nbyte; } */ *uap = v; register struct file *fp; register struct filedesc *fdp = p->p_fd; @@ -94,6 +94,9 @@ sys_read(p, v, retval) (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL || (fp->f_flag & FREAD) == 0) return (EBADF); + /* Don't allow nbyte to be larger than max return val */ + if (SCARG(uap, nbyte) > SSIZE_MAX) + return(EINVAL); aiov.iov_base = (caddr_t)SCARG(uap, buf); aiov.iov_len = SCARG(uap, nbyte); auio.uio_iov = &aiov; @@ -137,7 +140,7 @@ sys_readv(p, v, retval) register struct sys_readv_args /* { syscallarg(int) fd; syscallarg(struct iovec *) iovp; - syscallarg(u_int) iovcnt; + syscallarg(int) iovcnt; } */ *uap = v; register struct file *fp; register struct filedesc *fdp = p->p_fd; @@ -177,14 +180,12 @@ sys_readv(p, v, retval) if (error) goto done; auio.uio_resid = 0; - for (i = 0; i < SCARG(uap, iovcnt); i++) { - if (auio.uio_resid + iov->iov_len < auio.uio_resid) { + for (i = 0; i < SCARG(uap, iovcnt); i++, iov++) { + /* Don't allow sum > SSIZE_MAX */ + if ((ssize_t)(auio.uio_resid += iov->iov_len) <= 0) { error = EINVAL; goto done; } - - auio.uio_resid += iov->iov_len; - iov++; } #ifdef KTRACE /* @@ -228,8 +229,8 @@ sys_write(p, v, retval) { register struct sys_write_args /* { syscallarg(int) fd; - syscallarg(char *) buf; - syscallarg(u_int) nbyte; + syscallarg(void *) buf; + syscallarg(size_t) nbyte; } */ *uap = v; register struct file *fp; register struct filedesc *fdp = p->p_fd; @@ -244,6 +245,9 @@ sys_write(p, v, retval) (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL || (fp->f_flag & FWRITE) == 0) return (EBADF); + /* Don't allow nbyte to be larger than max return val */ + if (SCARG(uap, nbyte) > SSIZE_MAX) + return(EINVAL); aiov.iov_base = (caddr_t)SCARG(uap, buf); aiov.iov_len = SCARG(uap, nbyte); auio.uio_iov = &aiov; @@ -330,14 +334,12 @@ sys_writev(p, v, retval) if (error) goto done; auio.uio_resid = 0; - for (i = 0; i < SCARG(uap, iovcnt); i++) { - if (auio.uio_resid + iov->iov_len < auio.uio_resid) { + for (i = 0; i < SCARG(uap, iovcnt); i++, iov++) { + /* Don't allow sum > SSIZE_MAX */ + if ((ssize_t)(auio.uio_resid += iov->iov_len) <= 0) { error = EINVAL; goto done; } - - auio.uio_resid += iov->iov_len; - iov++; } #ifdef KTRACE /* |