summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrmacklem <rmacklem@FreeBSD.org>2015-05-21 23:14:18 +0000
committerrmacklem <rmacklem@FreeBSD.org>2015-05-21 23:14:18 +0000
commit9a564b79b59cca5b7c53e9a2930b491ad665455b (patch)
treec764221f165e87159f7c77bed3c4f4aa8b355a9c
parentbc74bc7ccccf4bea88611b8e0b37b13fa282721e (diff)
downloadFreeBSD-src-9a564b79b59cca5b7c53e9a2930b491ad665455b.zip
FreeBSD-src-9a564b79b59cca5b7c53e9a2930b491ad665455b.tar.gz
The NFS client wasn't handling getdirentries(2) requests for sizes
that are not an exact multiple of DIRBLKSIZ correctly. Fortunately readdir(3) always uses an exact multiple of DIRBLKSIZ, so few applications were affected. This patch fixes this problem by reducing the size of the directory read to an exact multiple of DIRBLKSIZ. Tested by: trasz Reported by: trasz Reviewed by: trasz MFC after: 2 weeks
-rw-r--r--sys/fs/nfsclient/nfs_clvnops.c16
1 files changed, 15 insertions, 1 deletions
diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c
index 513abf4..6aee675 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;
@@ -2239,6 +2239,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.
*/
tresid = uio->uio_resid;
@@ -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);
}
OpenPOWER on IntegriCloud