Linux Netfilter development
 help / color / mirror / Atom feed
* [PATCH v4 nf 0/2] ipvs: fix LBLC and LBLCR cache growth
@ 2026-09-10 10:08 Julian Anastasov
  2026-09-10 10:08 ` [PATCH v4 nf 1/2] ipvs: fix missing counter decrement in lblc Julian Anastasov
  2026-09-10 10:08 ` [PATCH v4 nf 2/2] ipvs: bound LBLCR and LBLC cache growth Julian Anastasov
  0 siblings, 2 replies; 3+ messages in thread
From: Julian Anastasov @ 2026-09-10 10:08 UTC (permalink / raw)
  To: Simon Horman
  Cc: Pablo Neira Ayuso, Florian Westphal, lvs-devel, netfilter-devel,
	Zhiling Zou, vega


        Hello,

        Following is a patchset with two changes:

1. fix for a missing decrement in LBLC

2. v3 of the LBLC/LBLCR patch from Zhiling Zou applied on top of the
first patch, as v4

        Zhiling Zou <zhilinz@nebusec.ai> explained the problem in v3:

We found and validated an issue in net/netfilter/ipvs/ip_vs_lblcr.c.
The bug is reachable by a non-root user through a new user and network
namespace. The same cache growth bound is also missing from the sibling
LBLC scheduler in net/netfilter/ipvs/ip_vs_lblc.c.

Bug details:

ip_vs_lblcr_new() allocates and publishes an LBLCR cache entry for
every previously unseen destination address. Although tbl->max_size is
initialized to 16384 entries, it is only used by the periodic collector
after cache growth has already exceeded the limit. The collector runs
once per minute and does not reclaim recently used entries.

An attacker can configure a fwmark-based LBLCR service and
continuously send UDP packets to distinct destination addresses. Each
new address creates an entry, allowing the table to grow without bound.
The allocations use GFP_ATOMIC and are not charged to the originating
socket or memory cgroup.

LBLC uses the same cache model and periodic collector. Bound new LBLC
cache entries the same way so both scheduler variants stop growing after
their table reaches max_size * 3 / 2.

The scheduler selects a destination before attempting to cache it and
already continues to use that destination when cache creation fails.
The fix therefore rejects only new cache entries once the table reaches
max_size * 3 / 2, while normal traffic to new addresses remains
serviceable without further cache growth.


Julian Anastasov (1):
  ipvs: fix missing counter decrement in lblc

Zhiling Zou (1):
  ipvs: bound LBLCR and LBLC cache growth

 net/netfilter/ipvs/ip_vs_lblc.c  | 4 ++++
 net/netfilter/ipvs/ip_vs_lblcr.c | 3 +++
 2 files changed, 7 insertions(+)

-- 
2.55.0



^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH v4 nf 1/2] ipvs: fix missing counter decrement in lblc
  2026-09-10 10:08 [PATCH v4 nf 0/2] ipvs: fix LBLC and LBLCR cache growth Julian Anastasov
@ 2026-09-10 10:08 ` Julian Anastasov
  2026-09-10 10:08 ` [PATCH v4 nf 2/2] ipvs: bound LBLCR and LBLC cache growth Julian Anastasov
  1 sibling, 0 replies; 3+ messages in thread
From: Julian Anastasov @ 2026-09-10 10:08 UTC (permalink / raw)
  To: Simon Horman
  Cc: Pablo Neira Ayuso, Florian Westphal, lvs-devel, netfilter-devel,
	Zhiling Zou, vega

LBLC may delete cache entries for destinations that are
removed or overloaded and replace them with available ones.
But ip_vs_lblc_new() forgets to decrement the tbl->entries
counter after calling ip_vs_lblc_del(). This can lead to
increased shrinking of the cache with every new garbage
collection.

Fixes: 2f3d771a35fe ("ipvs: do not use dest after ip_vs_dest_put in LBLC")
Link: https://sashiko.dev/#/patchset/0bdd5abe9968ded7ca2b9cb6844ba83d94cc8d53.1787318053.git.zhilinz%40nebusec.ai
Signed-off-by: Julian Anastasov <ja@ssi.bg>
---
 net/netfilter/ipvs/ip_vs_lblc.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/net/netfilter/ipvs/ip_vs_lblc.c b/net/netfilter/ipvs/ip_vs_lblc.c
index bff109c1c959..4d36c83d84cb 100644
--- a/net/netfilter/ipvs/ip_vs_lblc.c
+++ b/net/netfilter/ipvs/ip_vs_lblc.c
@@ -203,6 +203,7 @@ ip_vs_lblc_new(struct ip_vs_lblc_table *tbl, const union nf_inet_addr *daddr,
 		if (en->dest == dest)
 			return en;
 		ip_vs_lblc_del(en);
+		atomic_dec(&tbl->entries);
 	}
 	en = kmalloc_obj(*en, GFP_ATOMIC);
 	if (!en)
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH v4 nf 2/2] ipvs: bound LBLCR and LBLC cache growth
  2026-09-10 10:08 [PATCH v4 nf 0/2] ipvs: fix LBLC and LBLCR cache growth Julian Anastasov
  2026-09-10 10:08 ` [PATCH v4 nf 1/2] ipvs: fix missing counter decrement in lblc Julian Anastasov
@ 2026-09-10 10:08 ` Julian Anastasov
  1 sibling, 0 replies; 3+ messages in thread
From: Julian Anastasov @ 2026-09-10 10:08 UTC (permalink / raw)
  To: Simon Horman
  Cc: Pablo Neira Ayuso, Florian Westphal, lvs-devel, netfilter-devel,
	Zhiling Zou, vega

From: Zhiling Zou <zhilinz@nebusec.ai>

ip_vs_lblcr_new() and ip_vs_lblc_new() create cache entries for
every previously unseen destination address. The table max_size only
tells the periodic collector to reclaim entries after the cache has
already exceeded the limit. It does not reclaim entries that the
attacker continues to use.

Reject new cache entries once either table reaches max_size * 3 / 2.
The extra headroom lets the periodic collector catch up while the
existing scheduler fallback continues to use the selected destination
when cache creation fails. New traffic therefore stays serviceable
without growing the tables further.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Reported-by: Vega <vega@nebusec.ai>
Suggested-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Zhiling Zou <zhilinz@nebusec.ai>
Acked-by: Julian Anastasov <ja@ssi.bg>
---

changes in v4 (Julian):
- apply on top of "ipvs: fix missing counter decrement in lblc"
- v3 Link: https://lore.kernel.org/all/0bdd5abe9968ded7ca2b9cb6844ba83d94cc8d53.1787318053.git.zhilinz@nebusec.ai/

changes in v3:
- Allow 50% headroom above max_size before rejecting new cache entries,
  as suggested by Julian Anastasov.
- Apply the max_size * 3 / 2 cutoff to both LBLC and LBLCR.
- v2 Link: https://lore.kernel.org/all/17cbb1d0649f4e19aa2e407ab4b528d42b8edac4.1786949472.git.zhilinz@nebusec.ai/

changes in v2:
- Change the LBLCR limit check from >= max_size to > max_size.
- Apply the same cache growth bound to LBLC.
- Add Suggested-by: Julian Anastasov <ja@ssi.bg>.
- v1 Link: https://lore.kernel.org/all/62790a9f94ac5318f107a1811cff5a1f2fc7e0bf.1786884824.git.zhilinz@nebusec.ai/

 net/netfilter/ipvs/ip_vs_lblc.c  | 3 +++
 net/netfilter/ipvs/ip_vs_lblcr.c | 3 +++
 2 files changed, 6 insertions(+)

diff --git a/net/netfilter/ipvs/ip_vs_lblc.c b/net/netfilter/ipvs/ip_vs_lblc.c
index 4d36c83d84cb..e1111c3b2721 100644
--- a/net/netfilter/ipvs/ip_vs_lblc.c
+++ b/net/netfilter/ipvs/ip_vs_lblc.c
@@ -205,6 +205,9 @@ ip_vs_lblc_new(struct ip_vs_lblc_table *tbl, const union nf_inet_addr *daddr,
 		ip_vs_lblc_del(en);
 		atomic_dec(&tbl->entries);
 	}
+	if (atomic_read(&tbl->entries) >= tbl->max_size * 3 / 2)
+		return NULL;
+
 	en = kmalloc_obj(*en, GFP_ATOMIC);
 	if (!en)
 		return NULL;
diff --git a/net/netfilter/ipvs/ip_vs_lblcr.c b/net/netfilter/ipvs/ip_vs_lblcr.c
index c2853e07e787..dfb5bf83750d 100644
--- a/net/netfilter/ipvs/ip_vs_lblcr.c
+++ b/net/netfilter/ipvs/ip_vs_lblcr.c
@@ -363,6 +363,9 @@ ip_vs_lblcr_new(struct ip_vs_lblcr_table *tbl, const union nf_inet_addr *daddr,
 
 	en = ip_vs_lblcr_get(af, tbl, daddr);
 	if (!en) {
+		if (atomic_read(&tbl->entries) >= tbl->max_size * 3 / 2)
+			return NULL;
+
 		en = kmalloc_obj(*en, GFP_ATOMIC);
 		if (!en)
 			return NULL;
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-09-10 10:13 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-10 10:08 [PATCH v4 nf 0/2] ipvs: fix LBLC and LBLCR cache growth Julian Anastasov
2026-09-10 10:08 ` [PATCH v4 nf 1/2] ipvs: fix missing counter decrement in lblc Julian Anastasov
2026-09-10 10:08 ` [PATCH v4 nf 2/2] ipvs: bound LBLCR and LBLC cache growth Julian Anastasov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox