From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-qv1-f71.google.com (mail-qv1-f71.google.com [209.85.219.71]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7D6C23B7B72 for ; Wed, 23 Sep 2026 03:52:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.71 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790135555; cv=none; b=SlYj1GPg8h73ikyEzqEFaaBnRLpddbdR1svFehdsdUauEd7r1fWHTFX66crYYInpoZSwW9RLlCYIePoolajLezWH7YCW4e8zciZPh5FfbsGTjtYwd2eZns+herRRO2YBKK0UhzrkluSD45O4NJxr1ZvUqAd12vbpj9CB/d1v+QA= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790135555; c=relaxed/simple; bh=Dl/7sLT48SGnsqc02ginEt6412z6YI6qpdUrXPg08q0=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=KV20e+IL7x451l+cy0EJiR5C8WzyANfpGeXz1s1g6pW6imOGryyHPl6ve0NZOd80FSR2IyK17BMtTyBVp/BjY8nX58SKW+o5U5z9JrOLkZIztxjKIFbRejjRtSg977y/zJ7o2zJXR+UywjR4ct1mUxw3fntp1SzT4Ryl/QEvVRU= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--edumazet.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=f63gSroa; arc=none smtp.client-ip=209.85.219.71 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--edumazet.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="f63gSroa" Received: by mail-qv1-f71.google.com with SMTP id 6a1803df08f44-90e8135d7eeso9079496d6.1 for ; Tue, 22 Sep 2026 20:52:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1790135552; x=1790740352; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=7dGWsyugkeBiAvstwI3BqXWrM8JznyumSObXzLvLvUU=; b=f63gSroac+Q00agYD3WqF+XZZcwBEve/LtPKzN8O9xYfwuvs7uNYudh1w3vGj0+JBD mdp6ZvCVqq7hChrOGCQK7xY0MVh1iBxDYSKZymsOJEa5jvPe/ucfXTqYVhvV6id1ttak rjdHvkNU8K0SOUHC3Wf0Ze7l/KbeFNWUOMJvNZPj+NLHr0tINq3t3rvotF04PKyD2WQr xI/Wh1PIcMD6kkrz82rOTPBou4iUBFCv0z3b5jgLYLSIcP3mfyWLBnRq6MPXFsl3fjyx uhNeg/IRW5pleOlXRi/w+7/buiDDrzo8xotvPROoPwdGj5SYWloZn9YkflU+JW5S9Hdm sg7Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790135552; x=1790740352; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=7dGWsyugkeBiAvstwI3BqXWrM8JznyumSObXzLvLvUU=; b=X+slNZU/mEXVddnI38EoLrJHjdOIeNz8b1qgHL7yXJT6A0gX5Q11BEigSK5Rr06wKl YDbrSAJA+2DOYXG+9LoqKWat6uf60QqZADVZqpSRzHGWHGPfZsCr6cmx069jkjtD70+r Zu/klwr2sNMYYq9DKCBG9+mIAuEwUYZktCc4B0jeaFUgJldBl+2szXYglI4XbUcOu4w6 UoAaJKCPJjiW1Cj66P9sT1KbzwZhQ11jmqEt8zhq50PmnxFORhnAOjAQEKfO1m+JzJhY wFyVy3bZ2O5LK/WKaLzTK/eAn+2c8xdg9g3BiHZfjyOxbw8M1hrdSgtPyhPRovlgDrAk kuVg== X-Forwarded-Encrypted: i=1; AKwUvBzy9WPQMeWCQMh7pdS9sARkU/T6X3zOqyOZi89orscDYTOF4kDHuiUfrRES8+2NkD7wh6mPXQI=@vger.kernel.org X-Gm-Message-State: AFuF++lfXI+T1P2ICZefcu++ANDtLRSQaa5nz9y67/DdSlERdNKohzcD a8FjJFUefB4eiKod/IUsNp2GaO0O1yhtSOWyx4I8fz+yz/eKEskUsTqb0Bvi0rMYlxSo+zv6+8+ VksDEF042mdasQA== X-Received: from qvc3.prod.google.com ([2002:a05:6214:8103:b0:912:53a1:3e84]) (user=edumazet job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6214:3197:b0:912:4653:9a80 with SMTP id 6a1803df08f44-9140c41f94emr21645756d6.24.1790135552070; Tue, 22 Sep 2026 20:52:32 -0700 (PDT) Date: Wed, 23 Sep 2026 03:52:17 +0000 In-Reply-To: <20260923035217.179102-1-edumazet@google.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260923035217.179102-1-edumazet@google.com> X-Mailer: git-send-email 2.55.0.1082.g2b9226bbc0-goog Message-ID: <20260923035217.179102-6-edumazet@google.com> Subject: [PATCH net v3 5/5] gre: do not read inner frame as erspan metadata in collect_md mode From: Eric Dumazet To: "David S . Miller" , Jakub Kicinski , Paolo Abeni Cc: Simon Horman , Kuniyuki Iwashima , netdev@vger.kernel.org, eric.dumazet@gmail.com, William Tu , Eric Dumazet , stable@vger.kernel.org Content-Type: text/plain; charset="UTF-8" erspan_rcv() and ip6erspan_rcv() copy the ERSPAN metadata out of the packet for collect_md tunnels: pkt_md = (struct erspan_metadata *)(gh + gre_hdr_len + sizeof(*ershdr)); ... memcpy(md2, pkt_md, ver == 1 ? ERSPAN_V1_MDSIZE : ERSPAN_V2_MDSIZE); Both read 8 bytes at 12 bytes from the start of the GRE header, assuming an ERSPAN version 1 or 2 header was pulled. Because __iptunnel_pull_header() with ETH_P_TEB linearizes an extra ETH_HLEN (14) bytes beyond @len, this does not read past skb->tail, but when erspan_hdr_len(ver) is 0 it copies bytes from the inner Ethernet frame into md->u.md2. Two ways to get there: - An ERSPAN type I packet has a 4-byte ETH_P_ERSPAN GRE header and no ERSPAN header at all, so erspan_rcv() sets ver = 0 and only pulls the GRE header. It still falls back to a collect_md tunnel through itn->collect_md_tun, and there the ternary above picks ERSPAN_V2_MDSIZE and reads 8 bytes of the inner Ethernet header as ERSPAN v2 metadata. Also check tpi->proto == htons(ETH_P_ERSPAN) in is_erspan_type1() to match gre_parse_header() so a 4-byte ETH_P_ERSPAN2 frame is not treated as Type I. - A packet with an 8-byte GRE header (or IPv6 ERSPAN) and ershdr->ver == 0 is malformed, yet neither erspan_rcv() nor ip6erspan_rcv() validates the version before using it, so erspan_hdr_len(0) pulls 0 bytes (leaving the 4-byte ERSPAN base header inside the inner frame) and copies inner frame bytes into md->u.md2. A version above 2 also stores a version that the transmit side (erspan_fb_xmit(), ip6erspan_tunnel_xmit()) rejects. Reject a base header whose version is neither 1 nor 2, and skip the metadata extraction for type I, which has none: ip_tun_rx_dst() hands out a zeroed option area, so md->version = 0 alone describes it. Fixes: f989d546a2d5 ("erspan: Add type I version 0 support.") Cc: stable@vger.kernel.org Signed-off-by: Eric Dumazet --- net/ipv4/ip_gre.c | 43 +++++++++++++++++++++++++++---------------- net/ipv6/ip6_gre.c | 2 ++ 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 7385d66a94bf49c84bc674ded51ed3f9f5352e28..a00df7bda0012b03aed50fd569cfd0611a67ce9f 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(int gre_hdr_len, __be16 proto) { /* 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 proto == htons(ETH_P_ERSPAN) && gre_hdr_len == 4; } static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, @@ -274,7 +274,6 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, struct ip_tunnel_net *itn; struct ip_tunnel *tunnel; const struct iphdr *iph; - struct erspan_md2 *md2; int ver; int len; @@ -282,7 +281,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(gre_hdr_len, tpi->proto)) { ver = 0; __set_bit(IP_TUNNEL_NO_KEY_BIT, flags); tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, flags, @@ -294,6 +293,9 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, ershdr = (struct erspan_base_hdr *)(skb->data + gre_hdr_len); ver = ershdr->ver; + if (unlikely(ver != 1 && ver != 2)) + return PACKET_REJECT; + iph = ip_hdr(skb); __set_bit(IP_TUNNEL_KEY_BIT, flags); tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, flags, @@ -301,7 +303,7 @@ 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(gre_hdr_len, tpi->proto)) len = gre_hdr_len; else len = gre_hdr_len + erspan_hdr_len(ver); @@ -318,6 +320,7 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, if (tunnel->collect_md) { struct erspan_metadata *pkt_md, *md; struct ip_tunnel_info *info; + struct erspan_md2 *md2; unsigned char *gh; __be64 tun_id; @@ -334,19 +337,27 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, info = &tun_dst->u.tun_info; info->options_len = sizeof(*md); - /* skb can be uncloned in __iptunnel_pull_header, so - * old pkt_md is no longer valid and we need to reset - * it - */ - gh = skb_network_header(skb) + - skb_network_header_len(skb); - pkt_md = (struct erspan_metadata *)(gh + gre_hdr_len + - sizeof(*ershdr)); md = ip_tunnel_info_opts(&tun_dst->u.tun_info); md->version = ver; - md2 = &md->u.md2; - memcpy(md2, pkt_md, ver == 1 ? ERSPAN_V1_MDSIZE : - ERSPAN_V2_MDSIZE); + + /* Type I has no ERSPAN header, thus no metadata to + * extract: pkt_md would point into the inner Ethernet + * frame just pulled by __iptunnel_pull_header(). + * ip_tun_rx_dst() zeroed @md for us. + */ + if (!is_erspan_type1(gre_hdr_len, tpi->proto)) { + /* skb can be uncloned in __iptunnel_pull_header, so + * old pkt_md is no longer valid and we need to reset + * it + */ + gh = skb_network_header(skb) + + skb_network_header_len(skb); + pkt_md = (struct erspan_metadata *)(gh + gre_hdr_len + + sizeof(*ershdr)); + md2 = &md->u.md2; + memcpy(md2, pkt_md, ver == 1 ? ERSPAN_V1_MDSIZE : + ERSPAN_V2_MDSIZE); + } __set_bit(IP_TUNNEL_ERSPAN_OPT_BIT, info->key.tun_flags); diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index e61cb10b50dc96295c14aa6da4c9c0fe47151335..774975955747ec4d822b66b8aaaee824c8d331df 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -503,6 +503,8 @@ static int ip6erspan_rcv(struct sk_buff *skb, ipv6h = ipv6_hdr(skb); ershdr = (struct erspan_base_hdr *)skb->data; ver = ershdr->ver; + if (unlikely(ver != 1 && ver != 2)) + return PACKET_REJECT; tunnel = ip6gre_tunnel_lookup(skb->dev, &ipv6h->saddr, &ipv6h->daddr, tpi->key, -- 2.55.0.1082.g2b9226bbc0-goog