]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ipv4: Fix reference count leak when using error routes with nexthop objects
authorIdo Schimmel <idosch@nvidia.com>
Sun, 21 Dec 2025 14:48:28 +0000 (16:48 +0200)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 30 Dec 2025 09:39:22 +0000 (10:39 +0100)
When a nexthop object is deleted, it is marked as dead and then
fib_table_flush() is called to flush all the routes that are using the
dead nexthop.

The current logic in fib_table_flush() is to only flush error routes
(e.g., blackhole) when it is called as part of network namespace
dismantle (i.e., with flush_all=true). Therefore, error routes are not
flushed when their nexthop object is deleted:

 # ip link add name dummy1 up type dummy
 # ip nexthop add id 1 dev dummy1
 # ip route add 198.51.100.1/32 nhid 1
 # ip route add blackhole 198.51.100.2/32 nhid 1
 # ip nexthop del id 1
 # ip route show
 blackhole 198.51.100.2 nhid 1 dev dummy1

As such, they keep holding a reference on the nexthop object which in
turn holds a reference on the nexthop device, resulting in a reference
count leak:

 # ip link del dev dummy1
 [   70.516258] unregister_netdevice: waiting for dummy1 to become free. Usage count = 2

Fix by flushing error routes when their nexthop is marked as dead.

IPv6 does not suffer from this problem.

Fixes: 493ced1ac47c ("ipv4: Allow routes to use nexthop objects")
Reported-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Closes: https://lore.kernel.org/netdev/d943f806-4da6-4970-ac28-b9373b0e63ac@I-love.SAKURA.ne.jp/
Reported-by: syzbot+881d65229ca4f9ae8c84@syzkaller.appspotmail.com
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Link: https://patch.msgid.link/20251221144829.197694-1-idosch@nvidia.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
net/ipv4/fib_trie.c

index 59a6f0a9638f99a50f89d0903b16922ebf4d8bae..7e2c17fec3fc46f79ee8d39d6840c01c45c4a0ba 100644 (file)
@@ -2053,10 +2053,11 @@ int fib_table_flush(struct net *net, struct fib_table *tb, bool flush_all)
                                continue;
                        }
 
-                       /* Do not flush error routes if network namespace is
-                        * not being dismantled
+                       /* When not flushing the entire table, skip error
+                        * routes that are not marked for deletion.
                         */
-                       if (!flush_all && fib_props[fa->fa_type].error) {
+                       if (!flush_all && fib_props[fa->fa_type].error &&
+                           !(fi->fib_flags & RTNH_F_DEAD)) {
                                slen = fa->fa_slen;
                                continue;
                        }