Skip to content

Commit c87905b

Browse files
committed
mac80211: set bss_info data before configuring the channel
When mac80211 changes the channel, it also calls into the driver's bss_info_changed() callback, e.g. with BSS_CHANGED_IDLE. The driver may, like iwlwifi does, access more data from bss_info in that case and iwlwifi accesses the basic_rates bitmap, but if changing from a band with more (basic) rates to one with fewer, an out-of-bounds access of the rate array may result. While we can't avoid having invalid data at some point in time, we can avoid having it while we call the driver - so set up all the data before configuring the channel, and then apply it afterwards. This fixes https://bugzilla.kernel.org/show_bug.cgi?id=195677 Reported-by: Johannes Hirte <johannes.hirte@datenkhaos.de> Tested-by: Johannes Hirte <johannes.hirte@datenkhaos.de> Debugged-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
1 parent 44f6d42 commit c87905b

File tree

1 file changed

+28
-10
lines changed

1 file changed

+28
-10
lines changed

net/mac80211/mlme.c

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4392,15 +4392,19 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
43924392
return -ENOMEM;
43934393
}
43944394

4395-
if (new_sta || override) {
4396-
err = ieee80211_prep_channel(sdata, cbss);
4397-
if (err) {
4398-
if (new_sta)
4399-
sta_info_free(local, new_sta);
4400-
return -EINVAL;
4401-
}
4402-
}
4403-
4395+
/*
4396+
* Set up the information for the new channel before setting the
4397+
* new channel. We can't - completely race-free - change the basic
4398+
* rates bitmap and the channel (sband) that it refers to, but if
4399+
* we set it up before we at least avoid calling into the driver's
4400+
* bss_info_changed() method with invalid information (since we do
4401+
* call that from changing the channel - only for IDLE and perhaps
4402+
* some others, but ...).
4403+
*
4404+
* So to avoid that, just set up all the new information before the
4405+
* channel, but tell the driver to apply it only afterwards, since
4406+
* it might need the new channel for that.
4407+
*/
44044408
if (new_sta) {
44054409
u32 rates = 0, basic_rates = 0;
44064410
bool have_higher_than_11mbit;
@@ -4471,8 +4475,22 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
44714475
sdata->vif.bss_conf.sync_dtim_count = 0;
44724476
}
44734477
rcu_read_unlock();
4478+
}
44744479

4475-
/* tell driver about BSSID, basic rates and timing */
4480+
if (new_sta || override) {
4481+
err = ieee80211_prep_channel(sdata, cbss);
4482+
if (err) {
4483+
if (new_sta)
4484+
sta_info_free(local, new_sta);
4485+
return -EINVAL;
4486+
}
4487+
}
4488+
4489+
if (new_sta) {
4490+
/*
4491+
* tell driver about BSSID, basic rates and timing
4492+
* this was set up above, before setting the channel
4493+
*/
44764494
ieee80211_bss_info_change_notify(sdata,
44774495
BSS_CHANGED_BSSID | BSS_CHANGED_BASIC_RATES |
44784496
BSS_CHANGED_BEACON_INT);

0 commit comments

Comments
 (0)