Chuck Ebbert 4d20e68
From jasowang@redhat.com Sat Oct  8 20:56:54 2011
Chuck Ebbert 4d20e68
Subject: ipv6: fix NULL dereference in udp6_ufo_fragment()
Chuck Ebbert 4d20e68
To: gregkh@suse.de, stable@kernel.org
Chuck Ebbert 4d20e68
From: Jason Wang <jasowang@redhat.com>
Chuck Ebbert 4d20e68
Cc: davem@davemloft.net, eric.dumazet@gmail.com
Chuck Ebbert 4d20e68
Date: Sun, 09 Oct 2011 10:56:44 +0800
Chuck Ebbert 4d20e68
Message-ID: <20111009025644.9437.53281.stgit@dhcp-8-146.nay.redhat.com>
Chuck Ebbert 4d20e68
Chuck Ebbert 4d20e68
From: Jason Wang <jasowang@redhat.com>
Chuck Ebbert 4d20e68
Chuck Ebbert 4d20e68
This patch fixes the issue caused by ef81bb40bf15f350fe865f31fa42f1082772a576
Chuck Ebbert 4d20e68
which is a backport of upstream 87c48fa3b4630905f98268dde838ee43626a060c. The
Chuck Ebbert 4d20e68
problem does not exist in upstream.
Chuck Ebbert 4d20e68
Chuck Ebbert 4d20e68
We do not check whether route is attached before trying to assign ip
Chuck Ebbert 4d20e68
identification through route dest which lead NULL pointer dereference. This
Chuck Ebbert 4d20e68
happens when host bridge transmit a packet from guest.
Chuck Ebbert 4d20e68
Chuck Ebbert 4d20e68
This patch changes ipv6_select_ident() to accept in6_addr as its paramter and
Chuck Ebbert 4d20e68
fix the issue by using the destination address in ipv6 header when no route is
Chuck Ebbert 4d20e68
attached.
Chuck Ebbert 4d20e68
Chuck Ebbert 4d20e68
Signed-off-by: Jason Wang <jasowang@redhat.com>
Chuck Ebbert 4d20e68
Acked-by: David S. Miller <davem@davemloft.net>
Chuck Ebbert 4d20e68
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Chuck Ebbert 4d20e68
---
Chuck Ebbert 4d20e68
 include/net/ipv6.h    |    2 +-
Chuck Ebbert 4d20e68
 net/ipv6/ip6_output.c |   10 +++++-----
Chuck Ebbert 4d20e68
 net/ipv6/udp.c        |    4 +++-
Chuck Ebbert 4d20e68
 3 files changed, 9 insertions(+), 7 deletions(-)
Chuck Ebbert 4d20e68
Chuck Ebbert 4d20e68
--- a/include/net/ipv6.h
Chuck Ebbert 4d20e68
+++ b/include/net/ipv6.h
Chuck Ebbert 4d20e68
@@ -463,7 +463,7 @@ static inline int ipv6_addr_diff(const s
Chuck Ebbert 4d20e68
 	return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr));
Chuck Ebbert 4d20e68
 }
Chuck Ebbert 4d20e68
 
Chuck Ebbert 4d20e68
-extern void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt);
Chuck Ebbert 4d20e68
+extern void ipv6_select_ident(struct frag_hdr *fhdr, struct in6_addr *addr);
Chuck Ebbert 4d20e68
 
Chuck Ebbert 4d20e68
 /*
Chuck Ebbert 4d20e68
  *	Prototypes exported by ipv6
Chuck Ebbert 4d20e68
--- a/net/ipv6/ip6_output.c
Chuck Ebbert 4d20e68
+++ b/net/ipv6/ip6_output.c
Chuck Ebbert 4d20e68
@@ -620,9 +620,9 @@ static u32 __ipv6_select_ident(const str
Chuck Ebbert 4d20e68
 	return hash + newid;
Chuck Ebbert 4d20e68
 }
Chuck Ebbert 4d20e68
 
Chuck Ebbert 4d20e68
-void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)
Chuck Ebbert 4d20e68
+void ipv6_select_ident(struct frag_hdr *fhdr, struct in6_addr *addr)
Chuck Ebbert 4d20e68
 {
Chuck Ebbert 4d20e68
-	fhdr->identification = htonl(__ipv6_select_ident(&rt->rt6i_dst.addr));
Chuck Ebbert 4d20e68
+	fhdr->identification = htonl(__ipv6_select_ident(addr));
Chuck Ebbert 4d20e68
 }
Chuck Ebbert 4d20e68
 
Chuck Ebbert 4d20e68
 static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
Chuck Ebbert 4d20e68
@@ -709,7 +709,7 @@ int ip6_fragment(struct sk_buff *skb, in
Chuck Ebbert 4d20e68
 		skb_reset_network_header(skb);
Chuck Ebbert 4d20e68
 		memcpy(skb_network_header(skb), tmp_hdr, hlen);
Chuck Ebbert 4d20e68
 
Chuck Ebbert 4d20e68
-		ipv6_select_ident(fh, rt);
Chuck Ebbert 4d20e68
+		ipv6_select_ident(fh, &rt->rt6i_dst.addr);
Chuck Ebbert 4d20e68
 		fh->nexthdr = nexthdr;
Chuck Ebbert 4d20e68
 		fh->reserved = 0;
Chuck Ebbert 4d20e68
 		fh->frag_off = htons(IP6_MF);
Chuck Ebbert 4d20e68
@@ -855,7 +855,7 @@ slow_path:
Chuck Ebbert 4d20e68
 		fh->nexthdr = nexthdr;
Chuck Ebbert 4d20e68
 		fh->reserved = 0;
Chuck Ebbert 4d20e68
 		if (!frag_id) {
Chuck Ebbert 4d20e68
-			ipv6_select_ident(fh, rt);
Chuck Ebbert 4d20e68
+			ipv6_select_ident(fh, &rt->rt6i_dst.addr);
Chuck Ebbert 4d20e68
 			frag_id = fh->identification;
Chuck Ebbert 4d20e68
 		} else
Chuck Ebbert 4d20e68
 			fh->identification = frag_id;
Chuck Ebbert 4d20e68
@@ -1146,7 +1146,7 @@ static inline int ip6_ufo_append_data(st
Chuck Ebbert 4d20e68
 		skb_shinfo(skb)->gso_size = (mtu - fragheaderlen -
Chuck Ebbert 4d20e68
 					     sizeof(struct frag_hdr)) & ~7;
Chuck Ebbert 4d20e68
 		skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
Chuck Ebbert 4d20e68
-		ipv6_select_ident(&fhdr, rt);
Chuck Ebbert 4d20e68
+		ipv6_select_ident(&fhdr, &rt->rt6i_dst.addr);
Chuck Ebbert 4d20e68
 		skb_shinfo(skb)->ip6_frag_id = fhdr.identification;
Chuck Ebbert 4d20e68
 		__skb_queue_tail(&sk->sk_write_queue, skb);
Chuck Ebbert 4d20e68
 
Chuck Ebbert 4d20e68
--- a/net/ipv6/udp.c
Chuck Ebbert 4d20e68
+++ b/net/ipv6/udp.c
Chuck Ebbert 4d20e68
@@ -1309,6 +1309,7 @@ static struct sk_buff *udp6_ufo_fragment
Chuck Ebbert 4d20e68
 	u8 frag_hdr_sz = sizeof(struct frag_hdr);
Chuck Ebbert 4d20e68
 	int offset;
Chuck Ebbert 4d20e68
 	__wsum csum;
Chuck Ebbert 4d20e68
+	struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
Chuck Ebbert 4d20e68
 
Chuck Ebbert 4d20e68
 	mss = skb_shinfo(skb)->gso_size;
Chuck Ebbert 4d20e68
 	if (unlikely(skb->len <= mss))
Chuck Ebbert 4d20e68
@@ -1359,7 +1360,8 @@ static struct sk_buff *udp6_ufo_fragment
Chuck Ebbert 4d20e68
 	fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen);
Chuck Ebbert 4d20e68
 	fptr->nexthdr = nexthdr;
Chuck Ebbert 4d20e68
 	fptr->reserved = 0;
Chuck Ebbert 4d20e68
-	ipv6_select_ident(fptr, (struct rt6_info *)skb_dst(skb));
Chuck Ebbert 4d20e68
+	ipv6_select_ident(fptr,
Chuck Ebbert 4d20e68
+			  rt ? &rt->rt6i_dst.addr : &ipv6_hdr(skb)->daddr);
Chuck Ebbert 4d20e68
 
Chuck Ebbert 4d20e68
 	/* Fragment the skb. ipv6 header and the remaining fields of the
Chuck Ebbert 4d20e68
 	 * fragment header are updated in ipv6_gso_segment()