[PATCH 3.8 11/91] tcp: must unclone packets before mangling them

2013-11-07 Thread Kamal Mostafa
3.8.13.13 -stable review patch.  If anyone has any objections, please let me 
know.

--

From: Eric Dumazet 

[ Upstream commit c52e2421f7368fd36cbe330d2cf41b10452e39a9 ]

TCP stack should make sure it owns skbs before mangling them.

We had various crashes using bnx2x, and it turned out gso_size
was cleared right before bnx2x driver was populating TC descriptor
of the _previous_ packet send. TCP stack can sometime retransmit
packets that are still in Qdisc.

Of course we could make bnx2x driver more robust (using
ACCESS_ONCE(shinfo->gso_size) for example), but the bug is TCP stack.

We have identified two points where skb_unclone() was needed.

This patch adds a WARN_ON_ONCE() to warn us if we missed another
fix of this kind.

Kudos to Neal for finding the root cause of this bug. Its visible
using small MSS.

Signed-off-by: Eric Dumazet 
Signed-off-by: Neal Cardwell 
Cc: Yuchung Cheng 
Signed-off-by: David S. Miller 
Signed-off-by: Kamal Mostafa 
---
 net/ipv4/tcp_output.c | 9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index acda728..0eaef9a 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -1134,6 +1134,9 @@ static void tcp_queue_skb(struct sock *sk, struct sk_buff 
*skb)
 static void tcp_set_skb_tso_segs(const struct sock *sk, struct sk_buff *skb,
 unsigned int mss_now)
 {
+   /* Make sure we own this skb before messing gso_size/gso_segs */
+   WARN_ON_ONCE(skb_cloned(skb));
+
if (skb->len <= mss_now || !sk_can_gso(sk) ||
skb->ip_summed == CHECKSUM_NONE) {
/* Avoid the costly divide in the normal
@@ -1215,9 +1218,7 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, 
u32 len,
if (nsize < 0)
nsize = 0;
 
-   if (skb_cloned(skb) &&
-   skb_is_nonlinear(skb) &&
-   pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+   if (skb_unclone(skb, GFP_ATOMIC))
return -ENOMEM;
 
/* Get a new skb... force flag on. */
@@ -2368,6 +2369,8 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff 
*skb)
int oldpcount = tcp_skb_pcount(skb);
 
if (unlikely(oldpcount > 1)) {
+   if (skb_unclone(skb, GFP_ATOMIC))
+   return -ENOMEM;
tcp_init_tso_segs(sk, skb, cur_mss);
tcp_adjust_pcount(sk, skb, oldpcount - 
tcp_skb_pcount(skb));
}
-- 
1.8.1.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 3.8 11/91] tcp: must unclone packets before mangling them

2013-11-07 Thread Kamal Mostafa
3.8.13.13 -stable review patch.  If anyone has any objections, please let me 
know.

--

From: Eric Dumazet eduma...@google.com

[ Upstream commit c52e2421f7368fd36cbe330d2cf41b10452e39a9 ]

TCP stack should make sure it owns skbs before mangling them.

We had various crashes using bnx2x, and it turned out gso_size
was cleared right before bnx2x driver was populating TC descriptor
of the _previous_ packet send. TCP stack can sometime retransmit
packets that are still in Qdisc.

Of course we could make bnx2x driver more robust (using
ACCESS_ONCE(shinfo-gso_size) for example), but the bug is TCP stack.

We have identified two points where skb_unclone() was needed.

This patch adds a WARN_ON_ONCE() to warn us if we missed another
fix of this kind.

Kudos to Neal for finding the root cause of this bug. Its visible
using small MSS.

Signed-off-by: Eric Dumazet eduma...@google.com
Signed-off-by: Neal Cardwell ncardw...@google.com
Cc: Yuchung Cheng ych...@google.com
Signed-off-by: David S. Miller da...@davemloft.net
Signed-off-by: Kamal Mostafa ka...@canonical.com
---
 net/ipv4/tcp_output.c | 9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index acda728..0eaef9a 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -1134,6 +1134,9 @@ static void tcp_queue_skb(struct sock *sk, struct sk_buff 
*skb)
 static void tcp_set_skb_tso_segs(const struct sock *sk, struct sk_buff *skb,
 unsigned int mss_now)
 {
+   /* Make sure we own this skb before messing gso_size/gso_segs */
+   WARN_ON_ONCE(skb_cloned(skb));
+
if (skb-len = mss_now || !sk_can_gso(sk) ||
skb-ip_summed == CHECKSUM_NONE) {
/* Avoid the costly divide in the normal
@@ -1215,9 +1218,7 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, 
u32 len,
if (nsize  0)
nsize = 0;
 
-   if (skb_cloned(skb) 
-   skb_is_nonlinear(skb) 
-   pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+   if (skb_unclone(skb, GFP_ATOMIC))
return -ENOMEM;
 
/* Get a new skb... force flag on. */
@@ -2368,6 +2369,8 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff 
*skb)
int oldpcount = tcp_skb_pcount(skb);
 
if (unlikely(oldpcount  1)) {
+   if (skb_unclone(skb, GFP_ATOMIC))
+   return -ENOMEM;
tcp_init_tso_segs(sk, skb, cur_mss);
tcp_adjust_pcount(sk, skb, oldpcount - 
tcp_skb_pcount(skb));
}
-- 
1.8.1.2

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/