From: Anton Danilov <littlesmilingcloud@gmail.com>
To: netdev@vger.kernel.org
Cc: Eric Dumazet <edumazet@kernel.org>,
Florian Westphal <fw@strlen.de>, Jakub Kicinski <kuba@kernel.org>,
Paolo Abeni <pabeni@redhat.com>,
"David S . Miller" <davem@davemloft.net>,
Simon Horman <horms@kernel.org>, David Ahern <dsahern@kernel.org>,
Ido Schimmel <idosch@nvidia.com>,
Mazin Al Haddad <mazin@getstate.dev>,
Matthias May <matthias.may@westermo.com>,
linux-kernel@vger.kernel.org, stable@vger.kernel.org
Subject: [PATCH net v4] ip6_gre: use skb_vlan_inet_prepare() instead of pskb_inet_may_pull()
Date: Sun, 4 Oct 2026 17:52:04 +0300 [thread overview]
Message-ID: <20261004145205.226974-1-littlesmilingcloud@gmail.com> (raw)
ip6gre_tunnel_xmit() and ip6erspan_tunnel_xmit() check the packet length
with pskb_inet_may_pull(), which looks at skb->protocol only, while the
code that follows parses the packet through VLAN tags with
skb_protocol(skb, true). The parsing started to look through the tags
with the two commits in the Fixes tags; the check was left as it was.
A VLAN-tagged frame whose inner IPv4/IPv6 header is not in the linear
area passes the check, and the inner header is read anyway. A 20 byte
tagged frame on ip6gretap and a 10 byte frame on ip6erspan are sent
out, while an untagged frame that is too short for its IP header is
already dropped.
Use skb_vlan_inet_prepare(), as the IPv6 receive path does since
commit 81c734dae203 ("ip6_tunnel: use skb_vlan_inet_prepare() in
__ip6_tnl_rcv()"). The second argument (inner_proto_inherit) depends on
the device: ip6gre_tunnel_xmit() serves both ip6gre (ARPHRD_IP6GRE, no
MAC header) and ip6gretap (ARPHRD_ETHER), so it is
dev->type != ARPHRD_ETHER there; ip6erspan is always an Ethernet device,
so it is false. vxlan does the same with no_eth_encap.
The tag walk starts at skb->mac_len - VLAN_HLEN, or at ETH_HLEN if
skb->mac_len is 0, and on transmit skb->mac_len is still what the skb
was received with. For a packet that came in through an NBMA gre
device and is routed out of a VLAN on ip6gretap or ip6erspan, the walk
starts inside the inner IPv4 header. Clear skb->mac_len for Ethernet
devices first.
An ip6gre device created without a remote uses ip6gre_header_ops, and
ip6gre_header() pushes a pseudo IPv6 header in front of the packet, so
there skb->data is not where the packet starts. skb_vlan_inet_prepare()
would move the network header onto that pseudo header, whose payload
length and GRE words are never written, and an ICMPv6 error for the
packet then quotes them: KMSAN reports uninit-value in
icmpv6_push_pending_frames(). Keep pskb_inet_may_pull() for that case,
as before this change.
With this change the two short frames above are dropped. gre_gso.sh,
l2_tos_ttl_inherit.sh and the mirror_gre, mirror_gre_vlan,
mirror_gre_bridge_1q and mirror_gre_changes forwarding selftests pass.
A constant true instead breaks the ip6gretap cases of mirror_gre.sh,
and a constant false breaks the ip6gre GSO cases of gre_gso.sh.
Fixes: 3f8a8447fd0b ("ip6_gre: use actual protocol to select xmit")
Fixes: b09ab9c92e50 ("ip6_tunnel: allow to inherit from VLAN encapsulated IP")
Reported-by: syzbot+6023ea32e206eef7920a@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=6023ea32e206eef7920a
Suggested-by: Eric Dumazet <edumazet@kernel.org>
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Anton Danilov <littlesmilingcloud@gmail.com>
---
v4: Anton Danilov takes over the patch, as Eric suggested in the v3 thread.
- inner_proto_inherit follows the device type instead of being a
constant.
- Clear skb->mac_len for Ethernet devices before the VLAN walk.
- Keep pskb_inet_may_pull() for ip6gre with header_ops.
- Fixes tags point at the commits that made the parsing look through
VLAN tags, instead of d8a6213d70ac ("geneve: fix header validation
in geneve[6]_xmit_skb"), which only added the helper.
- Discussion: https://lore.kernel.org/netdev/20261003220513.107668-1-littlesmilingcloud@gmail.com/
v3: https://lore.kernel.org/netdev/20260119112512.28196-1-fw@strlen.de/
v2: https://lore.kernel.org/netdev/20260106144529.1424886-1-edumazet@google.com/
v1: https://lore.kernel.org/netdev/20260105100330.2258612-1-edumazet@google.com/
net/ipv6/ip6_gre.c | 25 ++++++++++++++++++++++---
1 file changed, 22 insertions(+), 3 deletions(-)
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index e61cb10b50dc..f48141820fb5 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -883,8 +883,22 @@ static netdev_tx_t ip6gre_tunnel_xmit(struct sk_buff *skb,
__be16 payload_protocol;
int ret;
- if (!pskb_inet_may_pull(skb))
- goto tx_err;
+ if (dev->type != ARPHRD_ETHER && dev->header_ops) {
+ /* ip6gre_header() has pushed a pseudo header in front of
+ * the packet, so skb->data is not where the packet starts.
+ */
+ if (!pskb_inet_may_pull(skb))
+ goto tx_err;
+ } else {
+ /* The VLAN tag walks below start at skb->mac_len - VLAN_HLEN,
+ * or at ETH_HLEN if it is 0, and a forwarded skb still has
+ * the mac_len of the device it was received on.
+ */
+ if (dev->type == ARPHRD_ETHER)
+ skb->mac_len = 0;
+ if (skb_vlan_inet_prepare(skb, dev->type != ARPHRD_ETHER))
+ goto tx_err;
+ }
if (!ip6_tnl_xmit_ctl(t, &t->parms.laddr, &t->parms.raddr))
goto tx_err;
@@ -934,7 +948,12 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
__u32 mtu;
int nhoff;
- if (!pskb_inet_may_pull(skb))
+ /* The VLAN tag walks below start at skb->mac_len - VLAN_HLEN, or at
+ * ETH_HLEN if it is 0, and a forwarded skb still has the mac_len of
+ * the device it was received on.
+ */
+ skb->mac_len = 0;
+ if (skb_vlan_inet_prepare(skb, false))
goto tx_err;
if (!ip6_tnl_xmit_ctl(t, &t->parms.laddr, &t->parms.raddr))
--
2.47.3
next reply other threads:[~2026-10-04 14:52 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-04 14:52 Anton Danilov [this message]
2026-10-05 14:55 ` [PATCH net v4] ip6_gre: use skb_vlan_inet_prepare() instead of pskb_inet_may_pull() netdev-bot+sashiko
2026-10-05 23:07 ` Anton Danilov
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=20261004145205.226974-1-littlesmilingcloud@gmail.com \
--to=littlesmilingcloud@gmail.com \
--cc=davem@davemloft.net \
--cc=dsahern@kernel.org \
--cc=edumazet@kernel.org \
--cc=fw@strlen.de \
--cc=horms@kernel.org \
--cc=idosch@nvidia.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=matthias.may@westermo.com \
--cc=mazin@getstate.dev \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=stable@vger.kernel.org \
/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.