Re: [PATCH net] net: team: stop reusing skb after queue override
From: Jakub Kicinski
Date: Wed Sep 30 2026 - 19:47:03 EST
This is an AI-generated review of your patch. The human sending this
email says "Lets fix all the bugs in this area in one series"
---
net: team: stop reusing skb after queue override
This patch fixes a use-after-free in team_xmit(). Before it,
team_queue_override_transmit() treated a non-zero dev_queue_xmit() return
as "no handoff" and then reused the skb, which had already been consumed.
The patch reports the handoff separately from transmit success and only
tries the first override port.
> diff --git a/drivers/net/team/team_core.c b/drivers/net/team/team_core.c
> index beffbe450612b..59dd94271ff19 100644
> --- a/drivers/net/team/team_core.c
> +++ b/drivers/net/team/team_core.c
[ ... ]
> @@ -1864,8 +1865,7 @@ static netdev_tx_t team_xmit(struct sk_buff *skb, struct net_device *dev)
> bool tx_success;
> unsigned int len = skb->len;
>
> - tx_success = team_queue_override_transmit(team, skb);
> - if (!tx_success)
> + if (!team_queue_override_transmit(team, skb, &tx_success))
> tx_success = READ_ONCE(team->ops.transmit)(team, skb);
[Severity: High]
This is a pre-existing issue, not one introduced by this patch. This fix
relies on the transmit op always consuming the skb. Does broadcast mode
break that rule?
In bc_transmit() in drivers/net/team/team_mode_broadcast.c, the original
skb is only handed off if a txable port was found:
if (last) {
ret = !team_dev_queue_xmit(team, last, skb);
if (!sum_ret)
sum_ret = ret;
}
return sum_ret;
If no port passes team_port_txable(), last is NULL and the skb is neither
sent nor freed. team_xmit() then only increments tx_dropped and returns
NETDEV_TX_OK.
Does this leak the skb and its sk_wmem_alloc charge, since sock_wfree()
never runs?
Can this state be reached? team_adjust_ops() picks the mode transmit op
based only on tx_en_port_count:
if (!team->tx_en_port_count || !team_is_mode_set(team) ||
!team->mode->ops->transmit)
WRITE_ONCE(team->ops.transmit, team_dummy_transmit);
else
WRITE_ONCE(team->ops.transmit, team->mode->ops->transmit);
However, team_port_txable() also requires port->linkup.
For example, say port A has link but its tx is disabled through the
tx_enabled option. Port B is oper-down but tx-enabled, which is the default
after team_port_add(). __team_carrier_check() keeps carrier on because port
A has link, and tx_en_port_count == 1 keeps bc_transmit() installed. Every
packet sent through the team device would then leak.
The same could happen if all tx-enabled ports lose link while transmits
are in flight. It could also happen if user_carrier_enabled keeps carrier
up while all ports are down.
The other transmit ops (roundrobin, random, loadbalance, activebackup and
team_dummy_transmit()) all call dev_kfree_skb_any() when they find no port.
Should bc_transmit() also call dev_kfree_skb_any(skb) when last is NULL?
[ ... ]
--
pw-bot: cr