summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorache <ache@FreeBSD.org>2001-08-21 21:20:42 +0000
committerache <ache@FreeBSD.org>2001-08-21 21:20:42 +0000
commit5b25e70c26430793468251e9a9f0505d225db1c6 (patch)
tree6c7fa56dc163bc97276370c1a686ab89b15937c0 /sys
parent2d8b87461880a28413751515a0b56b29bf14efad (diff)
downloadFreeBSD-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.c25
-rw-r--r--sys/kern/vfs_syscalls.c25
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);
}
OpenPOWER on IntegriCloud