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: Yongqiang Liu liuyongqiang13@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 ed67a43efdef..1dc32cbd20bb 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -2367,6 +2367,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 b3bcfb77077a..7b69df035a18 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -1225,7 +1225,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 877fbc65a2fe..ef65e46cbaf0 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -1205,4 +1205,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 bfbffc5088ac..78e39bf89bdf 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c @@ -572,7 +572,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; }