diff options
author | Johannes Berg <johannes.berg@intel.com> | 2013-03-25 11:51:14 +0100 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-03-25 13:50:33 +0100 |
commit | 3fbd45ca8d1c98f3c2582ef8bc70ade42f70947b (patch) | |
tree | e19f4ad8aeda39090f26643c2063fc1050300391 /net/mac80211/cfg.c | |
parent | mac80211: Don't restart sta-timer if not associated. (diff) | |
download | linux-3fbd45ca8d1c98f3c2582ef8bc70ade42f70947b.tar.xz linux-3fbd45ca8d1c98f3c2582ef8bc70ade42f70947b.zip |
mac80211: fix remain-on-channel cancel crash
If a ROC item is canceled just as it expires, the work
struct may be scheduled while it is running (and waiting
for the mutex). This results in it being run after being
freed, which obviously crashes.
To fix this don't free it when aborting is requested but
instead mark it as "to be freed", which makes the work a
no-op and allows freeing it outside.
Cc: stable@vger.kernel.org [3.6+]
Reported-by: Jouni Malinen <j@w1.fi>
Tested-by: Jouni Malinen <j@w1.fi>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r-- | net/mac80211/cfg.c | 6 |
1 files changed, 4 insertions, 2 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index fb306814576a..a6893602f87a 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2582,7 +2582,7 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local, list_del(&dep->list); mutex_unlock(&local->mtx); - ieee80211_roc_notify_destroy(dep); + ieee80211_roc_notify_destroy(dep, true); return 0; } @@ -2622,7 +2622,7 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local, ieee80211_start_next_roc(local); mutex_unlock(&local->mtx); - ieee80211_roc_notify_destroy(found); + ieee80211_roc_notify_destroy(found, true); } else { /* work may be pending so use it all the time */ found->abort = true; @@ -2632,6 +2632,8 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local, /* work will clean up etc */ flush_delayed_work(&found->work); + WARN_ON(!found->to_be_freed); + kfree(found); } return 0; |