Netdev List
 help / color / mirror / Atom feed
* [PATCH net-next] ipv6: Serialize hardware flag notifications
@ 2026-08-15  9:54 Yuyang Huang
  2026-08-19 11:50 ` Ido Schimmel
  0 siblings, 1 reply; 2+ messages in thread
From: Yuyang Huang @ 2026-08-15  9:54 UTC (permalink / raw)
  To: Yuyang Huang
  Cc: David S. Miller, Amit Cohen, David Ahern, Eric Dumazet,
	Ido Schimmel, Jakub Kicinski, Paolo Abeni, Simon Horman,
	linux-kernel, netdev

fib6_info_hw_flags_set() first performs a lockless check of fib6_node.
It then allocates a notification skb with GFP_KERNEL, which can sleep. A
concurrent route deletion can remove the route, set fib6_node to NULL, and
emit RTM_DELROUTE while the allocation sleeps. When the thread wakes up,
it can emit RTM_NEWROUTE for the already deleted route.

This can cause userspace routing daemons to receive RTM_DELROUTE followed
by RTM_NEWROUTE and incorrectly believe that the deleted route still
exists in the kernel.

Allocate the skb before taking tb6_lock, then recheck fib6_node while
holding the lock. Keep the lock until RTM_NEWROUTE is published. If route
deletion wins the race, the recheck sees NULL and drops the notification.
Otherwise, deletion cannot remove the route until RTM_NEWROUTE has been
published, preserving notification order.

RTM_DELROUTE is sent by fib6_del_route() with tb6_lock held, so
publishing RTM_NEWROUTE under the same lock is sufficient to guarantee
ordering. rt6_fill_node() does not sleep in this path, and the
notification uses GFP_ATOMIC, matching inet6_rt_notify() which already
broadcasts under tb6_lock.

The race was found by Sashiko during code review.

Fixes: 907eea486888 ("net: ipv6: Emit notification when fib hardware flags are changed")
Signed-off-by: Yuyang Huang <sigefriedhyy@gmail.com>
---
 net/ipv6/route.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 16dfac54a259..73db4f630dcc 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -6463,6 +6463,7 @@ void fib6_info_hw_flags_set(struct net *net, struct fib6_info *f6i,
 			    bool offload, bool trap, bool offload_failed)
 {
 	u8 fib_notify_on_flag_change;
+	struct fib6_table *table;
 	struct sk_buff *skb;
 	int err;
 
@@ -6491,22 +6492,33 @@ void fib6_info_hw_flags_set(struct net *net, struct fib6_info *f6i,
 	if (!fib_notify_on_flag_change)
 		return;
 
+	table = f6i->fib6_table;
 	skb = nlmsg_new(rt6_nlmsg_size(f6i), GFP_KERNEL);
 	if (!skb) {
 		err = -ENOBUFS;
 		goto errout;
 	}
 
+	spin_lock_bh(&table->tb6_lock);
+	if (!rcu_dereference_protected(f6i->fib6_node,
+				       lockdep_is_held(&table->tb6_lock))) {
+		spin_unlock_bh(&table->tb6_lock);
+		kfree_skb(skb);
+		return;
+	}
+
 	err = rt6_fill_node(net, skb, f6i, NULL, NULL, NULL, 0, RTM_NEWROUTE, 0,
 			    0, 0, RT_DEL_REASON_UNSPEC);
 	if (err < 0) {
 		/* -EMSGSIZE implies BUG in rt6_nlmsg_size() */
 		WARN_ON(err == -EMSGSIZE);
+		spin_unlock_bh(&table->tb6_lock);
 		kfree_skb(skb);
 		goto errout;
 	}
 
-	rtnl_notify(skb, net, 0, RTNLGRP_IPV6_ROUTE, NULL, GFP_KERNEL);
+	rtnl_notify(skb, net, 0, RTNLGRP_IPV6_ROUTE, NULL, GFP_ATOMIC);
+	spin_unlock_bh(&table->tb6_lock);
 	return;
 
 errout:
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-08-19 11:51 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-15  9:54 [PATCH net-next] ipv6: Serialize hardware flag notifications Yuyang Huang
2026-08-19 11:50 ` Ido Schimmel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox