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
This commit is contained in:
John Baldwin 2008-10-22 21:55:48 +00:00
parent e4bb8c6423
commit 63f8fe9e8b
4 changed files with 45 additions and 12 deletions

View file

@ -1762,6 +1762,24 @@ freebsd32_ftruncate(struct thread *td, struct freebsd32_ftruncate_args *uap)
return (ftruncate(td, &ap));
}
int
freebsd32_getdirentries(struct thread *td,
struct freebsd32_getdirentries_args *uap)
{
long base;
int32_t base32;
int error;
error = kern_getdirentries(td, uap->fd, uap->buf, uap->count, &base);
if (error)
return (error);
if (uap->basep != NULL) {
base32 = base;
error = copyout(&base32, uap->basep, sizeof(int32_t));
}
return (error);
}
#ifdef COMPAT_FREEBSD6
/* versions with the 'int pad' argument */
int

View file

@ -350,8 +350,8 @@
195 AUE_SETRLIMIT NOPROTO { int setrlimit(u_int which, \
struct rlimit *rlp); } setrlimit \
__setrlimit_args int
196 AUE_GETDIRENTRIES NOPROTO { int getdirentries(int fd, char *buf, \
u_int count, long *basep); }
196 AUE_GETDIRENTRIES STD { int freebsd32_getdirentries(int fd, \
char *buf, u_int count, int32_t *basep); }
197 AUE_MMAP COMPAT6 { caddr_t freebsd32_mmap(caddr_t addr, \
size_t len, int prot, int flags, int fd, \
int pad, u_int32_t poslo, \

View file

@ -4015,6 +4015,21 @@ getdirentries(td, uap)
u_int count;
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;
@ -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);

View file

@ -91,6 +91,8 @@ int kern_fstatfs(struct thread *td, int fd, struct statfs *buf);
int kern_ftruncate(struct thread *td, int fd, off_t length);
int kern_futimes(struct thread *td, int fd, struct timeval *tptr,
enum uio_seg tptrseg);
int kern_getdirentries(struct thread *td, int fd, char *buf, u_int count,
long *basep);
int kern_getfsstat(struct thread *td, struct statfs **buf, size_t bufsize,
enum uio_seg bufseg, int flags);
int kern_getgroups(struct thread *td, u_int *ngrp, gid_t *groups);