mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Ali Firas <alishmery18@gmail.com>
To: netdev@vger.kernel.org, idosch@nvidia.com
Cc: kuba@kernel.org, pabeni@redhat.com, davem@davemloft.net,
	edumazet@google.com, andrew+netdev@lunn.ch, razor@blackwall.org,
	roopa@nvidia.com, linux-kernel@vger.kernel.org,
	Ali Firas <alishmery18@gmail.com>
Subject: [PATCH net 1/3] vxlan: vnifilter: limit the VNI range of a single request
Date: Wed,  9 Sep 2026 12:26:43 +0300	[thread overview]
Message-ID: <20260909092645.3105263-2-alishmery18@gmail.com> (raw)
In-Reply-To: <20260909092645.3105263-1-alishmery18@gmail.com>

VXLAN_VNIFILTER_ENTRY_START and VXLAN_VNIFILTER_ENTRY_END are parsed
without any bound on how far apart they are, so a single RTM_NEWTUNNEL
message can ask for the whole 24-bit VNI space. vxlan_vni_add_del() then
loops over that span creating one VNI node and one per-CPU stats block
per iteration, all under rtnl_lock.

Two things follow from that, both reachable by an unprivileged user in a
user+network namespace, since adding VNIs only requires CAP_NET_ADMIN in
the network namespace's user namespace:

  - the allocation is unbounded. Each VNI costs 128 bytes of slab plus
    64 bytes per possible CPU, so a full in-range request costs roughly
    2.1 GiB + 1 GiB per possible CPU. Measured in a QEMU guest on 2, 4
    and 8 CPU configurations, every one of them ends in a global OOM
    with the allocating task in vxlan_vnifilter_process(). No errno is
    returned because the calling process is itself OOM-killed, and the
    OOM killer also killed unrelated root-owned processes.

  - rtnl_lock is held for the entire loop. rtnl is global rather than
    per-netns, so unrelated network configuration blocks everywhere for
    as long as the request runs. Measured with a plain "ip link add
    dummy0 type dummy" in a different network namespace: it takes 0.011
    s normally, 4.472 s while a 1,000,000 VNI request runs, and during a
    full-range request it never completes at all.

Cap the span of one request at 4096 VNIs. The limit is on a single
request, not on how many VNIs a device may hold: a device can still be
populated with the whole VNI space, it just takes more than one message.
The value follows from how the interface is used in practice, on bridged
VXLAN devices where the VNI is derived from the VLAN and so cannot
exceed the 4094 usable VLAN IDs.

The limit is written as a driver-local constant rather than reusing
VLAN_N_VID. The two numbers coincide today, but a bound on a VXLAN
netlink request is not a count of VLAN IDs, and tying them together
would make a change to one silently change the other.

The check sits in vxlan_process_vni_filter(), where the span is known
and before any VNI is created, so it rejects the request before any work
is done. Both RTM_NEWTUNNEL and RTM_DELTUNNEL reach vxlan_vni_add_del()
through this one function, so a single check covers add and delete.

The span is inclusive, so START=0 END=4095 is 4096 VNIs and is accepted,
while START=0 END=4096 is 4097 and is rejected. A request carrying only
END has START default to 0 and is bounded the same way. A start above
the end selects no VNI at all and is deliberately left behaving as it
does today, rather than being turned into an error by unsigned
wraparound.

Fixes: f9c4bb0b245c ("vxlan: vni filtering support on collect metadata device")
Assisted-by: LLM
Signed-off-by: Ali Firas <alishmery18@gmail.com>
---
 drivers/net/vxlan/vxlan_vnifilter.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c
index dd94085e0886..f18ce0e1e741 100644
--- a/drivers/net/vxlan/vxlan_vnifilter.c
+++ b/drivers/net/vxlan/vxlan_vnifilter.c
@@ -17,6 +17,14 @@
 
 #include "vxlan_private.h"
 
+/* Maximum number of VNIs a single RTM_NEWTUNNEL or RTM_DELTUNNEL request may
+ * span.  VNI filtering is mainly used on bridged VXLAN devices where the VNI
+ * is derived from the VLAN, so a span wider than the VLAN ID space has no
+ * practical use, while an unbounded span lets one netlink message create up
+ * to 2^24 VNIs under rtnl_lock.
+ */
+#define VXLAN_VNI_FILTER_RANGE_MAX	4096
+
 static inline int vxlan_vni_cmp(struct rhashtable_compare_arg *arg,
 				const void *ptr)
 {
@@ -869,6 +877,17 @@ static int vxlan_process_vni_filter(struct vxlan_dev *vxlan,
 		return -EINVAL;
 	}
 
+	/* Only bound a well-formed range; a start above the end selects no
+	 * VNI at all and is left behaving as before.
+	 */
+	if (vni_end >= vni_start &&
+	    vni_end - vni_start >= VXLAN_VNI_FILTER_RANGE_MAX) {
+		NL_SET_ERR_MSG_ATTR_FMT(extack, nlvnifilter,
+					"VNI range spans more than %u VNIs",
+					VXLAN_VNI_FILTER_RANGE_MAX);
+		return -EINVAL;
+	}
+
 	if (vattrs[VXLAN_VNIFILTER_ENTRY_GROUP]) {
 		group.sin.sin_addr.s_addr =
 			nla_get_in_addr(vattrs[VXLAN_VNIFILTER_ENTRY_GROUP]);
-- 
2.53.0


  reply	other threads:[~2026-09-09  9:27 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20260907141001.GA708129@shredder>
2026-09-09  9:26 ` [PATCH net 0/3] vxlan: vnifilter: bound the VNI range per request Ali Firas
2026-09-09  9:26   ` Ali Firas [this message]
2026-09-10  9:38     ` [PATCH net 1/3] vxlan: vnifilter: limit the VNI range of a single request netdev-bot+sashiko
2026-09-15  0:31     ` Jakub Kicinski
2026-09-09  9:26   ` [PATCH net 2/3] vxlan: vnifilter: account VNI node and per-CPU stats to memcg Ali Firas
2026-09-10  9:38     ` netdev-bot+sashiko
2026-09-15  0:31     ` Jakub Kicinski
2026-09-09  9:26   ` [PATCH net 3/3] selftests: net: test the vxlan vnifilter VNI range limit Ali Firas
2026-09-10  9:39     ` netdev-bot+sashiko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260909092645.3105263-2-alishmery18@gmail.com \
    --to=alishmery18@gmail.com \
    --cc=andrew+netdev@lunn.ch \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=idosch@nvidia.com \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=razor@blackwall.org \
    --cc=roopa@nvidia.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®