From: nbd Date: Thu, 20 Aug 2009 18:49:12 +0000 (+0000) Subject: mac80211: fix a race condition in the cfg80211 scanning code (thx, johill) X-Git-Url: https://git.rohieb.name/openwrt.git/commitdiff_plain/1a4a2b5ae76b2c685d4142402e1190431af629b8 mac80211: fix a race condition in the cfg80211 scanning code (thx, johill) git-svn-id: svn://svn.openwrt.org/openwrt/trunk@17341 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- diff --git a/package/mac80211/patches/100-cfg80211_fix_scan_check_again.patch b/package/mac80211/patches/100-cfg80211_fix_scan_check_again.patch new file mode 100644 index 000000000..77b795c12 --- /dev/null +++ b/package/mac80211/patches/100-cfg80211_fix_scan_check_again.patch @@ -0,0 +1,98 @@ +Subject: cfg80211: check lost scans later, fix bug + +When we lose a scan, cfg80211 tries to clean up after +the driver. However, it currently does this too early, +it does this in GOING_DOWN already instead of DOWN, so +it may happen with mac80211. Besides fixing this, also +make it more robust by leaking the scan request so if +the driver later actually finishes the scan, it won't +crash. Also check in ___cfg80211_scan_done whether a +scan request is still pending and exit if not. + +Signed-off-by: Johannes Berg +--- + net/wireless/core.c | 4 +++- + net/wireless/core.h | 2 +- + net/wireless/scan.c | 19 ++++++++++++++++--- + 3 files changed, 20 insertions(+), 5 deletions(-) + +--- a/net/wireless/core.c ++++ b/net/wireless/core.c +@@ -664,7 +664,7 @@ static void wdev_cleanup_work(struct wor + + if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == wdev->netdev)) { + rdev->scan_req->aborted = true; +- ___cfg80211_scan_done(rdev); ++ ___cfg80211_scan_done(rdev, true); + } + + cfg80211_unlock_rdev(rdev); +@@ -755,6 +755,8 @@ static int cfg80211_netdev_notifier_call + default: + break; + } ++ break; ++ case NETDEV_DOWN: + dev_hold(dev); + schedule_work(&wdev->cleanup_work); + break; +--- a/net/wireless/core.h ++++ b/net/wireless/core.h +@@ -374,7 +374,7 @@ void cfg80211_sme_scan_done(struct net_d + void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); + void cfg80211_sme_disassoc(struct net_device *dev, int idx); + void __cfg80211_scan_done(struct work_struct *wk); +-void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev); ++void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak); + void cfg80211_upload_connect_keys(struct wireless_dev *wdev); + + struct ieee80211_channel * +--- a/net/wireless/scan.c ++++ b/net/wireless/scan.c +@@ -18,7 +18,7 @@ + + #define IEEE80211_SCAN_RESULT_EXPIRE (15 * HZ) + +-void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev) ++void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) + { + struct cfg80211_scan_request *request; + struct net_device *dev; +@@ -28,6 +28,9 @@ void ___cfg80211_scan_done(struct cfg802 + + request = rdev->scan_req; + ++ if (!request) ++ return; ++ + dev = request->dev; + + /* +@@ -53,7 +56,17 @@ void ___cfg80211_scan_done(struct cfg802 + dev_put(dev); + + rdev->scan_req = NULL; +- kfree(request); ++ ++ /* ++ * OK. If this is invoked with "leak" then we can't ++ * free this ... but we've cleaned it up anyway. The ++ * driver failed to call the scan_done callback, so ++ * all bets are off, it might still be trying to use ++ * the scan request or not ... if it accesses the dev ++ * in there (it shouldn't anyway) then it may crash. ++ */ ++ if (!leak) ++ kfree(request); + } + + void __cfg80211_scan_done(struct work_struct *wk) +@@ -64,7 +77,7 @@ void __cfg80211_scan_done(struct work_st + scan_done_wk); + + cfg80211_lock_rdev(rdev); +- ___cfg80211_scan_done(rdev); ++ ___cfg80211_scan_done(rdev, false); + cfg80211_unlock_rdev(rdev); + } +