diff options
author | Eric Dumazet <edumazet@google.com> | 2013-03-14 05:40:32 +0000 |
---|---|---|
committer | Ben Hutchings <ben@decadent.org.uk> | 2013-03-27 02:41:06 +0000 |
commit | 3bb4aac6d51817928a722617d218d2d67aa11373 (patch) | |
tree | c4b885df7f41910da2d1174bb86f35a95deb6803 | |
parent | f43dc583024e3d5c8bfb71afd3d5070131b27025 (diff) | |
download | kernel_samsung_smdk4412-3bb4aac6d51817928a722617d218d2d67aa11373.zip kernel_samsung_smdk4412-3bb4aac6d51817928a722617d218d2d67aa11373.tar.gz kernel_samsung_smdk4412-3bb4aac6d51817928a722617d218d2d67aa11373.tar.bz2 |
tcp: fix skb_availroom()
[ Upstream commit 16fad69cfe4adbbfa813de516757b87bcae36d93 ]
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>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
-rw-r--r-- | include/linux/skbuff.h | 7 | ||||
-rw-r--r-- | net/ipv4/tcp.c | 2 | ||||
-rw-r--r-- | net/ipv4/tcp_output.c | 1 |
3 files changed, 6 insertions, 4 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 53dc7e7..da65890 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -455,7 +455,7 @@ struct sk_buff { union { __u32 mark; __u32 dropcount; - __u32 avail_size; + __u32 reserved_tailroom; }; __u16 vlan_tci; @@ -1332,7 +1332,10 @@ static inline int skb_tailroom(const struct sk_buff *skb) */ static inline int skb_availroom(const struct sk_buff *skb) { - return skb_is_nonlinear(skb) ? 0 : skb->avail_size - skb->len; + if (skb_is_nonlinear(skb)) + return 0; + + return skb->end - skb->tail - skb->reserved_tailroom; } /** diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 52edbb8..fe381c2 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -704,7 +704,7 @@ struct sk_buff *sk_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp) * Make sure that we have exactly size bytes * available to the caller, no more, no less. */ - skb->avail_size = size; + skb->reserved_tailroom = skb->end - skb->tail - size; return skb; } __kfree_skb(skb); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 921cbac..9bb7400 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1096,7 +1096,6 @@ static void __pskb_trim_head(struct sk_buff *skb, int len) eat = min_t(int, len, skb_headlen(skb)); if (eat) { __skb_pull(skb, eat); - skb->avail_size -= eat; len -= eat; if (!len) return; |