net: move fib_rules_unregister() under rtnl lock
authorWANG Cong <xiyou.wangcong@gmail.com>
Tue, 31 Mar 2015 18:01:46 +0000 (11:01 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 3 Apr 2015 00:52:34 +0000 (20:52 -0400)
We have to hold rtnl lock for fib_rules_unregister()
otherwise the following race could happen:

fib_rules_unregister(): fib_nl_delrule():
... ...
... ops = lookup_rules_ops();
list_del_rcu(&ops->list);
list_for_each_entry(ops->rules) {
fib_rules_cleanup_ops(ops);   ...
  list_del_rcu();   list_del_rcu();
}

Note, net->rules_mod_lock is actually not needed at all,
either upper layer netns code or rtnl lock guarantees
we are safe.

Cc: Alexander Duyck <alexander.h.duyck@redhat.com>
Cc: Thomas Graf <tgraf@suug.ch>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/core/fib_rules.c
net/decnet/dn_rules.c
net/ipv4/fib_frontend.c
net/ipv4/ipmr.c
net/ipv6/fib6_rules.c
net/ipv6/ip6mr.c

index 44706e81b2e03df3e9d39c1cd76879a4ede48d1e..e4fdc9dfb2c73fb371280464484ebcae87218be6 100644 (file)
@@ -175,9 +175,9 @@ void fib_rules_unregister(struct fib_rules_ops *ops)
 
        spin_lock(&net->rules_mod_lock);
        list_del_rcu(&ops->list);
-       fib_rules_cleanup_ops(ops);
        spin_unlock(&net->rules_mod_lock);
 
+       fib_rules_cleanup_ops(ops);
        call_rcu(&ops->rcu, fib_rules_put_rcu);
 }
 EXPORT_SYMBOL_GPL(fib_rules_unregister);
index faf7cc3483fe0822c26be6b915061ee8fdd8be9a..9d66a0f72f906733878de68e7f2e6bd80932c1b9 100644 (file)
@@ -248,7 +248,9 @@ void __init dn_fib_rules_init(void)
 
 void __exit dn_fib_rules_cleanup(void)
 {
+       rtnl_lock();
        fib_rules_unregister(dn_fib_rules_ops);
+       rtnl_unlock();
        rcu_barrier();
 }
 
index 57be71dd6a9e0163dceefd564bf71036c12dc9ba..23b9b3e86f4cd78987790f3456470318e3b82ece 100644 (file)
@@ -1111,11 +1111,10 @@ static void ip_fib_net_exit(struct net *net)
 {
        unsigned int i;
 
+       rtnl_lock();
 #ifdef CONFIG_IP_MULTIPLE_TABLES
        fib4_rules_exit(net);
 #endif
-
-       rtnl_lock();
        for (i = 0; i < FIB_TABLE_HASHSZ; i++) {
                struct fib_table *tb;
                struct hlist_head *head;
index bc40115bc39481de40cd725356742c19f274c884..fe54eba6d00d3462c287b095370e3a938e73b178 100644 (file)
@@ -283,8 +283,8 @@ static void __net_exit ipmr_rules_exit(struct net *net)
                list_del(&mrt->list);
                ipmr_free_table(mrt);
        }
-       rtnl_unlock();
        fib_rules_unregister(net->ipv4.mr_rules_ops);
+       rtnl_unlock();
 }
 #else
 #define ipmr_for_each_table(mrt, net) \
index 27ca79682efbf681a0ab6073f50f8fa73214028e..70bc6abc0639cf88d0b23b295c20d941b456d98b 100644 (file)
@@ -322,7 +322,9 @@ out_fib6_rules_ops:
 
 static void __net_exit fib6_rules_net_exit(struct net *net)
 {
+       rtnl_lock();
        fib_rules_unregister(net->ipv6.fib6_rules_ops);
+       rtnl_unlock();
 }
 
 static struct pernet_operations fib6_rules_net_ops = {
index 52028f449a892d9457314799e6767eef5a401824..2f1fd9ffcb34aacda122f996e8b5ae294350b412 100644 (file)
@@ -267,8 +267,8 @@ static void __net_exit ip6mr_rules_exit(struct net *net)
                list_del(&mrt->list);
                ip6mr_free_table(mrt);
        }
-       rtnl_unlock();
        fib_rules_unregister(net->ipv6.mr6_rules_ops);
+       rtnl_unlock();
 }
 #else
 #define ip6mr_for_each_table(mrt, net) \