aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_output.c
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2013-10-15 14:54:30 -0400
committerDavid S. Miller <davem@davemloft.net>2013-10-17 16:08:08 -0400
commitc52e2421f7368fd36cbe330d2cf41b10452e39a9 (patch)
tree337ead817a96c313068b3d4b0c4f844ef23014f9 /net/ipv4/tcp_output.c
parentdf709a18cae475de38ddaff63584692d50267b92 (diff)
tcp: must unclone packets before mangling them
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 <edumazet@google.com> Signed-off-by: Neal Cardwell <ncardwell@google.com> Cc: Yuchung Cheng <ycheng@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_output.c')
-rw-r--r--net/ipv4/tcp_output.c9
1 files changed, 6 insertions, 3 deletions
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index c6f01f2cdb32..8fad1c155688 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -986,6 +986,9 @@ static void tcp_queue_skb(struct sock *sk, struct sk_buff *skb)
986static void tcp_set_skb_tso_segs(const struct sock *sk, struct sk_buff *skb, 986static void tcp_set_skb_tso_segs(const struct sock *sk, struct sk_buff *skb,
987 unsigned int mss_now) 987 unsigned int mss_now)
988{ 988{
989 /* Make sure we own this skb before messing gso_size/gso_segs */
990 WARN_ON_ONCE(skb_cloned(skb));
991
989 if (skb->len <= mss_now || !sk_can_gso(sk) || 992 if (skb->len <= mss_now || !sk_can_gso(sk) ||
990 skb->ip_summed == CHECKSUM_NONE) { 993 skb->ip_summed == CHECKSUM_NONE) {
991 /* Avoid the costly divide in the normal 994 /* Avoid the costly divide in the normal
@@ -1067,9 +1070,7 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len,
1067 if (nsize < 0) 1070 if (nsize < 0)
1068 nsize = 0; 1071 nsize = 0;
1069 1072
1070 if (skb_cloned(skb) && 1073 if (skb_unclone(skb, GFP_ATOMIC))
1071 skb_is_nonlinear(skb) &&
1072 pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
1073 return -ENOMEM; 1074 return -ENOMEM;
1074 1075
1075 /* Get a new skb... force flag on. */ 1076 /* Get a new skb... force flag on. */
@@ -2344,6 +2345,8 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
2344 int oldpcount = tcp_skb_pcount(skb); 2345 int oldpcount = tcp_skb_pcount(skb);
2345 2346
2346 if (unlikely(oldpcount > 1)) { 2347 if (unlikely(oldpcount > 1)) {
2348 if (skb_unclone(skb, GFP_ATOMIC))
2349 return -ENOMEM;
2347 tcp_init_tso_segs(sk, skb, cur_mss); 2350 tcp_init_tso_segs(sk, skb, cur_mss);
2348 tcp_adjust_pcount(sk, skb, oldpcount - tcp_skb_pcount(skb)); 2351 tcp_adjust_pcount(sk, skb, oldpcount - tcp_skb_pcount(skb));
2349 } 2352 }