All of lore.kernel.org
 help / color / mirror / Atom feed
From: Larry Finger <Larry.Finger@lwfinger.net>
To: Eric Biggers <ebiggers3@gmail.com>
Cc: kvalo@codeaurora.org, linux-wireless@vger.kernel.org,
	netdev@vger.kernel.org, Stable <stable@vger.kernel.org>
Subject: Re: [PATCH for 3.19] rtlwifi: Fix error when accessing unmapped memory in skb
Date: Mon, 22 Dec 2014 16:41:22 -0600	[thread overview]
Message-ID: <54989E12.6050808@lwfinger.net> (raw)
In-Reply-To: <20141222194843.GA7575@zzz>

[-- Attachment #1: Type: text/plain, Size: 1246 bytes --]

On 12/22/2014 01:48 PM, Eric Biggers wrote:
> Is this really the same behavior as 3.17?  In 3.17, allocating the new skb is
> one of the first things the interrupt handler does, and if that fails it drops
> the packet and keeps using the old skb.  In this proposal, it's only after the
> packet has been received and the old skb has been freed that a new one is
> allocated.  And if that fails --- well, what are you expecting to happen
> exactly?

You are correct. In trying to get a small patch for stable, I missed some 
important points.

Please look at the attached patch. I think it handles the skb allocations 
correctly. The critical point is that _rtl_pci_init_one_rxdesc() cannot be 
allowed to fail to allocate an skb while in the interrupt path. Now, I have 
already allocated the skb before the call and bypassed this routine if the 
allocation fails. After a couple of crashes, this one now works for the case 
when the allocation wouldn't fail anyway. I will likely pull the allocation out 
of _rtl_pci_init_one_rxdesc() in all cases for the final patch.

@Kalle: Please drop the patch I submitted this morning with this subject. It 
would not help the problem. I will resubmit after I am sure of the proper fix.

Thanks,

Larry



[-- Attachment #2: fix_skb_alloc_v2 --]
[-- Type: text/plain, Size: 3218 bytes --]

Index: wireless-drivers/drivers/net/wireless/rtlwifi/pci.c
===================================================================
--- wireless-drivers.orig/drivers/net/wireless/rtlwifi/pci.c
+++ wireless-drivers/drivers/net/wireless/rtlwifi/pci.c
@@ -666,6 +666,7 @@ tx_status_ok:
 }
 
 static int _rtl_pci_init_one_rxdesc(struct ieee80211_hw *hw,
+				    struct sk_buff *new_skb,
 				    u8 *entry, int rxring_idx, int desc_idx)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -674,7 +675,10 @@ static int _rtl_pci_init_one_rxdesc(stru
 	u8 tmp_one = 1;
 	struct sk_buff *skb;
 
-	skb = dev_alloc_skb(rtlpci->rxbuffersize);
+	if (new_skb)
+		skb = new_skb;
+	else
+		skb = dev_alloc_skb(rtlpci->rxbuffersize);
 	if (!skb)
 		return 0;
 	rtlpci->rx_ring[rxring_idx].rx_buf[desc_idx] = skb;
@@ -772,6 +776,7 @@ static void _rtl_pci_rx_interrupt(struct
 	/*RX NORMAL PKT */
 	while (count--) {
 		struct ieee80211_hdr *hdr;
+		struct sk_buff *new_skb = NULL;
 		__le16 fc;
 		u16 len;
 		/*rx buffer descriptor */
@@ -800,6 +805,12 @@ static void _rtl_pci_rx_interrupt(struct
 				return;
 		}
 
+		new_skb = dev_alloc_skb(rtlpci->rxbuffersize);
+		if (unlikely(!new_skb)) {
+			RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV), DBG_DMESG,
+				 "can't alloc skb for rx\n");
+			goto end;
+		}
 		/* Reaching this point means: data is filled already
 		 * AAAAAAttention !!!
 		 * We can NOT access 'skb' before 'pci_unmap_single'
@@ -845,6 +856,7 @@ static void _rtl_pci_rx_interrupt(struct
 		if (rtlpriv->cfg->ops->rx_command_packet &&
 		    rtlpriv->cfg->ops->rx_command_packet(hw, stats, skb)) {
 				dev_kfree_skb_any(skb);
+				skb = new_skb;
 				goto end;
 		}
 
@@ -895,6 +907,7 @@ static void _rtl_pci_rx_interrupt(struct
 		} else {
 			dev_kfree_skb_any(skb);
 		}
+		skb = new_skb;
 		if (rtlpriv->use_new_trx_flow) {
 			rtlpci->rx_ring[hw_queue].next_rx_rp += 1;
 			rtlpci->rx_ring[hw_queue].next_rx_rp %=
@@ -912,12 +925,13 @@ static void _rtl_pci_rx_interrupt(struct
 		}
 end:
 		if (rtlpriv->use_new_trx_flow) {
-			if (!_rtl_pci_init_one_rxdesc(hw, (u8 *)buffer_desc,
-					     rxring_idx,
-					     rtlpci->rx_ring[rxring_idx].idx))
+			/* TODO: Can the following fail? */
+			if (!_rtl_pci_init_one_rxdesc(hw, skb,
+					 (u8 *)buffer_desc, rxring_idx,
+					 rtlpci->rx_ring[rxring_idx].idx))
 				return;
 		} else {
-			if (!_rtl_pci_init_one_rxdesc(hw, (u8 *)pdesc,
+			if (!_rtl_pci_init_one_rxdesc(hw, skb, (u8 *)pdesc,
 					     rxring_idx,
 					     rtlpci->rx_ring[rxring_idx].idx))
 				return;
@@ -1309,7 +1323,7 @@ static int _rtl_pci_init_rx_ring(struct
 		rtlpci->rx_ring[rxring_idx].idx = 0;
 		for (i = 0; i < rtlpci->rxringcount; i++) {
 			entry = &rtlpci->rx_ring[rxring_idx].buffer_desc[i];
-			if (!_rtl_pci_init_one_rxdesc(hw, (u8 *)entry,
+			if (!_rtl_pci_init_one_rxdesc(hw, NULL, (u8 *)entry,
 						      rxring_idx, i))
 				return -ENOMEM;
 		}
@@ -1334,7 +1348,7 @@ static int _rtl_pci_init_rx_ring(struct
 
 		for (i = 0; i < rtlpci->rxringcount; i++) {
 			entry = &rtlpci->rx_ring[rxring_idx].desc[i];
-			if (!_rtl_pci_init_one_rxdesc(hw, (u8 *)entry,
+			if (!_rtl_pci_init_one_rxdesc(hw, NULL, (u8 *)entry,
 						      rxring_idx, i))
 				return -ENOMEM;
 		}

WARNING: multiple messages have this Message-ID (diff)
From: Larry Finger <Larry.Finger-tQ5ms3gMjBLk1uMJSBkQmQ@public.gmane.org>
To: Eric Biggers <ebiggers3-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Cc: kvalo-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Stable <stable-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>
Subject: Re: [PATCH for 3.19] rtlwifi: Fix error when accessing unmapped memory in skb
Date: Mon, 22 Dec 2014 16:41:22 -0600	[thread overview]
Message-ID: <54989E12.6050808@lwfinger.net> (raw)
In-Reply-To: <20141222194843.GA7575@zzz>

[-- Attachment #1: Type: text/plain, Size: 1246 bytes --]

On 12/22/2014 01:48 PM, Eric Biggers wrote:
> Is this really the same behavior as 3.17?  In 3.17, allocating the new skb is
> one of the first things the interrupt handler does, and if that fails it drops
> the packet and keeps using the old skb.  In this proposal, it's only after the
> packet has been received and the old skb has been freed that a new one is
> allocated.  And if that fails --- well, what are you expecting to happen
> exactly?

You are correct. In trying to get a small patch for stable, I missed some 
important points.

Please look at the attached patch. I think it handles the skb allocations 
correctly. The critical point is that _rtl_pci_init_one_rxdesc() cannot be 
allowed to fail to allocate an skb while in the interrupt path. Now, I have 
already allocated the skb before the call and bypassed this routine if the 
allocation fails. After a couple of crashes, this one now works for the case 
when the allocation wouldn't fail anyway. I will likely pull the allocation out 
of _rtl_pci_init_one_rxdesc() in all cases for the final patch.

@Kalle: Please drop the patch I submitted this morning with this subject. It 
would not help the problem. I will resubmit after I am sure of the proper fix.

Thanks,

Larry



[-- Attachment #2: fix_skb_alloc_v2 --]
[-- Type: text/plain, Size: 3218 bytes --]

Index: wireless-drivers/drivers/net/wireless/rtlwifi/pci.c
===================================================================
--- wireless-drivers.orig/drivers/net/wireless/rtlwifi/pci.c
+++ wireless-drivers/drivers/net/wireless/rtlwifi/pci.c
@@ -666,6 +666,7 @@ tx_status_ok:
 }
 
 static int _rtl_pci_init_one_rxdesc(struct ieee80211_hw *hw,
+				    struct sk_buff *new_skb,
 				    u8 *entry, int rxring_idx, int desc_idx)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -674,7 +675,10 @@ static int _rtl_pci_init_one_rxdesc(stru
 	u8 tmp_one = 1;
 	struct sk_buff *skb;
 
-	skb = dev_alloc_skb(rtlpci->rxbuffersize);
+	if (new_skb)
+		skb = new_skb;
+	else
+		skb = dev_alloc_skb(rtlpci->rxbuffersize);
 	if (!skb)
 		return 0;
 	rtlpci->rx_ring[rxring_idx].rx_buf[desc_idx] = skb;
@@ -772,6 +776,7 @@ static void _rtl_pci_rx_interrupt(struct
 	/*RX NORMAL PKT */
 	while (count--) {
 		struct ieee80211_hdr *hdr;
+		struct sk_buff *new_skb = NULL;
 		__le16 fc;
 		u16 len;
 		/*rx buffer descriptor */
@@ -800,6 +805,12 @@ static void _rtl_pci_rx_interrupt(struct
 				return;
 		}
 
+		new_skb = dev_alloc_skb(rtlpci->rxbuffersize);
+		if (unlikely(!new_skb)) {
+			RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV), DBG_DMESG,
+				 "can't alloc skb for rx\n");
+			goto end;
+		}
 		/* Reaching this point means: data is filled already
 		 * AAAAAAttention !!!
 		 * We can NOT access 'skb' before 'pci_unmap_single'
@@ -845,6 +856,7 @@ static void _rtl_pci_rx_interrupt(struct
 		if (rtlpriv->cfg->ops->rx_command_packet &&
 		    rtlpriv->cfg->ops->rx_command_packet(hw, stats, skb)) {
 				dev_kfree_skb_any(skb);
+				skb = new_skb;
 				goto end;
 		}
 
@@ -895,6 +907,7 @@ static void _rtl_pci_rx_interrupt(struct
 		} else {
 			dev_kfree_skb_any(skb);
 		}
+		skb = new_skb;
 		if (rtlpriv->use_new_trx_flow) {
 			rtlpci->rx_ring[hw_queue].next_rx_rp += 1;
 			rtlpci->rx_ring[hw_queue].next_rx_rp %=
@@ -912,12 +925,13 @@ static void _rtl_pci_rx_interrupt(struct
 		}
 end:
 		if (rtlpriv->use_new_trx_flow) {
-			if (!_rtl_pci_init_one_rxdesc(hw, (u8 *)buffer_desc,
-					     rxring_idx,
-					     rtlpci->rx_ring[rxring_idx].idx))
+			/* TODO: Can the following fail? */
+			if (!_rtl_pci_init_one_rxdesc(hw, skb,
+					 (u8 *)buffer_desc, rxring_idx,
+					 rtlpci->rx_ring[rxring_idx].idx))
 				return;
 		} else {
-			if (!_rtl_pci_init_one_rxdesc(hw, (u8 *)pdesc,
+			if (!_rtl_pci_init_one_rxdesc(hw, skb, (u8 *)pdesc,
 					     rxring_idx,
 					     rtlpci->rx_ring[rxring_idx].idx))
 				return;
@@ -1309,7 +1323,7 @@ static int _rtl_pci_init_rx_ring(struct
 		rtlpci->rx_ring[rxring_idx].idx = 0;
 		for (i = 0; i < rtlpci->rxringcount; i++) {
 			entry = &rtlpci->rx_ring[rxring_idx].buffer_desc[i];
-			if (!_rtl_pci_init_one_rxdesc(hw, (u8 *)entry,
+			if (!_rtl_pci_init_one_rxdesc(hw, NULL, (u8 *)entry,
 						      rxring_idx, i))
 				return -ENOMEM;
 		}
@@ -1334,7 +1348,7 @@ static int _rtl_pci_init_rx_ring(struct
 
 		for (i = 0; i < rtlpci->rxringcount; i++) {
 			entry = &rtlpci->rx_ring[rxring_idx].desc[i];
-			if (!_rtl_pci_init_one_rxdesc(hw, (u8 *)entry,
+			if (!_rtl_pci_init_one_rxdesc(hw, NULL, (u8 *)entry,
 						      rxring_idx, i))
 				return -ENOMEM;
 		}

  reply	other threads:[~2014-12-22 22:41 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-12-22 17:37 [PATCH for 3.19] rtlwifi: Fix error when accessing unmapped memory in skb Larry Finger
2014-12-22 19:48 ` Eric Biggers
2014-12-22 22:41   ` Larry Finger [this message]
2014-12-22 22:41     ` Larry Finger
2014-12-22 23:33     ` Eric Biggers
2014-12-23  6:37     ` Kalle Valo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=54989E12.6050808@lwfinger.net \
    --to=larry.finger@lwfinger.net \
    --cc=ebiggers3@gmail.com \
    --cc=kvalo@codeaurora.org \
    --cc=linux-wireless@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.