DF-3345 / verdict.json
{ "finding_id": "DF-3345", "status": "not_reproduced", "reproduced": 0, "impact": "none", "confidence": "likely", "verdict": "Structural lock-protocol defect, certain from source: SIOCSLAGG (if_lagg.c:1085-1101) NULLs the protocol callbacks only AFTER sc->sc_detach() returns, but lagg_lacp_detach (if_lagg.c:2091-2106) explicitly drops the lagg WLock at 2101 for the duration of lacp_detach(), which NULLs sc->sc_psc (ieee8023ad_lacp.c:848) and kfrees the lacp_softc. During that window an unprivileged SIOCGLAGG still sees sc_req == lacp_req and calls lacp_req() on sc_psc == NULL (deref of lsc->lsc_active_aggregator, ieee8023ad_lacp.c:607); a concurrent SIOCSLAGGPORT still sees sc_port_create == lacp_port_create and LIST_INSERT_HEADs into the freed lsc (ieee8023ad_lacp.c:561); a concurrent clone-destroy re-invokes the still-installed sc_detach (double lacp_detach + nested WUNLOCK). Verification attempt: 6 unprivileged SIOCGLAGG spinner processes vs 1800 privileged laggproto lacp<->failover flips on the stock INVARIANTS guest - no panic, guest stayed up; the fatal sub-window (sc_psc NULLed until WLock reacquire) is real but too narrow to manifest at achievable ioctl rates. Filed as not reproduced / likely; the fix (NULL all callbacks before calling detach, and snapshot sc_detach in clone_destroy) is cheap and also hardens DF-3346.", "exploit_chain": "", "evidence": [ "findings/poc/DF-3345/run.log - 1800 flips x 6 spinners, vm.sh status up after both rounds", "sys/net/lagg/if_lagg.c:2101-2103 (WUNLOCK window), 1090-1100 (callbacks NULLed only after detach returns)", "sys/net/lagg/ieee8023ad_lacp.c:848 (sc_psc = NULL inside the window)" ], "kernel_refs": [ "sys/net/lagg/if_lagg.c:1085", "sys/net/lagg/if_lagg.c:1090", "sys/net/lagg/if_lagg.c:2101", "sys/net/lagg/if_lagg.c:2103", "sys/net/lagg/if_lagg.c:427", "sys/net/lagg/if_lagg.c:707", "sys/net/lagg/ieee8023ad_lacp.c:848", "sys/net/lagg/ieee8023ad_lacp.c:607", "sys/net/lagg/ieee8023ad_lacp.c:561" ], "poc_changes": "no seed; laggspin.c written from scratch (tight SIOCGLAGG loop).", "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": 420, "guest_dirty": 0, "build_cmd": "cc -O2 -o /tmp/laggspin laggspin.c -I/usr/src/sys", "run_cmd": "./run.sh (6 unpriv spinners vs 1500 priv flips; plus earlier 3 spinners x 300 flips)", "code_hash": "cf88e760ffec1e60be2bb82bdcc11d7d97c856e73aaa1bf64da44a4d1f818721", "notes": "Race not manifested within budget; finding stands on the explicit unlock-while-installed callbacks. Writer-priority lockmgr queuing further narrows reader entry during the window.", "recommended_fix": "NULL every sc_* protocol callback (including sc_select_tx_port) BEFORE invoking sc_detach, calling the stashed local pointer afterwards; snapshot+NULL sc_detach in lagg_clone_destroy before calling it." } |