aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-rx.c
diff options
context:
space:
mode:
authorZhu Yi <yi.zhu@intel.com>2009-10-23 16:42:25 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-10-27 16:50:01 -0400
commit29b1b2688fd71346f78f175d9669c006686b6dc3 (patch)
tree8d7a337761cc88dae60f4d5e44eb5fd9fbe53858 /drivers/net/wireless/iwlwifi/iwl-rx.c
parent52aa081c40324ecb04a47864e4e56dafc5a72a34 (diff)
iwlwifi: fix use after free bug for paged rx
In the paged rx patch (4854fde2), I introduced a bug that could possibly touch an already freed page. It is fixed by avoiding the access in this patch. I've also added some comments so that other people touching the code won't make the same mistake. In the future, if we cannot avoid access the page after being handled to the upper layer, we can use get_page/put_page to handle it. For now, it's just not necessary. It also fixed a debug message print bug reported by Stanislaw Gruszka <sgruszka@redhat.com>. Signed-off-by: Zhu Yi <yi.zhu@intel.com> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-rx.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c21
1 files changed, 14 insertions, 7 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index cfc31ae4712b..e5339c9ad13e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -241,6 +241,7 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority)
241 struct iwl_rx_mem_buffer *rxb; 241 struct iwl_rx_mem_buffer *rxb;
242 struct page *page; 242 struct page *page;
243 unsigned long flags; 243 unsigned long flags;
244 gfp_t gfp_mask = priority;
244 245
245 while (1) { 246 while (1) {
246 spin_lock_irqsave(&rxq->lock, flags); 247 spin_lock_irqsave(&rxq->lock, flags);
@@ -251,13 +252,13 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority)
251 spin_unlock_irqrestore(&rxq->lock, flags); 252 spin_unlock_irqrestore(&rxq->lock, flags);
252 253
253 if (rxq->free_count > RX_LOW_WATERMARK) 254 if (rxq->free_count > RX_LOW_WATERMARK)
254 priority |= __GFP_NOWARN; 255 gfp_mask |= __GFP_NOWARN;
255 256
256 if (priv->hw_params.rx_page_order > 0) 257 if (priv->hw_params.rx_page_order > 0)
257 priority |= __GFP_COMP; 258 gfp_mask |= __GFP_COMP;
258 259
259 /* Alloc a new receive buffer */ 260 /* Alloc a new receive buffer */
260 page = alloc_pages(priority, priv->hw_params.rx_page_order); 261 page = alloc_pages(gfp_mask, priv->hw_params.rx_page_order);
261 if (!page) { 262 if (!page) {
262 if (net_ratelimit()) 263 if (net_ratelimit())
263 IWL_DEBUG_INFO(priv, "alloc_pages failed, " 264 IWL_DEBUG_INFO(priv, "alloc_pages failed, "
@@ -922,6 +923,7 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
922{ 923{
923 struct sk_buff *skb; 924 struct sk_buff *skb;
924 int ret = 0; 925 int ret = 0;
926 __le16 fc = hdr->frame_control;
925 927
926 /* We only process data packets if the interface is open */ 928 /* We only process data packets if the interface is open */
927 if (unlikely(!priv->is_open)) { 929 if (unlikely(!priv->is_open)) {
@@ -946,9 +948,9 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
946 /* mac80211 currently doesn't support paged SKB. Convert it to 948 /* mac80211 currently doesn't support paged SKB. Convert it to
947 * linear SKB for management frame and data frame requires 949 * linear SKB for management frame and data frame requires
948 * software decryption or software defragementation. */ 950 * software decryption or software defragementation. */
949 if (ieee80211_is_mgmt(hdr->frame_control) || 951 if (ieee80211_is_mgmt(fc) ||
950 ieee80211_has_protected(hdr->frame_control) || 952 ieee80211_has_protected(fc) ||
951 ieee80211_has_morefrags(hdr->frame_control) || 953 ieee80211_has_morefrags(fc) ||
952 le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) 954 le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)
953 ret = skb_linearize(skb); 955 ret = skb_linearize(skb);
954 else 956 else
@@ -960,7 +962,12 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
960 goto out; 962 goto out;
961 } 963 }
962 964
963 iwl_update_stats(priv, false, hdr->frame_control, len); 965 /*
966 * XXX: We cannot touch the page and its virtual memory (hdr) after
967 * here. It might have already been freed by the above skb change.
968 */
969
970 iwl_update_stats(priv, false, fc, len);
964 memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); 971 memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
965 972
966 ieee80211_rx(priv->hw, skb); 973 ieee80211_rx(priv->hw, skb);