aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
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
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')
-rw-r--r--drivers/net/wireless/libertas/cfg.c9
-rw-r--r--drivers/net/wireless/mwifiex/sta_ioctl.c35
2 files changed, 34 insertions, 10 deletions
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index ec36868f6fc5..ec6d5d6b452e 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -298,6 +298,7 @@ static int lbs_add_common_rates_tlv(u8 *tlv, struct cfg80211_bss *bss)
298 const u8 *rates_eid, *ext_rates_eid; 298 const u8 *rates_eid, *ext_rates_eid;
299 int n = 0; 299 int n = 0;
300 300
301 rcu_read_lock();
301 rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES); 302 rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
302 ext_rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES); 303 ext_rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
303 304
@@ -325,6 +326,7 @@ static int lbs_add_common_rates_tlv(u8 *tlv, struct cfg80211_bss *bss)
325 *tlv++ = 0x96; 326 *tlv++ = 0x96;
326 n = 4; 327 n = 4;
327 } 328 }
329 rcu_read_unlock();
328 330
329 rate_tlv->header.len = cpu_to_le16(n); 331 rate_tlv->header.len = cpu_to_le16(n);
330 return sizeof(rate_tlv->header) + n; 332 return sizeof(rate_tlv->header) + n;
@@ -1140,11 +1142,13 @@ static int lbs_associate(struct lbs_private *priv,
1140 cmd->capability = cpu_to_le16(bss->capability); 1142 cmd->capability = cpu_to_le16(bss->capability);
1141 1143
1142 /* add SSID TLV */ 1144 /* add SSID TLV */
1145 rcu_read_lock();
1143 ssid_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SSID); 1146 ssid_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SSID);
1144 if (ssid_eid) 1147 if (ssid_eid)
1145 pos += lbs_add_ssid_tlv(pos, ssid_eid + 2, ssid_eid[1]); 1148 pos += lbs_add_ssid_tlv(pos, ssid_eid + 2, ssid_eid[1]);
1146 else 1149 else
1147 lbs_deb_assoc("no SSID\n"); 1150 lbs_deb_assoc("no SSID\n");
1151 rcu_read_unlock();
1148 1152
1149 /* add DS param TLV */ 1153 /* add DS param TLV */
1150 if (bss->channel) 1154 if (bss->channel)
@@ -1782,7 +1786,7 @@ static int lbs_ibss_join_existing(struct lbs_private *priv,
1782 struct cfg80211_ibss_params *params, 1786 struct cfg80211_ibss_params *params,
1783 struct cfg80211_bss *bss) 1787 struct cfg80211_bss *bss)
1784{ 1788{
1785 const u8 *rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES); 1789 const u8 *rates_eid;
1786 struct cmd_ds_802_11_ad_hoc_join cmd; 1790 struct cmd_ds_802_11_ad_hoc_join cmd;
1787 u8 preamble = RADIO_PREAMBLE_SHORT; 1791 u8 preamble = RADIO_PREAMBLE_SHORT;
1788 int ret = 0; 1792 int ret = 0;
@@ -1841,6 +1845,8 @@ static int lbs_ibss_join_existing(struct lbs_private *priv,
1841 1845
1842 /* set rates to the intersection of our rates and the rates in the 1846 /* set rates to the intersection of our rates and the rates in the
1843 bss */ 1847 bss */
1848 rcu_read_lock();
1849 rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
1844 if (!rates_eid) { 1850 if (!rates_eid) {
1845 lbs_add_rates(cmd.bss.rates); 1851 lbs_add_rates(cmd.bss.rates);
1846 } else { 1852 } else {
@@ -1860,6 +1866,7 @@ static int lbs_ibss_join_existing(struct lbs_private *priv,
1860 } 1866 }
1861 } 1867 }
1862 } 1868 }
1869 rcu_read_unlock();
1863 1870
1864 /* Only v8 and below support setting this */ 1871 /* Only v8 and below support setting this */
1865 if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8) { 1872 if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8) {
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,