From: Cheng Yongkang <teel4res@gmail.com>
To: Nikolay Aleksandrov <razor@blackwall.org>,
Ido Schimmel <idosch@nvidia.com>
Cc: "David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@kernel.org>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Simon Horman <horms@kernel.org>,
bridge@lists.linux.dev, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: [PATCH net] net: bridge: mcast: validate the source limit before replace
Date: Thu, 29 Oct 2026 07:12:20 -0700 [thread overview]
Message-ID: <179328314075.648427.9644307795980106759@gmail.com> (raw)
br_mdb_replace_group_srcs() marks every existing source for deletion and
then re-adds the sources named by the NLM_F_REPLACE request. The add loop
checks PG_SRC_ENT_LIMIT before allocating each new source; if the
transient source count reaches the limit, br_mdb_add_group_srcs() unwinds
by deleting every source it processed, including the pre-existing sources
it just refreshed. The error path only clears BR_SGRP_F_DELETE and
cannot restore those sources or their (S,G) entries.
A replace with E existing sources and N distinct request sources not
already in the group fails at the limit if and only if E + N exceeds
PG_SRC_ENT_LIMIT. The rejected request currently leaves the group with
one fewer source and removes that source's (S,G) entry:
before: (*,G) star_srcs=31, S present, (S,G) present
after rejected replace: star_srcs=30, S and (S,G) removed
Count those new sources and reject the request with -ENOSPC before any
source is marked deleted or added, so a rejected replace changes no
state. Valid replaces, including ones that transiently reach the limit,
keep the same behavior. Other add-loop failure paths are unchanged.
Fixes: 61f2183512a7 ("bridge: mcast: Support replacement of MDB port group entries")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Cheng Yongkang <teel4res@gmail.com>
---
net/bridge/br_mdb.c | 51 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 50 insertions(+), 1 deletion(-)
diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c
index 0adcd15..f5b9df4 100644
--- a/net/bridge/br_mdb.c
+++ b/net/bridge/br_mdb.c
@@ -925,6 +925,24 @@ err_del_group_srcs:
return err;
}
+static bool br_mdb_src_addr_is_same(const struct br_ip *a,
+ const struct br_ip *b)
+{
+ if (a->proto != b->proto)
+ return false;
+
+ switch (a->proto) {
+ case htons(ETH_P_IP):
+ return a->src.ip4 == b->src.ip4;
+#if IS_ENABLED(CONFIG_IPV6)
+ case htons(ETH_P_IPV6):
+ return ipv6_addr_equal(&a->src.ip6, &b->src.ip6);
+#endif
+ }
+
+ return false;
+}
+
static int br_mdb_replace_group_srcs(const struct br_mdb_config *cfg,
struct net_bridge_port_group *pg,
struct net_bridge_mcast *brmctx,
@@ -932,7 +950,38 @@ static int br_mdb_replace_group_srcs(const struct br_mdb_config *cfg,
{
struct net_bridge_group_src *ent;
struct hlist_node *tmp;
- int err;
+ unsigned int num_new = 0;
+ int i, j, err;
+
+ /* Sources that already exist in the port group are refreshed, not
+ * added, so only the request sources that are not in the group yet
+ * consume a new entry. All request sources are added before the
+ * sources that are not part of the request are pruned, so the
+ * transient source count can exceed PG_SRC_ENT_LIMIT even when the
+ * resulting source list fits in it. br_mdb_add_group_srcs() would
+ * then fail with -ENOSPC and its unwind would delete every source it
+ * processed, including the pre-existing ones it just refreshed,
+ * which the error path below cannot restore. Detect this case
+ * upfront so that a rejected NLM_F_REPLACE changes no state.
+ */
+ for (i = 0; i < cfg->num_src_entries; i++) {
+ struct br_ip *addr = &cfg->src_entries[i].addr;
+
+ if (br_multicast_find_group_src(pg, addr))
+ continue;
+
+ for (j = 0; j < i; j++)
+ if (br_mdb_src_addr_is_same(addr,
+ &cfg->src_entries[j].addr))
+ break;
+ if (j == i)
+ num_new++;
+ }
+
+ if (pg->src_ents + num_new > PG_SRC_ENT_LIMIT) {
+ NL_SET_ERR_MSG_MOD(extack, "Failed to add new source entry");
+ return -ENOSPC;
+ }
hlist_for_each_entry(ent, &pg->src_list, node)
ent->flags |= BR_SGRP_F_DELETE;
--
2.34.1
reply other threads:[~2026-10-29 14:13 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=179328314075.648427.9644307795980106759@gmail.com \
--to=teel4res@gmail.com \
--cc=bridge@lists.linux.dev \
--cc=davem@davemloft.net \
--cc=edumazet@kernel.org \
--cc=horms@kernel.org \
--cc=idosch@nvidia.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=razor@blackwall.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox