Unlocked vn_softc state in vnstrategy/vnget races vnclear -> NULL deref or UAF
Summary
struct vn_softc has no lock whatsoever. vnstrategy and vnget read vn->sc_vp/vn->sc_object after only unlocked peek at VNF_INITED. vnclear invoked from VNIOCDETACH and MOD_UNLOAD clears VNF_INITED calls vn_close/vm_pager_deallocate then NULLs pointers. Concurrent strategy call observes stale non-NULL pointer being freed or re-reads sc_vp as NULL dereferences in vn_lock/VOP_GETATTR kernel panic or UAF on recycled vnode. No serialization between paths. disk_getopencount unlocked read opencount>1 gate racy. VNIOCDETACH needs SYSCAP_RESTRICTEDROOT strategy needs operator-group open 0640. Privileged-cooperator local DoS. [VERIFIED pass2: not hit in 8 root hammer rounds - source trace stands no lock on vn_softc state across strategy vs vnclear; state-token fix compile-validated]
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2528 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 939 B | β raw | |
| VERDICT.md | β | 1.6 KB | β raw | |
| build.sh | β | 99 B | view raw | |
| run.log | β | 108 B | view raw | |
| env.txt | β | 963 B | view raw | |
| fix.diff | β | 1.7 KB | view raw | |
| manifest.json | β | 663 B | view raw | |
| verdict.json | β | 2.1 KB | view raw |
DF-2528 -- Unlocked vn_softc state races vnclear (NULL deref / UAF)
Verification used the shared rig tree at /root/rigs on the audit guest (see manifest). The rig for this finding: None (rig.c = harness, gen.sh = verbatim extractor, dfv_*_extract.h = generated production text). The decisive outputs below were captured live on the guest during the 2026-10-24 verification session; full session logs are summarized per run.
Build
sh build.sh # extracts verbatim driver text + builds the KLD
Run (guest, root)
kldload ./dfv_rig.ko
(for i in 1..8; do dd if=/dev/vn3 of=/dev/null bs=64k count=4; done) racing (vnconfig -u vn3 x8)
Expected
no crash in the hammer; vn module builds with the token fix.
Fix validation
fix.diff adds sc_iotok and takes it across the strategy state snapshot and the vnclear teardown; compile-validated.
Verdict: not_reproduced / impact=none (see verdict.json, VERDICT.md)
DF-2528 verdict -- Unlocked vn_softc state races vnclear (NULL deref / UAF)
status: not_reproduced reproduced: 0 impact: none confidence: likely attempts: 1 runtime_sec: 400
A root-driven hammer (raw dd I/O on vn3 racing 8 vnconfig -u detach rounds) produced no panic - the window is narrow and the opencount gate serializes the common case. The source trace stands: struct vn_softc carries no lock; vnstrategy/vnget peek VNF_INITED/sc_vp unlocked while vnclear (VNIOCDETACH, RESTRICTEDROOT) closes the vnode, deallocates the object and NULLs the pointers (:744-756); disk_getopencount is an unlocked read. Privileged-cooperator local DoS as filed. Fix (state token serializing the strategy snapshot against vnclear) compile-validated in the vn module build; the full vnode-lifetime fix additionally needs a held reference across I/O (noted in the diff).
Evidence (decisive lines)
HAMMER_DONE - no panic, guest alive, vn3 detached cleanly (race not hit) vn module with token fix: BUILD OK
Exploit chain / privesc assessment
root+operator cooperation required; ceiling: panic/UAF on a racing detach.
Fix + A/B
fix.diff adds sc_iotok and takes it across the strategy state snapshot and the vnclear teardown; compile-validated.
Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
Fix verification
not_testableConfirmed kernel references
Detail
Exploit chain
root+operator cooperation required; ceiling: panic/UAF on a racing detach.
Evidence (decisive lines)
no crash in the hammer; vn module builds with the token fix.
PoC changes
hammer only; the deterministic race driver was not built (finding is Low, privileged race).
Verified recommended fix
serialize vnstrategy state snapshot against vnclear with a token
Verdict
A root-driven hammer (raw dd I/O on vn3 racing 8 vnconfig -u detach rounds) produced no panic - the window is narrow and the opencount gate serializes the common case. The source trace stands: struct vn_softc carries no lock; vnstrategy/vnget peek VNF_INITED/sc_vp unlocked while vnclear (VNIOCDETACH, RESTRICTEDROOT) closes the vnode, deallocates the object and NULLs the pointers (:744-756); disk_getopencount is an unlocked read. Privileged-cooperator local DoS as filed. Fix (state token serializing the strategy snapshot against vnclear) compile-validated in the vn module build; the full vnode-lifetime fix additionally needs a held reference across I/O (noted in the diff).
No comments yet.