CVE-2026-89670: nfsd: hold rcu across localio cmpxchg retry
In the Linux kernel, the following vulnerability has been resolved:
nfsd: hold rcu across localio cmpxchg retry
nfsdfile objects are freed via callrcu (filecache.c:296), and nfsdfileslab is created without SLABTYPESAFEBYRCU (KMEMCACHE(nfsdfile, 0) at filecache.c:789), so the slab page backing a freed nfsdfile becomes freely reclaimable once the RCU grace period elapses.
The again: retry block in nfsdopenlocalfh() loads a pointer with cmpxchg and then calls nfsdfileget(new) (which is refcountincnotzero) without holding rcureadlock. The sole caller nfsopenlocalfh() drops rcureadlock before invoking this helper, so no outer reader-side critical section covers the load.
CPU 0 (nfsdopenlocalfh) CPU 1 (nfsdfileputlocal) ----- ----- new = cmpxchg(pnf, NULL, ...) nf = xchg(pnf, NULL) nfsdfileput(nf) last ref -> callrcu() / grace period elapses; slab page recycled / nfsdfileget(new) refcountincnotzero(&new->nfref) / operates on recycled memory /
A non-zero word at the nfref offset of the recycled object makes the refcount bump appear to succeed, and the caller then dereferences new->nfnet and new->nffile out of freed memory.
Fix by taking rcureadlock() immediately before the cmpxchg and releasing it on all three exits of the if (new) block: the goto-again retry, the lost-race cleanup path, and the install-succeeded path. nfsdfileput() and nfsdnetput() stay outside the RCU section so they remain free to block.
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Configuration
Modify nfsd_open_local_fh() so rcu_read_lock() is taken immediately before the cmpxchg in the goto-again retry block, and keep the RCU read-side lock held through subsequent refcount/dereference operations on the returned pointer, preventing use-after-free of recycled nfsd_file memory.
Linux kernel nfsd_file / nfsd_open_local_fh RCU locking around cmpxchg retry block (rcu_read_lock held immediately before cmpxchg and remains held through dereference) = Enable/hold rcu_read_lock immediately before the cmpxchg in nfsd_open_local_fh() again/retry block and ensure reader-side dereference (e.g., refcount_inc_not_zero(&new->nf_ref)) occurs while holding the RCU read-side critical section
Event History
Frequently Asked Questions
Who is exposed to this issue?
Systems running the Linux kernel NFS server code path that uses local I/O file-handle handling are exposed. The race involves nfsd_open_local_fh() and concurrent nfsd_file_put_local() activity.
What conditions are required to trigger the vulnerability?
An attacker or workload must cause a race between a compare-and-exchange retry in nfsd_open_local_fh() and another CPU removing the referenced nfsd_file and dropping its final reference. The RCU grace period must then elapse and the freed slab memory must be recycled before nfsd_file_get() operates on the stale pointer.
What can happen if the race succeeds?
The kernel may increment a refcount in recycled memory and subsequently dereference nf_net and nf_file through a freed nfsd_file pointer. This is a use-after-free condition in the kernel NFS server.
How can I determine whether a kernel contains the fix?
Check whether the kernel includes one of the referenced stable commits: 763c0bad872368304db718f79af7e93048885c67, 559570f91a7d4d199a72105e4980bef791f4cbf1, or 58884694978a3d7d111edb433d7fd6a6c5af2f34. The fix holds RCU protection across the compare-and-exchange retry path.