⬢ DragonFlyBSD Kernel Audit
DF-3345 / verdict.json
← back to finding ↓ download raw
{
  "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."
}