From: Nikolay Aleksandrov nikolay@nvidia.com
mainline inclusion from mainline-v5.16-rc8 commit 99b40610956a8a8755653a67392e2a8b772453be category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I6DKZJ CVE: NA
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
--------------------------------
As reported[1] if query interval is set too low and we have multiple bridges or even a single bridge with multiple querier vlans configured we can crash the machine. Add a 1 second minimum which must be enforced by overwriting the value if set lower (i.e. without returning an error) to avoid breaking user-space. If that happens a log message is emitted to let the administrator know that the interval has been set to the minimum. The issue has been present since these intervals could be user-controlled.
[1] https://lore.kernel.org/netdev/e8b9ce41-57b9-b6e2-a46a-ff9c791cf0ba@gmail.co...
Fixes: d902eee43f19 ("bridge: Add multicast count/interval sysfs entries") Reported-by: Eric Dumazet eric.dumazet@gmail.com Signed-off-by: Nikolay Aleksandrov nikolay@nvidia.com Signed-off-by: Jakub Kicinski kuba@kernel.org
Conflicts: net/bridge/br_multicast.c net/bridge/br_netlink.c net/bridge/br_private.h net/bridge/br_sysfs_br.c
Signed-off-by: Zhengchao Shao shaozhengchao@huawei.com Reviewed-by: Yue Haibing yuehaibing@huawei.com Signed-off-by: Jialin Zhang zhangjialin11@huawei.com --- net/bridge/br_multicast.c | 16 ++++++++++++++++ net/bridge/br_netlink.c | 2 +- net/bridge/br_private.h | 2 ++ net/bridge/br_sysfs_br.c | 2 +- 4 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 8ea85a4718f9..de79fbfe1611 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -3625,6 +3625,22 @@ void br_multicast_set_startup_query_intvl(struct net_bridge *br, br->multicast_startup_query_interval = intvl_jiffies; }
+void br_multicast_set_query_intvl(struct net_bridge *br, + unsigned long val) +{ + unsigned long intvl_jiffies = clock_t_to_jiffies(val); + + if (intvl_jiffies < BR_MULTICAST_QUERY_INTVL_MIN) { + br_info(br, + "trying to set multicast query interval below minimum, setting to %lu (%ums)\n", + jiffies_to_clock_t(BR_MULTICAST_QUERY_INTVL_MIN), + jiffies_to_msecs(BR_MULTICAST_QUERY_INTVL_MIN)); + intvl_jiffies = BR_MULTICAST_QUERY_INTVL_MIN; + } + + br->multicast_query_interval = intvl_jiffies; +} + /** * br_multicast_list_adjacent - Returns snooped multicast addresses * @dev: The bridge port adjacent to which to retrieve addresses diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 1f85c1b77c89..bed6c798fea9 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -1286,7 +1286,7 @@ static int br_changelink(struct net_device *brdev, struct nlattr *tb[], if (data[IFLA_BR_MCAST_QUERY_INTVL]) { u64 val = nla_get_u64(data[IFLA_BR_MCAST_QUERY_INTVL]);
- br->multicast_query_interval = clock_t_to_jiffies(val); + br_multicast_set_query_intvl(br, val); }
if (data[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL]) { diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index e439d9aae45a..bfd0e995b078 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -1572,4 +1572,6 @@ void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br, struct nd_msg *br_is_nd_neigh_msg(struct sk_buff *skb, struct nd_msg *m); void br_multicast_set_startup_query_intvl(struct net_bridge *br, unsigned long val); +void br_multicast_set_query_intvl(struct net_bridge *br, + unsigned long val); #endif diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index 1fdc491f648a..c8b477cbc4a3 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c @@ -594,7 +594,7 @@ static ssize_t multicast_query_interval_show(struct device *d,
static int set_query_interval(struct net_bridge *br, unsigned long val) { - br->multicast_query_interval = clock_t_to_jiffies(val); + br_multicast_set_query_intvl(br, val); return 0; }