]> git.hungrycats.org Git - linux/commitdiff
inet: fix possible memory corruption with UDP_CORK and UFO
authorHannes Frederic Sowa <hannes@stressinduktion.org>
Mon, 21 Oct 2013 22:07:47 +0000 (00:07 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 4 Nov 2013 12:35:18 +0000 (04:35 -0800)
[ This is a simplified -stable version of a set of upstream commits. ]

This is a replacement patch only for stable which does fix the problems
handled by the following two commits in -net:

"ip_output: do skb ufo init for peeked non ufo skb as well" (e93b7d748be887cd7639b113ba7d7ef792a7efb9)
"ip6_output: do skb ufo init for peeked non ufo skb as well" (c547dbf55d5f8cf615ccc0e7265e98db27d3fb8b)

Three frames are written on a corked udp socket for which the output
netdevice has UFO enabled.  If the first and third frame are smaller than
the mtu and the second one is bigger, we enqueue the second frame with
skb_append_datato_frags without initializing the gso fields. This leads
to the third frame appended regulary and thus constructing an invalid skb.

This fixes the problem by always using skb_append_datato_frags as soon
as the first frag got enqueued to the skb without marking the packet
as SKB_GSO_UDP.

The problem with only two frames for ipv6 was fixed by "ipv6: udp
packets following an UFO enqueued packet need also be handled by UFO"
(2811ebac2521ceac84f2bdae402455baa6a7fb47).

Cc: Jiri Pirko <jiri@resnulli.us>
Cc: Eric Dumazet <eric.dumazet@gmail.com>
Cc: David Miller <davem@davemloft.net>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
include/linux/skbuff.h
net/ipv4/ip_output.c
net/ipv6/ip6_output.c

index 3b71a4e8364200d85afe94b120e09e74edf35d32..6bd165be52e3a81ae5f578059deceff43283c92d 100644 (file)
@@ -1316,6 +1316,11 @@ static inline int skb_pagelen(const struct sk_buff *skb)
        return len + skb_headlen(skb);
 }
 
+static inline bool skb_has_frags(const struct sk_buff *skb)
+{
+       return skb_shinfo(skb)->nr_frags;
+}
+
 /**
  * __skb_fill_page_desc - initialise a paged fragment in an skb
  * @skb: buffer containing fragment to be initialised
index a04d872c54f919c7133e7830773301cdf070f3ed..7f4ab5d31c162464759bc18043bcbf4b37738073 100644 (file)
@@ -836,7 +836,7 @@ static int __ip_append_data(struct sock *sk,
                csummode = CHECKSUM_PARTIAL;
 
        cork->length += length;
-       if (((length > mtu) || (skb && skb_is_gso(skb))) &&
+       if (((length > mtu) || (skb && skb_has_frags(skb))) &&
            (sk->sk_protocol == IPPROTO_UDP) &&
            (rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len) {
                err = ip_ufo_append_data(sk, queue, getfrag, from, length,
index 44df1c92a0d66d0fc6828e22d2e39bd9235a8ea6..2e542d0a8916a6e2d6a21c3497a35d7ba0756f4a 100644 (file)
@@ -1252,7 +1252,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
        skb = skb_peek_tail(&sk->sk_write_queue);
        cork->length += length;
        if (((length > mtu) ||
-            (skb && skb_is_gso(skb))) &&
+            (skb && skb_has_frags(skb))) &&
            (sk->sk_protocol == IPPROTO_UDP) &&
            (rt->dst.dev->features & NETIF_F_UFO)) {
                err = ip6_ufo_append_data(sk, getfrag, from, length,