diff --git a/ipv6-udp-packets-following-an-UFO-enqueued-packet-ne.patch b/ipv6-udp-packets-following-an-UFO-enqueued-packet-ne.patch new file mode 100644 index 0000000..9310e05 --- /dev/null +++ b/ipv6-udp-packets-following-an-UFO-enqueued-packet-ne.patch @@ -0,0 +1,123 @@ +From 2811ebac2521ceac84f2bdae402455baa6a7fb47 Mon Sep 17 00:00:00 2001 +From: Hannes Frederic Sowa +Date: Sat, 21 Sep 2013 06:27:00 +0200 +Subject: [PATCH] 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 +Signed-off-by: Hannes Frederic Sowa +Reported-by: Dmitry Vyukov +Signed-off-by: David S. Miller +--- + net/ipv6/ip6_output.c | 53 +++++++++++++++++++++------------------------------ + 1 file changed, 22 insertions(+), 31 deletions(-) + +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) { +-- +1.8.3.1 + diff --git a/kernel.spec b/kernel.spec index f5c2a1a..5d52aef 100644 --- a/kernel.spec +++ b/kernel.spec @@ -795,6 +795,9 @@ Patch25115: elevator-acquire-q-sysfs_lock-in-elevator_change.patch #rhbz 1013000 Patch25116: HID-Revert-Revert-HID-Fix-logitech-dj-missing-Unifying-device-issue.patch +#CVE-2013-4387 rhbz 1011927 1015166 +Patch25121: ipv6-udp-packets-following-an-UFO-enqueued-packet-ne.patch + # END OF PATCH DEFINITIONS %endif @@ -1525,6 +1528,9 @@ ApplyPatch elevator-acquire-q-sysfs_lock-in-elevator_change.patch #rhbz 1013000 ApplyPatch HID-Revert-Revert-HID-Fix-logitech-dj-missing-Unifying-device-issue.patch +#CVE-2013-4387 rhbz 1011927 1015166 +ApplyPatch ipv6-udp-packets-following-an-UFO-enqueued-packet-ne.patch + # END OF PATCH APPLICATIONS %endif @@ -2366,6 +2372,9 @@ fi # ||----w | # || || %changelog +* Thu Oct 3 2013 Josh Boyer +- CVE-2013-4387 ipv6: panic when UFO=On for an interface (rhbz 1011927 1015166) + * Mon Sep 30 2013 Josh Boyer - Drop VC_MUTE patch (rhbz 859485)