DF-3434 / verdict.json
{ "finding_id": "DF-3434", "status": "reproduced", "reproduced": 1, "impact": "dos", "confidence": "certain", "verdict": "Deterministic on the stock INVARIANTS guest. With root having installed allow udp from any to any keep-state limit src-port 100 (documented ipfw3 grammar, lib/libipfw3/basic/ipfw3_basic.c:562-574 -> cmd->arg3=2), 320 identical UDP packets from an unprivileged fixed-port socket produced 638 oops console lines (dmesg) and grew M_IPFW3_STATE inuse 46 -> 646: check_keep_state() skips the RB_FIND de-dup for arg3!=0 (ip_fw3_state.c:296-300), allocates a fresh state per packet (:319), and on the RB_INSERT duplicate (:327) only kprintf(oops) (:328) - the allocation is leaked. Two effects per packet at line rate from any traffic the rule matches: bounded-per-tree 64B kernel memory leak (capped only by the never-decremented count gate, DF-0632) and an unbounded serial-console kprintf flood (console-lock amplification). Root configures the rule; unprivileged local users or unauthenticated remote peers trigger it.", "exploit_chain": "", "evidence": [ "run.log: dmesg oops count 38 -> 638 and M_IPFW3_STATE inuse 46 -> 646 for 20+300 identical packets; ipfw3 show line 00099 with 250360 matches", "VERDICT.md: root-cause walk ip_fw3_state.c:296-330", "run.patched.log: patched kernel - same 320-packet trigger, zero oops lines, flat M_IPFW3_STATE" ], "kernel_refs": [ "sys/net/ipfw3_basic/ip_fw3_state.c:296", "sys/net/ipfw3_basic/ip_fw3_state.c:301", "sys/net/ipfw3_basic/ip_fw3_state.c:317", "sys/net/ipfw3_basic/ip_fw3_state.c:319", "sys/net/ipfw3_basic/ip_fw3_state.c:327", "lib/libipfw3/basic/ipfw3_basic.c:562" ], "poc_changes": "Setup staged through a nohup script because kldload ipfw3 engages default-deny instantly and severs the staging ssh session; trigger runs unprivileged (run_user).", "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": 240, "guest_dirty": 0, "build_cmd": "cc -O2 -o /tmp/state_oops /tmp/state_oops.c", "run_cmd": "sh /tmp/fwsetup.sh (root, pre-staged); /tmp/state_oops 320 (user)", "code_hash": "9549c224b943855accad23f985f682255c637dc304c3d03911af338e15f937e4", "notes": "Related but distinct from DF-0632 (counters never decremented): this is the allocation-side defect (leak + kprintf per packet) inside the same rule path. The count gate bounds the leak; the console flood is unbounded. O(n)-per-packet RB_FOREACH limit counting (:302-312) is an additional amplification noted during verification (drain throttled to ~2-7k pps with a populated tree).", "recommended_fix": "RB_FIND before allocating in check_keep_state(); kfree on RB_INSERT collision instead of kprintf (fix.diff).", "fix_status": "fixed", "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #1: Sat Sep 12 16:56:02 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 module on two kernels (#2 16:27:37 and #1 16:56:02): the identical trigger (320 identical UDP packets, 640 rule evaluations confirmed by ipfw3 show pcnt) produced ZERO oops console lines (baseline: 638) and M_IPFW3_STATE inuse stayed at 6-8 (the per-CPU contexts only; baseline: 646 leaked). Duplicate packets now take the RB_FIND path and refresh the timestamp; no allocation, no kprintf.", "fix_evidence": [ "run.patched.log", "fix.diff" ] } |