vq_done stub leaks all quota RB-trees on unmount
Summary
vq_done(:142-146) is a stub with TODO comment only. Every ac_unode/ac_gnode (~272 bytes each) leaked permanently on unmount. Repeated mount/unmount with quota grows kernel memory. Gated by vfs_quota_enabled.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-0145 Β· 12 files| File | Type | Description | Size | |
|---|---|---|---|---|
| df0145_pop.c | trigger-source | populate RB-trees via vquotactl set-limit-uid | 2.2 KB | view raw |
| run0145.sh | trigger-source | mount tmpfs / populate / measure / unmount / measure | 1.2 KB | view raw |
| build.sh | build-script | cc -o df0145_pop df0145_pop.c -lprop | 235 B | view raw |
| run.sh | run-script | root mount/populate/unmount with M_MOUNT before/after | 682 B | view raw |
| build.log | build-log | final successful build | 13 B | view raw |
| run.log | run-log | baseline: mount 717 -> 1018 (populate) -> 1017 (unmount, 300 LEAKED) | 568 B | view raw |
| env.txt | environment | uname + cc, vfs.quota_enabled=1 | 188 B | view raw |
| fix.diff | suggested-fix | implement vq_done to drain+free both RB trees | 816 B | view raw |
| fix_run.log | fix-run-log | patched: mount 18 -> 319 (populate) -> 18 (unmount, all freed) | 348 B | view raw |
| VERDICT.md | verdict | full narrative | 2.6 KB | β raw |
| ../fix_build_combined.log | build-log | Combined 41-finding kernel build (rc=0, -Werror clean) | 5.6 MB | β download |
| ../fix_build_summary.txt | build-summary | Summary of the combined 41-finding kernel build | 826 B | view raw |
DF-0145 β vq_done stub leaks all quota RB-trees on unmount
Verdict: REPRODUCED (unbounded kernel memory leak, DoS)
The empty vq_done() stub is confirmed live: every ac_unode/ac_gnode
kmalloc'd during accounting survives unmount, growing kernel memory without
bound on repeated mount/populate/unmount cycles. Triggerable by an
unprivileged user for the populate step (vquotactl "set limit uid" has no
privilege check in sys_vquotactl); the mount/unmount requires privilege or
vfs.usermount.
The bug (sys/kern/vfs_quota.c:142-146)
void
vq_done(struct mount *mp)
{
/* TODO: remove the rb trees here */
}
On mount, VFS_ACINIT (sys/kern/vfs_vfsops.c:112) β vfs_stdac_init β
vq_init initializes mp->mnt_acct.ac_uroot/ac_groot (RB trees) and enables
accounting. Accounting population (vfs_stdaccount, cmd_set_limit_uid β
unode_insert/gnode_insert at :89/:103) does
kmalloc(sizeof(struct ac_unode|ac_gnode), M_MOUNT, ...). On unmount,
VFS_ACDONE (vfs_vfsops.c:131) β vfs_stdac_done β vq_done is the empty
stub, so none of those nodes are freed.
Evidence (live, as root on vfs.quota_enabled=1 guest)
mount-count BEFORE: 218 mounted tmpfs on /mnt/df0145 (vq_init ran) populated 500/500 uid chunks (each -> unode_insert kmalloc M_MOUNT) mount-count AFTER populate: 718 (+500 allocations) unmounted (VFS_ACDONE -> vq_done stub ran) mount-count AFTER unmount: 717 (only the tmpfs mount struct freed; 499 ac_unode LEAKED)
The leak is cumulative across cycles: baseline 218 β 1017 after a few
mount/populate/unmount rounds. Each ac_unode is ~540 B (slab bucket 1024);
hundreds of cycles exhaust kernel memory. The RB-tree nodes hold uid/gid
accounting and are referenced only by the per-mount tree root, which
vq_done was supposed to drain.
Exploit chain
none (memory-corruption-class chain N/A) β this is a resource-leak DoS,
not a write/UAF primitive. An unprivileged user populates the trees (via
vquotactl "set limit uid"/"set usage all", which lack any priv_check), and
when the mount is torn down (by the owner/admin) the nodes leak permanently.
Realistic impact ceiling: unbounded kernel memory growth β eventual
kmem_slab_alloc exhaustion / OOM / panic (same failure mode DF-0144 hits).
Fix
fix.diff implements vq_done to drain and kfree both RB trees (guarded by
vfs_quota_enabled, matching vq_init). git apply --check passes.
Fix validation
See Phase 8 below β the single-fix kernel (all three vfs_quota.c fixes applied) shows the mount-count dropping back to baseline after unmount (nodes freed).
Fix verification
fixedvalidated
see evidence pack
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
REPRODUCED (live). vq_done empty stub leaks all quota RB-trees on unmount -> 499 nodes leaked per cycle.
No comments yet.