DragonFlyBSD Kernel Audit
DF-2780 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-2780",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "dos",
  "confidence": "certain",
  "verdict": "Per-process mqueue limit bypass proven three ways on the stock kernel: (1) control = EMFILE at exactly 512 creates; (2) the open-EXISTING path performs no limit check at all - mq_open(existing) succeeded at the EMFILE limit; (3) fork path - a child that drops the last file reference of one inherited descriptor underflows its u_int p_mqueue_cnt 0->0xffffffff (decrement runs in the last-ref closer, not the opener; fork zeroes the child counter) after which the equality check '== mq_open_max' never matches: the child created 513 queues (exit 42 = bypass). Combined with DF-2781 this enables unbounded queue/memory creation; combined with repeated fork+close rounds the per-process limit is void.",
  "exploit_chain": "open 1 queue -> fork -> parent closes its copy (fo_close NOT run; parent count leaks) -> pipe-sync -> child closes inherited copy as LAST ref -> mq_close_fop decrements child's 0 counter to 0xffffffff -> equality limit check misses -> unlimited creates until fd limit; independently, opening existing queues bypasses the check without any fork.",
  "evidence": ["run.log: control 512/EMFILE, '[existing] ... SUCCEEDED', '[fork-child] created 513 queues ... exit=42 => BYPASS REPRODUCED'", "fix_validation.log: patched - existing path EMFILE, fork-child exactly 512, exit=1"],
  "kernel_refs": ["sys/kern/sys_mqueue.c:384", "sys/kern/sys_mqueue.c:452", "sys/kern/sys_mqueue.c:577", "sys/kern/sys_mqueue.c:592", "sys/kern/sys_mqueue.c:531-563", "sys/sys/proc.h:235", "sys/kern/kern_fork.c:444", "sys/kern/kern_fork.c:551"],
  "poc_changes": "Pipe-synchronized close ordering so the child's close is the last reference (first version closed in the wrong order and did not underflow); control-loop fds closed/unlinked between stages; raw syscalls.",
  "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": 30,
  "guest_dirty": 0,
  "build_cmd": "cc -O2 -o fork_cnt fork_cnt.c",
  "run_cmd": "./fork_cnt",
  "code_hash": "0f43b7b5cc64ef282fcffb1affd245fe5c369c37458883d79f9a8d846dc4efc8",
  "notes": "The opener-side counter leak (parent stuck at 1 with no fds) is the mirror bug - premature EMFILE - noted in the finding.",
  "recommended_fix": "Inherit p_mqueue_cnt across fork (count DTYPE_MQUEUE fds after fdcopy), use >= instead of ==, and enforce the limit on the open-existing path (fix.diff).",
  "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": "Patched kernel: existing-path open now returns EMFILE at the limit; fork child creates exactly 512 (no underflow effect) and exits 1 ('bypass not observed').",
  "fix_evidence": "fix_validation.log"
}