]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
ipv6: fix NULL dereference in udp6_ufo_fragment()
authorJason Wang <jasowang@redhat.com>
Sun, 9 Oct 2011 02:56:44 +0000 (10:56 +0800)
committerGreg Kroah-Hartman <gregkh@suse.de>
Sun, 16 Oct 2011 21:14:54 +0000 (14:14 -0700)
This patch fixes the issue caused by ef81bb40bf15f350fe865f31fa42f1082772a576
which is a backport of upstream 87c48fa3b4630905f98268dde838ee43626a060c. The
problem does not exist in upstream.

We do not check whether route is attached before trying to assign ip
identification through route dest which lead NULL pointer dereference. This
happens when host bridge transmit a packet from guest.

This patch changes ipv6_select_ident() to accept in6_addr as its paramter and
fix the issue by using the destination address in ipv6 header when no route is
attached.

Signed-off-by: Jason Wang <jasowang@redhat.com>
Acked-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
include/net/ipv6.h
net/ipv6/ip6_output.c
net/ipv6/udp.c

index 3b5ac1fbff39f50c51e55b07bd743172d1a9e0e5..c39121f6bc940d10d02214f2975d05f630e2b7f1 100644 (file)
@@ -463,7 +463,7 @@ static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_add
        return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr));
 }
 
-extern void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt);
+extern void ipv6_select_ident(struct frag_hdr *fhdr, struct in6_addr *addr);
 
 /*
  *     Prototypes exported by ipv6
index 16612968aaaf2f36959d49d10642b204f3778ce5..e17596b8407aaacce155b12890d2bae4ae669b00 100644 (file)
@@ -620,9 +620,9 @@ static u32 __ipv6_select_ident(const struct in6_addr *addr)
        return hash + newid;
 }
 
-void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)
+void ipv6_select_ident(struct frag_hdr *fhdr, struct in6_addr *addr)
 {
-       fhdr->identification = htonl(__ipv6_select_ident(&rt->rt6i_dst.addr));
+       fhdr->identification = htonl(__ipv6_select_ident(addr));
 }
 
 int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
@@ -709,7 +709,7 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
                skb_reset_network_header(skb);
                memcpy(skb_network_header(skb), tmp_hdr, hlen);
 
-               ipv6_select_ident(fh, rt);
+               ipv6_select_ident(fh, &rt->rt6i_dst.addr);
                fh->nexthdr = nexthdr;
                fh->reserved = 0;
                fh->frag_off = htons(IP6_MF);
@@ -855,7 +855,7 @@ slow_path:
                fh->nexthdr = nexthdr;
                fh->reserved = 0;
                if (!frag_id) {
-                       ipv6_select_ident(fh, rt);
+                       ipv6_select_ident(fh, &rt->rt6i_dst.addr);
                        frag_id = fh->identification;
                } else
                        fh->identification = frag_id;
@@ -1146,7 +1146,7 @@ static inline int ip6_ufo_append_data(struct sock *sk,
                skb_shinfo(skb)->gso_size = (mtu - fragheaderlen -
                                             sizeof(struct frag_hdr)) & ~7;
                skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
-               ipv6_select_ident(&fhdr, rt);
+               ipv6_select_ident(&fhdr, &rt->rt6i_dst.addr);
                skb_shinfo(skb)->ip6_frag_id = fhdr.identification;
                __skb_queue_tail(&sk->sk_write_queue, skb);
 
index 29213b51c4998e09a79f60fd534015269da54570..0d920c58de6afc31597c73b425bcbba0371b2a73 100644 (file)
@@ -1309,6 +1309,7 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, u32 features)
        u8 frag_hdr_sz = sizeof(struct frag_hdr);
        int offset;
        __wsum csum;
+       struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
 
        mss = skb_shinfo(skb)->gso_size;
        if (unlikely(skb->len <= mss))
@@ -1359,7 +1360,8 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, u32 features)
        fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen);
        fptr->nexthdr = nexthdr;
        fptr->reserved = 0;
-       ipv6_select_ident(fptr, (struct rt6_info *)skb_dst(skb));
+       ipv6_select_ident(fptr,
+                         rt ? &rt->rt6i_dst.addr : &ipv6_hdr(skb)->daddr);
 
        /* Fragment the skb. ipv6 header and the remaining fields of the
         * fragment header are updated in ipv6_gso_segment()