UBUNTU-CVE-2026-89708: Use After Free
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
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
ubuntu/linux-hwe-7.0to a version that resolves this vulnerability.Fixed in 7.0.0-42.42~24.04.1 - Upgrade
Upgrade
ubuntu/linux-riscv-7.0to a version that resolves this vulnerability.Fixed in 7.0.0-42.42.1~24.04.1 - Upgrade
Upgrade
ubuntu/linuxto a version that resolves this vulnerability.Fixed in 7.0.0-42.42 - Upgrade
Upgrade
ubuntu/linux-awsto a version that resolves this vulnerability.Fixed in 7.0.0-1016.17 - Upgrade
Upgrade
ubuntu/linux-gcpto a version that resolves this vulnerability.Fixed in 7.0.0-1016.18 - Upgrade
Upgrade
ubuntu/linux-ibmto a version that resolves this vulnerability.Fixed in 7.0.0-1017.17 - Upgrade
Upgrade
ubuntu/linux-oem-7.0to a version that resolves this vulnerability.Fixed in 7.0.0-1017.17 - Upgrade
Upgrade
ubuntu/linux-oracleto a version that resolves this vulnerability.Fixed in 7.0.0-1015.16 - Upgrade
Upgrade
ubuntu/linux-riscvto a version that resolves this vulnerability.Fixed in 7.0.0-42.42.1 - Compensating control
Convert cl_cb_session to an RCU-protected pointer: publish the session with rcu_assign_pointer() only after rpc_create() succeeds in setup_callback_client(), clear it with rcu_assign_pointer() on the error return in nfsd4_process_cb_update(), and have rpciod-side readers use rcu_read_lock()/rcu_dereference(), check for NULL, and follow the appropriate error or requeue path.
- Compensating control
Switch __free_session() from kfree() to kfree_rcu() so session memory is reclaimed only after an RCU grace period.
- Compensating control
Pass the session pointer directly to the nfsd_cb_seq_status and nfsd_cb_free_slot tracepoints instead of having those tracepoints re-read cl_cb_session.
- Compensating control
Make nfsd4_cb_prepare() call rpc_exit() when the session is NULL so callback completion follows the done/release path and requeues the callback.