]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/3.10.16/ipv6-udp-packets-following-an-ufo-enqueued-packet-need-also-be-handled-by-ufo.patch
Linux 4.14.95
[thirdparty/kernel/stable-queue.git] / releases / 3.10.16 / ipv6-udp-packets-following-an-ufo-enqueued-packet-need-also-be-handled-by-ufo.patch
1 From f8ed28cb5503ae2f8dd14f12d7e84063414b81bc Mon Sep 17 00:00:00 2001
2 From: Hannes Frederic Sowa <hannes@stressinduktion.org>
3 Date: Sat, 21 Sep 2013 06:27:00 +0200
4 Subject: ipv6: udp packets following an UFO enqueued packet need also be handled by UFO
5
6 From: Hannes Frederic Sowa <hannes@stressinduktion.org>
7
8 [ Upstream commit 2811ebac2521ceac84f2bdae402455baa6a7fb47 ]
9
10 In the following scenario the socket is corked:
11 If the first UDP packet is larger then the mtu we try to append it to the
12 write queue via ip6_ufo_append_data. A following packet, which is smaller
13 than the mtu would be appended to the already queued up gso-skb via
14 plain ip6_append_data. This causes random memory corruptions.
15
16 In ip6_ufo_append_data we also have to be careful to not queue up the
17 same skb multiple times. So setup the gso frame only when no first skb
18 is available.
19
20 This also fixes a shortcoming where we add the current packet's length to
21 cork->length but return early because of a packet > mtu with dontfrag set
22 (instead of sutracting it again).
23
24 Found with trinity.
25
26 Cc: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
27 Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
28 Reported-by: Dmitry Vyukov <dvyukov@google.com>
29 Signed-off-by: David S. Miller <davem@davemloft.net>
30 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
31 ---
32 net/ipv6/ip6_output.c | 53 ++++++++++++++++++++------------------------------
33 1 file changed, 22 insertions(+), 31 deletions(-)
34
35 --- a/net/ipv6/ip6_output.c
36 +++ b/net/ipv6/ip6_output.c
37 @@ -1039,6 +1039,8 @@ static inline int ip6_ufo_append_data(st
38 * udp datagram
39 */
40 if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) {
41 + struct frag_hdr fhdr;
42 +
43 skb = sock_alloc_send_skb(sk,
44 hh_len + fragheaderlen + transhdrlen + 20,
45 (flags & MSG_DONTWAIT), &err);
46 @@ -1059,12 +1061,6 @@ static inline int ip6_ufo_append_data(st
47
48 skb->ip_summed = CHECKSUM_PARTIAL;
49 skb->csum = 0;
50 - }
51 -
52 - err = skb_append_datato_frags(sk,skb, getfrag, from,
53 - (length - transhdrlen));
54 - if (!err) {
55 - struct frag_hdr fhdr;
56
57 /* Specify the length of each IPv6 datagram fragment.
58 * It has to be a multiple of 8.
59 @@ -1075,15 +1071,10 @@ static inline int ip6_ufo_append_data(st
60 ipv6_select_ident(&fhdr, rt);
61 skb_shinfo(skb)->ip6_frag_id = fhdr.identification;
62 __skb_queue_tail(&sk->sk_write_queue, skb);
63 -
64 - return 0;
65 }
66 - /* There is not enough support do UPD LSO,
67 - * so follow normal path
68 - */
69 - kfree_skb(skb);
70
71 - return err;
72 + return skb_append_datato_frags(sk, skb, getfrag, from,
73 + (length - transhdrlen));
74 }
75
76 static inline struct ipv6_opt_hdr *ip6_opt_dup(struct ipv6_opt_hdr *src,
77 @@ -1250,27 +1241,27 @@ int ip6_append_data(struct sock *sk, int
78 * --yoshfuji
79 */
80
81 - cork->length += length;
82 - if (length > mtu) {
83 - int proto = sk->sk_protocol;
84 - if (dontfrag && (proto == IPPROTO_UDP || proto == IPPROTO_RAW)){
85 - ipv6_local_rxpmtu(sk, fl6, mtu-exthdrlen);
86 - return -EMSGSIZE;
87 - }
88 -
89 - if (proto == IPPROTO_UDP &&
90 - (rt->dst.dev->features & NETIF_F_UFO)) {
91 + if ((length > mtu) && dontfrag && (sk->sk_protocol == IPPROTO_UDP ||
92 + sk->sk_protocol == IPPROTO_RAW)) {
93 + ipv6_local_rxpmtu(sk, fl6, mtu-exthdrlen);
94 + return -EMSGSIZE;
95 + }
96
97 - err = ip6_ufo_append_data(sk, getfrag, from, length,
98 - hh_len, fragheaderlen,
99 - transhdrlen, mtu, flags, rt);
100 - if (err)
101 - goto error;
102 - return 0;
103 - }
104 + skb = skb_peek_tail(&sk->sk_write_queue);
105 + cork->length += length;
106 + if (((length > mtu) ||
107 + (skb && skb_is_gso(skb))) &&
108 + (sk->sk_protocol == IPPROTO_UDP) &&
109 + (rt->dst.dev->features & NETIF_F_UFO)) {
110 + err = ip6_ufo_append_data(sk, getfrag, from, length,
111 + hh_len, fragheaderlen,
112 + transhdrlen, mtu, flags, rt);
113 + if (err)
114 + goto error;
115 + return 0;
116 }
117
118 - if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL)
119 + if (!skb)
120 goto alloc_new_skb;
121
122 while (length > 0) {