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

cw1200: Fix concurrency use-after-free bugs in cw1200_hw_scan()

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>

authored by

Jia-Ju Bai and committed by
Kalle Valo
4f68ef64 861cb5eb

+6 -7
+6 -7
drivers/net/wireless/st/cw1200/scan.c
··· 78 78 if (req->n_ssids > WSM_SCAN_MAX_NUM_OF_SSIDS) 79 79 return -EINVAL; 80 80 81 + /* will be unlocked in cw1200_scan_work() */ 82 + down(&priv->scan.lock); 83 + mutex_lock(&priv->conf_mutex); 84 + 81 85 frame.skb = ieee80211_probereq_get(hw, priv->vif->addr, NULL, 0, 82 86 req->ie_len); 83 87 if (!frame.skb) ··· 90 86 if (req->ie_len) 91 87 skb_put_data(frame.skb, req->ie, req->ie_len); 92 88 93 - /* will be unlocked in cw1200_scan_work() */ 94 - down(&priv->scan.lock); 95 - mutex_lock(&priv->conf_mutex); 96 - 97 89 ret = wsm_set_template_frame(priv, &frame); 98 90 if (!ret) { 99 91 /* Host want to be the probe responder. */ 100 92 ret = wsm_set_probe_responder(priv, true); 101 93 } 102 94 if (ret) { 95 + dev_kfree_skb(frame.skb); 103 96 mutex_unlock(&priv->conf_mutex); 104 97 up(&priv->scan.lock); 105 - dev_kfree_skb(frame.skb); 106 98 return ret; 107 99 } 108 100 ··· 120 120 ++priv->scan.n_ssids; 121 121 } 122 122 123 - mutex_unlock(&priv->conf_mutex); 124 - 125 123 if (frame.skb) 126 124 dev_kfree_skb(frame.skb); 125 + mutex_unlock(&priv->conf_mutex); 127 126 queue_work(priv->workqueue, &priv->scan.work); 128 127 return 0; 129 128 }