[Bug 299737] WITNESS lock order reversal: net80211 com mutex -> ifnet_sx via rtnetlink dump_iface (RTM_NEWLINK event)

From: <bugzilla-noreply_at_freebsd.org>
Date: Thu, 22 Oct 2026 15:07:07 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=299737

            Bug ID: 299737
           Summary: WITNESS lock order reversal: net80211 com mutex ->
                    ifnet_sx via rtnetlink dump_iface (RTM_NEWLINK event)
           Product: Base System
           Version: Unspecified
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Only Me
          Priority: ---
         Component: kern
          Assignee: bugs@FreeBSD.org
          Reporter: david@crap.solutions

Created attachment 276112
  --> https://bugs.freebsd.org/bugzilla/attachment.cgi?id=276112&action=edit
net: do not take ifnet_sx when iterating interface groups

Booting CURRENT with WITNESS produces, once per boot, when wpa_supplicant
brings wlan0 up:

  lock order reversal: (sleepable after non-sleepable)
   1st iwlwifi0_com_lo (sleep mutex) @ sys/net80211/ieee80211_ioctl.c:3711
   2nd ifnet_sx (sx) @ sys/net/if.c:1485
  #2 if_foreach_group  #3 dump_iface  #4 rtnl_handle_ifnet_event
  #5 ieee80211_notify_ifnet_change  #6 ieee80211_start_locked
  #7 ieee80211_ioctl  #8 ifhwioctl  #9 ifioctl  #10 kern_ioctl

net80211 posts an RTM_IFINFO/RTM_NEWLINK notification from
ieee80211_start_locked()/ieee80211_stop_locked() while holding its com
mutex (IEEE80211_LOCK, MTX_DEF|MTX_RECURSE). Since the rtnetlink
IFLAF_GROUP support the notification reaches dump_iface() -> dump_group()
-> if_foreach_group(), which acquires ifnet_sx with IFNET_RLOCK(), i.e.
sx_slock().  Which may sleep when ifnet_sx is write-held, so a sleepable
lock is taken under a non-sleepable mutex: it can deadlock if a thread
holding ifnet_sx waits for the com mutex, and with debug.witness.kdb=1
it drops into KDB during boot.

if_foreach_group() does not need ifnet_sx.  Group membership is
mutated under IFNET_WLOCK with the CK_STAILQ macros, and
_if_delgroup_locked() only frees ifg_list/ifg_group/ifg_member after
NET_EPOCH_WAIT(), so readers can walk ifp->if_groups in the net epoch,
the same way if_foreach_lladdr() and if_foreach_llmaddr() already walk
if_addrhead/if_multiaddrs.

-- 
You are receiving this mail because:
You are the assignee for the bug.