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

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)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-0145 Β· 12 files
FileTypeDescriptionSize
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
VERDICT.md verdict full narrative
↓ download 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

fixed

validated

see evidence pack
↓ fix.diffDragonFly 6.5-DEVELOPMENT #1: Fri Jul 17 18:57:29 UTC 2026

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.