DF-3352 / verdict.json
{ "finding_id": "DF-3352", "status": "reproduced", "reproduced": 1, "impact": "panic", "confidence": "certain", "verdict": "config_pipe() clamps flowset weight only against 0 and >100 (ip_dummynet3.c:1547-1551); a negative weight (e.g. -1) is stored verbatim in the flowset. dummynet_io() then does pipe->sum += fs->weight (:1150), so one flow on a weight=+1 flowset and one flow on a weight=-1 flowset of the same pipe drive pipe->sum to exactly 0 while a packet of the second flow sits in scheduler_heap. When the WF2Q credit timer fires, ready_event_wfq() moves that packet and executes p->V += (len << MY_M) / p->sum (:574) with sum==0 -> integer divide fault. Reproduced 1/1 on the stock INVARIANTS guest: Fatal trap 18 integer divide fault, Stopped at ready_event_wfq+0xd1: divq %rcx,%eax, current process Idle (netisr drain on cpu0), CPU0 stopped. Deterministic, ~12ms after the second trigger packet. Root-configured (raw-socket setsockopt IP_DUMMYNET_CONFIGURE behind SYSCAP_NONET_RAW), so local privileged DoS; same validation gap also lets sum go negative (V stalls, WF2Q eligibility corrupted). v1 twin file has the identical bug; it was missed by both pass-1 audits.", "exploit_chain": "root: setsockopt pipe{bw=1Mbit} + fs{w=+1} + fs{w=-1} on one pipe; 2 UDP packets via lo0 ipfw3 `queue` rules (different dst-ports -> different flowsets/flows); first flow sum=1, second flow sum=0; next wfq_ready_heap fire -> divq by zero -> kernel panic. No uid=0: divide-fault crash primitive only.", "evidence": [ "panic.txt: Fatal trap 18 integer divide fault, Stopped at ready_event_wfq+0xd1 divq %rcx,%eax", "run.log: full setup+trigger transcript (panic ~12ms after 2nd packet)", "dfv3.c: negweight subcommand (raw setsockopt structs verbatim from ip_dummynet3.h)" ], "kernel_refs": [ "sys/net/dummynet3/ip_dummynet3.c:1547", "sys/net/dummynet3/ip_dummynet3.c:1150", "sys/net/dummynet3/ip_dummynet3.c:574", "sys/net/dummynet3/ip_dummynet3.c:1182" ], "poc_changes": "PoC authored fresh (multi-trigger dfv3.c): raw setsockopt with ABI structs verbatim from ip_dummynet3.h; ipfw3 (not ipfw) `queue <fs> udp ... via lo0` rules divert lo0 UDP into the WF2Q path; setup.sh sets net.filters_default_to_accept=1 before kldload ipfw3 because ipfw3 defaults to deny-all and otherwise locks out ssh.", "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": 60, "guest_dirty": 0, "build_cmd": "in-guest root: cc -O -o /tmp/dfv3 /tmp/dfv3.c", "run_cmd": "in-guest root: sh /tmp/setup.sh && /tmp/dfv3 negweight", "code_hash": "9f8b5ab161a2890df06ccaf75ed7ddbbb746efb2f2320c50d209317fe5b42c09", "notes": "dummynet3.ko + ipfw3.ko + ipfw3_basic.ko kldloaded; triggers are UDP to 127.0.0.1 matched by ipfw3 queue rules. Panic findings verified once each on the stock INVARIANTS kernel; DF-3356 verified with control run. v1 twin (sys/net/dummynet/ip_dummynet.c) carries the same code.", "recommended_fix": "clamp weight <=0 to 1 at flowset creation (fix.diff hunk 3)", "fix_status": "fixed", "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #1: Fri Sep 11 07:37:10 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64 (dummynet3 fix.diff applied, rebuilt via make nativekernel)", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "Union fix.diff (all five DF-3352..DF-3356 hunks; this findings hunk is the one noted in recommended_fix) applied to the guest /usr/src, kernel rebuilt with make -j6 nativekernel KERNCONF=X86_64_GENERIC and installed (>>> Kernel build completed 07:41:12, install completed 07:42:30 UTC). weight<=0 clamped to 1 at flowset creation: negweight trigger survives 8s with no divide fault (baseline panicked within ~12ms); same config doubles as positive control showing WF2Q still passes traffic. All other four PoCs re-run on the same patched kernel: all clean.", "fix_evidence": [ "run.2.log (patched-kernel validation transcript)", "fix.diff (git-apply-able unified diff, 6 hunks vs sys/net/dummynet3/ip_dummynet3.c)" ] } |