diff options
author | ache <ache@FreeBSD.org> | 2001-08-21 21:20:42 +0000 |
---|---|---|
committer | ache <ache@FreeBSD.org> | 2001-08-21 21:20:42 +0000 |
commit | 5b25e70c26430793468251e9a9f0505d225db1c6 (patch) | |
tree | 6c7fa56dc163bc97276370c1a686ab89b15937c0 /sys | |
parent | 2d8b87461880a28413751515a0b56b29bf14efad (diff) | |
download | FreeBSD-src-5b25e70c26430793468251e9a9f0505d225db1c6.zip FreeBSD-src-5b25e70c26430793468251e9a9f0505d225db1c6.tar.gz |
Make lseek() POSIXed: for non character special files
1) handle off_t overflow with EOVERFLOW
2) handle negative offsets with EINVAL
Reviewed by: arch discussion
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/vfs_extattr.c | 25 | ||||
-rw-r--r-- | sys/kern/vfs_syscalls.c | 25 |
2 files changed, 40 insertions, 10 deletions
diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c index 086fd16..06f70d8 100644 --- a/sys/kern/vfs_extattr.c +++ b/sys/kern/vfs_extattr.c @@ -1615,29 +1615,44 @@ lseek(p, uap) register struct filedesc *fdp = p->p_fd; register struct file *fp; struct vattr vattr; - int error; + struct vnode *vp; + off_t offset; + int error, noneg; if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL) return (EBADF); if (fp->f_type != DTYPE_VNODE) return (ESPIPE); + vp = (struct vnode *)fp->f_data; + noneg = (vp->v_type != VCHR); + offset = SCARG(uap, offset); switch (SCARG(uap, whence)) { case L_INCR: - fp->f_offset += SCARG(uap, offset); + if (noneg && + ((offset > 0 && fp->f_offset > OFF_MAX - offset) || + (offset < 0 && fp->f_offset < OFF_MIN - offset))) + return (EOVERFLOW); + offset += fp->f_offset; break; case L_XTND: - error=VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p); + error = VOP_GETATTR(vp, &vattr, cred, p); if (error) return (error); - fp->f_offset = SCARG(uap, offset) + vattr.va_size; + if (noneg && + ((offset > 0 && vattr.va_size > OFF_MAX - offset) || + (offset < 0 && vattr.va_size < OFF_MIN - offset))) + return (EOVERFLOW); + offset += vattr.va_size; break; case L_SET: - fp->f_offset = SCARG(uap, offset); break; default: return (EINVAL); } + if (noneg && offset < 0) + return (EINVAL); + fp->f_offset = offset; *(off_t *)(p->p_retval) = fp->f_offset; return (0); } diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 086fd16..06f70d8 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -1615,29 +1615,44 @@ lseek(p, uap) register struct filedesc *fdp = p->p_fd; register struct file *fp; struct vattr vattr; - int error; + struct vnode *vp; + off_t offset; + int error, noneg; if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL) return (EBADF); if (fp->f_type != DTYPE_VNODE) return (ESPIPE); + vp = (struct vnode *)fp->f_data; + noneg = (vp->v_type != VCHR); + offset = SCARG(uap, offset); switch (SCARG(uap, whence)) { case L_INCR: - fp->f_offset += SCARG(uap, offset); + if (noneg && + ((offset > 0 && fp->f_offset > OFF_MAX - offset) || + (offset < 0 && fp->f_offset < OFF_MIN - offset))) + return (EOVERFLOW); + offset += fp->f_offset; break; case L_XTND: - error=VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p); + error = VOP_GETATTR(vp, &vattr, cred, p); if (error) return (error); - fp->f_offset = SCARG(uap, offset) + vattr.va_size; + if (noneg && + ((offset > 0 && vattr.va_size > OFF_MAX - offset) || + (offset < 0 && vattr.va_size < OFF_MIN - offset))) + return (EOVERFLOW); + offset += vattr.va_size; break; case L_SET: - fp->f_offset = SCARG(uap, offset); break; default: return (EINVAL); } + if (noneg && offset < 0) + return (EINVAL); + fp->f_offset = offset; *(off_t *)(p->p_retval) = fp->f_offset; return (0); } |