aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWANG Cong <xiyou.wangcong@gmail.com>2017-05-04 01:07:31 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-05-14 08:00:21 -0400
commitecbd3ed2ddfe5fbae4db6aa3a0903af479e0543d (patch)
tree278f138da83139c1d879da4d8277b63a38310f64
parent5d8e07740c69fac6ebd6cc0657a41e561e50d124 (diff)
ipv6: initialize route null entry in addrconf_init()
[ Upstream commit 2f460933f58eee3393aba64f0f6d14acb08d1724 ] 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: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--include/net/ip6_route.h1
-rw-r--r--net/ipv6/addrconf.c2
-rw-r--r--net/ipv6/route.c26
3 files changed, 18 insertions, 11 deletions
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index f83e78d071a3..2e347d4545cf 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -84,6 +84,7 @@ struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6,
84struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, 84struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
85 int ifindex, struct flowi6 *fl6, int flags); 85 int ifindex, struct flowi6 *fl6, int flags);
86 86
87void ip6_route_init_special_entries(void);
87int ip6_route_init(void); 88int ip6_route_init(void);
88void ip6_route_cleanup(void); 89void ip6_route_cleanup(void);
89 90
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index e0a083f49227..4d115b5cb231 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -6264,6 +6264,8 @@ int __init addrconf_init(void)
6264 goto errlo; 6264 goto errlo;
6265 } 6265 }
6266 6266
6267 ip6_route_init_special_entries();
6268
6267 for (i = 0; i < IN6_ADDR_HSIZE; i++) 6269 for (i = 0; i < IN6_ADDR_HSIZE; i++)
6268 INIT_HLIST_HEAD(&inet6_addr_lst[i]); 6270 INIT_HLIST_HEAD(&inet6_addr_lst[i]);
6269 6271
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 9f1bc756799a..57081bbf21d6 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -3798,6 +3798,21 @@ static struct notifier_block ip6_route_dev_notifier = {
3798 .priority = 0, 3798 .priority = 0,
3799}; 3799};
3800 3800
3801void __init ip6_route_init_special_entries(void)
3802{
3803 /* Registering of the loopback is done before this portion of code,
3804 * the loopback reference in rt6_info will not be taken, do it
3805 * manually for init_net */
3806 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
3807 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3808 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
3809 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
3810 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3811 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
3812 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3813 #endif
3814}
3815
3801int __init ip6_route_init(void) 3816int __init ip6_route_init(void)
3802{ 3817{
3803 int ret; 3818 int ret;
@@ -3824,17 +3839,6 @@ int __init ip6_route_init(void)
3824 3839
3825 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep; 3840 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
3826 3841
3827 /* Registering of the loopback is done before this portion of code,
3828 * the loopback reference in rt6_info will not be taken, do it
3829 * manually for init_net */
3830 init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
3831 init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3832 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
3833 init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
3834 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3835 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
3836 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
3837 #endif
3838 ret = fib6_init(); 3842 ret = fib6_init();
3839 if (ret) 3843 if (ret)
3840 goto out_register_subsys; 3844 goto out_register_subsys;