]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
nfsd4: Handle the NFSv4 READDIR 'dircount' hint being zero
authorTrond Myklebust <trond.myklebust@hammerspace.com>
Thu, 30 Sep 2021 19:44:41 +0000 (15:44 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 17 Oct 2021 08:04:43 +0000 (10:04 +0200)
commit f2e717d655040d632c9015f19aa4275f8b16e7f2 upstream.

RFC3530 notes that the 'dircount' field may be zero, in which case the
recommendation is to ignore it, and only enforce the 'maxcount' field.
In RFC5661, this recommendation to ignore a zero valued field becomes a
requirement.

Fixes: aee377644146 ("nfsd4: fix rd_dircount enforcement")
Cc: <stable@vger.kernel.org>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/nfsd/nfs4xdr.c

index ee0da259a3d3b44b0a84190640561235fe61cad6..87708608c0ffd6f6d9100084c41fc59d5a21c774 100644 (file)
@@ -2988,15 +2988,18 @@ nfsd4_encode_dirent(void *ccdv, const char *name, int namlen,
                goto fail;
        cd->rd_maxcount -= entry_bytes;
        /*
-        * RFC 3530 14.2.24 describes rd_dircount as only a "hint", so
-        * let's always let through the first entry, at least:
+        * RFC 3530 14.2.24 describes rd_dircount as only a "hint", and
+        * notes that it could be zero. If it is zero, then the server
+        * should enforce only the rd_maxcount value.
         */
-       if (!cd->rd_dircount)
-               goto fail;
-       name_and_cookie = 4 + 4 * XDR_QUADLEN(namlen) + 8;
-       if (name_and_cookie > cd->rd_dircount && cd->cookie_offset)
-               goto fail;
-       cd->rd_dircount -= min(cd->rd_dircount, name_and_cookie);
+       if (cd->rd_dircount) {
+               name_and_cookie = 4 + 4 * XDR_QUADLEN(namlen) + 8;
+               if (name_and_cookie > cd->rd_dircount && cd->cookie_offset)
+                       goto fail;
+               cd->rd_dircount -= min(cd->rd_dircount, name_and_cookie);
+               if (!cd->rd_dircount)
+                       cd->rd_maxcount = 0;
+       }
 
        cd->cookie_offset = cookie_offset;
 skip_entry: