From: Jun Yang <juny24602@gmail.com>
To: dsahern@kernel.org, idosch@nvidia.com
Cc: davem@davemloft.net, edumazet@kernel.org, kuba@kernel.org,
pabeni@redhat.com, horms@kernel.org, kaber@trash.net,
netdev@vger.kernel.org, Jun Yang <junvyyang@tencent.com>,
stable@kernel.org, TencentOS Corvus AI <corvus@tencent.com>
Subject: [PATCH net] ipv6: take tb6_lock across the fib6 dump sernum snapshot
Date: Mon, 12 Oct 2026 16:38:20 +0800 [thread overview]
Message-ID: <20261012083843.60510-1-juny24602@gmail.com> (raw)
From: Jun Yang <junvyyang@tencent.com>
A resumable RTM_GETROUTE dump parks a raw struct fib6_info pointer in
w->leaf when the skb fills (fib6_dump_node()) and resumes from it on the
next recvmsg(). No reference is held across the suspension; the only
thing standing between the walker and a freed route is the fn_sernum
check in fib6_dump_table(), which restarts from the root when the tree
changed.
That check is done outside tb6_lock at both ends: the snapshot after the
first walk is taken after spin_unlock_bh(), and on continuation the
compare runs before spin_lock_bh(). A writer that slips in between, e.g.
RTM_NEWROUTE with NLM_F_REPLACE on the route the walker is parked on,
frees the route via fib6_info_release() (the replace path has no
FOR_WALKERS fixup, unlike fib6_del_route()) and bumps fn_sernum, yet the
dump records the new serial next to the stale w->leaf, or passes the
compare and only then takes the lock. Either way the restart is skipped
and fib6_walk_continue() hands the freed route to rt6_fill_node():
BUG: KASAN: slab-use-after-free in rt6_fill_node (net/ipv6/route.c:5821)
Read of size 4 at addr ffff88810adb0c64 by task fib6dump-repro/541
CPU: 0 UID: 1000 PID: 541 Comm: fib6dump-repro Not tainted 7.3.0-rc6 #1 PREEMPT
Call Trace:
rt6_fill_node (net/ipv6/route.c:5821)
rt6_dump_route (net/ipv6/route.c:6130)
fib6_dump_node (net/ipv6/ip6_fib.c:534)
fib6_walk_continue (net/ipv6/ip6_fib.c:2180)
fib6_dump_table (net/ipv6/ip6_fib.c:620)
inet6_dump_fib (net/ipv6/ip6_fib.c:714)
rtnl_dumpit (net/core/rtnetlink.c:7006)
netlink_dump (net/netlink/af_netlink.c:2350)
netlink_recvmsg (net/netlink/af_netlink.c:2001)
sock_recvmsg (net/socket.c:1173)
__sys_recvfrom (net/socket.c:2331)
Take tb6_lock once at the top of fib6_dump_table() and hold it across
the snapshot, the comparison and the walker call, so fn_sernum is read
in the same critical section as the walk it describes.
Fixes: 2bec5a369ee7 ("ipv6: fib: fix crash when changing large fib while dumping it")
Cc: stable@kernel.org
Reported-by: TencentOS Corvus AI <corvus@tencent.com>
Assisted-by: tencentos-corvus-ai:hy4-preview
Signed-off-by: Jun Yang <junvyyang@tencent.com>
---
A KASAN reproducer for this issue is available if requested.
net/ipv6/ip6_fib.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 9ff761962b45..70482381165f 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -592,14 +592,13 @@ static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb,
w = (void *)cb->args[2];
w->root = &table->tb6_root;
+ spin_lock_bh(&table->tb6_lock);
if (cb->args[4] == 0) {
w->count = 0;
w->skip = 0;
w->skip_in_node = 0;
- spin_lock_bh(&table->tb6_lock);
res = fib6_walk(net, w);
- spin_unlock_bh(&table->tb6_lock);
if (res > 0) {
cb->args[4] = 1;
cb->args[5] = READ_ONCE(w->root->fn_sernum);
@@ -616,14 +615,13 @@ static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb,
} else
w->skip = 0;
- spin_lock_bh(&table->tb6_lock);
res = fib6_walk_continue(w);
- spin_unlock_bh(&table->tb6_lock);
if (res <= 0) {
fib6_walker_unlink(net, w);
cb->args[4] = 0;
}
}
+ spin_unlock_bh(&table->tb6_lock);
return res;
}
base-commit: a90ee4305c4a5df72c11b31dacfdc76e00fcf78a
--
2.43.7
next reply other threads:[~2026-10-12 8:39 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-12 8:38 Jun Yang [this message]
2026-10-13 8:41 ` [PATCH net] ipv6: take tb6_lock across the fib6 dump sernum snapshot netdev-bot+sashiko
2026-10-13 12:41 ` Ido Schimmel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261012083843.60510-1-juny24602@gmail.com \
--to=juny24602@gmail.com \
--cc=corvus@tencent.com \
--cc=davem@davemloft.net \
--cc=dsahern@kernel.org \
--cc=edumazet@kernel.org \
--cc=horms@kernel.org \
--cc=idosch@nvidia.com \
--cc=junvyyang@tencent.com \
--cc=kaber@trash.net \
--cc=kuba@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=stable@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.