wifi: cfg80211: hold wiphy mutex for send_interface
authorJohannes Berg <johannes.berg@intel.com>
Wed, 15 Nov 2023 12:06:16 +0000 (13:06 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 24 Nov 2023 17:30:48 +0000 (18:30 +0100)
Given all the locking rework in mac80211, we pretty much
need to get into the driver with the wiphy mutex held in
all callbacks. This is already mostly the case, but as
Johan reported, in the get_txpower it may not be true.

Lock the wiphy mutex around nl80211_send_iface(), then
is also around callers of nl80211_notify_iface(). This
is easy to do, fixes the problem, and aligns the locking
between various calls to it in different parts of the
code of cfg80211.

Fixes: 0e8185ce1dde ("wifi: mac80211: check wiphy mutex in ops")
Reported-by: Johan Hovold <johan@kernel.org>
Closes: https://lore.kernel.org/r/ZVOXX6qg4vXEx8dX@hovoldconsulting.com
Tested-by: Johan Hovold <johan+linaro@kernel.org>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/wireless/core.c
net/wireless/nl80211.c

index 3f756ce46602e903619eb82db30c169cf41ccdea..409d74c57ca0d8c8d36c2260897fce39557620ee 100644 (file)
@@ -191,13 +191,13 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
                return err;
        }
 
+       wiphy_lock(&rdev->wiphy);
        list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
                if (!wdev->netdev)
                        continue;
                nl80211_notify_iface(rdev, wdev, NL80211_CMD_DEL_INTERFACE);
        }
 
-       wiphy_lock(&rdev->wiphy);
        nl80211_notify_wiphy(rdev, NL80211_CMD_DEL_WIPHY);
 
        wiphy_net_set(&rdev->wiphy, net);
@@ -206,13 +206,13 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
        WARN_ON(err);
 
        nl80211_notify_wiphy(rdev, NL80211_CMD_NEW_WIPHY);
-       wiphy_unlock(&rdev->wiphy);
 
        list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
                if (!wdev->netdev)
                        continue;
                nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE);
        }
+       wiphy_unlock(&rdev->wiphy);
 
        return 0;
 }
index dbfed5a2d7b604a855ff7b32d9f3f4cdd6ffc629..1cbbb11ea5033fdeb0bfe1b8c1e796bfb748ec86 100644 (file)
@@ -3822,6 +3822,8 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag
        struct net_device *dev = wdev->netdev;
        void *hdr;
 
+       lockdep_assert_wiphy(&rdev->wiphy);
+
        WARN_ON(cmd != NL80211_CMD_NEW_INTERFACE &&
                cmd != NL80211_CMD_DEL_INTERFACE &&
                cmd != NL80211_CMD_SET_INTERFACE);
@@ -3989,6 +3991,7 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *
 
                if_idx = 0;
 
+               wiphy_lock(&rdev->wiphy);
                list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
                        if (if_idx < if_start) {
                                if_idx++;
@@ -3998,10 +4001,12 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *
                                               cb->nlh->nlmsg_seq, NLM_F_MULTI,
                                               rdev, wdev,
                                               NL80211_CMD_NEW_INTERFACE) < 0) {
+                               wiphy_unlock(&rdev->wiphy);
                                goto out;
                        }
                        if_idx++;
                }
+               wiphy_unlock(&rdev->wiphy);
 
                wp_idx++;
        }