[PATCH net 1/1] ipv6: flowlabel: enforce the per-socket lease cap on reused labels
From: Zhiling Zou <hidden>
Date: 2026-08-03 11:22:26
Subsystem:
networking [general], networking [ipv4/ipv6], the rest · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, David Ahern, Ido Schimmel, Linus Torvalds
ipv6_flowlabel_get() lets a socket reacquire an existing flowlabel and
link another ipv6_fl_socklist entry through the recheck path.
mem_check() only counts socket leases after fl_size falls below
FL_MAX_SIZE - FL_MAX_PER_SOCK. Reusing an existing flowlabel does not
increase fl_size, so duplicate GET requests can keep taking the
recheck path and grow one socket's lease list without ever hitting the
FL_MAX_PER_SOCK limit.
Check the current socket lease count before linking a reused
flowlabel. This keeps the duplicate-acquisition path consistent with
the long-standing per-socket cap without changing the global budget
logic for new flowlabels.
Fixes: 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Reported-by: Vega <redacted>
Signed-off-by: Zhiling Zou <redacted>
---
net/ipv6/ip6_flowlabel.c | 33 +++++++++++++++++++++++++++++----
1 file changed, 29 insertions(+), 4 deletions(-)
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
index 1ab5ad0dcf24f..e295f85bcc604 100644
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c@@ -493,6 +493,24 @@ static int mem_check(struct sock *sk) return 0; } +static int mem_check_dup(struct sock *sk) +{ + struct ipv6_fl_socklist *sfl; + int count = 0; + + lockdep_assert_held(&ip6_fl_lock); + + rcu_read_lock(); + for_each_sk_fl_rcu(sk, sfl) + count++; + rcu_read_unlock(); + + if (count >= FL_MAX_PER_SOCK && !capable(CAP_NET_ADMIN)) + return -ENOBUFS; + + return 0; +} + static inline void fl_link(struct sock *sk, struct ipv6_fl_socklist *sfl, struct ip6_flowlabel *fl) {
@@ -679,10 +697,17 @@ static int ipv6_flowlabel_get(struct sock *sk, struct in6_flowlabel_req *freq, err = -ENOMEM; if (!sfl1) goto release; - if (fl->linger > fl1->linger) - fl1->linger = fl->linger; - if ((long)(fl->expires - fl1->expires) > 0) - fl1->expires = fl->expires; + spin_lock_bh(&ip6_fl_lock); + err = mem_check_dup(sk); + if (err == 0) { + if (fl->linger > fl1->linger) + fl1->linger = fl->linger; + if ((long)(fl->expires - fl1->expires) > 0) + fl1->expires = fl->expires; + } + spin_unlock_bh(&ip6_fl_lock); + if (err != 0) + goto release; fl_link(sk, sfl1, fl1); fl_free(fl); return 0;
--
2.43.0