In the Linux kernel, the following vulnerability has been resolved:
nfsd: drop the stateid, not the stateowner, on seqid_op replay retry
In nfs4_preprocess_seqid_op() the stateid is obtained from
nfsd4_lookup_stateid(), which holds a reference on the nfs4_stid
(sc_count) but takes no reference on the stateowner. openlockstateid()
merely casts that stid and likewise takes no reference.
When nfsd4_cstate_assign_replay() returns -EAGAIN (the replay owner is
being torn down, RP_UNHASHED) it has not taken a stateowner reference on
that path. The error handling nevertheless called
nfs4_put_stateowner(stp->st_stateowner), dropping an so_count reference
the function never acquired -- risking a stateowner refcount underflow and
use-after-free -- while leaking the sc_count reference held on the stid.
The leaked stid reference can also stall a concurrent
nfsd4_close_open_stateid() waiting for sc_count to drop.
Drop the reference actually held -- the stid -- before retrying. The
stateowner stays alive through the reference held by the stid. This mirrors
the open path in nfsd4_process_open1(), where the put balances a reference
that path explicitly holds on the stateowner.
CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
CVSS Score: 9.8
AV:N - nfsd processes NFSv4 COMPOUND ops (CLOSE, OPEN_DOWNGRADE, LOCK, OPEN_CONFIRM) in the in-kernel NFS server on TCP/UDP 2049; those handlers call nfs4_preprocess_seqid_op(), so a remote peer reaches the bug with no local access.
AC:L - A remote NFSv4.0 client drives both sides by sending concurrent CLOSE and another seqid-mutating op on the same openowner; CLOSE's move_to_close_lru() sets RP_UNHASHED and waits on sc_count, so the window is attacker-controlled and retryable.
PR:N - Typical nfsd exports use AUTH_SYS/AUTH_NULL, so RPC uids are self-asserted and not cryptographically verified; any host allowed by the export list can SETCLIENTID, OPEN, then CLOSE/OPEN_DOWNGRADE with no local Linux account.
UI:N - The attacker issues the NFSv4 COMPOUND requests itself; no victim on the server must mount a filesystem, open a file, or take any other action.
S:U - The underflow frees an nfsd nfs4_stateowner in the NFS server kernel; impact stays in that kernel and does not cross a VM, IOMMU, or sandbox boundary.
C:H - nfs4_put_stateowner() drops an so_count the seqid path never took, freeing the stateowner while the stid and retry loop still use it; that UAF enables slab reclaim and kernel memory disclosure.
I:H - The same UAF exposes so_ops->so_unhash/so_free function pointers and list writes under cl_lock, yielding a kernel write and control-flow hijack primitive.
A:H - The UAF oopses or panics nfsd; the leaked stid sc_count also leaves move_to_close_lru() waiting forever for sc_count==2, hanging an nfsd thread, and the -EAGAIN retry can spin while RP_UNHASHED stays set.
| Attack Vector |
Network |
Scope |
Unchanged |
| Attack Complexity |
Low |
Confidentiality Impact |
High |
| Privileges Required |
None |
Integrity Impact |
High |
| User Interaction |
None |
Availability Impact |
High |
AV:N - nfsd processes NFSv4 COMPOUND ops (CLOSE, OPEN_DOWNGRADE, LOCK, OPEN_CONFIRM) in the in-kernel NFS server on TCP/UDP 2049; those handlers call nfs4_preprocess_seqid_op(), so a remote peer reaches the bug with no local access.
AC:L - A remote NFSv4.0 client drives both sides by sending concurrent CLOSE and another seqid-mutating op on the same openowner; CLOSE's move_to_close_lru() sets RP_UNHASHED and waits on sc_count, so the window is attacker-controlled and retryable.
PR:N - Typical nfsd exports use AUTH_SYS/AUTH_NULL, so RPC uids are self-asserted and not cryptographically verified; any host allowed by the export list can SETCLIENTID, OPEN, then CLOSE/OPEN_DOWNGRADE with no local Linux account.
UI:N - The attacker issues the NFSv4 COMPOUND requests itself; no victim on the server must mount a filesystem, open a file, or take any other action.
S:U - The underflow frees an nfsd nfs4_stateowner in the NFS server kernel; impact stays in that kernel and does not cross a VM, IOMMU, or sandbox boundary.
C:H - nfs4_put_stateowner() drops an so_count the seqid path never took, freeing the stateowner while the stid and retry loop still use it; that UAF enables slab reclaim and kernel memory disclosure.
I:H - The same UAF exposes so_ops->so_unhash/so_free function pointers and list writes under cl_lock, yielding a kernel write and control-flow hijack primitive.
A:H - The UAF oopses or panics nfsd; the leaked stid sc_count also leaves move_to_close_lru() waiting forever for sc_count==2, hanging an nfsd thread, and the -EAGAIN retry can spin while RP_UNHASHED stays set.
CVSS 3.1