Skip to content

Commit 908e4ea

Browse files
jtlaytonchucklever
authored andcommitted
nfsd: handle get_client_locked() failure in nfsd4_setclientid_confirm()
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: d20c11d ("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>
1 parent fdc368e commit 908e4ea

1 file changed

Lines changed: 15 additions & 5 deletions

File tree

fs/nfsd/nfs4state.c

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4690,10 +4690,16 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
46904690
}
46914691
status = nfs_ok;
46924692
if (conf) {
4693-
old = unconf;
4694-
unhash_client_locked(old);
4695-
nfsd4_change_callback(conf, &unconf->cl_cb_conn);
4696-
} else {
4693+
if (get_client_locked(conf) == nfs_ok) {
4694+
old = unconf;
4695+
unhash_client_locked(old);
4696+
nfsd4_change_callback(conf, &unconf->cl_cb_conn);
4697+
} else {
4698+
conf = NULL;
4699+
}
4700+
}
4701+
4702+
if (!conf) {
46974703
old = find_confirmed_client_by_name(&unconf->cl_name, nn);
46984704
if (old) {
46994705
status = nfserr_clid_inuse;
@@ -4710,10 +4716,14 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
47104716
}
47114717
trace_nfsd_clid_replaced(&old->cl_clientid);
47124718
}
4719+
status = get_client_locked(unconf);
4720+
if (status != nfs_ok) {
4721+
old = NULL;
4722+
goto out;
4723+
}
47134724
move_to_confirmed(unconf);
47144725
conf = unconf;
47154726
}
4716-
get_client_locked(conf);
47174727
spin_unlock(&nn->client_lock);
47184728
if (conf == unconf)
47194729
fsnotify_dentry(conf->cl_nfsd_info_dentry, FS_MODIFY);

0 commit comments

Comments
 (0)