CVE-2026-89708: nfsd: RCU-protect cl_cb_session to fix use-after-free on session teardown

Published Sep 11, 2026
·
Updated

In the Linux kernel, the following vulnerability has been resolved:

nfsd: RCU-protect clcbsession to fix use-after-free on session teardown

After a DESTROYSESSION the per-session teardown path can free a session while rpciod still holds an inflight callback rpctask that dereferences clp->clcbsession. nfsd4probecallbacksync() flushes clcallbackwq, but once nfsd4runcbwork() has called rpccallasync() the rpctask lives on rpciod; flushing the workqueue does not wait for it. rpcshutdownclient() does drain rpciod tasks, but uses a 1-second waiteventtimeout — tasks stuck in rpcdelay() (e.g. 2-second NFS4ERRDELAY retries) can outlive the drain.

destroy path rpciod ------------ ------ unhashsession(ses) nfsd4probecallbacksync(clp) flushworkqueue(clcallbackwq) / returns; rpctask still live / nfsd4putsessionlocked(ses) freesession(ses) -> kfree(ses) nfsd4cbsequencedone() reads cbclp->clcbsession / freed slab /

A second window exists in nfsd4processcbupdate(). When nfsd4findbackchannel() returns NULL because unhashsession() has already removed the destroyed session from clsessions, setupcallbackclient() takes the v4.1 early return so clp->clcbsession = ses never fires and the field retains a pointer to the about-to-be-freed session.

Fix both by converting clcbsession to an RCU-protected pointer:

- Move the clcbsession = ses assignment in setupcallbackclient() to after rpccreate() succeeds, so it is only published when a working backchannel exists. Clear clcbsession on the error return in nfsd4processcbupdate(). Both stores use rcuassignpointer().

- Annotate clcbsession with rcu. All rpciod-side readers use rcureadlock()/rcudereference() and check for NULL, bailing to the appropriate error or requeue path: encodecbsequence4args(), decodecbsequence4resok(), nfsd41cbgetslot(), nfsd41cbreleaseslot(), nfsd4cbprepare(), and nfsd4cbsequencedone().

- Switch freesession() from kfree() to kfreercu() so the session slab is not reclaimed until after an RCU grace period, guaranteeing that rpciod readers inside rcureadlock() never dereference freed memory.

- Pass the session pointer to the nfsdcbseqstatus and nfsdcbfreeslot tracepoints instead of having them re-read clcbsession.

- nfsd4cbprepare() calls rpcexit() when the session is NULL, routing through the done/release path to requeue the callback.

Affected Software

1 affected component
Linux Linux kernel

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Configuration

    Fix the nfsd use-after-free by converting clp->cl_cb_session to an RCU-protected pointer, using rcu_assign_pointer() when publishing it and rcu_read_lock()/rcu_dereference() with NULL checks in callback paths (e.g., nfsd4_process_cb_update() bails out when clp->cl_cb_session is NULL).

    Linux kernel nfsd cl_cb_session pointer handling = RCU-protected (rcu_assign_pointer/rcu_dereference + NULL checks)
  2. Configuration

    Switch the session teardown free path from free_session(ses) -> kfree(ses) to kfree_rcu() so the session slab is reclaimed only after an RCU grace period while rpciod readers are still in rcu_read_lock().

    Linux kernel nfsd Session free mechanism = kfree_rcu()
  3. Configuration

    Move the cl_cb_session = ses assignment into setup_callback_client() so the session pointer is only published after rpc_create() succeeds and the appropriate error/requeue paths are taken for early returns.

    Linux kernel nfsd cl_cb_session assignment timing = move assignment into setup_callback_client()
  4. Configuration

    Ensure nfsd4_cb_prepare() (and related callback flow such as nfsd4_cb_sequence_done()/nfsd4_process_cb_update()) handles a NULL cl_cb_session by bailing/returning (including calling rpc_exit() when the session is NULL) to avoid dereferencing freed memory.

    Linux kernel nfsd4 callback handling Null session behavior in nfsd4 callback = rpc_exit()/return
  5. Configuration

    Clear cl_cb_session on the error/teardown path so that any late readers see NULL and bail out rather than dereferencing freed memory.

    Linux kernel nfsd cl_cb_session clearing on error = clear cl_cb_session

Event History

Sep 11, 2026
CVE Published
via MITRE·07:46 PM
Data Sourced
via MITRE·07:46 PM
Description

Frequently Asked Questions

1

Which systems are exposed to this race?

Linux systems running the NFS server callback/session teardown path are exposed when a session is destroyed while an asynchronous callback RPC task remains in flight on rpciod. The issue specifically involves access to the callback session pointer after the session has been freed.

2

What timing conditions are required for the use-after-free to occur?

A DESTROY_SESSION operation must begin teardown after callback work has started an asynchronous RPC task. The task can outlive the callback workqueue flush, particularly when it is delayed in rpc_delay(), such as during NFS4ERR_DELAY retry handling.

3

Why is flushing the callback workqueue insufficient protection?

Once nfsd4_run_cb_work() has invoked rpc_call_async(), the RPC task is owned by rpciod rather than the callback workqueue. The client shutdown drain uses a one-second timeout, so delayed tasks can remain alive after session memory is released.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203