{
  "finding_id": "DF-2781",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "dos",
  "confidence": "certain",
  "verdict": "Unprivileged persistent kernel-memory exhaustion proven: 12 queues x 512 msgs x 16 KB = 96.4 MB remained allocated (vmstat -m: mqueues 97.5M) after the strander exited - queues and messages survive last close unless unlinked (sys_mqueue.c:391-399) and cannot be enumerated; sustained stranding drove the kernel to ENOMEM on mq_send/mq_open (M_WAITOK kmalloc failing) at ~390 MB on the 4 GB guest with 2.48 GB user memory still free, and retry loops made zero further progress - the ceiling is kernel-heap-side and the consumption is permanent until reboot. No system-wide or per-user queue/byte accounting exists (only per-process open count and per-queue geometry, sys_mqueue.c:71-76); Linux ships RLIMIT_MSGQUEUE + fs.mqueue.* for exactly this attack class.",
  "exploit_chain": "loop: mq_open(unique, {maxmsg=512, msgsize=16352}) -> send 512 x 16 KB messages (8.4 MB/queue) -> close (queue+messages persist) -> exit strander -> kernel retains everything; repeat with new names until kmalloc ENOMEM; no reclamation path without the (withheld) names.",
  "evidence": ["run.log: 96.4 MB stranded then 'mqueues 7.54K 97.5M' AFTER process exit", "run.exhaust.log: 'mq_send #280: Cannot allocate memory' + 'mq_open: Cannot allocate memory' at ~390 MB; zero progress across 2.5 min of retries", "fix_validation.log: with kern.mqueue.mq_max_queues=8 the strander stops after exactly 8 queues / 64.2 MB"],
  "kernel_refs": ["sys/kern/sys_mqueue.c:71-76", "sys/kern/sys_mqueue.c:391-399", "sys/kern/sys_mqueue.c:582-589"],
  "poc_changes": "msgsize lowered 16384->16352 (the send-path cap includes the 32-byte mq_msg header, so attr-accepted 16384 always EMSGSIZEs on send); brief/exhaust modes; byte accounting includes header+slack.",
  "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",
  "runtime_sec": 900,
  "guest_dirty": 0,
  "build_cmd": "cc -O2 -o strand strand.c",
  "run_cmd": "./strand brief; vmstat -m | grep -i mqueues; ./strand exhaust 100000",
  "code_hash": "9d0d97f87d09b0290da943736fd9b5569c74cadb22c75b5a0d0414b0addcc980",
  "notes": "Guest survived with basic ops working at the 390 MB ceiling (subsystem-dead degradation rather than full wedge on this box); the mechanism, permanence and ENOMEM are the demonstrated facts. Side observation: attr validation accepts mq_msgsize=16384 but mq_send1 rejects sending that size (header included in the cap) - cosmetic inconsistency, not filed.",
  "recommended_fix": "Add system-wide (and ideally per-uid) queue-count and queued-byte caps as sysctls (kern.mqueue.mq_max_queues in fix.diff, default 256); upstream should also consider an enumeration/cleanup interface.",
  "fix_status": "fixed",
  "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #1: Tue Sep  1 04:57:57 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "With kern.mqueue.mq_max_queues=8, strand exhaust stops after exactly 8 queues / 64.2 MB (mq_open ENOMEM at #9) and a second strander cannot create one queue; sysctl restored to 256. First fix iteration (cap check before lock acquisition, goto exit with mq==NULL) panicked the kernel - rejected, corrected placement; that incident surfaced DF-2782.",
  "fix_evidence": "fix_validation.log; fixiter1 analysis in VERDICT.md"
}
