| From 4dc28e08bd32a1f9d533347fd58090320fb93435 Mon Sep 17 00:00:00 2001 |
| From: Jia-Ju Bai <baijiaju1990@gmail.com> |
| Date: Fri, 14 Dec 2018 11:55:21 +0800 |
| Subject: cw1200: Fix concurrency use-after-free bugs in cw1200_hw_scan() |
| |
| [ Upstream commit 4f68ef64cd7feb1220232bd8f501d8aad340a099 ] |
| |
| The function cw1200_bss_info_changed() and cw1200_hw_scan() can be |
| concurrently executed. |
| The two functions both access a possible shared variable "frame.skb". |
| |
| This shared variable is freed by dev_kfree_skb() in cw1200_upload_beacon(), |
| which is called by cw1200_bss_info_changed(). The free operation is |
| protected by a mutex lock "priv->conf_mutex" in cw1200_bss_info_changed(). |
| |
| In cw1200_hw_scan(), this shared variable is accessed without the |
| protection of the mutex lock "priv->conf_mutex". |
| Thus, concurrency use-after-free bugs may occur. |
| |
| To fix these bugs, the original calls to mutex_lock(&priv->conf_mutex) and |
| mutex_unlock(&priv->conf_mutex) are moved to the places, which can |
| protect the accesses to the shared variable. |
| |
| Signed-off-by: Jia-Ju Bai <baijiaju1990@gmail.com> |
| Signed-off-by: Kalle Valo <kvalo@codeaurora.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/net/wireless/st/cw1200/scan.c | 13 ++++++------- |
| 1 file changed, 6 insertions(+), 7 deletions(-) |
| |
| diff --git a/drivers/net/wireless/st/cw1200/scan.c b/drivers/net/wireless/st/cw1200/scan.c |
| index cc2ce60f4f09..f22c8ae15ad8 100644 |
| --- a/drivers/net/wireless/st/cw1200/scan.c |
| +++ b/drivers/net/wireless/st/cw1200/scan.c |
| @@ -78,6 +78,10 @@ int cw1200_hw_scan(struct ieee80211_hw *hw, |
| if (req->n_ssids > WSM_SCAN_MAX_NUM_OF_SSIDS) |
| return -EINVAL; |
| |
| + /* will be unlocked in cw1200_scan_work() */ |
| + down(&priv->scan.lock); |
| + mutex_lock(&priv->conf_mutex); |
| + |
| frame.skb = ieee80211_probereq_get(hw, priv->vif->addr, NULL, 0, |
| req->ie_len); |
| if (!frame.skb) |
| @@ -86,19 +90,15 @@ int cw1200_hw_scan(struct ieee80211_hw *hw, |
| if (req->ie_len) |
| skb_put_data(frame.skb, req->ie, req->ie_len); |
| |
| - /* will be unlocked in cw1200_scan_work() */ |
| - down(&priv->scan.lock); |
| - mutex_lock(&priv->conf_mutex); |
| - |
| ret = wsm_set_template_frame(priv, &frame); |
| if (!ret) { |
| /* Host want to be the probe responder. */ |
| ret = wsm_set_probe_responder(priv, true); |
| } |
| if (ret) { |
| + dev_kfree_skb(frame.skb); |
| mutex_unlock(&priv->conf_mutex); |
| up(&priv->scan.lock); |
| - dev_kfree_skb(frame.skb); |
| return ret; |
| } |
| |
| @@ -120,10 +120,9 @@ int cw1200_hw_scan(struct ieee80211_hw *hw, |
| ++priv->scan.n_ssids; |
| } |
| |
| - mutex_unlock(&priv->conf_mutex); |
| - |
| if (frame.skb) |
| dev_kfree_skb(frame.skb); |
| + mutex_unlock(&priv->conf_mutex); |
| queue_work(priv->workqueue, &priv->scan.work); |
| return 0; |
| } |
| -- |
| 2.19.1 |
| |