]>
Commit | Line | Data |
---|---|---|
8dced6ec GKH |
1 | From foo@baz Thu May 11 11:08:24 CEST 2017 |
2 | From: WANG Cong <xiyou.wangcong@gmail.com> | |
3 | Date: Wed, 3 May 2017 22:07:31 -0700 | |
4 | Subject: ipv6: initialize route null entry in addrconf_init() | |
5 | ||
6 | From: WANG Cong <xiyou.wangcong@gmail.com> | |
7 | ||
8 | ||
9 | [ Upstream commit 2f460933f58eee3393aba64f0f6d14acb08d1724 ] | |
10 | ||
11 | Andrey reported a crash on init_net.ipv6.ip6_null_entry->rt6i_idev | |
12 | since it is always NULL. | |
13 | ||
14 | This is clearly wrong, we have code to initialize it to loopback_dev, | |
15 | unfortunately the order is still not correct. | |
16 | ||
17 | loopback_dev is registered very early during boot, we lose a chance | |
18 | to re-initialize it in notifier. addrconf_init() is called after | |
19 | ip6_route_init(), which means we have no chance to correct it. | |
20 | ||
21 | Fix it by moving this initialization explicitly after | |
22 | ipv6_add_dev(init_net.loopback_dev) in addrconf_init(). | |
23 | ||
24 | Reported-by: Andrey Konovalov <andreyknvl@google.com> | |
25 | Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com> | |
26 | Tested-by: Andrey Konovalov <andreyknvl@google.com> | |
27 | Signed-off-by: David S. Miller <davem@davemloft.net> | |
28 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
29 | --- | |
30 | include/net/ip6_route.h | 1 + | |
31 | net/ipv6/addrconf.c | 2 ++ | |
32 | net/ipv6/route.c | 26 +++++++++++++++----------- | |
33 | 3 files changed, 18 insertions(+), 11 deletions(-) | |
34 | ||
35 | --- a/include/net/ip6_route.h | |
36 | +++ b/include/net/ip6_route.h | |
37 | @@ -84,6 +84,7 @@ struct dst_entry *ip6_route_lookup(struc | |
38 | struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, | |
39 | int ifindex, struct flowi6 *fl6, int flags); | |
40 | ||
41 | +void ip6_route_init_special_entries(void); | |
42 | int ip6_route_init(void); | |
43 | void ip6_route_cleanup(void); | |
44 | ||
45 | --- a/net/ipv6/addrconf.c | |
46 | +++ b/net/ipv6/addrconf.c | |
47 | @@ -6264,6 +6264,8 @@ int __init addrconf_init(void) | |
48 | goto errlo; | |
49 | } | |
50 | ||
51 | + ip6_route_init_special_entries(); | |
52 | + | |
53 | for (i = 0; i < IN6_ADDR_HSIZE; i++) | |
54 | INIT_HLIST_HEAD(&inet6_addr_lst[i]); | |
55 | ||
56 | --- a/net/ipv6/route.c | |
57 | +++ b/net/ipv6/route.c | |
58 | @@ -3798,6 +3798,21 @@ static struct notifier_block ip6_route_d | |
59 | .priority = 0, | |
60 | }; | |
61 | ||
62 | +void __init ip6_route_init_special_entries(void) | |
63 | +{ | |
64 | + /* Registering of the loopback is done before this portion of code, | |
65 | + * the loopback reference in rt6_info will not be taken, do it | |
66 | + * manually for init_net */ | |
67 | + init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev; | |
68 | + init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); | |
69 | + #ifdef CONFIG_IPV6_MULTIPLE_TABLES | |
70 | + init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev; | |
71 | + init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); | |
72 | + init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev; | |
73 | + init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); | |
74 | + #endif | |
75 | +} | |
76 | + | |
77 | int __init ip6_route_init(void) | |
78 | { | |
79 | int ret; | |
80 | @@ -3824,17 +3839,6 @@ int __init ip6_route_init(void) | |
81 | ||
82 | ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep; | |
83 | ||
84 | - /* Registering of the loopback is done before this portion of code, | |
85 | - * the loopback reference in rt6_info will not be taken, do it | |
86 | - * manually for init_net */ | |
87 | - init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev; | |
88 | - init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); | |
89 | - #ifdef CONFIG_IPV6_MULTIPLE_TABLES | |
90 | - init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev; | |
91 | - init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); | |
92 | - init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev; | |
93 | - init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); | |
94 | - #endif | |
95 | ret = fib6_init(); | |
96 | if (ret) | |
97 | goto out_register_subsys; |