diff options
author | WANG Cong <xiyou.wangcong@gmail.com> | 2017-05-04 01:07:31 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-05-14 08:00:21 -0400 |
commit | ecbd3ed2ddfe5fbae4db6aa3a0903af479e0543d (patch) | |
tree | 278f138da83139c1d879da4d8277b63a38310f64 | |
parent | 5d8e07740c69fac6ebd6cc0657a41e561e50d124 (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.h | 1 | ||||
-rw-r--r-- | net/ipv6/addrconf.c | 2 | ||||
-rw-r--r-- | net/ipv6/route.c | 26 |
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, | |||
84 | struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, | 84 | struct 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 | ||
87 | void ip6_route_init_special_entries(void); | ||
87 | int ip6_route_init(void); | 88 | int ip6_route_init(void); |
88 | void ip6_route_cleanup(void); | 89 | void 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 | ||
3801 | void __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 | |||
3801 | int __init ip6_route_init(void) | 3816 | int __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; |