aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2012-06-18 08:08:33 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-07-16 11:47:37 -0400
commit5eceb057268c275e8193a03ed159bf540038feac (patch)
treeb6ffd2d8578febb613c69ef38a6267ba9189a357 /net/ipv6
parent76886430203577bfa3b437630058aa0346cb3168 (diff)
ipv6: Move ipv6 proc file registration to end of init order
[ Upstream commit d189634ecab947c10f6f832258b103d0bbfe73cc ] /proc/net/ipv6_route reflects the contents of fib_table_hash. The proc handler is installed in ip6_route_net_init() whereas fib_table_hash is allocated in fib6_net_init() _after_ the proc handler has been installed. This opens up a short time frame to access fib_table_hash with its pants down. Move the registration of the proc files to a later point in the init order to avoid the race. Tested :-) Signed-off-by: Thomas Graf <tgraf@suug.ch> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/route.c41
1 files changed, 31 insertions, 10 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 8e600f827fe..7c5b4cb8838 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -2846,10 +2846,6 @@ static int __net_init ip6_route_net_init(struct net *net)
2846 net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ; 2846 net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ;
2847 net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40; 2847 net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
2848 2848
2849#ifdef CONFIG_PROC_FS
2850 proc_net_fops_create(net, "ipv6_route", 0, &ipv6_route_proc_fops);
2851 proc_net_fops_create(net, "rt6_stats", S_IRUGO, &rt6_stats_seq_fops);
2852#endif
2853 net->ipv6.ip6_rt_gc_expire = 30*HZ; 2849 net->ipv6.ip6_rt_gc_expire = 30*HZ;
2854 2850
2855 ret = 0; 2851 ret = 0;
@@ -2870,10 +2866,6 @@ out_ip6_dst_ops:
2870 2866
2871static void __net_exit ip6_route_net_exit(struct net *net) 2867static void __net_exit ip6_route_net_exit(struct net *net)
2872{ 2868{
2873#ifdef CONFIG_PROC_FS
2874 proc_net_remove(net, "ipv6_route");
2875 proc_net_remove(net, "rt6_stats");
2876#endif
2877 kfree(net->ipv6.ip6_null_entry); 2869 kfree(net->ipv6.ip6_null_entry);
2878#ifdef CONFIG_IPV6_MULTIPLE_TABLES 2870#ifdef CONFIG_IPV6_MULTIPLE_TABLES
2879 kfree(net->ipv6.ip6_prohibit_entry); 2871 kfree(net->ipv6.ip6_prohibit_entry);
@@ -2882,11 +2874,33 @@ static void __net_exit ip6_route_net_exit(struct net *net)
2882 dst_entries_destroy(&net->ipv6.ip6_dst_ops); 2874 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
2883} 2875}
2884 2876
2877static int __net_init ip6_route_net_init_late(struct net *net)
2878{
2879#ifdef CONFIG_PROC_FS
2880 proc_net_fops_create(net, "ipv6_route", 0, &ipv6_route_proc_fops);
2881 proc_net_fops_create(net, "rt6_stats", S_IRUGO, &rt6_stats_seq_fops);
2882#endif
2883 return 0;
2884}
2885
2886static void __net_exit ip6_route_net_exit_late(struct net *net)
2887{
2888#ifdef CONFIG_PROC_FS
2889 proc_net_remove(net, "ipv6_route");
2890 proc_net_remove(net, "rt6_stats");
2891#endif
2892}
2893
2885static struct pernet_operations ip6_route_net_ops = { 2894static struct pernet_operations ip6_route_net_ops = {
2886 .init = ip6_route_net_init, 2895 .init = ip6_route_net_init,
2887 .exit = ip6_route_net_exit, 2896 .exit = ip6_route_net_exit,
2888}; 2897};
2889 2898
2899static struct pernet_operations ip6_route_net_late_ops = {
2900 .init = ip6_route_net_init_late,
2901 .exit = ip6_route_net_exit_late,
2902};
2903
2890static struct notifier_block ip6_route_dev_notifier = { 2904static struct notifier_block ip6_route_dev_notifier = {
2891 .notifier_call = ip6_route_dev_notify, 2905 .notifier_call = ip6_route_dev_notify,
2892 .priority = 0, 2906 .priority = 0,
@@ -2936,19 +2950,25 @@ int __init ip6_route_init(void)
2936 if (ret) 2950 if (ret)
2937 goto xfrm6_init; 2951 goto xfrm6_init;
2938 2952
2953 ret = register_pernet_subsys(&ip6_route_net_late_ops);
2954 if (ret)
2955 goto fib6_rules_init;
2956
2939 ret = -ENOBUFS; 2957 ret = -ENOBUFS;
2940 if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL) || 2958 if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL) ||
2941 __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL) || 2959 __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL) ||
2942 __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL)) 2960 __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL))
2943 goto fib6_rules_init; 2961 goto out_register_late_subsys;
2944 2962
2945 ret = register_netdevice_notifier(&ip6_route_dev_notifier); 2963 ret = register_netdevice_notifier(&ip6_route_dev_notifier);
2946 if (ret) 2964 if (ret)
2947 goto fib6_rules_init; 2965 goto out_register_late_subsys;
2948 2966
2949out: 2967out:
2950 return ret; 2968 return ret;
2951 2969
2970out_register_late_subsys:
2971 unregister_pernet_subsys(&ip6_route_net_late_ops);
2952fib6_rules_init: 2972fib6_rules_init:
2953 fib6_rules_cleanup(); 2973 fib6_rules_cleanup();
2954xfrm6_init: 2974xfrm6_init:
@@ -2967,6 +2987,7 @@ out_kmem_cache:
2967void ip6_route_cleanup(void) 2987void ip6_route_cleanup(void)
2968{ 2988{
2969 unregister_netdevice_notifier(&ip6_route_dev_notifier); 2989 unregister_netdevice_notifier(&ip6_route_dev_notifier);
2990 unregister_pernet_subsys(&ip6_route_net_late_ops);
2970 fib6_rules_cleanup(); 2991 fib6_rules_cleanup();
2971 xfrm6_fini(); 2992 xfrm6_fini();
2972 fib6_gc_cleanup(); 2993 fib6_gc_cleanup();