Merge branch 'bridge-mcast-fix-a-possible-use-after-free-when-removing-a-bridge-port'

Ido Schimmel says:

====================
bridge: mcast: Fix a possible use-after-free when removing a bridge port

Patch #1 fixes a possible use-after-free when removing a bridge port.

Patch #2 adds a test case that triggers the problem.

In net-next we can:

1. Add DEBUG_NET_WARN_ON_ONCE() when a port multicast context is
de-initialized while enabled.

2. When de-initializing a port multicast context, synchronously shutdown
all the timers that were initialized when the context was initialized.
====================

Link: https://patch.msgid.link/20260517121122.188333-1-idosch@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2026-05-19 18:15:23 -07:00
commit 90fc1a3937
2 changed files with 46 additions and 6 deletions

View File

@ -4640,10 +4640,24 @@ static void br_multicast_start_querier(struct net_bridge_mcast *brmctx,
rcu_read_unlock();
}
static void br_multicast_del_grps(struct net_bridge *br)
static void br_multicast_enable_all_ports(struct net_bridge *br)
{
struct net_bridge_port *port;
if (br_opt_get(br, BROPT_MCAST_VLAN_SNOOPING_ENABLED))
return;
list_for_each_entry(port, &br->port_list, list)
__br_multicast_enable_port_ctx(&port->multicast_ctx);
}
static void br_multicast_disable_all_ports(struct net_bridge *br)
{
struct net_bridge_port *port;
if (br_opt_get(br, BROPT_MCAST_VLAN_SNOOPING_ENABLED))
return;
list_for_each_entry(port, &br->port_list, list)
__br_multicast_disable_port_ctx(&port->multicast_ctx);
}
@ -4651,7 +4665,6 @@ static void br_multicast_del_grps(struct net_bridge *br)
int br_multicast_toggle(struct net_bridge *br, unsigned long val,
struct netlink_ext_ack *extack)
{
struct net_bridge_port *port;
bool change_snoopers = false;
int err = 0;
@ -4668,7 +4681,7 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val,
br_opt_toggle(br, BROPT_MULTICAST_ENABLED, !!val);
if (!br_opt_get(br, BROPT_MULTICAST_ENABLED)) {
change_snoopers = true;
br_multicast_del_grps(br);
br_multicast_disable_all_ports(br);
goto unlock;
}
@ -4676,8 +4689,7 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val,
goto unlock;
br_multicast_open(br);
list_for_each_entry(port, &br->port_list, list)
__br_multicast_enable_port_ctx(&port->multicast_ctx);
br_multicast_enable_all_ports(br);
change_snoopers = true;

View File

@ -4,7 +4,7 @@
ALL_TESTS="vlmc_control_test vlmc_querier_test vlmc_igmp_mld_version_test \
vlmc_last_member_test vlmc_startup_query_test vlmc_membership_test \
vlmc_querier_intvl_test vlmc_query_intvl_test vlmc_query_response_intvl_test \
vlmc_router_port_test vlmc_filtering_test"
vlmc_router_port_test vlmc_filtering_test vlmc_mcast_toggle_test"
NUM_NETIFS=4
CHECK_TC="yes"
TEST_GROUP="239.10.10.10"
@ -537,6 +537,34 @@ vlmc_filtering_test()
log_test "Disable multicast vlan snooping when vlan filtering is disabled"
}
vlmc_mcast_toggle_test()
{
RET=0
ip link add name br1-mcast up type bridge mcast_snooping 1 mcast_querier 1 vlan_filtering 1
ip link add name dummy1-mcast up master br1-mcast type dummy
# Enabling per-VLAN multicast snooping should disable the per-port
# multicast context on "dummy1-mcast".
ip link set dev br1-mcast type bridge mcast_vlan_snooping 1
# Toggling multicast snooping on the bridge should not affect the
# per-port multicast context on "dummy1-mcast" given that per-VLAN
# multicast snooping is enabled.
ip link set dev br1-mcast type bridge mcast_snooping 0
ip link set dev br1-mcast type bridge mcast_snooping 1
# If both the per-port and per-{port, VLAN} multicast contexts are
# enabled on "dummy1-mcast", removing it from the bridge will result
# in a splat.
ip link set dev dummy1-mcast nomaster
log_test "Toggling mcast snooping with per-VLAN mcast snooping enabled"
ip link del dev dummy1-mcast
ip link del dev br1-mcast
}
trap cleanup EXIT
setup_prepare