__team_change_mode() clears team->ops with memset() before restoring safe dummy handlers via team_adjust_ops(). A concurrent team_xmit() running under RCU on another CPU can read team->ops.transmit during this window and call a NULL function pointer, crashing the kernel. The race requires CAP_NET_ADMIN (in init_user_ns) to trigger via TEAM_CMD_OPTIONS_SET, plus AF_PACKET sendto() on a team device with forced carrier and no ports. BUG: kernel NULL pointer dereference, address: 0000000000000000 Oops: 0010 [#1] SMP KASAN NOPTI RIP: 0010:0x0 Call Trace: team_xmit (drivers/net/team/team_core.c:1853) dev_hard_start_xmit (net/core/dev.c:3904) __dev_queue_xmit (net/core/dev.c:4871) packet_sendmsg (net/packet/af_packet.c:3109) __sys_sendto (net/socket.c:2265) Fix this by reading team->ops.transmit with READ_ONCE() into a local variable and falling back to team_dummy_transmit if NULL. This matches what team_adjust_ops() would have installed moments later. Fixes: 3d249d4ca7d0 ("net: introduce ethernet teaming device") Reported-by: Xiang Mei Signed-off-by: Weiming Shi --- drivers/net/team/team_core.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/team/team_core.c b/drivers/net/team/team_core.c index 0c87f9972457..3ff08b5deccd 100644 --- a/drivers/net/team/team_core.c +++ b/drivers/net/team/team_core.c @@ -1844,8 +1844,14 @@ static netdev_tx_t team_xmit(struct sk_buff *skb, struct net_device *dev) unsigned int len = skb->len; tx_success = team_queue_override_transmit(team, skb); - if (!tx_success) - tx_success = team->ops.transmit(team, skb); + if (!tx_success) { + bool (*transmit)(struct team *team, struct sk_buff *skb); + + transmit = READ_ONCE(team->ops.transmit); + if (unlikely(!transmit)) + transmit = team_dummy_transmit; + tx_success = transmit(team, skb); + } if (tx_success) { struct team_pcpu_stats *pcpu_stats; -- 2.43.0