[PATCH v4 0/9] NFSD: Fix UAFs in client teardown and state revocation

Chuck Lever <[email protected]>
Newsgroups gmane.linux.nfs
Message-ID <[email protected]>
An NFSv4 stateid, and a bare lock owner reachable through the client's
owner hash, hold only a raw pointer to the owning nfs4_client. That
client outlives its state only because __destroy_client() drains every
stateid and owner before free_client() runs. A walk that dereferences
the client, or the owner, through one of those raw pointers after
dropping the lock that kept it reachable races a concurrent teardown
that can free it first. The NULL-pointer dereference reported during
client teardown was one such race; auditing the pattern found more
across the revocation and laundromat-reaping paths.

Where the racing object is the client, the fix is uniform: pin it with
cl_rpc_users across the window in which nn->client_lock is dropped.
Skipping a client that is already expiring is part of the correctness
argument, not cleanup. force_expire_client() stops consulting
cl_rpc_users once its wait has passed, so a pin taken then would not
hold the client; the walk must instead leave that client's state for
its own teardown to drain. Testing the expiry and taking the pin under
nn->client_lock is what makes the choice atomic against the expiry.

Pinning the client from these paths introduces a lock-order edge that
did not exist before: nn->client_lock now nests outside the inner
region of nn->deleg_lock and outside nn->blocked_locks_lock, both leaf
acquisitions everywhere else. The nesting is one-directional, and
netns.h records the deleg_lock relationship; a reaping path added later
must take nn->client_lock first.

Two changes sit apart from the lifetime races. The revocation and
reaping fixes left four open-coded copies of the pin-drop idiom,
consolidated here into put_client_no_renew() helpers (patch 6). The
same audit turned up an unrelated svc_export leak:
free_ol_stateid_reaplist() reaps open and lock stateids through
->sc_free() directly, bypassing the reference drop nfs4_put_stid()
performs, so the export stays pinned and blocks unmount (patch 9).

---
Changes in v4:
- Fix svc_export double put in nfs4_put_stid() (sashiko)
- Link to v3: https://patch.msgid.link/20260707-cel-v3-0-7c0cc16fd54f-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org

Changes in v3:
- Fix client UAF in laundromat blocked-lock reaping (Neil)
- Fix client UAF in laundromat close_lru reaping (sashiko)
- Fix svc_export leak when reaping open stateids (sashiko)
- Link to v2: https://patch.msgid.link/20260705-cel-v2-0-d88c3b68e8bc-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org

Changes in v2:
- Add matching UAF fixes in several other paths

---
Chuck Lever (9):
      NFSD: Prevent lock owner use-after-free during client teardown
      NFSD: Prevent client use-after-free during delegation revoke
      NFSD: Prevent client use-after-free during admin state revocation
      NFSD: Prevent client use-after-free during export state revocation
      NFSD: Prevent client use-after-free during NFSv4.0 revoked-state cleanup
      NFSD: Consolidate the revocation-path client unpin
      NFSD: Prevent client use-after-free during blocked-lock reaping
      NFSD: Prevent client use-after-free during close_lru reaping
      NFSD: Release the export reference when reaping open stateids

 fs/nfsd/netns.h     |   6 ++-
 fs/nfsd/nfs4state.c | 149 ++++++++++++++++++++++++++++++++++++++++++++--------
 2 files changed, 131 insertions(+), 24 deletions(-)
---
base-commit: ee6ae4a6bf3565b880dfb420017337475dfbc9ea
change-id: 20260705-cel-61c1c70caa03

Best regards,
--  
Chuck Lever
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.