acctwatch() ignores VFS_STATFS failure (decides suspend/resume on uninitialized stack statfs) and races vgone(): NULL v_mount dereference panic
| Field | Value |
|---|---|
| ID | DF-2945 |
| Status | new |
| Severity | Low |
| CVSS 3.1 | CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:U/C:N/I:N/A:L |
| CWE | CWE-362 / CWE-457 / CWE-476 |
| File | sys/kern/kern_acct.c |
| Lines | 332-359 (vgone window: vfs_subr.c:1585-1603) |
| Area | kern |
| Confidence | likely |
| Discovered | 2026-09-02 |
| Pass | 2 (GLM 5.3 second pass) |
| Bucket | base:kern |
| Reported | pending |
| Known CVE | none |
| CVE match | novel |
Summary
acctwatch() calls (void)VFS_STATFS(vp->v_mount, &sb, proc0.p_ucred)
and then tests sb.f_bavail/f_blocks without checking the return value;
'struct statfs sb' is stack-local and uninitialized, so any statfs
failure (e.g. NFS accounting file with an unreachable server) drives
the suspend/resume decision from stack garbage. Additionally the
'vp->v_type == VBAD' guard does not cover the vgone() window: vclean
swaps in deadfs vops and vgone_vxlocked detaches the vnode from its
mount (v_mount=NULL) BEFORE setting v_type=VBAD; acctwatch holds
acct_lock, not the vnode VX lock, so it can observe v_mount==NULL
while v_type is still VREG and pass NULL to vfs_statfs(), which
dereferences mp->mnt_op unconditionally β kernel NULL-deref panic.
Requires privileged setup (root enabled accounting + NFS statfs
failure or umount -f racing the 15s acctwatch callout); genuine
reachable defect in the exact scenario the code comments warn about.
Not built (Low, privileged-only per contract). Fix: check statfs
return + test v_mount explicitly (or set v_type=VBAD before clearing
v_mount kernel-wide).
Timeline
- 2026-09-02 Discovered during pass-2 audit of kern_acct.c (GLM 5.3).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2945 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 597 B | β raw | |
| VERDICT.md | β | 2.0 KB | β raw | |
| env.txt | β | 401 B | view raw | |
| fix.diff | β | 1.0 KB | view raw | |
| manifest.json | β | 521 B | view raw | |
| verdict.json | β | 1.9 KB | view raw |
DF-2945 PoC evidence pack
What
acctwatch ignores VFS_STATFS failure (uninit stack decisions) and races vgone() (NULL v_mount deref).
Build
(none)
Run
(none)
Expected
static confirmation (ignored VFS_STATFS return; vgone v_mount-then-VBAD window)
Guest: DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:04 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64 All logs are full untrimmed captures unless noted. fix.diff is the git-apply-able verified fix (authored after verification; never applied to the audit tree).
DF-2945 - verification verdict
Status: not_reproduced | reproduced: 0 | impact: panic | confidence: likely
Both defects confirmed statically with exact line anchors; live trigger not honestly constructible. acctwatch (kern_acct.c:332-359) casts VFS_STATFS to void and tests stack-local sb.f_bavail/f_blocks with no return check (:340-341, :354-355) - any statfs failure (NFS accounting file, unreachable server) drives suspend/resume from uninitialized stack. The v_mount NULL window is real: vgone_vxlocked detaches the vnode from the mount (vfs_subr.c:1585-1587, insmntque(vp, NULL)) BEFORE setting v_type=VBAD (:1603), and acctwatch (holding acct_lock, not the VX lock) can pass the VBAD test and deref vp->v_mount == NULL in vfs_statfs (vfs_vfsops.c:181 derefs mp->mnt_op). Trigger needs root-enabled accounting on a force-unmountable/NFS mount racing the 15s callout - a microsecond window on a 15s cadence; not reproduced. Fix (statfs return check + explicit v_mount test) compiled.
Evidence pointers
static: kern_acct.c:340/:354 ignored returns; vfs_subr.c:1585-1603 ordering
Kernel references
- sys/kern/kern_acct.c:340
- sys/kern/kern_acct.c:354
- sys/kern/vfs_subr.c:1585
- sys/kern/vfs_vfsops.c:181
PoC changes vs the filing sketch
verification not attempted (setup disproportionate to Low); line-accurate confirmation only
Fix
recommendation: check VFS_STATFS return + test v_mount explicitly (or set VBAD before clearing v_mount)
fix status: not_testable
compile-validated in fix-all kernel
Guest: DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:04 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64
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_testablecompile-validated in fix-all kernel
Confirmed kernel references
Detail
Evidence (decisive lines)
static: kern_acct.c:340/:354 ignored returns; vfs_subr.c:1585-1603 ordering
PoC changes
verification not attempted (setup disproportionate to Low); line-accurate confirmation only
Verified recommended fix
check VFS_STATFS return + test v_mount explicitly (or set VBAD before clearing v_mount)
Verdict
Both defects confirmed statically with exact line anchors; live trigger not honestly constructible. acctwatch (kern_acct.c:332-359) casts VFS_STATFS to void and tests stack-local sb.f_bavail/f_blocks with no return check (:340-341, :354-355) - any statfs failure (NFS accounting file, unreachable server) drives suspend/resume from uninitialized stack. The v_mount NULL window is real: vgone_vxlocked detaches the vnode from the mount (vfs_subr.c:1585-1587, insmntque(vp, NULL)) BEFORE setting v_type=VBAD (:1603), and acctwatch (holding acct_lock, not the VX lock) can pass the VBAD test and deref vp->v_mount == NULL in vfs_statfs (vfs_vfsops.c:181 derefs mp->mnt_op). Trigger needs root-enabled accounting on a force-unmountable/NFS mount racing the 15s callout - a microsecond window on a 15s cadence; not reproduced. Fix (statfs return check + explicit v_mount test) compiled.
No comments yet.