Merge branch 'ipv6-fix-suspicious-rcu-usage-in-route-hardware-flags-notification'

Ido Schimmel says:

====================
ipv6: Fix suspicious RCU usage in route hardware flags notification

fib6_info_hw_flags_set() is called by drivers to update the hardware
flags of an IPv6 route and to emit a notification when
fib_notify_on_flag_change is set. Drivers call it from process context
without RTNL or RCU, so when the route uses a nexthop object, building
the notification triggers suspicious RCU usage splats.

Patch #1 fixes the problem by holding RCU while building the
notification.

Patch #2 adds IPv4 and IPv6 test cases for routes that use nexthop
objects. Without patch #1, the IPv6 one triggers the splats.
====================

Link: https://patch.msgid.link/20261019140337.2886875-1-idosch@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2026-10-20 14:17:16 -07:00
commit 06d870fe6c
2 changed files with 72 additions and 1 deletions

View File

@ -6509,7 +6509,9 @@ void fib6_info_hw_flags_set(struct net *net, struct fib6_info *f6i,
if (!fib_notify_on_flag_change)
return;
skb = nlmsg_new(rt6_nlmsg_size(f6i), GFP_KERNEL);
rcu_read_lock();
skb = nlmsg_new(rt6_nlmsg_size(f6i), GFP_ATOMIC);
if (!skb) {
err = -ENOBUFS;
goto errout;
@ -6522,10 +6524,13 @@ void fib6_info_hw_flags_set(struct net *net, struct fib6_info *f6i,
goto errout;
}
rcu_read_unlock();
rtnl_notify(skb, net, 0, RTNLGRP_IPV6_ROUTE, NULL, GFP_KERNEL);
return;
errout:
rcu_read_unlock();
rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
}
EXPORT_SYMBOL(fib6_info_hw_flags_set);

View File

@ -8,10 +8,12 @@ ALL_TESTS="
ipv4_route_deletion_test
ipv4_route_replacement_test
ipv4_route_offload_failed_test
ipv4_route_nexthop_test
ipv6_route_addition_test
ipv6_route_deletion_test
ipv6_route_replacement_test
ipv6_route_offload_failed_test
ipv6_route_nexthop_test
"
NETDEVSIM_PATH=/sys/bus/netdevsim/
@ -269,6 +271,50 @@ ipv4_route_offload_failed_test()
log_test "IPv4 route offload failed"
}
route_nexthop_check()
{
local ip=$1; shift
local route=$1; shift
local nhid=$1; shift
local expected_num_notifications=$1; shift
local outfile
ip netns exec testns1 sysctl -qw net.$ip.fib_notify_on_flag_change=1
outfile=$(mktemp)
$IP monitor route &> $outfile &
sleep 1
$IP route add $route nhid $nhid
sleep 1
kill_process %%
route_notify_check $outfile $expected_num_notifications
rm -f $outfile
$IP route del $route nhid $nhid
}
ipv4_route_nexthop_test()
{
RET=0
local ip="ipv4"
local route=192.0.2.0/24
local nhid=1
$IP -4 nexthop add id $nhid dev dummy1
# Make sure two notifications will be emitted for a programmed route
# that uses a nexthop object.
local expected_num_notifications=2
route_nexthop_check $ip $route $nhid $expected_num_notifications
$IP nexthop del id $nhid
log_test "IPv4 route with nexthop object"
}
ipv6_route_addition_test()
{
RET=0
@ -385,6 +431,26 @@ ipv6_route_offload_failed_test()
log_test "IPv6 route offload failed"
}
ipv6_route_nexthop_test()
{
RET=0
local ip="ipv6"
local route=2001:db8:1::/64
local nhid=1
$IP -6 nexthop add id $nhid dev dummy1
# Make sure two notifications will be emitted for a programmed route
# that uses a nexthop object.
local expected_num_notifications=2
route_nexthop_check $ip $route $nhid $expected_num_notifications
$IP nexthop del id $nhid
log_test "IPv6 route with nexthop object"
}
setup_prepare()
{
modprobe netdevsim &> /dev/null