]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ipv6: Protect fib6_link_table() with spinlock.
authorKuniyuki Iwashima <kuniyu@amazon.com>
Fri, 18 Apr 2025 00:03:53 +0000 (17:03 -0700)
committerPaolo Abeni <pabeni@redhat.com>
Thu, 24 Apr 2025 07:29:56 +0000 (09:29 +0200)
We will get rid of RTNL from RTM_NEWROUTE and SIOCADDRT.

If the request specifies a new table ID, fib6_new_table() is
called to create a new routing table.

Two concurrent requests could specify the same table ID, so we
need a lock to protect net->ipv6.fib_table_hash[h].

Let's add a spinlock to protect the hash bucket linkage.

Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Acked-by: Paolo Abeni <pabeni@redhat.com>
Link: https://patch.msgid.link/20250418000443.43734-13-kuniyu@amazon.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
include/net/netns/ipv6.h
net/ipv6/ip6_fib.c

index 5f2cfd84570aea8dd225208d36065b47b27b6b10..47dc70d8100a4b24517cec3117e1af960f4ca233 100644 (file)
@@ -72,6 +72,7 @@ struct netns_ipv6 {
        struct rt6_statistics   *rt6_stats;
        struct timer_list       ip6_fib_timer;
        struct hlist_head       *fib_table_hash;
+       spinlock_t              fib_table_hash_lock;
        struct fib6_table       *fib6_main_tbl;
        struct list_head        fib6_walkers;
        rwlock_t                fib6_walker_lock;
index bf727149fdece63bb9b6944ba18416b87ddd698e..79b672f3fc532e5621caec083aef4891bf01e5ee 100644 (file)
@@ -249,19 +249,33 @@ static struct fib6_table *fib6_alloc_table(struct net *net, u32 id)
 
 struct fib6_table *fib6_new_table(struct net *net, u32 id)
 {
-       struct fib6_table *tb;
+       struct fib6_table *tb, *new_tb;
 
        if (id == 0)
                id = RT6_TABLE_MAIN;
+
        tb = fib6_get_table(net, id);
        if (tb)
                return tb;
 
-       tb = fib6_alloc_table(net, id);
-       if (tb)
-               fib6_link_table(net, tb);
+       new_tb = fib6_alloc_table(net, id);
+       if (!new_tb)
+               return NULL;
+
+       spin_lock_bh(&net->ipv6.fib_table_hash_lock);
+
+       tb = fib6_get_table(net, id);
+       if (unlikely(tb)) {
+               spin_unlock_bh(&net->ipv6.fib_table_hash_lock);
+               kfree(new_tb);
+               return tb;
+       }
 
-       return tb;
+       fib6_link_table(net, new_tb);
+
+       spin_unlock_bh(&net->ipv6.fib_table_hash_lock);
+
+       return new_tb;
 }
 EXPORT_SYMBOL_GPL(fib6_new_table);
 
@@ -2423,6 +2437,8 @@ static int __net_init fib6_net_init(struct net *net)
        if (!net->ipv6.fib_table_hash)
                goto out_rt6_stats;
 
+       spin_lock_init(&net->ipv6.fib_table_hash_lock);
+
        net->ipv6.fib6_main_tbl = kzalloc(sizeof(*net->ipv6.fib6_main_tbl),
                                          GFP_KERNEL);
        if (!net->ipv6.fib6_main_tbl)