aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2013-03-14 01:40:32 -0400
committerDavid S. Miller <davem@davemloft.net>2013-03-14 11:49:45 -0400
commit16fad69cfe4adbbfa813de516757b87bcae36d93 (patch)
tree5b16184db33e16e398fa88ca1dcbb4f054fdaffa
parentb701f16dd490d3f346724050f17d60beda094998 (diff)
tcp: fix skb_availroom()
Chrome OS team reported a crash on a Pixel ChromeBook in TCP stack : https://code.google.com/p/chromium/issues/detail?id=182056 commit a21d45726acac (tcp: avoid order-1 allocations on wifi and tx path) did a poor choice adding an 'avail_size' field to skb, while what we really needed was a 'reserved_tailroom' one. It would have avoided commit 22b4a4f22da (tcp: fix retransmit of partially acked frames) and this commit. Crash occurs because skb_split() is not aware of the 'avail_size' management (and should not be aware) Signed-off-by: Eric Dumazet <edumazet@google.com> Reported-by: Mukesh Agrawal <quiche@chromium.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/skbuff.h7
-rw-r--r--net/ipv4/tcp.c2
-rw-r--r--net/ipv4/tcp_output.c1
3 files changed, 6 insertions, 4 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 821c7f45d2a7..6f2bb860e051 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -500,7 +500,7 @@ struct sk_buff {
500 union { 500 union {
501 __u32 mark; 501 __u32 mark;
502 __u32 dropcount; 502 __u32 dropcount;
503 __u32 avail_size; 503 __u32 reserved_tailroom;
504 }; 504 };
505 505
506 sk_buff_data_t inner_transport_header; 506 sk_buff_data_t inner_transport_header;
@@ -1447,7 +1447,10 @@ static inline int skb_tailroom(const struct sk_buff *skb)
1447 */ 1447 */
1448static inline int skb_availroom(const struct sk_buff *skb) 1448static inline int skb_availroom(const struct sk_buff *skb)
1449{ 1449{
1450 return skb_is_nonlinear(skb) ? 0 : skb->avail_size - skb->len; 1450 if (skb_is_nonlinear(skb))
1451 return 0;
1452
1453 return skb->end - skb->tail - skb->reserved_tailroom;
1451} 1454}
1452 1455
1453/** 1456/**
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 47e854fcae24..e22020790709 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -775,7 +775,7 @@ struct sk_buff *sk_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp)
775 * Make sure that we have exactly size bytes 775 * Make sure that we have exactly size bytes
776 * available to the caller, no more, no less. 776 * available to the caller, no more, no less.
777 */ 777 */
778 skb->avail_size = size; 778 skb->reserved_tailroom = skb->end - skb->tail - size;
779 return skb; 779 return skb;
780 } 780 }
781 __kfree_skb(skb); 781 __kfree_skb(skb);
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index e2b4461074da..817fbb396bc8 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -1298,7 +1298,6 @@ static void __pskb_trim_head(struct sk_buff *skb, int len)
1298 eat = min_t(int, len, skb_headlen(skb)); 1298 eat = min_t(int, len, skb_headlen(skb));
1299 if (eat) { 1299 if (eat) {
1300 __skb_pull(skb, eat); 1300 __skb_pull(skb, eat);
1301 skb->avail_size -= eat;
1302 len -= eat; 1301 len -= eat;
1303 if (!len) 1302 if (!len)
1304 return; 1303 return;