Date: Sat, 16 Jul 2011 10:43:15 +0000 From: gk@FreeBSD.org To: svn-soc-all@FreeBSD.org Subject: socsvn commit: r224305 - in soc2011/gk/ino64-head/sys: fs/nfsclient nfsclient Message-ID: <20110716104315.3834F106566B@hub.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: gk Date: Sat Jul 16 10:43:14 2011 New Revision: 224305 URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=224305 Log: Fix NFS readdir offset and buffer size alignment Align read result by DIRBLKSIZ (512 bytes) Fail if buffer is less than DIRBLKSIZ Bug fixed: getdirentries() call with not DIRBLKSIZ aligned offset and/or buffer size results in file offset that doesn't start on dirent boundary. Next getdirentries() call will return garbled output. Todo: Application is still allowed to use arbitrary offsets. Unlike other filesystems NFS readdir will not "correct" offset and will fill buffer with data that doesn't start on dirent boundary. Modified: soc2011/gk/ino64-head/sys/fs/nfsclient/nfs_clbio.c soc2011/gk/ino64-head/sys/nfsclient/nfs_bio.c Modified: soc2011/gk/ino64-head/sys/fs/nfsclient/nfs_clbio.c ============================================================================== --- soc2011/gk/ino64-head/sys/fs/nfsclient/nfs_clbio.c Sat Jul 16 10:43:03 2011 (r224304) +++ soc2011/gk/ino64-head/sys/fs/nfsclient/nfs_clbio.c Sat Jul 16 10:43:14 2011 (r224305) @@ -459,6 +459,8 @@ return (0); if (uio->uio_offset < 0) /* XXX VDIR cookies can be negative */ return (EINVAL); + if (vp->v_type == VDIR && uio->uio_resid < DIRBLKSIZ) + return (EINVAL); td = uio->uio_td; mtx_lock(&nmp->nm_mtx); @@ -601,6 +603,8 @@ && uio->uio_offset >= np->n_direofoffset) { return (0); } + if (uio->uio_resid < DIRBLKSIZ) + return (0); lbn = (uoff_t)uio->uio_offset / NFS_DIRBLKSIZ; on = uio->uio_offset & (NFS_DIRBLKSIZ - 1); bp = nfs_getcacheblk(vp, lbn, NFS_DIRBLKSIZ, td); @@ -709,6 +713,9 @@ n = lmin(uio->uio_resid, NFS_DIRBLKSIZ - bp->b_resid - on); if (np->n_direofoffset && n > np->n_direofoffset - uio->uio_offset) n = np->n_direofoffset - uio->uio_offset; + else + /* Align offset. Abort if n <= 0 or resid < DIRBLKSIZ */ + n -= (uio->uio_offset + n) & (DIRBLKSIZ - 1); break; default: ncl_printf(" ncl_bioread: type %x unexpected\n", vp->v_type); Modified: soc2011/gk/ino64-head/sys/nfsclient/nfs_bio.c ============================================================================== --- soc2011/gk/ino64-head/sys/nfsclient/nfs_bio.c Sat Jul 16 10:43:03 2011 (r224304) +++ soc2011/gk/ino64-head/sys/nfsclient/nfs_bio.c Sat Jul 16 10:43:14 2011 (r224305) @@ -458,6 +458,8 @@ return (0); if (uio->uio_offset < 0) /* XXX VDIR cookies can be negative */ return (EINVAL); + if (vp->v_type == VDIR && uio->uio_resid < DIRBLKSIZ) + return (EINVAL); td = uio->uio_td; mtx_lock(&nmp->nm_mtx); @@ -594,6 +596,8 @@ && uio->uio_offset >= np->n_direofoffset) { return (0); } + if (uio->uio_resid < DIRBLKSIZ) + return (0); lbn = (uoff_t)uio->uio_offset / NFS_DIRBLKSIZ; on = uio->uio_offset & (NFS_DIRBLKSIZ - 1); bp = nfs_getcacheblk(vp, lbn, NFS_DIRBLKSIZ, td); @@ -702,6 +706,10 @@ n = lmin(uio->uio_resid, NFS_DIRBLKSIZ - bp->b_resid - on); if (np->n_direofoffset && n > np->n_direofoffset - uio->uio_offset) n = np->n_direofoffset - uio->uio_offset; + else { + /* Align offset. Abort if n <= 0 or resid < DIRBLKSIZ */ + n -= (uio->uio_offset + n) & (DIRBLKSIZ - 1); + } break; default: nfs_printf(" nfs_bioread: type %x unexpected\n", vp->v_type);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20110716104315.3834F106566B>