⬢ DragonFlyBSD Kernel Audit
DF-5683 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-5683",
  "status": "reproduced",
  "reproduced": true,
  "impact": "leak",
  "confidence": "certain",
  "verdict": "REPRODUCED: sys_vquotactl(2) leaks the copyind prop_dictionary, the allocated command string, the pa_out array and the output dictionary on EVERY call (plus nlookup state on error paths). Unprivileged uid 1001, vfs.quota_enabled=1 boot tunable. Measured linear leak ~1.6-1.9KB kernel heap per syscall across 6 prop malloc types (2000 calls -> +9,770 live objects / +1.9MB, InUse never drops); vm.kmem_size 390MB exhausts after ~250k calls (minutes). fix.diff (prop_object_release on all exits + get_cstring_nocopy + nlookup_done) validated on a rebuilt kernel: 2000 calls -> +2 objects total. Distinct from DF-2231 (which covers the unbounded pref_len/copyin-size defect in prop_kern.c itself).",
  "exploit_chain": "",
  "evidence": "run.log (t0/t1/t2 vmstat -m triples: propdict 178->3100->6030, proparay 9->1009->1960), run.patched.log (flat after fix), fix_build.log (kernel #1 build), VERDICT.md",
  "kernel_refs": [
    "sys/kern/vfs_quota.c:346",
    "sys/kern/vfs_quota.c:351",
    "sys/kern/vfs_quota.c:362",
    "sys/kern/vfs_quota.c:374",
    "sys/kern/vfs_quota.c:405",
    "sys/libprop/prop_kern.c:454",
    "sys/libprop/prop_dictionary_util.c:185"
  ],
  "poc_changes": "Original lead referenced vfs_quota.c:404 reassigns dict; confirmed the leak is broader (cmd copy at :362, pa_out at :374, output dict at :405, nlookup state at :351-356). vq_leak.sh shell variant via /sbin/vquota was too slow (fork/exec per call) and the guest vquota CLI differs from the tree (show/limit/ulim, not get usage all) \u2014 replaced with the in-process syscall driver vq_leak_loop.c.",
  "attempts": 3,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul  2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64 (baseline) / #1: Sat Oct 10 00:36:54 UTC 2026 (patched)",
  "runtime_sec": 780,
  "guest_dirty": 0,
  "build_cmd": "cc -O2 -o vq_leak_loop vq_leak_loop.c",
  "run_cmd": "./vq_leak_loop / 1000 ; vmstat -m | grep -i prop ; ./vq_leak_loop / 1000 ; vmstat -m | grep -i prop",
  "code_hash": "0a55198cb3a9134ff7115f4528a8501fdb2060178d76450462c369cbd404b8b2",
  "notes": "Guest reset (vm.sh reset with-src) performed after the run; evidence captured on baseline kernel #0 and patched kernel #1.",
  "recommended_fix": "Release dict/pa_out/odict on every exit path, use prop_dictionary_get_cstring_nocopy for cmd, nlookup_done on error paths",
  "fix_status": "fixed",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "Rebuilt kernel with fix_combined.diff (leak fixes + priv gate + copyin error check): 2000 root-driven calls leak +2 objects total vs +9,770 on baseline; unprivileged callers are EPERM-gated before allocation. Leak eliminated, no functional regression for privileged vquota use.",
  "fix_evidence": "run.patched.log (proparay 1->2, propdict 150->152 over 2000 calls), fix_build.log",
  "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #1: Sat Oct 10 00:36:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64"
}