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 at all, so it
is passed up as the start of the inner Ethernet frame, and in collect_md
mode the metadata is copied from 8 bytes after the base header, which
pskb_may_pull() did not cover.
Reject such packets, as a packet with a truncated ERSPAN header already
is.
Fixes: f551c91de262 ("net: erspan: introduce erspan v2 for ip_gre")
Fixes: 94d7d8f29287 ("ip6_gre: add erspan v2 support")
Signed-off-by: Haishuang Yan <redacted>
---
net/ipv4/ip_gre.c | 4 +++-
net/ipv6/ip6_gre.c | 3 +++
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 3ee437fa3eae..2f112c1edf7c 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -303,8 +303,10 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi,
if (tunnel) {
if (is_erspan_type1(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 3d08240ea00c..3fe395ed92f9 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;
--
2.43.0