Commit ac42c12d authored by Jérôme Pouiller's avatar Jérôme Pouiller Committed by Greg Kroah-Hartman

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: 9ced9b59 ("staging: wfx: simplify hif_join()")
Signed-off-by: default avatarJérôme Pouiller <jerome.pouiller@silabs.com>
Link: https://lore.kernel.org/r/20200310101356.182818-6-Jerome.Pouiller@silabs.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 046cc2ef
...@@ -290,7 +290,7 @@ int hif_stop_scan(struct wfx_vif *wvif) ...@@ -290,7 +290,7 @@ int hif_stop_scan(struct wfx_vif *wvif)
} }
int hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, int hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
const struct ieee80211_channel *channel, const u8 *ssidie) struct ieee80211_channel *channel, const u8 *ssid, int ssidlen)
{ {
int ret; int ret;
struct hif_msg *hif; struct hif_msg *hif;
...@@ -308,9 +308,9 @@ int hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, ...@@ -308,9 +308,9 @@ int hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
body->basic_rate_set = body->basic_rate_set =
cpu_to_le32(wfx_rate_mask_to_hw(wvif->wdev, conf->basic_rates)); cpu_to_le32(wfx_rate_mask_to_hw(wvif->wdev, conf->basic_rates));
memcpy(body->bssid, conf->bssid, sizeof(body->bssid)); memcpy(body->bssid, conf->bssid, sizeof(body->bssid));
if (!conf->ibss_joined && ssidie) { if (!conf->ibss_joined && ssid) {
body->ssid_length = cpu_to_le32(ssidie[1]); body->ssid_length = cpu_to_le32(ssidlen);
memcpy(body->ssid, &ssidie[2], ssidie[1]); memcpy(body->ssid, ssid, ssidlen);
} }
wfx_fill_header(hif, wvif->id, HIF_REQ_ID_JOIN, sizeof(*body)); wfx_fill_header(hif, wvif->id, HIF_REQ_ID_JOIN, sizeof(*body));
ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
......
...@@ -46,7 +46,7 @@ int hif_scan(struct wfx_vif *wvif, struct cfg80211_scan_request *req80211, ...@@ -46,7 +46,7 @@ int hif_scan(struct wfx_vif *wvif, struct cfg80211_scan_request *req80211,
int chan_start, int chan_num); int chan_start, int chan_num);
int hif_stop_scan(struct wfx_vif *wvif); int hif_stop_scan(struct wfx_vif *wvif);
int hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, int hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
const struct ieee80211_channel *channel, const u8 *ssidie); struct ieee80211_channel *channel, const u8 *ssid, int ssidlen);
int hif_set_pm(struct wfx_vif *wvif, bool ps, int dynamic_ps_timeout); int hif_set_pm(struct wfx_vif *wvif, bool ps, int dynamic_ps_timeout);
int hif_set_bss_params(struct wfx_vif *wvif, int hif_set_bss_params(struct wfx_vif *wvif,
const struct hif_req_set_bss_params *arg); const struct hif_req_set_bss_params *arg);
......
...@@ -491,9 +491,11 @@ static void wfx_set_mfp(struct wfx_vif *wvif, ...@@ -491,9 +491,11 @@ static void wfx_set_mfp(struct wfx_vif *wvif,
static void wfx_do_join(struct wfx_vif *wvif) static void wfx_do_join(struct wfx_vif *wvif)
{ {
int ret; int ret;
const u8 *ssidie;
struct ieee80211_bss_conf *conf = &wvif->vif->bss_conf; struct ieee80211_bss_conf *conf = &wvif->vif->bss_conf;
struct cfg80211_bss *bss = NULL; struct cfg80211_bss *bss = NULL;
u8 ssid[IEEE80211_MAX_SSID_LEN];
const u8 *ssidie = NULL;
int ssidlen = 0;
wfx_tx_lock_flush(wvif->wdev); wfx_tx_lock_flush(wvif->wdev);
...@@ -514,11 +516,14 @@ static void wfx_do_join(struct wfx_vif *wvif) ...@@ -514,11 +516,14 @@ static void wfx_do_join(struct wfx_vif *wvif)
if (!wvif->beacon_int) if (!wvif->beacon_int)
wvif->beacon_int = 1; wvif->beacon_int = 1;
rcu_read_lock(); rcu_read_lock(); // protect ssidie
if (!conf->ibss_joined) if (!conf->ibss_joined)
ssidie = ieee80211_bss_get_ie(bss, WLAN_EID_SSID); ssidie = ieee80211_bss_get_ie(bss, WLAN_EID_SSID);
else if (ssidie) {
ssidie = NULL; ssidlen = ssidie[1];
memcpy(ssid, &ssidie[2], ssidie[1]);
}
rcu_read_unlock();
wfx_tx_flush(wvif->wdev); wfx_tx_flush(wvif->wdev);
...@@ -527,10 +532,8 @@ static void wfx_do_join(struct wfx_vif *wvif) ...@@ -527,10 +532,8 @@ static void wfx_do_join(struct wfx_vif *wvif)
wfx_set_mfp(wvif, bss); wfx_set_mfp(wvif, bss);
/* Perform actual join */
wvif->wdev->tx_burst_idx = -1; wvif->wdev->tx_burst_idx = -1;
ret = hif_join(wvif, conf, wvif->channel, ssidie); ret = hif_join(wvif, conf, wvif->channel, ssid, ssidlen);
rcu_read_unlock();
if (ret) { if (ret) {
ieee80211_connection_loss(wvif->vif); ieee80211_connection_loss(wvif->vif);
wvif->join_complete_status = -1; wvif->join_complete_status = -1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment