[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#804293: linux-image-4.2.0-1-amd64: Crash in ip6_datagram_connect



Control: tags -1 patch

On Wed, Dec 02 2015, Gerald Turner wrote:
> Sadly this too crashed, however at least it was a different crash!

Oooh found it!

This last oops I got after peeling off a few commits was reported in the
kernel.org bug tracking system:

  https://bugzilla.kernel.org/show_bug.cgi?id=106611

Martin KaFai Lau responded saying that there are fixes in the 4.3
kernel:

  > There is a fix related to 8d0b94afdca84598912347e61defa846a0988d04
  > in 4.2.5:
  >   58d772c ipv6: Don't call with rt6_uncached_list_flush_dev
  >
  > Also, there is a ipsec related fix for ipv6 which is currently in
  > 4.3:
  >   ebfa45f ipv6: Move common init code for rt6_info to a new function
  > rt6_info_init()
  >   0a1f596 ipv6: Initialize rt6_info properly in
  > ip6_blackhole_route()
  >
  > Can you give 4.3 a try?

Indeed.  I built 4.2.6 with commits ebfa45f and 0a1f596 cherry picked.
No more crashes!

I must've been really lucky identifying the ipv6_route_sharing merge as
being the culprit, or maybe I did something smart, but either way, I
should've spent more time scouring bugzilla.k.o rather than burn ~20
hours bisecting and cargo-culting commits ;-)

What's the likeliness that stretch will be released with a >=4.3 kernel,
or that linux-stable will be updated with a 4.2.7 that cherry picks
these patches?

-- 
Gerald Turner <gturner@unzane.com>        Encrypted mail preferred!
OpenPGP: 4096R / CA89 B27A 30FA 66C5 1B80  3858 EC94 2276 FDB8 716D
commit ebfa45f0d952e5e7bb30a7f9daaad681de138728
Author: Martin KaFai Lau <kafai@fb.com>
Date:   Thu Oct 15 16:39:57 2015 -0700

    ipv6: Move common init code for rt6_info to a new function rt6_info_init()
    
    Introduce rt6_info_init() to do the common init work for
    'struct rt6_info' (after calling dst_alloc).
    
    It is a prep work to fix the rt6_info init logic in the
    ip6_blackhole_route().
    
    Signed-off-by: Martin KaFai Lau <kafai@fb.com>
    Cc: Hannes Frederic Sowa <hannes@stressinduktion.org>
    Cc: Julian Anastasov <ja@ssi.bg>
    Cc: Phil Sutter <phil@nwl.cc>
    Cc: Steffen Klassert <steffen.klassert@secunet.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index ed04e29..4198017 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -319,6 +319,15 @@ static const struct rt6_info ip6_blk_hole_entry_template = {
 
 #endif
 
+static void rt6_info_init(struct rt6_info *rt)
+{
+	struct dst_entry *dst = &rt->dst;
+
+	memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst));
+	INIT_LIST_HEAD(&rt->rt6i_siblings);
+	INIT_LIST_HEAD(&rt->rt6i_uncached);
+}
+
 /* allocate dst with ip6_dst_ops */
 static struct rt6_info *__ip6_dst_alloc(struct net *net,
 					struct net_device *dev,
@@ -327,13 +336,9 @@ static struct rt6_info *__ip6_dst_alloc(struct net *net,
 	struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
 					0, DST_OBSOLETE_FORCE_CHK, flags);
 
-	if (rt) {
-		struct dst_entry *dst = &rt->dst;
+	if (rt)
+		rt6_info_init(rt);
 
-		memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst));
-		INIT_LIST_HEAD(&rt->rt6i_siblings);
-		INIT_LIST_HEAD(&rt->rt6i_uncached);
-	}
 	return rt;
 }
 
commit 0a1f59620068fb82a2e2aded202e62f4bb856d52
Author: Martin KaFai Lau <kafai@fb.com>
Date:   Thu Oct 15 16:39:58 2015 -0700

    ipv6: Initialize rt6_info properly in ip6_blackhole_route()
    
    ip6_blackhole_route() does not initialize the newly allocated
    rt6_info properly.  This patch:
    1. Call rt6_info_init() to initialize rt6i_siblings and rt6i_uncached
    
    2. The current rt->dst._metrics init code is incorrect:
       - 'rt->dst._metrics = ort->dst._metris' is not always safe
       - Not sure what dst_copy_metrics() is trying to do here
         considering ip6_rt_blackhole_cow_metrics() always returns
         NULL
    
       Fix:
       - Always do dst_copy_metrics()
       - Replace ip6_rt_blackhole_cow_metrics() with
         dst_cow_metrics_generic()
    
    3. Mask out the RTF_PCPU bit from the newly allocated blackhole route.
       This bug triggers an oops (reported by Phil Sutter) in rt6_get_cookie().
       It is because RTF_PCPU is set while rt->dst.from is NULL.
    
    Fixes: d52d3997f843 ("ipv6: Create percpu rt6_info")
    Signed-off-by: Martin KaFai Lau <kafai@fb.com>
    Reported-by: Phil Sutter <phil@nwl.cc>
    Tested-by: Phil Sutter <phil@nwl.cc>
    Cc: Hannes Frederic Sowa <hannes@stressinduktion.org>
    Cc: Julian Anastasov <ja@ssi.bg>
    Cc: Phil Sutter <phil@nwl.cc>
    Cc: Steffen Klassert <steffen.klassert@secunet.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 4198017..968f31c 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -248,12 +248,6 @@ static void ip6_rt_blackhole_redirect(struct dst_entry *dst, struct sock *sk,
 {
 }
 
-static u32 *ip6_rt_blackhole_cow_metrics(struct dst_entry *dst,
-					 unsigned long old)
-{
-	return NULL;
-}
-
 static struct dst_ops ip6_dst_blackhole_ops = {
 	.family			=	AF_INET6,
 	.destroy		=	ip6_dst_destroy,
@@ -262,7 +256,7 @@ static struct dst_ops ip6_dst_blackhole_ops = {
 	.default_advmss		=	ip6_default_advmss,
 	.update_pmtu		=	ip6_rt_blackhole_update_pmtu,
 	.redirect		=	ip6_rt_blackhole_redirect,
-	.cow_metrics		=	ip6_rt_blackhole_cow_metrics,
+	.cow_metrics		=	dst_cow_metrics_generic,
 	.neigh_lookup		=	ip6_neigh_lookup,
 };
 
@@ -1219,24 +1213,20 @@ struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_ori
 
 	rt = dst_alloc(&ip6_dst_blackhole_ops, ort->dst.dev, 1, DST_OBSOLETE_NONE, 0);
 	if (rt) {
-		new = &rt->dst;
-
-		memset(new + 1, 0, sizeof(*rt) - sizeof(*new));
+		rt6_info_init(rt);
 
+		new = &rt->dst;
 		new->__use = 1;
 		new->input = dst_discard;
 		new->output = dst_discard_sk;
 
-		if (dst_metrics_read_only(&ort->dst))
-			new->_metrics = ort->dst._metrics;
-		else
-			dst_copy_metrics(new, &ort->dst);
+		dst_copy_metrics(new, &ort->dst);
 		rt->rt6i_idev = ort->rt6i_idev;
 		if (rt->rt6i_idev)
 			in6_dev_hold(rt->rt6i_idev);
 
 		rt->rt6i_gateway = ort->rt6i_gateway;
-		rt->rt6i_flags = ort->rt6i_flags;
+		rt->rt6i_flags = ort->rt6i_flags & ~RTF_PCPU;
 		rt->rt6i_metric = 0;
 
 		memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));

Attachment: signature.asc
Description: PGP signature


Reply to: