aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2013-03-14 05:40:32 +0000
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-03-28 12:11:53 -0700
commitb6da578e2a610a64e89f2a983f7675eb301c5d35 (patch)
treee9a01ac902578dcb3c0cca6b9126e294d02942a7
parent6a2d122cdd939e33279baf351c7cbf12c50eaeb5 (diff)
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: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-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 c1bae8dff77..4aea870cc1a 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -479,7 +479,7 @@ struct sk_buff {
union {
__u32 mark;
__u32 dropcount;
- __u32 avail_size;
+ __u32 reserved_tailroom;
};
sk_buff_data_t transport_header;
@@ -1373,7 +1373,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 01870bd2919..dcb19f59376 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 2d27e1af930..952f7dd8d51 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;