summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrmacklem <rmacklem@FreeBSD.org>2010-04-04 23:19:11 +0000
committerrmacklem <rmacklem@FreeBSD.org>2010-04-04 23:19:11 +0000
commit71f4a9b7efa07b37f3300fd48a4c8343ce712d87 (patch)
tree5cf21e6a590277679edac1e6664a01a44d39ff15
parentca9540f0dcc7ca3a4a9fe641bdbc0e69de32c895 (diff)
downloadFreeBSD-src-71f4a9b7efa07b37f3300fd48a4c8343ce712d87.zip
FreeBSD-src-71f4a9b7efa07b37f3300fd48a4c8343ce712d87.tar.gz
Harden the experimental NFS server a little, by adding extra checks
in the readdir functions for non-positive byte count arguments. For the negative case, set it to the maximum allowable, since it was actually a large positive value (unsigned) on the wire. Also, fix up the readdir function comment a bit. Suggested by: dillon AT apollo.backplane.com MFC after: 2 weeks
-rw-r--r--sys/fs/nfsserver/nfs_nfsdport.c23
1 files changed, 11 insertions, 12 deletions
diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c
index 724d46b..ba367e3 100644
--- a/sys/fs/nfsserver/nfs_nfsdport.c
+++ b/sys/fs/nfsserver/nfs_nfsdport.c
@@ -1397,24 +1397,16 @@ nfsvno_fillattr(struct nfsrv_descript *nd, struct vnode *vp,
* nfs readdir service
* - mallocs what it thinks is enough to read
* count rounded up to a multiple of DIRBLKSIZ <= NFS_MAXREADDIR
- * - calls nfsvno_readdir()
+ * - calls VOP_READDIR()
* - loops around building the reply
* if the output generated exceeds count break out of loop
* The NFSM_CLGET macro is used here so that the reply will be packed
* tightly in mbuf clusters.
- * - it only knows that it has encountered eof when the nfsvno_readdir()
- * reads nothing
- * - as such one readdir rpc will return eof false although you are there
- * and then the next will return eof
* - it trims out records with d_fileno == 0
* this doesn't matter for Unix clients, but they might confuse clients
* for other os'.
* - it trims out records with d_type == DT_WHT
* these cannot be seen through NFS (unless we extend the protocol)
- * NB: It is tempting to set eof to true if the nfsvno_readdir() reads less
- * than requested, but this may not apply to all filesystems. For
- * example, client NFS does not { although it is never remote mounted
- * anyhow }
* The alternate call nfsrvd_readdirplus() does lookups as well.
* PS: The NFS protocol spec. does not clarify what the "count" byte
* argument is a count of.. just name strings and file id's or the
@@ -1456,7 +1448,7 @@ nfsrvd_readdir(struct nfsrv_descript *nd, int isdgram,
}
toff = off;
cnt = fxdr_unsigned(int, *tl);
- if (cnt > NFS_SRVMAXDATA(nd))
+ if (cnt > NFS_SRVMAXDATA(nd) || cnt < 0)
cnt = NFS_SRVMAXDATA(nd);
siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
fullsiz = siz;
@@ -1474,6 +1466,13 @@ nfsrvd_readdir(struct nfsrv_descript *nd, int isdgram,
nd->nd_repstat = NFSERR_BAD_COOKIE;
#endif
}
+ if (nd->nd_repstat == 0 && cnt == 0) {
+ if (nd->nd_flag & ND_NFSV2)
+ /* NFSv2 does not have NFSERR_TOOSMALL */
+ nd->nd_repstat = EPERM;
+ else
+ nd->nd_repstat = NFSERR_TOOSMALL;
+ }
if (!nd->nd_repstat)
nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
@@ -1696,7 +1695,7 @@ nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdgram,
* Use the server's maximum data transfer size as the upper bound
* on reply datalen.
*/
- if (cnt > NFS_SRVMAXDATA(nd))
+ if (cnt > NFS_SRVMAXDATA(nd) || cnt < 0)
cnt = NFS_SRVMAXDATA(nd);
/*
@@ -1705,7 +1704,7 @@ nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdgram,
* so I set it to cnt for that case. I also round it up to the
* next multiple of DIRBLKSIZ.
*/
- if (siz == 0)
+ if (siz <= 0)
siz = cnt;
siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
OpenPOWER on IntegriCloud