DF-3354 / verdict.json
{ "finding_id": "DF-3354", "status": "reproduced", "reproduced": 1, "impact": "panic", "confidence": "certain", "verdict": "config_pipe() stores ioc_pipe->bandwidth verbatim (ip_dummynet3.c:1519) with no sign check. With bandwidth<0 on a pipe carrying a WF2Q queue, the tick computation at :641 is guarded by (p->bandwidth > 0) so t stays 0; :642 then does TAILQ_LAST(&p->p_queue, dn_pkt_queue)->output_time += t. On the next dummynet tick the pipe is re-extracted with an empty delay line (delay=0 packets were already transmitted), TAILQ_LAST returns NULL and the kernel writes to NULL+0x30 (offset of output_time in struct dn_pkt). Reproduced 1/1 on the stock guest: Fatal trap 12: page fault, fault virtual address = 0x30, supervisor write data, Stopped at ready_event_wfq+0x274: addq %rdx,0x30(%rax), current process Idle. Identical code and signature to the verified v1 finding DF-3350 (sys/net/dummynet/ip_dummynet.c:1516/618-623); with delay>0 the same defect instead reinserts the pipe into wfq_ready_heap with key==curr_time forever, wedging the netisr drain loop (verified for v1; same code here).", "exploit_chain": "root: setsockopt pipe{bw=-1, delay=0} + queue{parent}; 1 UDP packet via lo0 ipfw3 `queue` rule -> WF2Q path -> ready_event_wfq -> next tick TAILQ_LAST on empty delay line -> write to NULL+0x30 -> panic. Fixed-address NULL write; crash/wedge primitive only, no uid=0.", "evidence": [ "panic.txt: Fatal trap 12, fault VA 0x30 supervisor write, ready_event_wfq+0x274 addq %rdx,0x30(%rax)", "run.log: config + single trigger packet transcript; panic ~1ms after tick", "dfv3.c: negbw subcommand" ], "kernel_refs": [ "sys/net/dummynet3/ip_dummynet3.c:1519", "sys/net/dummynet3/ip_dummynet3.c:637", "sys/net/dummynet3/ip_dummynet3.c:641", "sys/net/dummynet3/ip_dummynet3.c:642", "sys/net/dummynet3/ip_dummynet3.c:649" ], "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. Second iteration added <string.h> to dfv3.c (userland segv on the error path, kernel behavior unaffected).", "attempts": 2, "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 negbw 0", "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": "reject bandwidth<0 at config_pipe + NULL-guard the TAILQ_LAST write (fix.diff hunks 1-2)", "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). config_pipe returns EINVAL for bandwidth<0: PoC exits with config pipe: Invalid argument rc=1 instead of configuring the pipe (baseline: config accepted, then Fatal trap 12 write to NULL+0x30). 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)" ] } |