{"id":21630,"date":"2026-09-12T04:31:26","date_gmt":"2026-09-11T20:31:26","guid":{"rendered":"https:\/\/www.54iter.cn\/?vuln=cve-2026-89708"},"modified":"2026-09-12T04:31:26","modified_gmt":"2026-09-11T20:31:26","slug":"cve-2026-89708","status":"publish","type":"vuln","link":"https:\/\/www.54iter.cn\/?vuln=cve-2026-89708","title":{"rendered":"CVE-2026-89708 &#8211; In the Linux kernel, the following vulnerability has been resolved:\n\nnfsd: RCU-protect cl_"},"content":{"rendered":"<p>In the Linux kernel, the following vulnerability has been resolved:<\/p>\n<p>nfsd: RCU-protect cl_cb_session to fix use-after-free on session teardown<\/p>\n<p>After a DESTROY_SESSION the per-session teardown path can free a<br \/>\nsession while rpciod still holds an inflight callback rpc_task that<br \/>\ndereferences clp-&gt;cl_cb_session.  nfsd4_probe_callback_sync() flushes<br \/>\ncl_callback_wq, but once nfsd4_run_cb_work() has called<br \/>\nrpc_call_async() the rpc_task lives on rpciod; flushing the workqueue<br \/>\ndoes not wait for it.  rpc_shutdown_client() does drain rpciod tasks,<br \/>\nbut uses a 1-second wait_event_timeout \u2014 tasks stuck in rpc_delay()<br \/>\n(e.g. 2-second NFS4ERR_DELAY retries) can outlive the drain.<\/p>\n<p>    destroy path                       rpciod<br \/>\n    &#8212;&#8212;&#8212;&#8212;                       &#8212;&#8212;<br \/>\n    unhash_session(ses)<br \/>\n    nfsd4_probe_callback_sync(clp)<br \/>\n      flush_workqueue(cl_callback_wq)<br \/>\n      \/* returns; rpc_task still live *\/<br \/>\n    nfsd4_put_session_locked(ses)<br \/>\n    free_session(ses) -&gt; kfree(ses)<br \/>\n                                       nfsd4_cb_sequence_done()<br \/>\n                                         reads cb_clp-&gt;cl_cb_session<br \/>\n                                         \/* freed slab *\/<\/p>\n<p>A second window exists in nfsd4_process_cb_update().  When<br \/>\n__nfsd4_find_backchannel() returns NULL because unhash_session() has<br \/>\nalready removed the destroyed session from cl_sessions,<br \/>\nsetup_callback_client() takes the v4.1 early return so<br \/>\nclp-&gt;cl_cb_session = ses never fires and the field retains a pointer<br \/>\nto the about-to-be-freed session.<\/p>\n<p>Fix both by converting cl_cb_session to an RCU-protected pointer:<\/p>\n<p>  &#8211; Move the cl_cb_session = ses assignment in setup_callback_client()<br \/>\n    to after rpc_create() succeeds, so it is only published when a<br \/>\n    working backchannel exists.  Clear cl_cb_session on the error<br \/>\n    return in nfsd4_process_cb_update().  Both stores use<br \/>\n    rcu_assign_pointer().<\/p>\n<p>  &#8211; Annotate cl_cb_session with __rcu.  All rpciod-side readers use<br \/>\n    rcu_read_lock()\/rcu_dereference() and check for NULL, bailing to<br \/>\n    the appropriate error or requeue path:<br \/>\n    encode_cb_sequence4args(), decode_cb_sequence4resok(),<br \/>\n    nfsd41_cb_get_slot(), nfsd41_cb_release_slot(),<br \/>\n    nfsd4_cb_prepare(), and nfsd4_cb_sequence_done().<\/p>\n<p>  &#8211; Switch __free_session() from kfree() to kfree_rcu() so the<br \/>\n    session slab is not reclaimed until after an RCU grace period,<br \/>\n    guaranteeing that rpciod readers inside rcu_read_lock() never<br \/>\n    dereference freed memory.<\/p>\n<p>  &#8211; Pass the session pointer to the nfsd_cb_seq_status and<br \/>\n    nfsd_cb_free_slot tracepoints instead of having them re-read<br \/>\n    cl_cb_session.<\/p>\n<p>  &#8211; nfsd4_cb_prepare() calls rpc_exit() when the session is NULL,<br \/>\n    routing through the done\/release path to requeue the callback.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the Linux kernel, the following vulnerability has been resolved:<\/p>\n<p>nfsd: RCU-protect cl_cb_session to fix use-after-free on session teardown<\/p>\n<p>After a DESTROY_SESSION the per-session teardown path ca<\/p>\n","protected":false},"template":"","meta":[],"categories":[],"tags":[],"class_list":["post-21630","vuln","type-vuln","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.54iter.cn\/index.php?rest_route=\/wp\/v2\/vuln\/21630","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.54iter.cn\/index.php?rest_route=\/wp\/v2\/vuln"}],"about":[{"href":"https:\/\/www.54iter.cn\/index.php?rest_route=\/wp\/v2\/types\/vuln"}],"wp:attachment":[{"href":"https:\/\/www.54iter.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=21630"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.54iter.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=21630"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.54iter.cn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=21630"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}