The branch stable/13 has been updated by rmacklem:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=968abc191ea145040f4c2105755d11b63ecb2427

commit 968abc191ea145040f4c2105755d11b63ecb2427
Author:     Rick Macklem <rmack...@freebsd.org>
AuthorDate: 2025-01-10 03:54:41 +0000
Commit:     Rick Macklem <rmack...@freebsd.org>
CommitDate: 2025-01-24 02:30:22 +0000

    nfscl: Fix a crash when a readdir entry has nul in it
    
    Commit 026cdaa3b3a9 added a check for a nul or "/" in a file
    name in a readdir reply.  Unfortunately, the minimal testing
    done on it did not detect a bug that can cause the client
    to crash.
    
    This patch fixes the code so that it does not crash.
    
    Note that a NFS server will not normally return a file
    name in a readdir reply that has a nul or "/" in it,
    so the crash is unlikely.
    
    PR:     283965
    
    (cherry picked from commit f9f0a1d61c7b97c705246c747baec385e0592966)
---
 sys/fs/nfsclient/nfs_clrpcops.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c
index b3062b5a5d88..f3ab2bda8f85 100644
--- a/sys/fs/nfsclient/nfs_clrpcops.c
+++ b/sys/fs/nfsclient/nfs_clrpcops.c
@@ -3079,6 +3079,7 @@ nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 
*cookiep,
        nfsattrbit_t attrbits, dattrbits;
        u_int32_t rderr, *tl2 = NULL;
        size_t tresid;
+       bool validentry;
 
        KASSERT(uiop->uio_iovcnt == 1 &&
            (uiop->uio_resid & (DIRBLKSIZ - 1)) == 0,
@@ -3305,6 +3306,7 @@ nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 
*cookiep,
 
                /* loop through the dir entries, doctoring them to 4bsd form */
                while (more_dirs && bigenough) {
+                       validentry = true;
                        if (nd->nd_flag & ND_NFSV4) {
                                NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
                                ncookie.lval[0] = *tl++;
@@ -3384,6 +3386,7 @@ nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 
*cookiep,
                                        uiop->uio_offset = savoff;
                                        uiop->uio_resid = savresid;
                                        blksiz = savblksiz;
+                                       validentry = false;
                                } else {
                                        cp = uiop->uio_iov->iov_base;
                                        tlen -= len;
@@ -3421,7 +3424,7 @@ nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 
*cookiep,
                                ncookie.lval[0] = 0;
                                ncookie.lval[1] = *tl++;
                        }
-                       if (bigenough) {
+                       if (bigenough && validentry) {
                            if (nd->nd_flag & ND_NFSV4) {
                                if (rderr) {
                                    dp->d_fileno = 0;
@@ -3560,7 +3563,7 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, 
nfsuint64 *cookiep,
        size_t tresid;
        u_int32_t *tl2 = NULL, rderr;
        struct timespec dctime, ts;
-       bool attr_ok;
+       bool attr_ok, validentry;
 
        KASSERT(uiop->uio_iovcnt == 1 &&
            (uiop->uio_resid & (DIRBLKSIZ - 1)) == 0,
@@ -3771,6 +3774,7 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, 
nfsuint64 *cookiep,
 
                /* loop through the dir entries, doctoring them to 4bsd form */
                while (more_dirs && bigenough) {
+                       validentry = true;
                        NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
                        if (nd->nd_flag & ND_NFSV4) {
                                ncookie.lval[0] = *tl++;
@@ -3846,6 +3850,7 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, 
nfsuint64 *cookiep,
                                        uiop->uio_offset = savoff;
                                        uiop->uio_resid = savresid;
                                        blksiz = savblksiz;
+                                       validentry = false;
                                } else {
                                        cp = uiop->uio_iov->iov_base;
                                        tlen -= len;
@@ -3902,7 +3907,7 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, 
nfsuint64 *cookiep,
                                        goto nfsmout;
                        }
 
-                       if (bigenough) {
+                       if (bigenough && validentry) {
                            if (nd->nd_flag & ND_NFSV4) {
                                if (rderr) {
                                    dp->d_fileno = 0;

Reply via email to