mirror of
https://github.com/torvalds/linux.git
synced 2026-09-11 20:13:02 +02:00
ipv6: flowlabel: cap duplicate leases per socket
ipv6_flowlabel_get() allocates an ipv6_fl_socklist entry for every
successful GET. The recheck path for a compatible existing flowlabel
links another lease without applying any lease admission check. Repeated
GET requests for one shareable label can therefore grow a socket's lease
list without bound.
Reject a new unprivileged lease once the socket already holds
FL_MAX_PER_SOCK leases. Check this on the shared recheck path so reuse
of a globally interned label, including the fl_intern() collision path,
is covered as well. New-label admission remains under the existing
mem_check() policy.
Use capable(CAP_NET_ADMIN) rather than ns_capable(), matching
mem_check(). An unprivileged user must not bypass the cap by creating a
user namespace and a netns where they have CAP_NET_ADMIN, which would
still consume host memory.
Check the capability only when the socket reaches the limit, so
successful unprivileged GET requests below the cap do not generate a
capability audit. Do the admission check before updating linger and
expires so a rejected GET does not refresh the shared label, matching
the existing socket-list allocation failure path.
Fixes: 1da177e4c3 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Reported-by: Vega <vega@nebusec.ai>
Suggested-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Zhiling Zou <zhilinz@nebusec.ai>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/83f8535972ff6e3741548476a1d50dec24c758be.1788415194.git.zhilinz@nebusec.ai
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
4ff75f130d
commit
8d6cd18850
|
|
@ -461,6 +461,21 @@ fl_create(struct net *net, struct sock *sk, struct in6_flowlabel_req *freq,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static bool fl_sock_at_lease_limit(const struct sock *sk)
|
||||
{
|
||||
const struct ipv6_fl_socklist *sfl;
|
||||
int count = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
for_each_sk_fl_rcu(sk, sfl) {
|
||||
if (++count >= FL_MAX_PER_SOCK)
|
||||
break;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
return count >= FL_MAX_PER_SOCK;
|
||||
}
|
||||
|
||||
static int mem_check(struct sock *sk)
|
||||
{
|
||||
const int unpriv_total_limit = FL_MAX_SIZE - (FL_MAX_SIZE / 4);
|
||||
|
|
@ -679,6 +694,10 @@ static int ipv6_flowlabel_get(struct sock *sk, struct in6_flowlabel_req *freq,
|
|||
err = -ENOMEM;
|
||||
if (!sfl1)
|
||||
goto release;
|
||||
err = -ENOBUFS;
|
||||
if (fl_sock_at_lease_limit(sk) &&
|
||||
!capable(CAP_NET_ADMIN))
|
||||
goto release;
|
||||
if (fl->linger > fl1->linger)
|
||||
fl1->linger = fl->linger;
|
||||
if ((long)(fl->expires - fl1->expires) > 0)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user