DF-3276 / verdict.json
{ "finding_id": "DF-3276", "status": "reproduced", "reproduced": 1, "impact": "panic", "confidence": "certain", "verdict": "Deterministic kernel NULL-deref panic: bridge_span() hands mirrored packets to bridge_enqueue(), whose handler dereferences dst_ifp->if_bridge -- always NULL for span ports (only member add sets it, if_bridge.c:1300; bridge_delete_span KASSERTs the invariant, if_bridge.c:1152). Reproduced on the first attempt on the stock guest: with a span port configured, the bridges own IPv6 DAD output via bridge_output()->bridge_span() panicked the box before any injected frame (Fatal trap 12, fault virtual address 0x3b8, Stopped at bridge_handoff+0x11: movq 0x3b8(%rdi),%rax with rdi==NULL; 0x3b8 == offsetof(bridge_softc, sc_ifp)). Any frame through a span-configured bridge triggers it. Tree is byte-identical to DragonFlyBSD master (live upstream bug). Fix (mirror via bridge_handoff(sc,dst_if,mc,0) + NULL guard in bridge_enqueue_handler) validated on a rebuilt kernel: same PoC injects 8 frames, guest stays up.", "exploit_chain": "", "evidence": [ "panic.txt: Stopped at bridge_handoff+0x11: movq 0x3b8(%rdi),%rax with %rdi=NULL, faulting address 0x3b8 (offsetof sc_ifp)", "run.log: baseline ssh transcript ending in the panic", "run_fixed.log: patched kernel, 8 frames injected, still alive -- no panic observed, guest up", "fix.diff: bridge_span direct handoff + enqueue-handler NULL guard" ], "kernel_refs": [ "sys/net/bridge/if_bridge.c:3279", "sys/net/bridge/if_bridge.c:4430", "sys/net/bridge/if_bridge.c:4440", "sys/net/bridge/if_bridge.c:1300", "sys/net/bridge/if_bridge.c:1152" ], "poc_changes": "Seed PoC (none existed for this fresh pass-2 finding) written from scratch: bridge/tap setup via ifconfig + BRDGADDS via raw SIOCSDRVSPEC (ifconfig has no spanport subcommand); frame type ETHERTYPE_ARP so ip_lengthcheck does not drop the frame pre-bridge.", "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": 20, "guest_dirty": 0, "build_cmd": "cc -O -Wall -o span_panic span_panic.c", "run_cmd": "sh run.sh (root, guest console; panics the box)", "code_hash": "94aff1267361c5585f4460bb1c1ee8e70d6c35661b13e7ba3d8910090bfaee08", "notes": "Trigger observed in the captured run was the bridge interfaces own IPv6 DAD output (bridge_output path, if_bridge.c:2241/2358) -- i.e. once a span port exists, ANY packet, local or forwarded, panics the kernel. Secondary vector folded into the same fix: member deletion between enqueue and handler also yields if_bridge==NULL at the same sink (cleared at if_bridge.c:1071 before netmsg_service_sync).", "recommended_fix": "bridge_span: mirror via bridge_handoff(sc, dst_if, mc, 0) instead of bridge_enqueue(span_ifp); add NULL guard in bridge_enqueue_handler", "fix_status": "fixed", "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #1: Thu Sep 10 00:48:01 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "Rebuilt kernel with fix_all.diff (patch -p1, make -j6 nativekernel, make installkernel, reboot). Identical PoC: 8 frames injected through the span-configured bridge, no panic, guest remains up and responsive (run_fixed.log). Baseline panic signature gone.", "fix_evidence": "findings/poc/DF-3276/run_fixed.log; findings/poc/DF-3276/fix.diff; combined /root/build.log BUILD_DONE on guest" } |