nfs_lookup/nfs_mkdir error paths vrele() vnodes that nfs_nget returned LK_EXCLUSIVE-locked β permanent vnode-lock leak, mount wedge / vnode exhaustion DoS from malformed server replies
| Field | Value |
|---|---|
| ID | DF-2997 |
| Status | new |
| Severity | Medium |
| CVSS 3.1 | CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:H |
| CWE | CWE-667 |
| File | sys/vfs/nfs/nfs_vnops.c |
| Lines | 1270-1274, 2346-2361 (contrast: :1088, :1228) |
| Area | vfs/nfs |
| Confidence | certain |
| Discovered | 2026-09-02 |
| Pass | 2 (GLM 5.3 second pass) |
| Bucket | base:vfs |
| Reported | pending |
| Known CVE | none |
| CVE match | novel |
Summary
nfs_nget returns vnodes locked LK_EXCLUSIVE (nfs_node.c:129 vget, :216 vx_downgrade). nfs_lookup's error exit and the ERROROUT post-op-attr paths reached with a successfully nget'd newvp, plus nfs_mkdir's 'EEXIST || !gotvp' vrele and its error tail, drop those vnodes with vrele() instead of vput() β the exclusive lock is never released, so the vnode can never be locked or recycled again. nfs_nresolve (the new-API equivalent) does it correctly with vput(), proving the inconsistency. Trigger: a malicious server that returns a valid file handle in a LOOKUP/MKDIR reply followed by malformed post-op attributes (nfsm_dissect NULL β EBADRPC) β each occurrence permanently wedges one vnode; repetition exhausts the vnode pool and stalls all operations touching the affected vnodes (including unkillable processes on the mount). Unpriv local user on a client whose NFS server is malicious/compromised (or an active spoofer). Not verified this run (budget spent on DF-2996); code-reading certain. Fix: vput() on nfs_nget-sourced vnodes (vrele remains correct for the dvp-echo vref'd case).
Timeline
- 2026-09-02 Discovered during pass-2 audit of nfs_vnops.c (GLM 5.3).
No comments yet.