]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
net: bridge: mcast: add and enforce query interval minimum
authorNikolay Aleksandrov <nikolay@nvidia.com>
Mon, 27 Dec 2021 17:21:15 +0000 (19:21 +0200)
committerJakub Kicinski <kuba@kernel.org>
Wed, 29 Dec 2021 20:59:37 +0000 (12:59 -0800)
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.com/

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>
net/bridge/br_multicast.c
net/bridge/br_netlink.c
net/bridge/br_private.h
net/bridge/br_sysfs_br.c
net/bridge/br_vlan_options.c

index f3d751105343ce035c3885ded7f778b07ada4ff0..998da4a2d209258e9f2707a7c521ef99ec5820e7 100644 (file)
@@ -4522,6 +4522,22 @@ int br_multicast_set_mld_version(struct net_bridge_mcast *brmctx,
 }
 #endif
 
+void br_multicast_set_query_intvl(struct net_bridge_mcast *brmctx,
+                                 unsigned long val)
+{
+       unsigned long intvl_jiffies = clock_t_to_jiffies(val);
+
+       if (intvl_jiffies < BR_MULTICAST_QUERY_INTVL_MIN) {
+               br_info(brmctx->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;
+       }
+
+       brmctx->multicast_query_interval = intvl_jiffies;
+}
+
 /**
  * br_multicast_list_adjacent - Returns snooped multicast addresses
  * @dev:       The bridge port adjacent to which to retrieve addresses
index 0c8b5f1a15bc0ba772f3f2a6b1f7e975a33cd42a..701dd8b8455e81c6f6954fe9633abc85b2ded890 100644 (file)
@@ -1357,7 +1357,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_ctx.multicast_query_interval = clock_t_to_jiffies(val);
+               br_multicast_set_query_intvl(&br->multicast_ctx, val);
        }
 
        if (data[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL]) {
index c0efd697865abea651263fc5258715e50c151726..4ed7f11042e87e14316a755ab17cafbf552df94c 100644 (file)
@@ -28,6 +28,7 @@
 #define BR_MAX_PORTS   (1<<BR_PORT_BITS)
 
 #define BR_MULTICAST_DEFAULT_HASH_MAX 4096
+#define BR_MULTICAST_QUERY_INTVL_MIN msecs_to_jiffies(1000)
 
 #define BR_HWDOM_MAX BITS_PER_LONG
 
@@ -963,6 +964,8 @@ int br_multicast_dump_querier_state(struct sk_buff *skb,
                                    int nest_attr);
 size_t br_multicast_querier_state_size(void);
 size_t br_rports_size(const struct net_bridge_mcast *brmctx);
+void br_multicast_set_query_intvl(struct net_bridge_mcast *brmctx,
+                                 unsigned long val);
 
 static inline bool br_group_is_l2(const struct br_ip *group)
 {
index d9a89ddd03310c0da2011adf76252f1316c97c58..f5bd1114a434ddec42bc214f7e1e5d155978ac87 100644 (file)
@@ -658,7 +658,7 @@ static ssize_t multicast_query_interval_show(struct device *d,
 static int set_query_interval(struct net_bridge *br, unsigned long val,
                              struct netlink_ext_ack *extack)
 {
-       br->multicast_ctx.multicast_query_interval = clock_t_to_jiffies(val);
+       br_multicast_set_query_intvl(&br->multicast_ctx, val);
        return 0;
 }
 
index 8ffd4ed2563c6c12431c9455e30d8907b23ed132..bf1ac087427941ea3e136ac160ac6561c79d95cd 100644 (file)
@@ -521,7 +521,7 @@ static int br_vlan_process_global_one_opts(const struct net_bridge *br,
                u64 val;
 
                val = nla_get_u64(tb[BRIDGE_VLANDB_GOPTS_MCAST_QUERY_INTVL]);
-               v->br_mcast_ctx.multicast_query_interval = clock_t_to_jiffies(val);
+               br_multicast_set_query_intvl(&v->br_mcast_ctx, val);
                *changed = true;
        }
        if (tb[BRIDGE_VLANDB_GOPTS_MCAST_QUERY_RESPONSE_INTVL]) {