aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2014-01-22 04:14:18 -0500
committerJohannes Berg <johannes.berg@intel.com>2014-02-06 03:55:19 -0500
commita617302c531eaf497ccd02a61d380efc119ba999 (patch)
tree823c1fcd1eee75b502a5ac2181481841a702778b
parent8ffcc704c963b4157391bd87a4544cdfd18b574d (diff)
cfg80211: fix scan done race
When an interface/wdev is removed, any ongoing scan should be cancelled by the driver. This will make it call cfg80211, which only queues a work struct. If interface/wdev removal is quick enough, this can leave the scan request pending and processed only after the interface is gone, causing a use-after-free. Fix this by making sure the scan request is not pending after the interface is destroyed. We can't flush or cancel the work item due to locking concerns, but when it'll run it shouldn't find anything to do. This leaves a potential issue, if a new scan gets requested before the work runs, it prematurely stops the running scan, potentially causing another crash. I'll fix that in the next patch. This was particularly observed with P2P_DEVICE wdevs, likely because freeing them is quicker than freeing netdevs. Reported-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com> Fixes: 4a58e7c38443 ("cfg80211: don't "leak" uncompleted scans") Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--net/wireless/core.c14
1 files changed, 10 insertions, 4 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 77fe4c791269..02ed00dbf2df 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -203,8 +203,11 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
203 203
204 rdev->opencount--; 204 rdev->opencount--;
205 205
206 WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev && 206 if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
207 !rdev->scan_req->notified); 207 if (WARN_ON(!rdev->scan_req->notified))
208 rdev->scan_req->aborted = true;
209 ___cfg80211_scan_done(rdev);
210 }
208} 211}
209 212
210static int cfg80211_rfkill_set_block(void *data, bool blocked) 213static int cfg80211_rfkill_set_block(void *data, bool blocked)
@@ -856,8 +859,11 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
856 break; 859 break;
857 case NETDEV_DOWN: 860 case NETDEV_DOWN:
858 cfg80211_update_iface_num(rdev, wdev->iftype, -1); 861 cfg80211_update_iface_num(rdev, wdev->iftype, -1);
859 WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev && 862 if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
860 !rdev->scan_req->notified); 863 if (WARN_ON(!rdev->scan_req->notified))
864 rdev->scan_req->aborted = true;
865 ___cfg80211_scan_done(rdev);
866 }
861 867
862 if (WARN_ON(rdev->sched_scan_req && 868 if (WARN_ON(rdev->sched_scan_req &&
863 rdev->sched_scan_req->dev == wdev->netdev)) { 869 rdev->sched_scan_req->dev == wdev->netdev)) {