[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