mirror of
https://github.com/torvalds/linux.git
synced 2024-12-28 05:41:55 +00:00
mac80211: fix racy usage of chanctx->refcount
Channel context refcount is protected by chanctx_mtx. Accessing the value without holding the mutex is racy. RCU section didn't guarantee anything here. Theoretically ieee80211_channel_switch() could fail to see refcount change and read "1" instead of, e.g. "2". This means mac80211 could accept CSA even though it shouldn't have. Signed-off-by: Michal Kazior <michal.kazior@tieto.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
1f0d54cdcf
commit
2b32713d72
@ -3225,7 +3225,7 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
struct ieee80211_chanctx_conf *conf;
|
||||
struct ieee80211_chanctx *chanctx;
|
||||
int err, num_chanctx, changed = 0;
|
||||
|
||||
@ -3241,23 +3241,24 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
|
||||
&sdata->vif.bss_conf.chandef))
|
||||
return -EINVAL;
|
||||
|
||||
rcu_read_lock();
|
||||
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
|
||||
if (!chanctx_conf) {
|
||||
rcu_read_unlock();
|
||||
mutex_lock(&local->chanctx_mtx);
|
||||
conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
|
||||
lockdep_is_held(&local->chanctx_mtx));
|
||||
if (!conf) {
|
||||
mutex_unlock(&local->chanctx_mtx);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* don't handle for multi-VIF cases */
|
||||
chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
|
||||
chanctx = container_of(conf, struct ieee80211_chanctx, conf);
|
||||
if (chanctx->refcount > 1) {
|
||||
rcu_read_unlock();
|
||||
mutex_unlock(&local->chanctx_mtx);
|
||||
return -EBUSY;
|
||||
}
|
||||
num_chanctx = 0;
|
||||
list_for_each_entry_rcu(chanctx, &local->chanctx_list, list)
|
||||
num_chanctx++;
|
||||
rcu_read_unlock();
|
||||
mutex_unlock(&local->chanctx_mtx);
|
||||
|
||||
if (num_chanctx > 1)
|
||||
return -EBUSY;
|
||||
|
Loading…
Reference in New Issue
Block a user