]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
nfsd: handle get_client_locked() failure in nfsd4_setclientid_confirm()
authorJeff Layton <jlayton@kernel.org>
Wed, 4 Jun 2025 16:01:10 +0000 (12:01 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 20 Aug 2025 16:40:46 +0000 (18:40 +0200)
commit 908e4ead7f757504d8b345452730636e298cbf68 upstream.

Lei Lu recently reported that nfsd4_setclientid_confirm() did not check
the return value from get_client_locked(). a SETCLIENTID_CONFIRM could
race with a confirmed client expiring and fail to get a reference. That
could later lead to a UAF.

Fix this by getting a reference early in the case where there is an
extant confirmed client. If that fails then treat it as if there were no
confirmed client found at all.

In the case where the unconfirmed client is expiring, just fail and
return the result from get_client_locked().

Reported-by: lei lu <llfamsec@gmail.com>
Closes: https://lore.kernel.org/linux-nfs/CAEBF3_b=UvqzNKdnfD_52L05Mqrqui9vZ2eFamgAbV0WG+FNWQ@mail.gmail.com/
Fixes: d20c11d86d8f ("nfsd: Protect session creation and client confirm using client_lock")
Cc: stable@vger.kernel.org
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/nfsd/nfs4state.c

index d5694987f86fadab985e55cce6261ad680e83b69..d61a7910dde3b8536b8715c2eebd1f1faec95f8f 100644 (file)
@@ -4697,10 +4697,16 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
        }
        status = nfs_ok;
        if (conf) {
-               old = unconf;
-               unhash_client_locked(old);
-               nfsd4_change_callback(conf, &unconf->cl_cb_conn);
-       } else {
+               if (get_client_locked(conf) == nfs_ok) {
+                       old = unconf;
+                       unhash_client_locked(old);
+                       nfsd4_change_callback(conf, &unconf->cl_cb_conn);
+               } else {
+                       conf = NULL;
+               }
+       }
+
+       if (!conf) {
                old = find_confirmed_client_by_name(&unconf->cl_name, nn);
                if (old) {
                        status = nfserr_clid_inuse;
@@ -4717,10 +4723,14 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
                        }
                        trace_nfsd_clid_replaced(&old->cl_clientid);
                }
+               status = get_client_locked(unconf);
+               if (status != nfs_ok) {
+                       old = NULL;
+                       goto out;
+               }
                move_to_confirmed(unconf);
                conf = unconf;
        }
-       get_client_locked(conf);
        spin_unlock(&nn->client_lock);
        if (conf == unconf)
                fsnotify_dentry(conf->cl_nfsd_info_dentry, FS_MODIFY);