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)
PoC verification
Evidence pack
findings/poc/DF-2844 Β· 2 files| File | Type | Description | Size | |
|---|---|---|---|---|
| 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).
Recommended fix (defense in depth)
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_testableConfirmed 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.
No comments yet.