diff options
Diffstat (limited to 'iwlwifi-fix-internal-scan-race.patch')
-rw-r--r-- | iwlwifi-fix-internal-scan-race.patch | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/iwlwifi-fix-internal-scan-race.patch b/iwlwifi-fix-internal-scan-race.patch new file mode 100644 index 0000000..18b3156 --- /dev/null +++ b/iwlwifi-fix-internal-scan-race.patch @@ -0,0 +1,123 @@ +From reinette.chatre@intel.com Thu May 13 17:49:59 2010 +Return-path: <reinette.chatre@intel.com> +Envelope-to: linville@tuxdriver.com +Delivery-date: Thu, 13 May 2010 17:49:59 -0400 +Received: from mga09.intel.com ([134.134.136.24]) + by smtp.tuxdriver.com with esmtp (Exim 4.63) + (envelope-from <reinette.chatre@intel.com>) + id 1OCgI1-0007H3-Eg + for linville@tuxdriver.com; Thu, 13 May 2010 17:49:59 -0400 +Received: from orsmga002.jf.intel.com ([10.7.209.21]) + by orsmga102.jf.intel.com with ESMTP; 13 May 2010 14:48:04 -0700 +X-ExtLoop1: 1 +X-IronPort-AV: E=Sophos;i="4.53,224,1272870000"; + d="scan'208";a="517743256" +Received: from rchatre-desk.amr.corp.intel.com.jf.intel.com (HELO localhost.localdomain) ([134.134.15.94]) + by orsmga002.jf.intel.com with ESMTP; 13 May 2010 14:49:12 -0700 +From: Reinette Chatre <reinette.chatre@intel.com> +To: linville@tuxdriver.com +Cc: linux-wireless@vger.kernel.org, ipw3945-devel@lists.sourceforge.net, Reinette Chatre <reinette.chatre@intel.com> +Subject: [PATCH 1/2] iwlwifi: fix internal scan race +Date: Thu, 13 May 2010 14:49:44 -0700 +Message-Id: <1273787385-9248-2-git-send-email-reinette.chatre@intel.com> +X-Mailer: git-send-email 1.6.3.3 +In-Reply-To: <1273787385-9248-1-git-send-email-reinette.chatre@intel.com> +References: <1273787385-9248-1-git-send-email-reinette.chatre@intel.com> +X-Spam-Score: -4.2 (----) +X-Spam-Status: No +Status: RO +Content-Length: 3370 +Lines: 91 + +From: Reinette Chatre <reinette.chatre@intel.com> + +It is possible for internal scan to race against itself if the device is +not returning the scan results from first requests. What happens in this +case is the cleanup done during the abort of the first internal scan also +cleans up part of the new scan, causing it to access memory it shouldn't. + +Here are details: +* First internal scan is triggered and scan command sent to device. +* After seven seconds there is no scan results so the watchdog timer + triggers a scan abort. +* The scan abort succeeds and a SCAN_COMPLETE_NOTIFICATION is received for + failed scan. +* During processing of SCAN_COMPLETE_NOTIFICATION we clear STATUS_SCANNING + and queue the "scan_completed" work. +** At this time, since the problem that caused the internal scan in first + place is still present, a new internal scan is triggered. +The behavior at this point is a bit different between 2.6.34 and 2.6.35 +since 2.6.35 has a lot of this synchronized. The rest of the race +description will thus be generalized. +** As part of preparing for the scan "is_internal_short_scan" is set to +true. +* At this point the completion work for fist scan is run. As part of this + there is some locking missing around the "is_internal_short_scan" + variable and it is set to "false". +** Now the second scan runs and it considers itself a real (not internal0 + scan and thus causes problems with wrong memory being accessed. + +The fix is twofold. +* Since "is_internal_short_scan" should be protected by mutex, fix this in + scan completion work so that changes to it can be serialized. +* Do not queue a new internal scan if one is in progress. + +This fixes https://bugzilla.kernel.org/show_bug.cgi?id=15824 + +Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> +--- + drivers/net/wireless/iwlwifi/iwl-scan.c | 21 ++++++++++++++++++--- + 1 files changed, 18 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c +index 2367286..a2c4855 100644 +--- a/drivers/net/wireless/iwlwifi/iwl-scan.c ++++ b/drivers/net/wireless/iwlwifi/iwl-scan.c +@@ -560,6 +560,11 @@ static void iwl_bg_start_internal_scan(struct work_struct *work) + + mutex_lock(&priv->mutex); + ++ if (priv->is_internal_short_scan == true) { ++ IWL_DEBUG_SCAN(priv, "Internal scan already in progress\n"); ++ goto unlock; ++ } ++ + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_SCAN(priv, "not ready or exit pending\n"); + goto unlock; +@@ -957,17 +962,27 @@ void iwl_bg_scan_completed(struct work_struct *work) + { + struct iwl_priv *priv = + container_of(work, struct iwl_priv, scan_completed); ++ bool internal = false; + + IWL_DEBUG_SCAN(priv, "SCAN complete scan\n"); + + cancel_delayed_work(&priv->scan_check); + +- if (!priv->is_internal_short_scan) +- ieee80211_scan_completed(priv->hw, false); +- else { ++ mutex_lock(&priv->mutex); ++ if (priv->is_internal_short_scan) { + priv->is_internal_short_scan = false; + IWL_DEBUG_SCAN(priv, "internal short scan completed\n"); ++ internal = true; + } ++ mutex_unlock(&priv->mutex); ++ ++ /* ++ * Do not hold mutex here since this will cause mac80211 to call ++ * into driver again into functions that will attempt to take ++ * mutex. ++ */ ++ if (!internal) ++ ieee80211_scan_completed(priv->hw, false); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; +-- +1.6.3.3 + + + |