aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/mwifiex/sta_ioctl.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-11-28 19:25:20 -0500
committerJohannes Berg <johannes.berg@intel.com>2012-11-30 07:42:20 -0500
commit9caf03640279e64d0ba36539b42daa1b43a49486 (patch)
treecb094a4a577f61421d1b402e16f0e68f151d5726 /drivers/net/wireless/mwifiex/sta_ioctl.c
parentb9a9ada14aab17f08c1d9735601f1097cdcfc6de (diff)
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 'drivers/net/wireless/mwifiex/sta_ioctl.c')
-rw-r--r--drivers/net/wireless/mwifiex/sta_ioctl.c35
1 files changed, 26 insertions, 9 deletions
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index 24af6ba7d8a1..5d7b83e2dc4d 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -158,12 +158,22 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
158 struct cfg80211_bss *bss, 158 struct cfg80211_bss *bss,
159 struct mwifiex_bssdescriptor *bss_desc) 159 struct mwifiex_bssdescriptor *bss_desc)
160{ 160{
161 int ret; 161 int ret, beacon_ie_len;
162 u8 *beacon_ie; 162 u8 *beacon_ie;
163 struct mwifiex_bss_priv *bss_priv = (void *)bss->priv; 163 struct mwifiex_bss_priv *bss_priv = (void *)bss->priv;
164 const struct cfg80211_bss_ies *ies;
165
166 rcu_read_lock();
167 ies = rcu_dereference(bss->ies);
168 if (WARN_ON(!ies)) {
169 /* should never happen */
170 rcu_read_unlock();
171 return -EINVAL;
172 }
173 beacon_ie = kmemdup(ies->data, ies->len, GFP_ATOMIC);
174 beacon_ie_len = ies->len;
175 rcu_read_unlock();
164 176
165 beacon_ie = kmemdup(bss->information_elements, bss->len_beacon_ies,
166 GFP_KERNEL);
167 if (!beacon_ie) { 177 if (!beacon_ie) {
168 dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n"); 178 dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n");
169 return -ENOMEM; 179 return -ENOMEM;
@@ -172,7 +182,7 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
172 memcpy(bss_desc->mac_address, bss->bssid, ETH_ALEN); 182 memcpy(bss_desc->mac_address, bss->bssid, ETH_ALEN);
173 bss_desc->rssi = bss->signal; 183 bss_desc->rssi = bss->signal;
174 bss_desc->beacon_buf = beacon_ie; 184 bss_desc->beacon_buf = beacon_ie;
175 bss_desc->beacon_buf_size = bss->len_beacon_ies; 185 bss_desc->beacon_buf_size = beacon_ie_len;
176 bss_desc->beacon_period = bss->beacon_interval; 186 bss_desc->beacon_period = bss->beacon_interval;
177 bss_desc->cap_info_bitmap = bss->capability; 187 bss_desc->cap_info_bitmap = bss->capability;
178 bss_desc->bss_band = bss_priv->band; 188 bss_desc->bss_band = bss_priv->band;
@@ -198,18 +208,23 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
198static int mwifiex_process_country_ie(struct mwifiex_private *priv, 208static int mwifiex_process_country_ie(struct mwifiex_private *priv,
199 struct cfg80211_bss *bss) 209 struct cfg80211_bss *bss)
200{ 210{
201 u8 *country_ie, country_ie_len; 211 const u8 *country_ie;
212 u8 country_ie_len;
202 struct mwifiex_802_11d_domain_reg *domain_info = 213 struct mwifiex_802_11d_domain_reg *domain_info =
203 &priv->adapter->domain_reg; 214 &priv->adapter->domain_reg;
204 215
205 country_ie = (u8 *)ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY); 216 rcu_read_lock();
206 217 country_ie = ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY);
207 if (!country_ie) 218 if (!country_ie) {
219 rcu_read_unlock();
208 return 0; 220 return 0;
221 }
209 222
210 country_ie_len = country_ie[1]; 223 country_ie_len = country_ie[1];
211 if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) 224 if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) {
225 rcu_read_unlock();
212 return 0; 226 return 0;
227 }
213 228
214 domain_info->country_code[0] = country_ie[2]; 229 domain_info->country_code[0] = country_ie[2];
215 domain_info->country_code[1] = country_ie[3]; 230 domain_info->country_code[1] = country_ie[3];
@@ -223,6 +238,8 @@ static int mwifiex_process_country_ie(struct mwifiex_private *priv,
223 memcpy((u8 *)domain_info->triplet, 238 memcpy((u8 *)domain_info->triplet,
224 &country_ie[2] + IEEE80211_COUNTRY_STRING_LEN, country_ie_len); 239 &country_ie[2] + IEEE80211_COUNTRY_STRING_LEN, country_ie_len);
225 240
241 rcu_read_unlock();
242
226 if (mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11D_DOMAIN_INFO, 243 if (mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11D_DOMAIN_INFO,
227 HostCmd_ACT_GEN_SET, 0, NULL)) { 244 HostCmd_ACT_GEN_SET, 0, NULL)) {
228 wiphy_err(priv->adapter->wiphy, 245 wiphy_err(priv->adapter->wiphy,