Skip to content

Commit 4540181

Browse files
jmberg-intelgregkh
authored andcommitted
wifi: cfg80211: make hash table duplicates more survivable
[ Upstream commit 7f12e26 ] Jiazi Li reported that they occasionally see hash table duplicates as evidenced by the WARN_ON() in rb_insert_bss() in this code. It isn't clear how that happens, nor have I been able to reproduce it, but if it does happen, the kernel crashes later, when it tries to unhash the entry that's now not hashed. Try to make this situation more survivable by removing the BSS from the list(s) as well, that way it's fully leaked here (as had been the intent in the hash insert error path), and no longer reachable through the list(s) so it shouldn't be unhashed again later. Link: https://lore.kernel.org/r/20231026013528.GA24122@Jiazi.Li Signed-off-by: Johannes Berg <johannes.berg@intel.com> Link: https://msgid.link/20240607181726.36835-2-johannes@sipsolutions.net Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 82fff0a commit 4540181

1 file changed

Lines changed: 34 additions & 12 deletions

File tree

net/wireless/scan.c

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1604,7 +1604,7 @@ struct cfg80211_bss *__cfg80211_get_bss(struct wiphy *wiphy,
16041604
}
16051605
EXPORT_SYMBOL(__cfg80211_get_bss);
16061606

1607-
static void rb_insert_bss(struct cfg80211_registered_device *rdev,
1607+
static bool rb_insert_bss(struct cfg80211_registered_device *rdev,
16081608
struct cfg80211_internal_bss *bss)
16091609
{
16101610
struct rb_node **p = &rdev->bss_tree.rb_node;
@@ -1620,7 +1620,7 @@ static void rb_insert_bss(struct cfg80211_registered_device *rdev,
16201620

16211621
if (WARN_ON(!cmp)) {
16221622
/* will sort of leak this BSS */
1623-
return;
1623+
return false;
16241624
}
16251625

16261626
if (cmp < 0)
@@ -1631,6 +1631,7 @@ static void rb_insert_bss(struct cfg80211_registered_device *rdev,
16311631

16321632
rb_link_node(&bss->rbn, parent, p);
16331633
rb_insert_color(&bss->rbn, &rdev->bss_tree);
1634+
return true;
16341635
}
16351636

16361637
static struct cfg80211_internal_bss *
@@ -1657,6 +1658,34 @@ rb_find_bss(struct cfg80211_registered_device *rdev,
16571658
return NULL;
16581659
}
16591660

1661+
static void cfg80211_insert_bss(struct cfg80211_registered_device *rdev,
1662+
struct cfg80211_internal_bss *bss)
1663+
{
1664+
lockdep_assert_held(&rdev->bss_lock);
1665+
1666+
if (!rb_insert_bss(rdev, bss))
1667+
return;
1668+
list_add_tail(&bss->list, &rdev->bss_list);
1669+
rdev->bss_entries++;
1670+
}
1671+
1672+
static void cfg80211_rehash_bss(struct cfg80211_registered_device *rdev,
1673+
struct cfg80211_internal_bss *bss)
1674+
{
1675+
lockdep_assert_held(&rdev->bss_lock);
1676+
1677+
rb_erase(&bss->rbn, &rdev->bss_tree);
1678+
if (!rb_insert_bss(rdev, bss)) {
1679+
list_del(&bss->list);
1680+
if (!list_empty(&bss->hidden_list))
1681+
list_del_init(&bss->hidden_list);
1682+
if (!list_empty(&bss->pub.nontrans_list))
1683+
list_del_init(&bss->pub.nontrans_list);
1684+
rdev->bss_entries--;
1685+
}
1686+
rdev->bss_generation++;
1687+
}
1688+
16601689
static bool cfg80211_combine_bsses(struct cfg80211_registered_device *rdev,
16611690
struct cfg80211_internal_bss *new)
16621691
{
@@ -1969,9 +1998,7 @@ __cfg80211_bss_update(struct cfg80211_registered_device *rdev,
19691998
bss_ref_get(rdev, bss_from_pub(tmp->pub.transmitted_bss));
19701999
}
19712000

1972-
list_add_tail(&new->list, &rdev->bss_list);
1973-
rdev->bss_entries++;
1974-
rb_insert_bss(rdev, new);
2001+
cfg80211_insert_bss(rdev, new);
19752002
found = new;
19762003
}
19772004

@@ -3354,19 +3381,14 @@ void cfg80211_update_assoc_bss_entry(struct wireless_dev *wdev,
33543381
if (!WARN_ON(!__cfg80211_unlink_bss(rdev, new)))
33553382
rdev->bss_generation++;
33563383
}
3357-
3358-
rb_erase(&cbss->rbn, &rdev->bss_tree);
3359-
rb_insert_bss(rdev, cbss);
3360-
rdev->bss_generation++;
3384+
cfg80211_rehash_bss(rdev, cbss);
33613385

33623386
list_for_each_entry_safe(nontrans_bss, tmp,
33633387
&cbss->pub.nontrans_list,
33643388
nontrans_list) {
33653389
bss = bss_from_pub(nontrans_bss);
33663390
bss->pub.channel = chan;
3367-
rb_erase(&bss->rbn, &rdev->bss_tree);
3368-
rb_insert_bss(rdev, bss);
3369-
rdev->bss_generation++;
3391+
cfg80211_rehash_bss(rdev, bss);
33703392
}
33713393

33723394
done:

0 commit comments

Comments
 (0)