Here it is what POSIX says about lseek():

[EINVAL]    

The whence argument is not a proper value, or the resulting file offset
would be negative for a regular file, block special file, or directory.

[EOVERFLOW] 

The resulting file offset would be a value which cannot be represented
correctly in an object of type off_t.

The patch below adds both cases, i.e. disallow negative seeks for VREG,
VDIR, VBLK and add off_t overflow checks.

I plan to commit this, please review.


--- vfs_syscalls.c.old  Wed Aug 15 04:45:30 2001
+++ vfs_syscalls.c      Wed Aug 15 12:46:12 2001
@@ -1614,29 +1614,44 @@
        register struct filedesc *fdp = p->p_fd;
        register struct file *fp;
        struct vattr vattr;
-       int error;
+       off_t offset;
+       int error, no_neg_seek;
 
        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);
+       error = VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p);
+       no_neg_seek = (!error &&
+                      (vattr.va_type == VREG ||
+                       vattr.va_type == VDIR ||
+                       vattr.va_type == VBLK));
+       offset = SCARG(uap, offset);
        switch (SCARG(uap, whence)) {
        case L_INCR:
-               fp->f_offset += SCARG(uap, offset);
+               if ((fp->f_offset > 0 && offset > 0 &&
+                    offset + fp->f_offset < 0) ||
+                   (fp->f_offset < 0 && offset < 0 &&
+                    offset + fp->f_offset > 0))
+                       return (EOVERFLOW);
+               offset += fp->f_offset;
                break;
        case L_XTND:
-               error=VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p);
                if (error)
                        return (error);
-               fp->f_offset = SCARG(uap, offset) + vattr.va_size;
+               if (offset > 0 && (off_t)(offset + vattr.va_size) < 0)
+                       return (EOVERFLOW);
+               offset += vattr.va_size;
                break;
        case L_SET:
-               fp->f_offset = SCARG(uap, offset);
                break;
        default:
                return (EINVAL);
        }
+       if (no_neg_seek && offset < 0)
+               return (EINVAL);
+       fp->f_offset = offset;
        *(off_t *)(p->p_retval) = fp->f_offset;
        return (0);
 }

-- 
Andrey A. Chernov
http://ache.pp.ru/

To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message

Reply via email to