[PATCH net 1/1] ipv6: flowlabel: enforce the per-socket lease cap on reused labels

Zhiling Zou <[email protected]>
Newsgroups org.kernel.vger.netdev
Message-ID <cf4fdc79ae4dc46bd4eb7eeb57e5de2091c13cd3.1785746178.git.zhilinz@nebusec.ai>
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: [email protected]
Reported-by: Vega <[email protected]>
Signed-off-by: Zhiling Zou <[email protected]>
---
 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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.