]>
Commit | Line | Data |
---|---|---|
d6e9c606 GKH |
1 | From 2cbf892200d0d5bdc8e97ca8cfe6277c6f2a8ee2 Mon Sep 17 00:00:00 2001 |
2 | From: Eric Dumazet <edumazet@google.com> | |
3 | Date: Thu, 14 Mar 2013 05:40:32 +0000 | |
4 | Subject: tcp: fix skb_availroom() | |
5 | ||
6 | ||
7 | From: Eric Dumazet <edumazet@google.com> | |
8 | ||
9 | [ Upstream commit 16fad69cfe4adbbfa813de516757b87bcae36d93 ] | |
10 | ||
11 | Chrome OS team reported a crash on a Pixel ChromeBook in TCP stack : | |
12 | ||
13 | https://code.google.com/p/chromium/issues/detail?id=182056 | |
14 | ||
15 | commit a21d45726acac (tcp: avoid order-1 allocations on wifi and tx | |
16 | path) did a poor choice adding an 'avail_size' field to skb, while | |
17 | what we really needed was a 'reserved_tailroom' one. | |
18 | ||
19 | It would have avoided commit 22b4a4f22da (tcp: fix retransmit of | |
20 | partially acked frames) and this commit. | |
21 | ||
22 | Crash occurs because skb_split() is not aware of the 'avail_size' | |
23 | management (and should not be aware) | |
24 | ||
25 | Signed-off-by: Eric Dumazet <edumazet@google.com> | |
26 | Reported-by: Mukesh Agrawal <quiche@chromium.org> | |
27 | Signed-off-by: David S. Miller <davem@davemloft.net> | |
28 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
29 | --- | |
30 | include/linux/skbuff.h | 7 +++++-- | |
31 | net/ipv4/tcp.c | 2 +- | |
32 | net/ipv4/tcp_output.c | 1 - | |
33 | 3 files changed, 6 insertions(+), 4 deletions(-) | |
34 | ||
35 | --- a/include/linux/skbuff.h | |
36 | +++ b/include/linux/skbuff.h | |
37 | @@ -491,7 +491,7 @@ struct sk_buff { | |
38 | union { | |
39 | __u32 mark; | |
40 | __u32 dropcount; | |
41 | - __u32 avail_size; | |
42 | + __u32 reserved_tailroom; | |
43 | }; | |
44 | ||
45 | sk_buff_data_t inner_transport_header; | |
46 | @@ -1428,7 +1428,10 @@ static inline int skb_tailroom(const str | |
47 | */ | |
48 | static inline int skb_availroom(const struct sk_buff *skb) | |
49 | { | |
50 | - return skb_is_nonlinear(skb) ? 0 : skb->avail_size - skb->len; | |
51 | + if (skb_is_nonlinear(skb)) | |
52 | + return 0; | |
53 | + | |
54 | + return skb->end - skb->tail - skb->reserved_tailroom; | |
55 | } | |
56 | ||
57 | /** | |
58 | --- a/net/ipv4/tcp.c | |
59 | +++ b/net/ipv4/tcp.c | |
60 | @@ -773,7 +773,7 @@ struct sk_buff *sk_stream_alloc_skb(stru | |
61 | * Make sure that we have exactly size bytes | |
62 | * available to the caller, no more, no less. | |
63 | */ | |
64 | - skb->avail_size = size; | |
65 | + skb->reserved_tailroom = skb->end - skb->tail - size; | |
66 | return skb; | |
67 | } | |
68 | __kfree_skb(skb); | |
69 | --- a/net/ipv4/tcp_output.c | |
70 | +++ b/net/ipv4/tcp_output.c | |
71 | @@ -1298,7 +1298,6 @@ static void __pskb_trim_head(struct sk_b | |
72 | eat = min_t(int, len, skb_headlen(skb)); | |
73 | if (eat) { | |
74 | __skb_pull(skb, eat); | |
75 | - skb->avail_size -= eat; | |
76 | len -= eat; | |
77 | if (!len) | |
78 | return; |