diff options
author | John Baldwin <jhb@FreeBSD.org> | 2008-10-22 21:55:48 +0000 |
---|---|---|
committer | John Baldwin <jhb@FreeBSD.org> | 2008-10-22 21:55:48 +0000 |
commit | 63f8fe9e8b3689fa8ff9e0e7fa825c838bf5579a (patch) | |
tree | 52c2acf2cfeb0ab76a95a909620cf9d9508ff19a /sys/kern | |
parent | e4bb8c6423442a232a1ba9b5b91617a7bb467931 (diff) |
Split the copyout of *base at the end of getdirentries() out leaving the
rest in kern_getdirentries(). Use kern_getdirentries() to implement
freebsd32_getdirentries(). This fixes a bug where calls to getdirentries()
in 32-bit binaries would trash the 4 bytes after the 'long base' in
userland.
Submitted by: ups
MFC after: 1 week
Notes
Notes:
svn path=/head/; revision=184183
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/vfs_syscalls.c | 33 |
1 files changed, 23 insertions, 10 deletions
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index ad4031805883..94c9422cf61c 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -4016,6 +4016,21 @@ getdirentries(td, uap) long *basep; } */ *uap; { + long base; + int error; + + error = kern_getdirentries(td, uap->fd, uap->buf, uap->count, &base); + if (error) + return (error); + if (uap->basep != NULL) + error = copyout(&base, uap->basep, sizeof(long)); + return (error); +} + +int +kern_getdirentries(struct thread *td, int fd, char *buf, u_int count, + long *basep) +{ struct vnode *vp; struct file *fp; struct uio auio; @@ -4024,8 +4039,8 @@ getdirentries(td, uap) long loff; int error, eofflag; - AUDIT_ARG(fd, uap->fd); - if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0) + AUDIT_ARG(fd, fd); + if ((error = getvnode(td->td_proc->p_fd, fd, &fp)) != 0) return (error); if ((fp->f_flag & FREAD) == 0) { fdrop(fp, td); @@ -4039,14 +4054,14 @@ unionread: error = EINVAL; goto fail; } - aiov.iov_base = uap->buf; - aiov.iov_len = uap->count; + aiov.iov_base = buf; + aiov.iov_len = count; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_rw = UIO_READ; auio.uio_segflg = UIO_USERSPACE; auio.uio_td = td; - auio.uio_resid = uap->count; + auio.uio_resid = count; /* vn_lock(vp, LK_SHARED | LK_RETRY); */ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); AUDIT_ARG(vnode, vp, ARG_VNODE1); @@ -4063,7 +4078,7 @@ unionread: VFS_UNLOCK_GIANT(vfslocked); goto fail; } - if (uap->count == auio.uio_resid && + if (count == auio.uio_resid && (vp->v_vflag & VV_ROOT) && (vp->v_mount->mnt_flag & MNT_UNION)) { struct vnode *tvp = vp; @@ -4078,10 +4093,8 @@ unionread: } VOP_UNLOCK(vp, 0); VFS_UNLOCK_GIANT(vfslocked); - if (uap->basep != NULL) { - error = copyout(&loff, uap->basep, sizeof(long)); - } - td->td_retval[0] = uap->count - auio.uio_resid; + *basep = loff; + td->td_retval[0] = count - auio.uio_resid; fail: fdrop(fp, td); return (error); |