Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'net-bridge-mcast-add-and-enforce-query-interval-minimum'

Nikolay Aleksandrov says:

====================
net: bridge: mcast: add and enforce query interval minimum

This set adds and enforces 1 second minimum value for bridge multicast
query and startup query intervals in order to avoid rearming the timers
too often which could lock and crash the host. I doubt anyone is using
such low values or anything lower than 1 second, so it seems like a good
minimum. In order to be compatible if the value is lower then it is
overwritten and a log message is emitted, since we can't return an error
at this point.

Eric, I looked for the syzbot reports in its dashboard but couldn't find
them so I've added you as the reporter.

I've prepared a global bridge igmp rate limiting patch but wasn't
sure if it's ok for -net. It adds a static limit of 32k packets per
second, I plan to send it for net-next with added drop counters for
each bridge so it can be easily debugged.

Original report can be seen at:
https://lore.kernel.org/netdev/e8b9ce41-57b9-b6e2-a46a-ff9c791cf0ba@gmail.com/
====================

Link: https://lore.kernel.org/r/20211227172116.320768-1-nikolay@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+44 -6
+32
net/bridge/br_multicast.c
··· 4522 4522 } 4523 4523 #endif 4524 4524 4525 + void br_multicast_set_query_intvl(struct net_bridge_mcast *brmctx, 4526 + unsigned long val) 4527 + { 4528 + unsigned long intvl_jiffies = clock_t_to_jiffies(val); 4529 + 4530 + if (intvl_jiffies < BR_MULTICAST_QUERY_INTVL_MIN) { 4531 + br_info(brmctx->br, 4532 + "trying to set multicast query interval below minimum, setting to %lu (%ums)\n", 4533 + jiffies_to_clock_t(BR_MULTICAST_QUERY_INTVL_MIN), 4534 + jiffies_to_msecs(BR_MULTICAST_QUERY_INTVL_MIN)); 4535 + intvl_jiffies = BR_MULTICAST_QUERY_INTVL_MIN; 4536 + } 4537 + 4538 + brmctx->multicast_query_interval = intvl_jiffies; 4539 + } 4540 + 4541 + void br_multicast_set_startup_query_intvl(struct net_bridge_mcast *brmctx, 4542 + unsigned long val) 4543 + { 4544 + unsigned long intvl_jiffies = clock_t_to_jiffies(val); 4545 + 4546 + if (intvl_jiffies < BR_MULTICAST_STARTUP_QUERY_INTVL_MIN) { 4547 + br_info(brmctx->br, 4548 + "trying to set multicast startup query interval below minimum, setting to %lu (%ums)\n", 4549 + jiffies_to_clock_t(BR_MULTICAST_STARTUP_QUERY_INTVL_MIN), 4550 + jiffies_to_msecs(BR_MULTICAST_STARTUP_QUERY_INTVL_MIN)); 4551 + intvl_jiffies = BR_MULTICAST_STARTUP_QUERY_INTVL_MIN; 4552 + } 4553 + 4554 + brmctx->multicast_startup_query_interval = intvl_jiffies; 4555 + } 4556 + 4525 4557 /** 4526 4558 * br_multicast_list_adjacent - Returns snooped multicast addresses 4527 4559 * @dev: The bridge port adjacent to which to retrieve addresses
+2 -2
net/bridge/br_netlink.c
··· 1357 1357 if (data[IFLA_BR_MCAST_QUERY_INTVL]) { 1358 1358 u64 val = nla_get_u64(data[IFLA_BR_MCAST_QUERY_INTVL]); 1359 1359 1360 - br->multicast_ctx.multicast_query_interval = clock_t_to_jiffies(val); 1360 + br_multicast_set_query_intvl(&br->multicast_ctx, val); 1361 1361 } 1362 1362 1363 1363 if (data[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL]) { ··· 1369 1369 if (data[IFLA_BR_MCAST_STARTUP_QUERY_INTVL]) { 1370 1370 u64 val = nla_get_u64(data[IFLA_BR_MCAST_STARTUP_QUERY_INTVL]); 1371 1371 1372 - br->multicast_ctx.multicast_startup_query_interval = clock_t_to_jiffies(val); 1372 + br_multicast_set_startup_query_intvl(&br->multicast_ctx, val); 1373 1373 } 1374 1374 1375 1375 if (data[IFLA_BR_MCAST_STATS_ENABLED]) {
+6
net/bridge/br_private.h
··· 28 28 #define BR_MAX_PORTS (1<<BR_PORT_BITS) 29 29 30 30 #define BR_MULTICAST_DEFAULT_HASH_MAX 4096 31 + #define BR_MULTICAST_QUERY_INTVL_MIN msecs_to_jiffies(1000) 32 + #define BR_MULTICAST_STARTUP_QUERY_INTVL_MIN BR_MULTICAST_QUERY_INTVL_MIN 31 33 32 34 #define BR_HWDOM_MAX BITS_PER_LONG 33 35 ··· 965 963 int nest_attr); 966 964 size_t br_multicast_querier_state_size(void); 967 965 size_t br_rports_size(const struct net_bridge_mcast *brmctx); 966 + void br_multicast_set_query_intvl(struct net_bridge_mcast *brmctx, 967 + unsigned long val); 968 + void br_multicast_set_startup_query_intvl(struct net_bridge_mcast *brmctx, 969 + unsigned long val); 968 970 969 971 static inline bool br_group_is_l2(const struct br_ip *group) 970 972 {
+2 -2
net/bridge/br_sysfs_br.c
··· 658 658 static int set_query_interval(struct net_bridge *br, unsigned long val, 659 659 struct netlink_ext_ack *extack) 660 660 { 661 - br->multicast_ctx.multicast_query_interval = clock_t_to_jiffies(val); 661 + br_multicast_set_query_intvl(&br->multicast_ctx, val); 662 662 return 0; 663 663 } 664 664 ··· 706 706 static int set_startup_query_interval(struct net_bridge *br, unsigned long val, 707 707 struct netlink_ext_ack *extack) 708 708 { 709 - br->multicast_ctx.multicast_startup_query_interval = clock_t_to_jiffies(val); 709 + br_multicast_set_startup_query_intvl(&br->multicast_ctx, val); 710 710 return 0; 711 711 } 712 712
+2 -2
net/bridge/br_vlan_options.c
··· 521 521 u64 val; 522 522 523 523 val = nla_get_u64(tb[BRIDGE_VLANDB_GOPTS_MCAST_QUERY_INTVL]); 524 - v->br_mcast_ctx.multicast_query_interval = clock_t_to_jiffies(val); 524 + br_multicast_set_query_intvl(&v->br_mcast_ctx, val); 525 525 *changed = true; 526 526 } 527 527 if (tb[BRIDGE_VLANDB_GOPTS_MCAST_QUERY_RESPONSE_INTVL]) { ··· 535 535 u64 val; 536 536 537 537 val = nla_get_u64(tb[BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_INTVL]); 538 - v->br_mcast_ctx.multicast_startup_query_interval = clock_t_to_jiffies(val); 538 + br_multicast_set_startup_query_intvl(&v->br_mcast_ctx, val); 539 539 *changed = true; 540 540 } 541 541 if (tb[BRIDGE_VLANDB_GOPTS_MCAST_QUERIER]) {