[PATCH net] netdevsim: tc: serialize access to nsim_block_cb_list
From: Weiming Shi <hidden>
Date: 2026-07-19 17:50:55
Also in:
lkml, stable
Subsystem:
netdevsim, networking drivers, the rest · Maintainers:
Jakub Kicinski, Andrew Lunn, "David S. Miller", Eric Dumazet, Paolo Abeni, Linus Torvalds
nsim_setup_tc() passes a single global nsim_block_cb_list, shared by every
netdevsim device, to flow_block_cb_setup_simple(). That helper does
list_add_tail()/list_del() on the list on block bind/unbind and walks it
in flow_block_cb_is_busy(); it takes no lock of its own and relies on the
caller for serialization.
The tc control path calls ndo_setup_tc(TC_SETUP_BLOCK) under rtnl, but the
nf_tables hardware offload path reaches it under the per-netns nftables
commit_mutex only. Two nft transactions committing offload chains from
different netns thus run flow_block_cb_setup_simple() on the same list
concurrently, corrupting it and freeing a flow_block_cb that the other CPU
still walks:
list_del corruption. prev->next should be ffff88801f18ff00, but was ffff88801de82b00.
kernel BUG at lib/list_debug.c:62!
RIP: 0010:__list_del_entry_valid_or_report (lib/list_debug.c:62)
flow_block_cb_setup_simple (net/core/flow_offload.c:369)
nsim_setup_tc (drivers/net/netdevsim/tc.c)
nft_block_offload_cmd (net/netfilter/nf_tables_offload.c:394)
nft_flow_rule_offload_commit (net/netfilter/nf_tables_offload.c:585)
nf_tables_commit (net/netfilter/nf_tables_api.c:10490)
nfnetlink_rcv_batch (net/netfilter/nfnetlink.c:577)
nfnetlink_rcv (net/netfilter/nfnetlink.c:649)
netlink_unicast (net/netlink/af_netlink.c:1314)
netlink_sendmsg (net/netlink/af_netlink.c:1889)
__sys_sendto (net/socket.c:729)
With KASAN the same race is reported as a slab-use-after-free read of the
freed flow_block_cb (kmalloc-192) in flow_block_cb_setup_simple(). The
trace above is from a 6.12.y reproduction.
Serialize the list with a mutex. ndo_setup_tc(TC_SETUP_BLOCK) always runs
in process context, so sleeping on the mutex is fine.
Fixes: 955bcb6ea0df ("drivers: net: use flow block API")
Reported-by: Xiang Mei <redacted>
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Weiming Shi <redacted>
---
drivers/net/netdevsim/tc.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/drivers/net/netdevsim/tc.c b/drivers/net/netdevsim/tc.c
index a415e02a6df1..30dd7f924b71 100644
--- a/drivers/net/netdevsim/tc.c
+++ b/drivers/net/netdevsim/tc.c@@ -72,11 +72,13 @@ static int nsim_setup_tc_ets(struct net_device *dev, } static LIST_HEAD(nsim_block_cb_list); +static DEFINE_MUTEX(nsim_block_cb_lock); int nsim_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data) { struct netdevsim *ns = netdev_priv(dev); + int err; switch (type) { case TC_SETUP_QDISC_TAPRIO:
@@ -84,10 +86,13 @@ nsim_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data) case TC_SETUP_QDISC_ETS: return nsim_setup_tc_ets(dev, type_data); case TC_SETUP_BLOCK: - return flow_block_cb_setup_simple(type_data, - &nsim_block_cb_list, - nsim_setup_tc_block_cb, - ns, ns, true); + mutex_lock(&nsim_block_cb_lock); + err = flow_block_cb_setup_simple(type_data, + &nsim_block_cb_list, + nsim_setup_tc_block_cb, + ns, ns, true); + mutex_unlock(&nsim_block_cb_lock); + return err; case TC_SETUP_FT: return 0; default:
--
2.43.0