Unresolved multicast cache entries retain up to four received skbs while
waiting for userspace to install an MFC route. The cache entry count was
tracked but no longer bounded, so a stream of distinct source and group
pairs could retain packet memory until the system ran out of memory.
Restore the unresolved-entry limit for both IPv4 and IPv6 multicast
routing. Reject new cache entries once the limit is reached while keeping
existing entries available for normal route resolution.
Fixes: 0079ad8e8dc3 ("ipmr: remove hard code cache_resolve_queue_len limit")
Cc: stable@vger.kernel.org
Reported-by: Vega <redacted>
Assisted-by: Codex:gpt-5.4
Signed-off-by: Zihan Xi <redacted>
---
include/linux/mroute_base.h | 3 +++
net/ipv4/ipmr.c | 6 ++++++
net/ipv6/ip6mr.c | 5 +++++
3 files changed, 14 insertions(+)
diff --git a/include/linux/mroute_base.h b/include/linux/mroute_base.h
index 4d55827e9705..af9247bb3f4d 100644
--- a/include/linux/mroute_base.h
+++ b/include/linux/mroute_base.h
@@ -224,6 +224,9 @@ struct mr_table_ops {
void *cmparg_any;
};
+/* Bound unresolved MFC entries and their queued skbs. */
+#define MFC_UNRES_QUEUE_LEN_MAX 10
+
/**
* struct mr_table - a multicast routing table
* @work: used for table destructiondiff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index e5f2b1c6150d..3155ad921ddc 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -1165,6 +1165,12 @@ static int ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi,
if (!found) {
/* Create a new entry if allowable */
+ if (mrt->cache_resolve_queue_len >= MFC_UNRES_QUEUE_LEN_MAX) {
+ c = NULL;
+ err = -ENOBUFS;
+ goto err;
+ }
+
c = ipmr_cache_alloc_unres();
if (!c) {
err = -ENOBUFS;diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 3f2ed9b77deb..551b04d4fa7c 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -1207,6 +1207,11 @@ static int ip6mr_cache_unresolved(struct mr_table *mrt, mifi_t mifi,
/*
* Create a new entry if allowable
*/
+ if (mrt->cache_resolve_queue_len >= MFC_UNRES_QUEUE_LEN_MAX) {
+ c = NULL;
+ err = -ENOBUFS;
+ goto err;
+ }
c = ip6mr_cache_alloc_unres();
if (!c) {--
2.43.0