summaryrefslogtreecommitdiffstats
path: root/net/wireless/sme.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-11-29 01:25:20 +0100
committerJohannes Berg <johannes.berg@intel.com>2012-11-30 13:42:20 +0100
commit9caf03640279e64d0ba36539b42daa1b43a49486 (patch)
treecb094a4a577f61421d1b402e16f0e68f151d5726 /net/wireless/sme.c
parentmac80211: remove probe response temporary buffer allocation (diff)
downloadlinux-9caf03640279e64d0ba36539b42daa1b43a49486.tar.xz
linux-9caf03640279e64d0ba36539b42daa1b43a49486.zip
cfg80211: fix BSS struct IE access races
When a BSS struct is updated, the IEs are currently overwritten or freed. This can lead to races if some other CPU is accessing the BSS struct and using the IEs concurrently. Fix this by always allocating the IEs in a new struct that holds the data and length and protecting access to this new struct with RCU. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless/sme.c')
-rw-r--r--net/wireless/sme.c13
1 files changed, 11 insertions, 2 deletions
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index c7490027237d..f2431e41a373 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -417,7 +417,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
struct cfg80211_bss *bss)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
- u8 *country_ie;
+ const u8 *country_ie;
#ifdef CONFIG_CFG80211_WEXT
union iwreq_data wrqu;
#endif
@@ -501,7 +501,15 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
wdev->sme_state = CFG80211_SME_CONNECTED;
cfg80211_upload_connect_keys(wdev);
- country_ie = (u8 *) ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY);
+ rcu_read_lock();
+ country_ie = ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY);
+ if (!country_ie) {
+ rcu_read_unlock();
+ return;
+ }
+
+ country_ie = kmemdup(country_ie, 2 + country_ie[1], GFP_ATOMIC);
+ rcu_read_unlock();
if (!country_ie)
return;
@@ -515,6 +523,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
bss->channel->band,
country_ie + 2,
country_ie[1]);
+ kfree(country_ie);
}
void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,