ipv6: fix possible infinite loop in fib6_info_uses_dev()
[ Upstream commit f8d8ce1b515a0a6af72b30502670a406cfb75073 ]
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.
BUG=b/440033339
TEST=presubmit
RELEASE_NOTE=Fixed CVE-2025-38587 in the Linux kernel.
cos-patch: security-moderate
Fixes: d9ccb18f83ea ("ipv6: Fix soft lockups in fib6_select_path under high next hop churn")
Change-Id: I4428d00557080502bfaa367cc7ef376925ce641b
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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Robert Kolchmeyer <rkolchmeyer@google.com>
Reviewed-on: https://cos-review.googlesource.com/c/third_party/kernel/+/111089
Reviewed-by: Chenglong Tang <chenglongtang@google.com>
Tested-by: Cusky Presubmit Bot <presubmit@cos-infra-prod.iam.gserviceaccount.com>
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 4e6b833..f674b89 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -5866,16 +5866,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;
}