From: Tristan Madani <tristmd@gmail.com>
To: "David S . Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>
Cc: Mahesh Bandewar <maheshb@google.com>,
Andrew Lunn <andrew+netdev@lunn.ch>,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
stable@vger.kernel.org,
Tristan Madani <tristan@talencesecurity.com>
Subject: [PATCH net] ipvlan: add xmit recursion protection
Date: Sat, 11 Jul 2026 13:47:32 +0000 [thread overview]
Message-ID: <20260711134732.1385563-1-tristmd@gmail.com> (raw)
From: Tristan Madani <tristan@talencesecurity.com>
ipvlan devices can enter infinite transmit recursion when combined with
packet forwarding configurations (such as IPVS) that route traffic back
through the same ipvlan interface.
The recursion path is:
ipvlan_start_xmit -> ipvlan_queue_xmit -> ipvlan_xmit_mode_l3
-> ipvlan_process_outbound -> ip_local_out -> netfilter hooks
-> dev_queue_xmit -> ipvlan_start_xmit (recurse)
The existing per-CPU xmit recursion counter in __dev_queue_xmit()
(XMIT_RECURSION_LIMIT = 8) does detect the loop, but fires too late:
each recursion level consumes roughly 2KB of stack space through
ip_local_out and netfilter, and at 8 levels the cumulative usage
exceeds the 16KB kernel stack on x86_64. The resulting stack overflow
hits the VMAP_STACK guard page and causes a kernel panic.
Add a per-CPU counter that prevents any re-entry into
ipvlan_queue_xmit() while it is already executing on the same CPU.
This mirrors the approach used by tunnel devices (see
IP_TUNNEL_RECURSION_LIMIT in ip_tunnels.h) but with a stricter limit
appropriate for ipvlan.
Fixes: 2ad7bf363841 ("ipvlan: Initial check-in of the IPVLAN driver.")
Cc: stable@vger.kernel.org
Signed-off-by: Tristan Madani <tristan@talencesecurity.com>
---
drivers/net/ipvlan/ipvlan_core.c | 25 +++++++++++++++++++++----
1 file changed, 21 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c
index 835e04835..ab99eb624 100644
--- a/drivers/net/ipvlan/ipvlan_core.c
+++ b/drivers/net/ipvlan/ipvlan_core.c
@@ -9,6 +9,8 @@
static u32 ipvlan_jhash_secret __read_mostly;
+static DEFINE_PER_CPU(int, ipvlan_xmit_depth);
+
void ipvlan_init_secret(void)
{
net_get_random_once(&ipvlan_jhash_secret, sizeof(ipvlan_jhash_secret));
@@ -676,6 +678,7 @@ int ipvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ipvl_dev *ipvlan = netdev_priv(dev);
struct ipvl_port *port = ipvlan_port_get_rcu_bh(ipvlan->phy_dev);
+ int ret = NET_XMIT_DROP;
if (!port)
goto out;
@@ -683,18 +686,32 @@ int ipvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev)
if (unlikely(!pskb_may_pull(skb, sizeof(struct ethhdr))))
goto out;
+ if (this_cpu_read(ipvlan_xmit_depth)) {
+ net_crit_ratelimited("ipvlan: xmit recursion detected on dev %s\n",
+ dev->name);
+ goto out;
+ }
+
+ this_cpu_inc(ipvlan_xmit_depth);
switch(port->mode) {
case IPVLAN_MODE_L2:
- return ipvlan_xmit_mode_l2(skb, dev);
+ ret = ipvlan_xmit_mode_l2(skb, dev);
+ break;
case IPVLAN_MODE_L3:
#ifdef CONFIG_IPVLAN_L3S
case IPVLAN_MODE_L3S:
#endif
- return ipvlan_xmit_mode_l3(skb, dev);
+ ret = ipvlan_xmit_mode_l3(skb, dev);
+ break;
+ default:
+ WARN_ONCE(true, "%s called for mode = [%x]\n",
+ __func__, port->mode);
+ kfree_skb(skb);
+ break;
}
+ this_cpu_dec(ipvlan_xmit_depth);
+ return ret;
- /* Should not reach here */
- WARN_ONCE(true, "%s called for mode = [%x]\n", __func__, port->mode);
out:
kfree_skb(skb);
return NET_XMIT_DROP;
--
2.47.3
next reply other threads:[~2026-07-11 13:47 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-11 13:47 Tristan Madani [this message]
2026-07-11 14:00 ` [PATCH net] ipvlan: add xmit recursion protection Eric Dumazet
2026-07-11 20:47 ` [PATCH net v2] net: reduce XMIT_RECURSION_LIMIT under KASAN Tristan Madani
2026-07-21 20:04 ` Jakub Kicinski
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=20260711134732.1385563-1-tristmd@gmail.com \
--to=tristmd@gmail.com \
--cc=andrew+netdev@lunn.ch \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=maheshb@google.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=stable@vger.kernel.org \
--cc=tristan@talencesecurity.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.