| From foo@baz Thu May 11 11:08:24 CEST 2017 |
| From: WANG Cong <xiyou.wangcong@gmail.com> |
| Date: Wed, 3 May 2017 22:07:31 -0700 |
| Subject: ipv6: initialize route null entry in addrconf_init() |
| |
| From: WANG Cong <xiyou.wangcong@gmail.com> |
| |
| |
| [ 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> |
| --- |
| include/net/ip6_route.h | 1 + |
| net/ipv6/addrconf.c | 2 ++ |
| net/ipv6/route.c | 26 +++++++++++++++----------- |
| 3 files changed, 18 insertions(+), 11 deletions(-) |
| |
| --- a/include/net/ip6_route.h |
| +++ b/include/net/ip6_route.h |
| @@ -84,6 +84,7 @@ struct dst_entry *ip6_route_lookup(struc |
| struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, |
| int ifindex, struct flowi6 *fl6, int flags); |
| |
| +void ip6_route_init_special_entries(void); |
| int ip6_route_init(void); |
| void ip6_route_cleanup(void); |
| |
| --- a/net/ipv6/addrconf.c |
| +++ b/net/ipv6/addrconf.c |
| @@ -6264,6 +6264,8 @@ int __init addrconf_init(void) |
| goto errlo; |
| } |
| |
| + ip6_route_init_special_entries(); |
| + |
| for (i = 0; i < IN6_ADDR_HSIZE; i++) |
| INIT_HLIST_HEAD(&inet6_addr_lst[i]); |
| |
| --- a/net/ipv6/route.c |
| +++ b/net/ipv6/route.c |
| @@ -3798,6 +3798,21 @@ static struct notifier_block ip6_route_d |
| .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; |
| @@ -3824,17 +3839,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; |