β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-2844

vnode_pager_haspage() divides by mnt_stat.f_iosize without a zero guard (autofs leaves f_iosize=0)

Field Value
ID DF-2844
Status new
Severity Info
CVSS 3.1 CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:H
CWE CWE-369 Divide By Zero
File sys/vm/vnode_pager.c
Lines 259-260
Area vm
Confidence speculative
Discovered 2026-08-31
Pass 2 (GLM 5.3 second pass)
Bucket base:vm
Reported pending
Known CVE none
CVE match novel

Summary

vnode_pager_haspage() computes loffset % f_iosize with no validation. All FSes that give vnodes VM objects initialize it positively at mount, but autofs leaves mnt_stat.f_iosize == 0 (autofs_vfsops.c:285) and is currently unreachable only because autofs vnodes never acquire a VM object β€” one future vinitvmio() away from a kernel div-by-zero panic. Defense-in-depth: guard (if (bsize <= 0) return TRUE;) and give autofs a real f_iosize.

Timeline

  • 2026-08-31 Discovered during pass-2 audit of vnode_pager.c (GLM 5.3).

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2844 Β· 2 files
FileTypeDescriptionSize
README.md β€” 1.8 KB ↓ raw
verdict.json β€” 1.2 KB view raw

DF-2844 β€” vnode_pager_haspage() divides by mount f_iosize without a zero check

Bug: sys/vm/vnode_pager.c:259-260 Class: hardening (divide-by-zero landmine) Severity: Info Confidence: speculative (reachability currently blocked) Phase V: not run (Info).

259:    bsize = vp->v_mount->mnt_stat.f_iosize;
260:    voff = loffset % bsize;

vnode_pager_haspage() computes loffset % bsize from the mount's f_iosize with no validation. Every other f_iosize consumer in the tree (uipc_syscalls.c:1821, vfs_vnops.c:1238, vfs_bio.c:2504, ufs_bmap.c:142, msdosfs_vnops.c:1812, ...) makes the same assumption.

Current reachability analysis (why Info, not a finding with severity): * mount-time initialization is via VFS_STATFS(mp, &mp->mnt_stat, cred) for every filesystem that gives vnodes VM objects β€” all of which set a constant/validated f_iosize (ffs: fs->fs_bsize validated at mount; hammer2: HAMMER2_PBUFSIZE; tmpfs: PAGE_SIZE; nfs: nfs_iosize() clamps to >= PAGE_SIZE at nfs_vfsops.c:nfs_iosize). * autofs does leave f_iosize == 0 (autofs_vfsops.c:285 sets it in statfs, called at mount via :185), but autofs vnodes never acquire a VM object (no vinitvmio callers), mmap/exec cannot reach them, so vnode_pager_haspage() cannot run against an autofs mount today. It is exactly one future vinitvmio() call away from a divide-by-zero panic in kernel mode (local DoS at best).

259:    bsize = vp->v_mount->mnt_stat.f_iosize;
+   if (bsize <= 0)
+       return TRUE;    /* let the pager I/O path decide */
260:    voff = loffset % bsize;

(and, better, fix autofs to report a real f_iosize).

Fix verification

not_testable
per-fix-DF-2844

Confirmed kernel references

Detail

Evidence (decisive lines)

['README.md: analysis + fix']

Verified recommended fix

guard bsize<=0 in vnode_pager_haspage (return TRUE, defer to I/O path) and give autofs a real f_iosize

Verdict

vnode_pager_haspage() (sys/vm/vnode_pager.c:260) computes loffset % f_iosize with no zero guard. All filesystems that hand vnodes VM objects initialize f_iosize to a positive constant at mount, so the division is currently safe; however autofs leaves mnt_stat.f_iosize == 0 (autofs_vfsops.c:285 via mount-time VFS_STATFS at :185) and is only unreachable because autofs vnodes never get VM objects. One future vinitvmio() in autofs turns this into a kernel divide-by-zero panic. Filed as Info hardening.