]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ipv6: fix possible infinite loop in fib6_info_uses_dev()
authorEric Dumazet <edumazet@google.com>
Fri, 25 Jul 2025 14:07:24 +0000 (14:07 +0000)
committerJakub Kicinski <kuba@kernel.org>
Sat, 26 Jul 2025 18:31:00 +0000 (11:31 -0700)
fib6_info_uses_dev() seems to rely on RCU without an explicit
protection.

Like the prior fix in rt6_nlmsg_size(),
we need to make sure fib6_del_route() or fib6_add_rt2node()
have not removed the anchor from the list, or we risk an infinite loop.

Fixes: d9ccb18f83ea ("ipv6: Fix soft lockups in fib6_select_path under high next hop churn")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20250725140725.3626540-4-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/ipv6/route.c

index 6d4e147ae46bc245ccd195e5fb0e254f34ec65a4..04f2b860ca6156776e0cedd18d96877effd287a4 100644 (file)
@@ -5958,16 +5958,21 @@ static bool fib6_info_uses_dev(const struct fib6_info *f6i,
        if (f6i->fib6_nh->fib_nh_dev == dev)
                return true;
 
-       if (f6i->fib6_nsiblings) {
-               struct fib6_info *sibling, *next_sibling;
+       if (READ_ONCE(f6i->fib6_nsiblings)) {
+               const struct fib6_info *sibling;
 
-               list_for_each_entry_safe(sibling, next_sibling,
-                                        &f6i->fib6_siblings, fib6_siblings) {
-                       if (sibling->fib6_nh->fib_nh_dev == dev)
+               rcu_read_lock();
+               list_for_each_entry_rcu(sibling, &f6i->fib6_siblings,
+                                       fib6_siblings) {
+                       if (sibling->fib6_nh->fib_nh_dev == dev) {
+                               rcu_read_unlock();
                                return true;
+                       }
+                       if (!READ_ONCE(f6i->fib6_nsiblings))
+                               break;
                }
+               rcu_read_unlock();
        }
-
        return false;
 }