summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2008-10-22 21:55:48 +0000
committerjhb <jhb@FreeBSD.org>2008-10-22 21:55:48 +0000
commit327ae6eb3a1a8aa10419a446a94f60c35996d868 (patch)
tree52c2acf2cfeb0ab76a95a909620cf9d9508ff19a /sys/kern
parent486f9a87d63369b9373a2644a6ec68fb77d6e818 (diff)
downloadFreeBSD-src-327ae6eb3a1a8aa10419a446a94f60c35996d868.zip
FreeBSD-src-327ae6eb3a1a8aa10419a446a94f60c35996d868.tar.gz
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
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/vfs_syscalls.c33
1 files changed, 23 insertions, 10 deletions
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index ad40318..94c9422 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);
OpenPOWER on IntegriCloud