Netdev List
 help / color / mirror / Atom feed
* [PATCH net 0/5] vxlan: fixes for skb header pulling, cloning, and concurrency in TX path
@ 2026-07-23 14:42 Eric Dumazet
  2026-07-23 14:42 ` [PATCH net 1/5] vxlan: re-fetch eth header after route_shortcircuit() Eric Dumazet
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Eric Dumazet @ 2026-07-23 14:42 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, Ido Schimmel, Andrew Lunn, netdev, eric.dumazet,
	Eric Dumazet

While working on RTNL-less fill_info for vxlan, Sashiko found annoying
pre-existing issues, adding noise to an already complex work.

This series addresses some of them in VXLAN transmit path,
primarily within route_shortcircuit(), header validation, and neighbour lookup.

Patch 1 fixes a potential use-after-free in vxlan_xmit() caused by caching
the Ethernet header pointer ('eth') before calling route_shortcircuit(), which
can reallocate skb->head via pskb_may_pull().

Patch 2 calls skb_cow_head() in route_shortcircuit() before modifying the
Ethernet header in-place, preventing packet header corruption when the skb
is cloned (e.g., by packet sockets, tcpdump, or dev_queue_xmit).

Patch 3 replaces direct reads of n->ha in route_shortcircuit() with
neigh_ha_snapshot() to safely snapshot the neighbour hardware address under
seqlock protection, avoiding potential torn reads during asynchronous updates.

Patch 4 changes route_shortcircuit() to use pskb_network_may_pull() instead
of pskb_may_pull(). Since skb->data points to the MAC header on transmit
(skb_network_offset(skb) == ETH_HLEN), pskb_may_pull() was only checking 6
bytes into the IP header, leaving the remainder un-pulled in non-linear frags.

Patch 5 applies pskb_network_may_pull() to the remaining transmit-path header
pull checks in arp_reduce(), ND solicitation proxy checks, and MDB entry lookup,
where skb->data similarly points to the Ethernet header.

Eric Dumazet (5):
  vxlan: re-fetch eth header after route_shortcircuit()
  vxlan: unclone skb head before modifying eth header in
    route_shortcircuit()
  vxlan: use neigh_ha_snapshot() in route_shortcircuit()
  vxlan: use pskb_network_may_pull() in route_shortcircuit()
  vxlan: use pskb_network_may_pull() for transmit path header pulls

 drivers/net/vxlan/vxlan_core.c | 21 ++++++++++++++-------
 drivers/net/vxlan/vxlan_mdb.c  |  4 ++--
 2 files changed, 16 insertions(+), 9 deletions(-)

-- 
2.55.0.229.g6434b31f56-goog


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH net 1/5] vxlan: re-fetch eth header after route_shortcircuit()
  2026-07-23 14:42 [PATCH net 0/5] vxlan: fixes for skb header pulling, cloning, and concurrency in TX path Eric Dumazet
@ 2026-07-23 14:42 ` Eric Dumazet
  2026-07-23 14:42 ` [PATCH net 2/5] vxlan: unclone skb head before modifying eth header in route_shortcircuit() Eric Dumazet
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Eric Dumazet @ 2026-07-23 14:42 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, Ido Schimmel, Andrew Lunn, netdev, eric.dumazet,
	Eric Dumazet, stable

Before route_shortcircuit(), the eth header pointer is cached from eth_hdr(skb).

Inside route_shortcircuit(), pskb_may_pull() can be called, which may
reallocate skb->head.

In this case, returning to vxlan_xmit() leaves the cached eth pointer pointing to
freed memory, leading to a use-after-free when dereferencing eth->h_dest.

Fix this by updating eth = eth_hdr(skb) after calling route_shortcircuit().

Fixes: ae8840825605 ("VXLAN: Allow L2 redirection with L3 switching")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
 drivers/net/vxlan/vxlan_core.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index 67c367cc566233e809b0f70e0d939dd1c1ac0d9f..9060a1259ac283d4db4b7a854ce74203496e9313 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -2796,6 +2796,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
 	    (ntohs(eth->h_proto) == ETH_P_IP ||
 	     ntohs(eth->h_proto) == ETH_P_IPV6)) {
 		did_rsc = route_shortcircuit(dev, skb);
+		eth = eth_hdr(skb);
 		if (did_rsc)
 			f = vxlan_find_mac_tx(vxlan, eth->h_dest, vni);
 	}
-- 
2.55.0.229.g6434b31f56-goog


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH net 2/5] vxlan: unclone skb head before modifying eth header in route_shortcircuit()
  2026-07-23 14:42 [PATCH net 0/5] vxlan: fixes for skb header pulling, cloning, and concurrency in TX path Eric Dumazet
  2026-07-23 14:42 ` [PATCH net 1/5] vxlan: re-fetch eth header after route_shortcircuit() Eric Dumazet
@ 2026-07-23 14:42 ` Eric Dumazet
  2026-07-23 14:42 ` [PATCH net 3/5] vxlan: use neigh_ha_snapshot() " Eric Dumazet
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Eric Dumazet @ 2026-07-23 14:42 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, Ido Schimmel, Andrew Lunn, netdev, eric.dumazet,
	Eric Dumazet, stable

When route_shortcircuit() performs L3 short-circuit routing, it modifies
the Ethernet header of the skb in-place:
    memcpy(eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, dev->addr_len);
    memcpy(eth_hdr(skb)->h_dest, n->ha, dev->addr_len);

If the incoming skb is cloned (for example by packet sockets, tcpdump, or
dev_queue_xmit), modifying the Ethernet header without uncloning can corrupt
the packet header for other readers holding a reference to the cloned skb.

Ensure the skb header is writable and unshared by calling skb_cow_head(skb, 0)
prior to updating the Ethernet header. If skb_cow_head() fails, abort short-circuiting
and return false to allow standard packet processing fallback.

Fixes: e4f67addf158 ("add DOVE extensions for VXLAN")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
 drivers/net/vxlan/vxlan_core.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index 9060a1259ac283d4db4b7a854ce74203496e9313..fb4a706cd5786d1937b1922acced31ffdb187c2f 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -2163,6 +2163,10 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)
 
 		diff = !ether_addr_equal(eth_hdr(skb)->h_dest, n->ha);
 		if (diff) {
+			if (skb_cow_head(skb, 0)) {
+				neigh_release(n);
+				return false;
+			}
 			memcpy(eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest,
 				dev->addr_len);
 			memcpy(eth_hdr(skb)->h_dest, n->ha, dev->addr_len);
-- 
2.55.0.229.g6434b31f56-goog


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH net 3/5] vxlan: use neigh_ha_snapshot() in route_shortcircuit()
  2026-07-23 14:42 [PATCH net 0/5] vxlan: fixes for skb header pulling, cloning, and concurrency in TX path Eric Dumazet
  2026-07-23 14:42 ` [PATCH net 1/5] vxlan: re-fetch eth header after route_shortcircuit() Eric Dumazet
  2026-07-23 14:42 ` [PATCH net 2/5] vxlan: unclone skb head before modifying eth header in route_shortcircuit() Eric Dumazet
@ 2026-07-23 14:42 ` Eric Dumazet
  2026-07-23 14:42 ` [PATCH net 4/5] vxlan: use pskb_network_may_pull() " Eric Dumazet
  2026-07-23 14:42 ` [PATCH net 5/5] vxlan: use pskb_network_may_pull() for transmit path header pulls Eric Dumazet
  4 siblings, 0 replies; 6+ messages in thread
From: Eric Dumazet @ 2026-07-23 14:42 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, Ido Schimmel, Andrew Lunn, netdev, eric.dumazet,
	Eric Dumazet, stable

The neighbour hardware address n->ha can be updated asynchronously by the
neighbour subsystem, protected by n->ha_lock seqlock. Reading n->ha without
holding the seqlock loop can lead to torn reads or reading a partially updated
MAC address.

Use neigh_ha_snapshot() in route_shortcircuit() to safely copy n->ha under
read_seqbegin()/read_seqretry() lock protection before using it.

Note that arp_reduce() and neigh_reduce() seem to have the same issue
left for future patches.

Fixes: e4f67addf158 ("add DOVE extensions for VXLAN")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
 drivers/net/vxlan/vxlan_core.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index fb4a706cd5786d1937b1922acced31ffdb187c2f..10dd19eec09e266197ee51330a652f4e76c9643a 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -2159,9 +2159,11 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)
 	}
 
 	if (n) {
+		u8 haddr[ETH_ALEN];
 		bool diff;
 
-		diff = !ether_addr_equal(eth_hdr(skb)->h_dest, n->ha);
+		neigh_ha_snapshot(haddr, n, dev);
+		diff = !ether_addr_equal_unaligned(eth_hdr(skb)->h_dest, haddr);
 		if (diff) {
 			if (skb_cow_head(skb, 0)) {
 				neigh_release(n);
@@ -2169,7 +2171,7 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)
 			}
 			memcpy(eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest,
 				dev->addr_len);
-			memcpy(eth_hdr(skb)->h_dest, n->ha, dev->addr_len);
+			memcpy(eth_hdr(skb)->h_dest, haddr, dev->addr_len);
 		}
 		neigh_release(n);
 		return diff;
-- 
2.55.0.229.g6434b31f56-goog


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH net 4/5] vxlan: use pskb_network_may_pull() in route_shortcircuit()
  2026-07-23 14:42 [PATCH net 0/5] vxlan: fixes for skb header pulling, cloning, and concurrency in TX path Eric Dumazet
                   ` (2 preceding siblings ...)
  2026-07-23 14:42 ` [PATCH net 3/5] vxlan: use neigh_ha_snapshot() " Eric Dumazet
@ 2026-07-23 14:42 ` Eric Dumazet
  2026-07-23 14:42 ` [PATCH net 5/5] vxlan: use pskb_network_may_pull() for transmit path header pulls Eric Dumazet
  4 siblings, 0 replies; 6+ messages in thread
From: Eric Dumazet @ 2026-07-23 14:42 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, Ido Schimmel, Andrew Lunn, netdev, eric.dumazet,
	Eric Dumazet, stable

route_shortcircuit() currently calls pskb_may_pull(skb, sizeof(struct iphdr))
(or ipv6hdr), which checks if bytes are available starting from skb->data.

However, in vxlan_xmit(), skb->data points to the MAC header, so
skb_network_offset(skb) is ETH_HLEN (14 bytes). Using pskb_may_pull(skb, 20)
only checks 20 bytes from skb->data (which is 14 bytes MAC header + 6 bytes of
IP header), leaving the rest of the IP header potentially un-pulled in non-linear
frags. Subsequent dereferences of ip_hdr(skb)->daddr can read beyond the pulled
linear buffer length.

Fix this by using pskb_network_may_pull(), which adds skb_network_offset(skb) to
the length check to ensure the full network header is present in the linear buffer.

Fixes: e4f67addf158 ("add DOVE extensions for VXLAN")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
 drivers/net/vxlan/vxlan_core.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index 10dd19eec09e266197ee51330a652f4e76c9643a..9ccbebda860480f8378918ff360deee1c46f3f7d 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -2111,7 +2111,7 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)
 	{
 		struct iphdr *pip;
 
-		if (!pskb_may_pull(skb, sizeof(struct iphdr)))
+		if (!pskb_network_may_pull(skb, sizeof(struct iphdr)))
 			return false;
 		pip = ip_hdr(skb);
 		n = neigh_lookup(&arp_tbl, &pip->daddr, dev);
@@ -2137,7 +2137,7 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)
 		 */
 		if (!ipv6_mod_enabled())
 			return false;
-		if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
+		if (!pskb_network_may_pull(skb, sizeof(struct ipv6hdr)))
 			return false;
 		pip6 = ipv6_hdr(skb);
 		n = neigh_lookup(&nd_tbl, &pip6->daddr, dev);
-- 
2.55.0.229.g6434b31f56-goog


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH net 5/5] vxlan: use pskb_network_may_pull() for transmit path header pulls
  2026-07-23 14:42 [PATCH net 0/5] vxlan: fixes for skb header pulling, cloning, and concurrency in TX path Eric Dumazet
                   ` (3 preceding siblings ...)
  2026-07-23 14:42 ` [PATCH net 4/5] vxlan: use pskb_network_may_pull() " Eric Dumazet
@ 2026-07-23 14:42 ` Eric Dumazet
  4 siblings, 0 replies; 6+ messages in thread
From: Eric Dumazet @ 2026-07-23 14:42 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, Ido Schimmel, Andrew Lunn, netdev, eric.dumazet,
	Eric Dumazet, stable

In vxlan_xmit(), arp_reduce(), and vxlan_mdb_entry_skb_get(), pskb_may_pull() was
being called to verify the availability of network layer headers (ARP, IPv6/ND,
IP/IPv6 MDB keys).

However, during transmit skb->data points to the MAC header, so skb_network_offset(skb)
is ETH_HLEN (14 bytes). Using pskb_may_pull(skb, len) only checks len bytes from skb->data
rather than skb_network_offset(skb) + len, which can leave part of the network header
in non-linear frags.

Replace these remaining pskb_may_pull() calls with pskb_network_may_pull() to properly
account for the MAC header offset.

Fixes: 465016142711 ("vxlan: Add ARP reduction support")
Fixes: 9e061a50a116 ("vxlan: Add IPv6 Neighbor Discovery reduction support")
Fixes: 4e94f09d84bf ("vxlan: add MDB support")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: stable@vger.kernel.org
---
 drivers/net/vxlan/vxlan_core.c | 6 +++---
 drivers/net/vxlan/vxlan_mdb.c  | 4 ++--
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index 9ccbebda860480f8378918ff360deee1c46f3f7d..eff17987c5b531ecb1e2943b6274d20c1827d299 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -1850,7 +1850,7 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni)
 	if (dev->flags & IFF_NOARP)
 		goto out;
 
-	if (!pskb_may_pull(skb, arp_hdr_len(dev))) {
+	if (!pskb_network_may_pull(skb, arp_hdr_len(dev))) {
 		dev_dstats_tx_dropped(dev);
 		vxlan_vnifilter_count(vxlan, vni, NULL,
 				      VXLAN_VNI_STATS_TX_DROPS, 0);
@@ -2763,8 +2763,8 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
 			return arp_reduce(dev, skb, vni);
 #if IS_ENABLED(CONFIG_IPV6)
 		else if (ntohs(eth->h_proto) == ETH_P_IPV6 &&
-			 pskb_may_pull(skb, sizeof(struct ipv6hdr) +
-					    sizeof(struct nd_msg)) &&
+			 pskb_network_may_pull(skb, sizeof(struct ipv6hdr) +
+						    sizeof(struct nd_msg)) &&
 			 ipv6_hdr(skb)->nexthdr == IPPROTO_ICMPV6) {
 			struct nd_msg *m = (struct nd_msg *)(ipv6_hdr(skb) + 1);
 
diff --git a/drivers/net/vxlan/vxlan_mdb.c b/drivers/net/vxlan/vxlan_mdb.c
index af7a0d7f95a57a17486a8ecc277b7bb9d921a061..9a9038ae90c18c5f0e4362b2b254b0c48dfdad0e 100644
--- a/drivers/net/vxlan/vxlan_mdb.c
+++ b/drivers/net/vxlan/vxlan_mdb.c
@@ -1631,7 +1631,7 @@ struct vxlan_mdb_entry *vxlan_mdb_entry_skb_get(struct vxlan_dev *vxlan,
 
 	switch (skb->protocol) {
 	case htons(ETH_P_IP):
-		if (!pskb_may_pull(skb, sizeof(struct iphdr)))
+		if (!pskb_network_may_pull(skb, sizeof(struct iphdr)))
 			return NULL;
 		group.dst.sa.sa_family = AF_INET;
 		group.dst.sin.sin_addr.s_addr = ip_hdr(skb)->daddr;
@@ -1640,7 +1640,7 @@ struct vxlan_mdb_entry *vxlan_mdb_entry_skb_get(struct vxlan_dev *vxlan,
 		break;
 #if IS_ENABLED(CONFIG_IPV6)
 	case htons(ETH_P_IPV6):
-		if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
+		if (!pskb_network_may_pull(skb, sizeof(struct ipv6hdr)))
 			return NULL;
 		group.dst.sa.sa_family = AF_INET6;
 		group.dst.sin6.sin6_addr = ipv6_hdr(skb)->daddr;
-- 
2.55.0.229.g6434b31f56-goog


^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-07-23 14:43 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-23 14:42 [PATCH net 0/5] vxlan: fixes for skb header pulling, cloning, and concurrency in TX path Eric Dumazet
2026-07-23 14:42 ` [PATCH net 1/5] vxlan: re-fetch eth header after route_shortcircuit() Eric Dumazet
2026-07-23 14:42 ` [PATCH net 2/5] vxlan: unclone skb head before modifying eth header in route_shortcircuit() Eric Dumazet
2026-07-23 14:42 ` [PATCH net 3/5] vxlan: use neigh_ha_snapshot() " Eric Dumazet
2026-07-23 14:42 ` [PATCH net 4/5] vxlan: use pskb_network_may_pull() " Eric Dumazet
2026-07-23 14:42 ` [PATCH net 5/5] vxlan: use pskb_network_may_pull() for transmit path header pulls Eric Dumazet

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox