]> git.hungrycats.org Git - linux/commitdiff
ipv6: initialize route null entry in addrconf_init()
authorWANG Cong <xiyou.wangcong@gmail.com>
Thu, 4 May 2017 05:07:31 +0000 (22:07 -0700)
committerBen Hutchings <ben@decadent.org.uk>
Fri, 15 Sep 2017 17:30:14 +0000 (18:30 +0100)
commit 2f460933f58eee3393aba64f0f6d14acb08d1724 upstream.

Andrey reported a crash on init_net.ipv6.ip6_null_entry->rt6i_idev
since it is always NULL.

This is clearly wrong, we have code to initialize it to loopback_dev,
unfortunately the order is still not correct.

loopback_dev is registered very early during boot, we lose a chance
to re-initialize it in notifier. addrconf_init() is called after
ip6_route_init(), which means we have no chance to correct it.

Fix it by moving this initialization explicitly after
ipv6_add_dev(init_net.loopback_dev) in addrconf_init().

Reported-by: Andrey Konovalov <andreyknvl@google.com>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Tested-by: Andrey Konovalov <andreyknvl@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
include/net/ip6_route.h
net/ipv6/addrconf.c
net/ipv6/route.c

index eda131d179d971147f5b7ac254876dbf07946861..2e765849ccd6b3833d5c689eea96155511807876 100644 (file)
@@ -69,6 +69,7 @@ struct dst_entry *ip6_route_output(struct net *net, const struct sock *sk,
 struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6,
                                   int flags);
 
+void ip6_route_init_special_entries(void);
 int ip6_route_init(void);
 void ip6_route_cleanup(void);
 
index cd12b63faf109ea21b43deb7fbdc87e12437b6a8..e0ec0c32df763bdd07cf9f8f67259d8ec349b89a 100644 (file)
@@ -5382,6 +5382,8 @@ int __init addrconf_init(void)
        if (err)
                goto errlo;
 
+       ip6_route_init_special_entries();
+
        for (i = 0; i < IN6_ADDR_HSIZE; i++)
                INIT_HLIST_HEAD(&inet6_addr_lst[i]);
 
index 54e60b4208304ca3d5c8068506e51ecd06454ad7..29c4be84ec81c0eb95b71fd7e9a6e63ff745707c 100644 (file)
@@ -3141,6 +3141,21 @@ static struct notifier_block ip6_route_dev_notifier = {
        .priority = 0,
 };
 
+void __init ip6_route_init_special_entries(void)
+{
+       /* Registering of the loopback is done before this portion of code,
+        * the loopback reference in rt6_info will not be taken, do it
+        * manually for init_net */
+       init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
+       init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
+  #ifdef CONFIG_IPV6_MULTIPLE_TABLES
+       init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
+       init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
+       init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
+       init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
+  #endif
+}
+
 int __init ip6_route_init(void)
 {
        int ret;
@@ -3166,17 +3181,6 @@ int __init ip6_route_init(void)
 
        ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
 
-       /* Registering of the loopback is done before this portion of code,
-        * the loopback reference in rt6_info will not be taken, do it
-        * manually for init_net */
-       init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
-       init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
-  #ifdef CONFIG_IPV6_MULTIPLE_TABLES
-       init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
-       init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
-       init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
-       init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
-  #endif
        ret = fib6_init();
        if (ret)
                goto out_register_subsys;