DragonFlyBSD Kernel Audit
DF-2829 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-2829",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "leak",
  "confidence": "certain",
  "verdict": "zinit() kmallocs struct vm_zone without M_ZERO (vm_zone.c:453) and zinitna() never initializes z->znalloc (vm_zone.c:347-436; the field is only incremented at :773/:786). The world-readable sysctl vm.zone prints it (:848,:854-858) - verified readable as nobody. On the stock INVARIANTS guest, a heap-groomed KLD harness produced REQUESTS=4702111234474983745 (0x4141414141414141) for a zero-activity zone: the groomed 8-byte heap marker crossed verbatim to unprivileged userspace on the first attempt. Stock exposure: SWAPMETA (swap_pager.c:441, every kernel) and the netbt pools (bt_proto.c:139-149, device bluetooth); on a fresh boot the stale qword read 0 (early-boot fresh pages), so the realistic yield is boot-time heap residue; the structural uninitialized read is default-config present. Fixed by znalloc init + M_ZERO + bzero-before-zlist-insert: patched kernel #1 prints REQUESTS 00000000 for the identical run.",
  "exploit_chain": "unpriv user -> sysctl vm.zone -> REQUESTS column of zinit()-created zones = 8 bytes of stale kernel heap (decimal) per zone, incl. the transient pre-bzero zpcpu window; read primitive only, no escalation",
  "evidence": "run.log: 'leakmark_zon 000064, 00000000, 000000, 000000, 4702111234474983745' (=0x4141414141414141) from 'su -m nobody -c sysctl vm.zone'; fix_validation.log: same run on kernel #1 gives REQUESTS 00000000; dmesg line 'zone=0xfffff80118628000 sizeof(struct vm_zone)=16640'",
  "kernel_refs": ["sys/vm/vm_zone.c:453", "sys/vm/vm_zone.c:347-363", "sys/vm/vm_zone.c:773", "sys/vm/vm_zone.c:786", "sys/vm/vm_zone.c:848", "sys/vm/vm_zone.c:854-858", "sys/vm/swap_pager.c:441", "sys/netbt/bt_proto.c:139-149"],
  "poc_changes": "self-authored harness (no seed); groom = 16x kmalloc(sizeof(struct vm_zone)) memset 0x41 then kfree, immediately followed by zinit so the freed block is reused; verified nobody can read vm.zone via 'su -m nobody -c sysctl vm.zone'",
  "attempts": 1,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 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": 1140,
  "guest_dirty": 0,
  "build_cmd": "cd /root/df2829 && make (KLD: cc -O2 -D_KERNEL ... -c df2829_harness.c; cc -Wl,... -r -o df2829.ko)",
  "run_cmd": "kldload /root/df2829/df2829.ko && su -m nobody -c 'sysctl vm.zone' | grep leakmark",
  "code_hash": "fb5bfa58a5dc91d707e7f81f245dbbbfe6bdc2de65eb36e6e707dd8cbea094b5",
  "notes": "Same unprivileged reader surface as DF-0951 (sysctl_vm_zone). Secondary init-window issue folded in: LIST_INSERT (vm_zone.c:359) precedes bzero(z->zpcpu) (vm_zone.c:362). Stock SWAPMETA row read 00000001 at fresh boot (stale qword was 0).",
  "recommended_fix": "Initialize z->znalloc=0 in zinitna's init block, allocate the zone with M_ZERO in zinit(), and bzero(z->zpcpu) before LIST_INSERT_HEAD onto zlist (see fix.diff)",
  "fix_status": "fixed",
  "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #1: Tue Sep  1 20:57:06 UTC 2026  root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC  x86_64",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "Applied fix.diff to guest /usr/src/sys/vm/vm_zone.c, make nativekernel KERNCONF=X86_64_GENERIC (vm_zone.o rebuilt, kernel relinked), installkernel + reboot into #1. Identical PoC rerun (same groom/module): leakmark REQUESTS=00000000 - marker leak eliminated; no regressions in other rows.",
  "fix_evidence": "findings/poc/DF-2829/fix_validation.log (patched run), fix.diff, compare run.log (baseline 4702111234474983745)"
}