]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
nfsd: fix refcount leak in nfsd_set_fh_dentry()
authorNeilBrown <neil@brown.name>
Wed, 8 Oct 2025 13:52:25 +0000 (09:52 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 24 Nov 2025 09:35:59 +0000 (10:35 +0100)
commit 8a7348a9ed70bda1c1f51d3f1815bcbdf9f3b38c upstream.

nfsd exports a "pseudo root filesystem" which is used by NFSv4 to find
the various exported filesystems using LOOKUP requests from a known root
filehandle.  NFSv3 uses the MOUNT protocol to find those exported
filesystems and so is not given access to the pseudo root filesystem.

If a v3 (or v2) client uses a filehandle from that filesystem,
nfsd_set_fh_dentry() will report an error, but still stores the export
in "struct svc_fh" even though it also drops the reference (exp_put()).
This means that when fh_put() is called an extra reference will be dropped
which can lead to use-after-free and possible denial of service.

Normal NFS usage will not provide a pseudo-root filehandle to a v3
client.  This bug can only be triggered by the client synthesising an
incorrect filehandle.

To fix this we move the assignments to the svc_fh later, after all
possible error cases have been detected.

Reported-and-tested-by: tianshuo han <hantianshuo233@gmail.com>
Fixes: ef7f6c4904d0 ("nfsd: move V4ROOT version check to nfsd_set_fh_dentry()")
Signed-off-by: NeilBrown <neil@brown.name>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Cc: stable@vger.kernel.org
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/nfsd/nfsfh.c

index 854dcdc36b2ce61ad958e94f8b488a4e26026969..9e85fdccf85085ec92f5762be17a7c985e27a2b2 100644 (file)
@@ -268,9 +268,6 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct net *net,
                                dentry);
        }
 
-       fhp->fh_dentry = dentry;
-       fhp->fh_export = exp;
-
        switch (fhp->fh_maxsize) {
        case NFS4_FHSIZE:
                if (dentry->d_sb->s_export_op->flags & EXPORT_OP_NOATOMIC_ATTR)
@@ -292,6 +289,9 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct net *net,
                        goto out;
        }
 
+       fhp->fh_dentry = dentry;
+       fhp->fh_export = exp;
+
        return 0;
 out:
        exp_put(exp);