mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +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
1 changed files with 9 additions and 8 deletions
|
@ -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_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||||
struct ieee80211_local *local = sdata->local;
|
struct ieee80211_local *local = sdata->local;
|
||||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
struct ieee80211_chanctx_conf *conf;
|
||||||
struct ieee80211_chanctx *chanctx;
|
struct ieee80211_chanctx *chanctx;
|
||||||
int err, num_chanctx, changed = 0;
|
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))
|
&sdata->vif.bss_conf.chandef))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
rcu_read_lock();
|
mutex_lock(&local->chanctx_mtx);
|
||||||
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
|
conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
|
||||||
if (!chanctx_conf) {
|
lockdep_is_held(&local->chanctx_mtx));
|
||||||
rcu_read_unlock();
|
if (!conf) {
|
||||||
|
mutex_unlock(&local->chanctx_mtx);
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* don't handle for multi-VIF cases */
|
/* 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) {
|
if (chanctx->refcount > 1) {
|
||||||
rcu_read_unlock();
|
mutex_unlock(&local->chanctx_mtx);
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
num_chanctx = 0;
|
num_chanctx = 0;
|
||||||
list_for_each_entry_rcu(chanctx, &local->chanctx_list, list)
|
list_for_each_entry_rcu(chanctx, &local->chanctx_list, list)
|
||||||
num_chanctx++;
|
num_chanctx++;
|
||||||
rcu_read_unlock();
|
mutex_unlock(&local->chanctx_mtx);
|
||||||
|
|
||||||
if (num_chanctx > 1)
|
if (num_chanctx > 1)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
Loading…
Reference in a new issue