mirror of
https://github.com/torvalds/linux.git
synced 2026-09-24 06:24:02 +02:00
NFSD: Prevent client use-after-free during close_lru reaping
An nfs4_openowner left on nn->close_lru after its final CLOSE keeps
its last closed stateid in oo_last_closed_stid, holding only a raw
pointer to its nfs4_client. The laundromat reaps timed-out entries,
drops nn->client_lock, and calls nfs4_put_stid(), which dereferences
the client through cl_lock. Nothing pins the client across that
window, so a concurrent force_expire_client() can free it and
nfs4_put_stid() reads freed memory. __destroy_client() hits the same
race, walking clp->cl_openowners without cl_lock.
Pin the client with cl_rpc_users before dropping client_lock, and
skip clients already expiring. __destroy_client() then cleans up its
own close_lru entries through release_last_closed_stateid(), so
teardown no longer races the laundromat.
Fixes: 217526e7ec ("nfsd: protect the close_lru list and oo_last_closed_stid with client_lock")
Cc: stable@vger.kernel.org
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260709-cel-v4-8-1d519d9be0cb@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>
This commit is contained in:
parent
9026932ac8
commit
2330b788d7
|
|
@ -7581,11 +7581,16 @@ nfs4_laundromat(struct nfsd_net *nn)
|
|||
if (!state_expired(<, oo->oo_time))
|
||||
break;
|
||||
list_del_init(&oo->oo_close_lru);
|
||||
clp = oo->oo_owner.so_client;
|
||||
if (is_client_expired(clp))
|
||||
continue;
|
||||
stp = oo->oo_last_closed_stid;
|
||||
oo->oo_last_closed_stid = NULL;
|
||||
atomic_inc(&clp->cl_rpc_users);
|
||||
spin_unlock(&nn->client_lock);
|
||||
nfs4_put_stid(&stp->st_stid);
|
||||
spin_lock(&nn->client_lock);
|
||||
put_client_no_renew_locked(clp);
|
||||
}
|
||||
spin_unlock(&nn->client_lock);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user