wifi: cfg80211: update hidden BSSes to avoid WARN_ON
authorJohannes Berg <johannes.berg@intel.com>
Wed, 5 Oct 2022 21:11:43 +0000 (23:11 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 15 Oct 2022 05:59:03 +0000 (07:59 +0200)
commit c90b93b5b782891ebfda49d4e5da36632fefd5d1 upstream.

When updating beacon elements in a non-transmitted BSS,
also update the hidden sub-entries to the same beacon
elements, so that a future update through other paths
won't trigger a WARN_ON().

The warning is triggered because the beacon elements in
the hidden BSSes that are children of the BSS should
always be the same as in the parent.

Reported-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
Tested-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
Fixes: 0b8fb8235be8 ("cfg80211: Parsing of Multiple BSSID information in scanning")
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
net/wireless/scan.c

index a21baf7..f0de22a 100644 (file)
@@ -1609,6 +1609,23 @@ struct cfg80211_non_tx_bss {
        u8 bssid_index;
 };
 
+static void cfg80211_update_hidden_bsses(struct cfg80211_internal_bss *known,
+                                        const struct cfg80211_bss_ies *new_ies,
+                                        const struct cfg80211_bss_ies *old_ies)
+{
+       struct cfg80211_internal_bss *bss;
+
+       /* Assign beacon IEs to all sub entries */
+       list_for_each_entry(bss, &known->hidden_list, hidden_list) {
+               const struct cfg80211_bss_ies *ies;
+
+               ies = rcu_access_pointer(bss->pub.beacon_ies);
+               WARN_ON(ies != old_ies);
+
+               rcu_assign_pointer(bss->pub.beacon_ies, new_ies);
+       }
+}
+
 static bool
 cfg80211_update_known_bss(struct cfg80211_registered_device *rdev,
                          struct cfg80211_internal_bss *known,
@@ -1632,7 +1649,6 @@ cfg80211_update_known_bss(struct cfg80211_registered_device *rdev,
                        kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
        } else if (rcu_access_pointer(new->pub.beacon_ies)) {
                const struct cfg80211_bss_ies *old;
-               struct cfg80211_internal_bss *bss;
 
                if (known->pub.hidden_beacon_bss &&
                    !list_empty(&known->hidden_list)) {
@@ -1660,16 +1676,7 @@ cfg80211_update_known_bss(struct cfg80211_registered_device *rdev,
                if (old == rcu_access_pointer(known->pub.ies))
                        rcu_assign_pointer(known->pub.ies, new->pub.beacon_ies);
 
-               /* Assign beacon IEs to all sub entries */
-               list_for_each_entry(bss, &known->hidden_list, hidden_list) {
-                       const struct cfg80211_bss_ies *ies;
-
-                       ies = rcu_access_pointer(bss->pub.beacon_ies);
-                       WARN_ON(ies != old);
-
-                       rcu_assign_pointer(bss->pub.beacon_ies,
-                                          new->pub.beacon_ies);
-               }
+               cfg80211_update_hidden_bsses(known, new->pub.beacon_ies, old);
 
                if (old)
                        kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
@@ -2319,6 +2326,8 @@ cfg80211_update_notlisted_nontrans(struct wiphy *wiphy,
        } else {
                old = rcu_access_pointer(nontrans_bss->beacon_ies);
                rcu_assign_pointer(nontrans_bss->beacon_ies, new_ies);
+               cfg80211_update_hidden_bsses(bss_from_pub(nontrans_bss),
+                                            new_ies, old);
                rcu_assign_pointer(nontrans_bss->ies, new_ies);
                if (old)
                        kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);