aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorMichal Kubeček <mkubecek@suse.cz>2013-09-09 15:45:04 -0400
committerDavid S. Miller <davem@davemloft.net>2013-09-11 17:04:09 -0400
commit2c861cc65ef4604011a0082e4dcdba2819aa191a (patch)
treed6fe5436cf4d492c727cfb370232c87254d72097 /net
parent444fa88ac35aa1bf9b7c23945444bc67f631033b (diff)
ipv6: don't call fib6_run_gc() until routing is ready
When loading the ipv6 module, ndisc_init() is called before ip6_route_init(). As the former registers a handler calling fib6_run_gc(), this opens a window to run the garbage collector before necessary data structures are initialized. If a network device is initialized in this window, adding MAC address to it triggers a NETDEV_CHANGEADDR event, leading to a crash in fib6_clean_all(). Take the event handler registration out of ndisc_init() into a separate function ndisc_late_init() and move it after ip6_route_init(). Signed-off-by: Michal Kubecek <mkubecek@suse.cz> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv6/af_inet6.c6
-rw-r--r--net/ipv6/ndisc.c18
2 files changed, 17 insertions, 7 deletions
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 136fe55c1a47..7c96100b021e 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -915,6 +915,9 @@ static int __init inet6_init(void)
915 err = ip6_route_init(); 915 err = ip6_route_init();
916 if (err) 916 if (err)
917 goto ip6_route_fail; 917 goto ip6_route_fail;
918 err = ndisc_late_init();
919 if (err)
920 goto ndisc_late_fail;
918 err = ip6_flowlabel_init(); 921 err = ip6_flowlabel_init();
919 if (err) 922 if (err)
920 goto ip6_flowlabel_fail; 923 goto ip6_flowlabel_fail;
@@ -981,6 +984,8 @@ ipv6_exthdrs_fail:
981addrconf_fail: 984addrconf_fail:
982 ip6_flowlabel_cleanup(); 985 ip6_flowlabel_cleanup();
983ip6_flowlabel_fail: 986ip6_flowlabel_fail:
987 ndisc_late_cleanup();
988ndisc_late_fail:
984 ip6_route_cleanup(); 989 ip6_route_cleanup();
985ip6_route_fail: 990ip6_route_fail:
986#ifdef CONFIG_PROC_FS 991#ifdef CONFIG_PROC_FS
@@ -1043,6 +1048,7 @@ static void __exit inet6_exit(void)
1043 ipv6_exthdrs_exit(); 1048 ipv6_exthdrs_exit();
1044 addrconf_cleanup(); 1049 addrconf_cleanup();
1045 ip6_flowlabel_cleanup(); 1050 ip6_flowlabel_cleanup();
1051 ndisc_late_cleanup();
1046 ip6_route_cleanup(); 1052 ip6_route_cleanup();
1047#ifdef CONFIG_PROC_FS 1053#ifdef CONFIG_PROC_FS
1048 1054
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 12179457b2cd..f8a55ff1971b 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -1727,24 +1727,28 @@ int __init ndisc_init(void)
1727 if (err) 1727 if (err)
1728 goto out_unregister_pernet; 1728 goto out_unregister_pernet;
1729#endif 1729#endif
1730 err = register_netdevice_notifier(&ndisc_netdev_notifier);
1731 if (err)
1732 goto out_unregister_sysctl;
1733out: 1730out:
1734 return err; 1731 return err;
1735 1732
1736out_unregister_sysctl:
1737#ifdef CONFIG_SYSCTL 1733#ifdef CONFIG_SYSCTL
1738 neigh_sysctl_unregister(&nd_tbl.parms);
1739out_unregister_pernet: 1734out_unregister_pernet:
1740#endif
1741 unregister_pernet_subsys(&ndisc_net_ops); 1735 unregister_pernet_subsys(&ndisc_net_ops);
1742 goto out; 1736 goto out;
1737#endif
1743} 1738}
1744 1739
1745void ndisc_cleanup(void) 1740int __init ndisc_late_init(void)
1741{
1742 return register_netdevice_notifier(&ndisc_netdev_notifier);
1743}
1744
1745void ndisc_late_cleanup(void)
1746{ 1746{
1747 unregister_netdevice_notifier(&ndisc_netdev_notifier); 1747 unregister_netdevice_notifier(&ndisc_netdev_notifier);
1748}
1749
1750void ndisc_cleanup(void)
1751{
1748#ifdef CONFIG_SYSCTL 1752#ifdef CONFIG_SYSCTL
1749 neigh_sysctl_unregister(&nd_tbl.parms); 1753 neigh_sysctl_unregister(&nd_tbl.parms);
1750#endif 1754#endif