diff options
Diffstat (limited to 'main/linux-grsec/ipv6-udp-packets-following-an-UFO-enqueued-packet-needs-al.patch')
-rw-r--r-- | main/linux-grsec/ipv6-udp-packets-following-an-UFO-enqueued-packet-needs-al.patch | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/main/linux-grsec/ipv6-udp-packets-following-an-UFO-enqueued-packet-needs-al.patch b/main/linux-grsec/ipv6-udp-packets-following-an-UFO-enqueued-packet-needs-al.patch new file mode 100644 index 0000000000..a98faca44e --- /dev/null +++ b/main/linux-grsec/ipv6-udp-packets-following-an-UFO-enqueued-packet-needs-al.patch @@ -0,0 +1,118 @@ +From 2811ebac2521ceac84f2bdae402455baa6a7fb47 Mon Sep 17 00:00:00 2001 +From: Hannes Frederic Sowa <hannes@stressinduktion.org> +Date: Sat, 21 Sep 2013 04:27:00 +0000 +Subject: ipv6: udp packets following an UFO enqueued packet need also be handled by UFO + +In the following scenario the socket is corked: +If the first UDP packet is larger then the mtu we try to append it to the +write queue via ip6_ufo_append_data. A following packet, which is smaller +than the mtu would be appended to the already queued up gso-skb via +plain ip6_append_data. This causes random memory corruptions. + +In ip6_ufo_append_data we also have to be careful to not queue up the +same skb multiple times. So setup the gso frame only when no first skb +is available. + +This also fixes a shortcoming where we add the current packet's length to +cork->length but return early because of a packet > mtu with dontfrag set +(instead of sutracting it again). + +Found with trinity. + +Cc: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> +Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org> +Reported-by: Dmitry Vyukov <dvyukov@google.com> +Signed-off-by: David S. Miller <davem@davemloft.net> +--- +diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c +index 3a692d5..a54c45c 100644 +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -1015,6 +1015,8 @@ static inline int ip6_ufo_append_data(struct sock *sk, + * udp datagram + */ + if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) { ++ struct frag_hdr fhdr; ++ + skb = sock_alloc_send_skb(sk, + hh_len + fragheaderlen + transhdrlen + 20, + (flags & MSG_DONTWAIT), &err); +@@ -1036,12 +1038,6 @@ static inline int ip6_ufo_append_data(struct sock *sk, + skb->protocol = htons(ETH_P_IPV6); + skb->ip_summed = CHECKSUM_PARTIAL; + skb->csum = 0; +- } +- +- err = skb_append_datato_frags(sk,skb, getfrag, from, +- (length - transhdrlen)); +- if (!err) { +- struct frag_hdr fhdr; + + /* Specify the length of each IPv6 datagram fragment. + * It has to be a multiple of 8. +@@ -1052,15 +1048,10 @@ static inline int ip6_ufo_append_data(struct sock *sk, + ipv6_select_ident(&fhdr, rt); + skb_shinfo(skb)->ip6_frag_id = fhdr.identification; + __skb_queue_tail(&sk->sk_write_queue, skb); +- +- return 0; + } +- /* There is not enough support do UPD LSO, +- * so follow normal path +- */ +- kfree_skb(skb); + +- return err; ++ return skb_append_datato_frags(sk, skb, getfrag, from, ++ (length - transhdrlen)); + } + + static inline struct ipv6_opt_hdr *ip6_opt_dup(struct ipv6_opt_hdr *src, +@@ -1227,27 +1218,27 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, + * --yoshfuji + */ + +- cork->length += length; +- if (length > mtu) { +- int proto = sk->sk_protocol; +- if (dontfrag && (proto == IPPROTO_UDP || proto == IPPROTO_RAW)){ +- ipv6_local_rxpmtu(sk, fl6, mtu-exthdrlen); +- return -EMSGSIZE; +- } +- +- if (proto == IPPROTO_UDP && +- (rt->dst.dev->features & NETIF_F_UFO)) { ++ if ((length > mtu) && dontfrag && (sk->sk_protocol == IPPROTO_UDP || ++ sk->sk_protocol == IPPROTO_RAW)) { ++ ipv6_local_rxpmtu(sk, fl6, mtu-exthdrlen); ++ return -EMSGSIZE; ++ } + +- err = ip6_ufo_append_data(sk, getfrag, from, length, +- hh_len, fragheaderlen, +- transhdrlen, mtu, flags, rt); +- if (err) +- goto error; +- return 0; +- } ++ skb = skb_peek_tail(&sk->sk_write_queue); ++ cork->length += length; ++ if (((length > mtu) || ++ (skb && skb_is_gso(skb))) && ++ (sk->sk_protocol == IPPROTO_UDP) && ++ (rt->dst.dev->features & NETIF_F_UFO)) { ++ err = ip6_ufo_append_data(sk, getfrag, from, length, ++ hh_len, fragheaderlen, ++ transhdrlen, mtu, flags, rt); ++ if (err) ++ goto error; ++ return 0; + } + +- if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) ++ if (!skb) + goto alloc_new_skb; + + while (length > 0) { +-- +cgit v0.9.2 |