Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

staging: wfx: fix RCU usage between hif_join() and ieee80211_bss_get_ie()

Access to result of ieee80211_bss_get_ie() is protected by RCU. In other
hand, function hif_join() can sleep and cannot be called with RCU
locked.

Provide a copy of "ssidie" to hif_join() to solve this behavior.

Fixes: 9ced9b593741 ("staging: wfx: simplify hif_join()")
Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
Link: https://lore.kernel.org/r/20200310101356.182818-6-Jerome.Pouiller@silabs.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Jérôme Pouiller and committed by
Greg Kroah-Hartman
ac42c12d 046cc2ef

+15 -12
+4 -4
drivers/staging/wfx/hif_tx.c
··· 290 290 } 291 291 292 292 int hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, 293 - const struct ieee80211_channel *channel, const u8 *ssidie) 293 + struct ieee80211_channel *channel, const u8 *ssid, int ssidlen) 294 294 { 295 295 int ret; 296 296 struct hif_msg *hif; ··· 308 308 body->basic_rate_set = 309 309 cpu_to_le32(wfx_rate_mask_to_hw(wvif->wdev, conf->basic_rates)); 310 310 memcpy(body->bssid, conf->bssid, sizeof(body->bssid)); 311 - if (!conf->ibss_joined && ssidie) { 312 - body->ssid_length = cpu_to_le32(ssidie[1]); 313 - memcpy(body->ssid, &ssidie[2], ssidie[1]); 311 + if (!conf->ibss_joined && ssid) { 312 + body->ssid_length = cpu_to_le32(ssidlen); 313 + memcpy(body->ssid, ssid, ssidlen); 314 314 } 315 315 wfx_fill_header(hif, wvif->id, HIF_REQ_ID_JOIN, sizeof(*body)); 316 316 ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
+1 -1
drivers/staging/wfx/hif_tx.h
··· 46 46 int chan_start, int chan_num); 47 47 int hif_stop_scan(struct wfx_vif *wvif); 48 48 int hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, 49 - const struct ieee80211_channel *channel, const u8 *ssidie); 49 + struct ieee80211_channel *channel, const u8 *ssid, int ssidlen); 50 50 int hif_set_pm(struct wfx_vif *wvif, bool ps, int dynamic_ps_timeout); 51 51 int hif_set_bss_params(struct wfx_vif *wvif, 52 52 const struct hif_req_set_bss_params *arg);
+10 -7
drivers/staging/wfx/sta.c
··· 491 491 static void wfx_do_join(struct wfx_vif *wvif) 492 492 { 493 493 int ret; 494 - const u8 *ssidie; 495 494 struct ieee80211_bss_conf *conf = &wvif->vif->bss_conf; 496 495 struct cfg80211_bss *bss = NULL; 496 + u8 ssid[IEEE80211_MAX_SSID_LEN]; 497 + const u8 *ssidie = NULL; 498 + int ssidlen = 0; 497 499 498 500 wfx_tx_lock_flush(wvif->wdev); 499 501 ··· 516 514 if (!wvif->beacon_int) 517 515 wvif->beacon_int = 1; 518 516 519 - rcu_read_lock(); 517 + rcu_read_lock(); // protect ssidie 520 518 if (!conf->ibss_joined) 521 519 ssidie = ieee80211_bss_get_ie(bss, WLAN_EID_SSID); 522 - else 523 - ssidie = NULL; 520 + if (ssidie) { 521 + ssidlen = ssidie[1]; 522 + memcpy(ssid, &ssidie[2], ssidie[1]); 523 + } 524 + rcu_read_unlock(); 524 525 525 526 wfx_tx_flush(wvif->wdev); 526 527 ··· 532 527 533 528 wfx_set_mfp(wvif, bss); 534 529 535 - /* Perform actual join */ 536 530 wvif->wdev->tx_burst_idx = -1; 537 - ret = hif_join(wvif, conf, wvif->channel, ssidie); 538 - rcu_read_unlock(); 531 + ret = hif_join(wvif, conf, wvif->channel, ssid, ssidlen); 539 532 if (ret) { 540 533 ieee80211_connection_loss(wvif->vif); 541 534 wvif->join_complete_status = -1;