mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH net-next v3] erspan: drop packets with an unknown ERSPAN version
@ 2026-11-08 19:35 Haishuang Yan
  2026-11-09 11:37 ` netdev-bot+sashiko
  0 siblings, 1 reply; 2+ messages in thread
From: Haishuang Yan @ 2026-11-08 19:35 UTC (permalink / raw)
  To: netdev
  Cc: David Ahern, Ido Schimmel, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Simon Horman, William Tu,
	linux-kernel

The ERSPAN type II and III receive paths take the length of the ERSPAN
header from the version field of the packet, with erspan_hdr_len(), but
never check that the version is one they know: 1 for type II or 2 for
type III.

For any other version, erspan_hdr_len() returns 0 or the type III
length. With version 0, the ERSPAN header is not pulled, so it is
passed up as the start of the inner Ethernet frame, and in collect_md
mode the metadata is filled from the wrong part of the header. The
ETH_HLEN pull in __iptunnel_pull_header() still covers the bytes that
are copied, so nothing is read past the pulled data.

Reject such packets, as a packet with a truncated ERSPAN header already
is.

On IPv4, a packet with a 4-byte GRE header is taken as type I without
looking at the protocol. gre_parse_header() treats an ETH_P_ERSPAN2
packet as carrying an ERSPAN header whatever the GRE header length,
but erspan_rcv() then skips that header's version and passes it up as
the inner frame. Type I only uses ETH_P_ERSPAN, so check the protocol
too. Such a packet now goes through the type III path and its version
check.

Signed-off-by: Haishuang Yan <yanhaishuang@cmss.chinamobile.com>
---
Tested on net-next fa5196392691 (x86_64 KVM guest), with hand-built
GRE/ERSPAN packets sent over a veth into erspan and ip6erspan devices,
in plain and collect_md mode: version 0 packets and ERSPAN2 packets
with a 4-byte GRE header and version 0 or 3 are now dropped, version 1
and 2 packets are unchanged, and erspan v1/v2 ping over IPv4 and IPv6
still works.

v3:
- Also check the protocol when classifying a packet as type I, so that
  an ETH_P_ERSPAN2 packet with a 4-byte GRE header gets the version
  check too (Sashiko).
v2: https://lore.kernel.org/netdev/20261107130030.35220-1-yanhaishuang@cmss.chinamobile.com/
- Drop the Fixes tags and correct the commit message: the ETH_HLEN pull
  of __iptunnel_pull_header() covers the metadata copy, so there is no
  out of bounds read (Ido, Sashiko).
- Drop the patch that skipped the type III sub-header, as no device is
  known to send it (Ido).
v1: https://lore.kernel.org/netdev/20261018090236.2487997-1-yanhaishuang@cmss.chinamobile.com/

 net/ipv4/ip_gre.c  | 12 +++++++-----
 net/ipv6/ip6_gre.c |  3 +++
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 5485586fa0e6..f8a7c4353502 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -255,13 +255,13 @@ static void gre_err(struct sk_buff *skb, u32 info)
 	ipgre_err(skb, info, &tpi);
 }
 
-static bool is_erspan_type1(int gre_hdr_len)
+static bool is_erspan_type1(const struct tnl_ptk_info *tpi, int gre_hdr_len)
 {
 	/* Both ERSPAN type I (version 0) and type II (version 1) use
 	 * protocol 0x88BE, but the type I has only 4-byte GRE header,
 	 * while type II has 8-byte.
 	 */
-	return gre_hdr_len == 4;
+	return tpi->proto == htons(ETH_P_ERSPAN) && gre_hdr_len == 4;
 }
 
 static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi,
@@ -282,7 +282,7 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi,
 
 	itn = net_generic(net, erspan_net_id);
 	iph = ip_hdr(skb);
-	if (is_erspan_type1(gre_hdr_len)) {
+	if (is_erspan_type1(tpi, gre_hdr_len)) {
 		ver = 0;
 		__set_bit(IP_TUNNEL_NO_KEY_BIT, flags);
 		tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, flags,
@@ -301,10 +301,12 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi,
 	}
 
 	if (tunnel) {
-		if (is_erspan_type1(gre_hdr_len))
+		if (is_erspan_type1(tpi, gre_hdr_len))
 			len = gre_hdr_len;
-		else
+		else if (ver == ERSPAN_VERSION || ver == ERSPAN_VERSION2)
 			len = gre_hdr_len + erspan_hdr_len(ver);
+		else
+			return PACKET_REJECT;
 
 		if (unlikely(!pskb_may_pull(skb, len)))
 			return PACKET_REJECT;
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index b5d6ed8f0c36..46fac89a0743 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -507,6 +507,9 @@ static int ip6erspan_rcv(struct sk_buff *skb,
 	if (tunnel) {
 		int len = erspan_hdr_len(ver);
 
+		if (unlikely(ver != ERSPAN_VERSION && ver != ERSPAN_VERSION2))
+			return PACKET_REJECT;
+
 		if (unlikely(!pskb_may_pull(skb, len)))
 			return PACKET_REJECT;
 

base-commit: fa5196392691051963726787944db872420dfa75
-- 
2.43.0




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

end of thread, other threads:[~2026-11-09 11:37 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-08 19:35 [PATCH net-next v3] erspan: drop packets with an unknown ERSPAN version Haishuang Yan
2026-11-09 11:37 ` netdev-bot+sashiko

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®