diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c index 513abf4d70c4..6aee675041fe 100644 --- a/sys/fs/nfsclient/nfs_clvnops.c +++ b/sys/fs/nfsclient/nfs_clvnops.c @@ -2210,7 +2210,7 @@ nfs_readdir(struct vop_readdir_args *ap) struct vnode *vp = ap->a_vp; struct nfsnode *np = VTONFS(vp); struct uio *uio = ap->a_uio; - ssize_t tresid; + ssize_t tresid, left; int error = 0; struct vattr vattr; @@ -2238,6 +2238,17 @@ nfs_readdir(struct vop_readdir_args *ap) } } + /* + * NFS always guarantees that directory entries don't straddle + * DIRBLKSIZ boundaries. As such, we need to limit the size + * to an exact multiple of DIRBLKSIZ, to avoid copying a partial + * directory entry. + */ + left = uio->uio_resid % DIRBLKSIZ; + if (left == uio->uio_resid) + return (EINVAL); + uio->uio_resid -= left; + /* * Call ncl_bioread() to do the real work. */ @@ -2249,6 +2260,9 @@ nfs_readdir(struct vop_readdir_args *ap) if (ap->a_eofflag != NULL) *ap->a_eofflag = 1; } + + /* Add the partial DIRBLKSIZ (left) back in. */ + uio->uio_resid += left; return (error); }