[PATCH net] net/mlx5: E-Switch, prevent mc_list repopulation during vport disable
From: Tariq Toukan
Date: Wed Sep 02 2026 - 16:05:10 EST
From: Lama Kayal <lkayal@xxxxxxxxxx>
In mlx5_esw_vport_disable(), move esw_apply_vport_rx_mode() ahead
of esw_vport_change_handle_locked() so vport->allmulti_rule is
NULL before the change handler observes it.
During FW-fatal recovery the disable runs while dev->state ==
INTERNAL_ERROR. The promisc query inside esw_update_vport_rx_mode()
fails and returns early, leaving vport->allmulti_rule intact, so
esw_update_vport_mc_promisc() runs and adds MLX5_ACTION_ADD entries
to vport->mc_list whose flow rules are then installed in the FDB
by esw_add_mc_addr(). esw_destroy_legacy_table() tears down the
FDB with those refs still held, corrupting the sub-tree and
leaving dangling flow_rule pointers in vport->mc_list.
Two-stage failure on `echo 1 > /sys/bus/pci/devices/<bdf>/reset`:
refcount_t: underflow; use-after-free.
tree_put_node+0xef/0x110 [mlx5_core]
clean_tree+0x44/0xd0 [mlx5_core] (x5)
mlx5_fs_core_cleanup+0x57/0x1c0 [mlx5_core]
mlx5_unload+0x65/0xd0 [mlx5_core]
... mlx5_health_try_recover
BUG: unable to handle page fault for address: 0000000003000055
down_write+0x1c/0x60
mlx5_del_flow_rules+0x33/0x1f0 [mlx5_core]
esw_del_mc_addr+0x7b/0x170 [mlx5_core]
esw_apply_vport_addr_list+0x56/0xf0 [mlx5_core]
esw_vport_change_handle_locked+0x28b/0x310 [mlx5_core]
mlx5_esw_vport_enable+0x270/0x4a0 [mlx5_core]
... mlx5_load ... mlx5_health_try_recover
esw_apply_vport_rx_mode(false, false) clears vport->allmulti_rule
via its local state machine even when the FW del fails. With the
rule NULL the !IS_ERR_OR_NULL(allmulti_rule) gate in the change
handler closes, no rules are installed during disable, and the
reload starts with a clean mc_list.
Fixes: 922f56e9a795 ("net/mlx5: Fix steering rules cleanup")
Signed-off-by: Lama Kayal <lkayal@xxxxxxxxxx>
Reviewed-by: Cosmin Ratiu <cratiu@xxxxxxxxxx>
Signed-off-by: Tariq Toukan <tariqt@xxxxxxxxxx>
---
drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
index b6e2c153b4f7..4c7fa4a52b0e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
@@ -1040,13 +1040,19 @@ void mlx5_esw_vport_disable(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
(vport->info.ipsec_crypto_enabled || vport->info.ipsec_packet_enabled))
esw->enabled_ipsec_vf_count--;
+ /* Clear rx-mode before esw_vport_change_handle_locked(): on
+ * MLX5_VPORT_PROMISC_CHANGE it calls esw_update_vport_mc_promisc()
+ * when vport->allmulti_rule is set, repopulating mc_list with FDB
+ * rules that dangle once the FDB is destroyed. NULL allmulti_rule
+ * here skips that path.
+ */
+ esw_apply_vport_rx_mode(esw, vport, false, false);
/* We don't assume VFs will cleanup after themselves.
* Calling vport change handler while vport is disabled will cleanup
* the vport resources.
*/
esw_vport_change_handle_locked(vport);
vport->enabled_events = 0;
- esw_apply_vport_rx_mode(esw, vport, false, false);
esw_vport_cleanup(esw, vport);
esw->enabled_vports--;
--
2.44.0