DF-4940 / verdict.json
{ "finding_id": "DF-4940", "status": "reproduced", "reproduced": 1, "impact": "dos", "confidence": "certain", "verdict": "REPRODUCED: icoutput() unconditionally sets IFF_RUNNING (if_ic.c:347), so a single packet routed to a DOWN (or never-properly-up) ic0 \u2014 ip_output has no IFF_UP gate (ip_output.c:698,742) and if_down deletes no routes \u2014 flips the interface to RUNNING without iicbus_request_bus() and without buffer allocation. Demonstrated on the guest: flags 808810 -> 808850 (RUNNING while DOWN) after one ping, Opkts=1 (transmit over un-owned bus), and the following SIOCSIFFLAGS up allocated nothing (devbuf 819->819) while a control cycle allocated 2 (819->821). This permanently skips the up branch (if_ic.c:188) and thereby sustains the DF-2001 NULL-deref state; also causes un-owned bus transmissions and spurious iicbus release (parent callback fires before ownership check, iiconf.c:131-140). Fix (gate icoutput on UP|RUNNING + non-NULL buffers, drop the forced flag) validated: patched module returns ENETDOWN, no phantom RUNNING, proper up transition restored.", "exploit_chain": "admin brings ic0 up with address (or half-configures it: SIOCSIFADDR/SIOCSIFFLAGS wrapper leaves IFF_UP set even when the drivers bus request fails, if.c:2159-2171, if_ic.c:176) -> any unprivileged user sends a packet routed via ic0 while it is DOWN -> icoutput sets IFF_RUNNING -> every future ifconfig ic0 up skips allocation+bus acquisition -> on a never-allocated interface ic_obuf/ic_ifbuf stay NULL and every subsequent packet hits the bcopy NULL deref at if_ic.c:358 (sink owned by DF-2001) -> kernel panic (local DoS); additionally each such TX corrupts any in-flight transfer of the actual iicbus owner.", "evidence": "run.log B.step3: flags 808850 (RUNNING) on a down interface after ping (Opkts=1); B.step5: up allocates nothing (devbuf 819->819) vs control 819->821 (+2); FIX section: sendto: Network is down, flags stay 808810, proper 808851 after up.", "kernel_refs": [ "sys/dev/netif/ic/if_ic.c:347", "sys/dev/netif/ic/if_ic.c:188-202", "sys/dev/netif/ic/if_ic.c:176", "sys/netinet/ip_output.c:698", "sys/netinet/ip_output.c:742", "sys/net/if.c:2134-2175", "sys/net/if.c:1730-1768", "sys/bus/iicbus/iiconf.c:125-148" ], "poc_changes": "New pass-2 finding, no seed PoC. Reproduction required the virtual-I2C-bridge harness (lpbbfake.ko, shared with DF-4939) and a destination address for the point-to-point interface. TX-while-down is reached via the surviving connected route (in_if_down purges cloned routes only).", "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": 300, "guest_dirty": 0, "build_cmd": "sh build.sh (harness); fix: apply fix.diff in guest /usr/src copy, cd sys/dev/netif/ic && make, install if_ic.ko, reboot", "run_cmd": "sh run.sh", "code_hash": "9ad16f1f7ec71d6be7f4a16b4b61439f8f4a3fda0d526bf72246be7045f53969", "notes": "Severity Low: requires if_ic present (I2C-attached system or attacker-loadable modules) plus prior admin configuration; direct NULL-deref sinks are DF-2001 (pass 1) and are cited, not re-claimed. Guest reset to clean-source snapshot after validation.", "recommended_fix": "Remove the unconditional ifp->if_flags |= IFF_RUNNING in icoutput; refuse to transmit unless (if_flags & (IFF_UP|IFF_RUNNING)) == both and buffers are non-NULL (fix.diff).", "fix_status": "fixed", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "Patched if_ic.ko: ping-while-down returns ENETDOWN, no phantom RUNNING flag (808810 stays), subsequent up performs the proper transition (808851) with buffers reused (no leak). Baseline bad behaviors all absent.", "fix_evidence": "run.log FIX VALIDATION section (fixB.step1-4)" } |