wifi: cfg80211: hold wiphy lock when sending wiphy
authorJohannes Berg <johannes.berg@intel.com>
Tue, 6 Jun 2023 12:49:24 +0000 (14:49 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 7 Jun 2023 17:53:13 +0000 (19:53 +0200)
Sending the wiphy out might cause calls to the driver,
notably get_txq_stats() and get_antenna(). These aren't
very important, since the normally have their own locks
and/or just send out static data, but if the contract
should be that the wiphy lock is always held, these are
also affected. Fix that.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/wireless/core.c
net/wireless/nl80211.c

index a04b6ee..151a856 100644 (file)
@@ -129,6 +129,7 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
        int result;
 
        ASSERT_RTNL();
+       lockdep_assert_wiphy(&rdev->wiphy);
 
        /* Ignore nop renames */
        if (strcmp(newname, wiphy_name(&rdev->wiphy)) == 0)
@@ -195,6 +196,8 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
                        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);
@@ -203,6 +206,8 @@ 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;
@@ -941,8 +946,10 @@ int wiphy_register(struct wiphy *wiphy)
        rdev->wiphy.features |= NL80211_FEATURE_SCAN_FLUSH;
 
        rtnl_lock();
+       wiphy_lock(&rdev->wiphy);
        res = device_add(&rdev->wiphy.dev);
        if (res) {
+               wiphy_unlock(&rdev->wiphy);
                rtnl_unlock();
                return res;
        }
@@ -956,6 +963,7 @@ int wiphy_register(struct wiphy *wiphy)
 
        cfg80211_debugfs_rdev_add(rdev);
        nl80211_notify_wiphy(rdev, NL80211_CMD_NEW_WIPHY);
+       wiphy_unlock(&rdev->wiphy);
 
        /* set up regulatory info */
        wiphy_regulatory_register(wiphy);
index 087d60c..a52bd73 100644 (file)
@@ -3081,6 +3081,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
                if (state->filter_wiphy != -1 &&
                    state->filter_wiphy != rdev->wiphy_idx)
                        continue;
+               wiphy_lock(&rdev->wiphy);
                /* attempt to fit multiple wiphy data chunks into the skb */
                do {
                        ret = nl80211_send_wiphy(rdev, NL80211_CMD_NEW_WIPHY,
@@ -3107,6 +3108,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
                                    cb->min_dump_alloc < 4096) {
                                        cb->min_dump_alloc = 4096;
                                        state->split_start = 0;
+                                       wiphy_unlock(&rdev->wiphy);
                                        rtnl_unlock();
                                        return 1;
                                }
@@ -3114,6 +3116,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
                                break;
                        }
                } while (state->split_start > 0);
+               wiphy_unlock(&rdev->wiphy);
                break;
        }
        rtnl_unlock();