]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/4.9.28/tcp-do-not-underestimate-skb-truesize-in-tcp_trim_head.patch
5.1-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 4.9.28 / tcp-do-not-underestimate-skb-truesize-in-tcp_trim_head.patch
CommitLineData
8dced6ec
GKH
1From foo@baz Thu May 11 11:08:24 CEST 2017
2From: Eric Dumazet <edumazet@google.com>
3Date: Wed, 26 Apr 2017 17:15:40 -0700
4Subject: tcp: do not underestimate skb->truesize in tcp_trim_head()
5
6From: Eric Dumazet <edumazet@google.com>
7
8
9[ Upstream commit 7162fb242cb8322beb558828fd26b33c3e9fc805 ]
10
11Andrey found a way to trigger the WARN_ON_ONCE(delta < len) in
12skb_try_coalesce() using syzkaller and a filter attached to a TCP
13socket over loopback interface.
14
15I believe one issue with looped skbs is that tcp_trim_head() can end up
16producing skb with under estimated truesize.
17
18It hardly matters for normal conditions, since packets sent over
19loopback are never truncated.
20
21Bytes trimmed from skb->head should not change skb truesize, since
22skb->head is not reallocated.
23
24Signed-off-by: Eric Dumazet <edumazet@google.com>
25Reported-by: Andrey Konovalov <andreyknvl@google.com>
26Tested-by: Andrey Konovalov <andreyknvl@google.com>
27Signed-off-by: David S. Miller <davem@davemloft.net>
28Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
29---
30 net/ipv4/tcp_output.c | 19 ++++++++++++-------
31 1 file changed, 12 insertions(+), 7 deletions(-)
32
33--- a/net/ipv4/tcp_output.c
34+++ b/net/ipv4/tcp_output.c
35@@ -1246,7 +1246,7 @@ int tcp_fragment(struct sock *sk, struct
36 * eventually). The difference is that pulled data not copied, but
37 * immediately discarded.
38 */
39-static void __pskb_trim_head(struct sk_buff *skb, int len)
40+static int __pskb_trim_head(struct sk_buff *skb, int len)
41 {
42 struct skb_shared_info *shinfo;
43 int i, k, eat;
44@@ -1256,7 +1256,7 @@ static void __pskb_trim_head(struct sk_b
45 __skb_pull(skb, eat);
46 len -= eat;
47 if (!len)
48- return;
49+ return 0;
50 }
51 eat = len;
52 k = 0;
53@@ -1282,23 +1282,28 @@ static void __pskb_trim_head(struct sk_b
54 skb_reset_tail_pointer(skb);
55 skb->data_len -= len;
56 skb->len = skb->data_len;
57+ return len;
58 }
59
60 /* Remove acked data from a packet in the transmit queue. */
61 int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len)
62 {
63+ u32 delta_truesize;
64+
65 if (skb_unclone(skb, GFP_ATOMIC))
66 return -ENOMEM;
67
68- __pskb_trim_head(skb, len);
69+ delta_truesize = __pskb_trim_head(skb, len);
70
71 TCP_SKB_CB(skb)->seq += len;
72 skb->ip_summed = CHECKSUM_PARTIAL;
73
74- skb->truesize -= len;
75- sk->sk_wmem_queued -= len;
76- sk_mem_uncharge(sk, len);
77- sock_set_flag(sk, SOCK_QUEUE_SHRUNK);
78+ if (delta_truesize) {
79+ skb->truesize -= delta_truesize;
80+ sk->sk_wmem_queued -= delta_truesize;
81+ sk_mem_uncharge(sk, delta_truesize);
82+ sock_set_flag(sk, SOCK_QUEUE_SHRUNK);
83+ }
84
85 /* Any change of skb->len requires recalculation of tso factor. */
86 if (tcp_skb_pcount(skb) > 1)