From: Chengfeng Ye <nicoyip.dev@gmail.com>
To: netdev@vger.kernel.org
Cc: Antoine Tenart <atenart@kernel.org>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Simon Horman <horms@kernel.org>, David Ahern <dsahern@kernel.org>,
Ido Schimmel <idosch@nvidia.com>,
linux-kernel@vger.kernel.org,
Chengfeng Ye <nicoyip.dev@gmail.com>,
stable@vger.kernel.org
Subject: [PATCH net v2] fou: ensure GUE headers have enough headroom
Date: Fri, 21 Aug 2026 22:59:08 +0800 [thread overview]
Message-ID: <20260821145908.2829132-1-nicoyip.dev@gmail.com> (raw)
In-Reply-To: <20260801060115.3538849-1-nicoyip.dev@gmail.com>
ipgre_changelink() installs GUE encapsulation before it publishes the
new GRE header length and updates dev->needed_headroom. The transmit
path does not serialize with RTNL, so it can interleave as follows:
CPU 0 (ipgre_changelink) CPU 1 (ipgre_xmit)
install GUE encapsulation
reserve the old needed_headroom
publish larger GRE flags
update tunnel->tun_hlen
push the larger GRE header
push the GUE and UDP headers
update dev->needed_headroom
With REMCSUM, the new layout can push 16 bytes of GRE and 20 bytes of
GUE/UDP headers into an skb with only 32 bytes of actual headroom. The
final UDP push writes four bytes before skb->head.
With the update window widened, the kernel reported:
skbuff: skb_under_panic: ... len:128 put:8 ... dev:gre0poc
kernel BUG at net/core/skbuff.c:214!
Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI
Call Trace:
skb_push
fou_build_udp
gue_build_header
ip_tunnel_xmit
__gre_xmit
ipgre_xmit
Make __gue_build_header() ensure space for both the GUE header it is
about to push and the UDP header that follows. On normally sized skbs
the check is a no-op. If configuration changes race with transmission,
skb_cow_head() expands the head before either GUE write, or returns an
error without modifying the packet.
skb_cow_head() may move skb->head. Refresh skb-derived inner_iph
pointers after encapsulation, and read the tunnel fragment and TTL
fields before ip_tunnel_encap() so ip_tunnel_xmit() does not dereference
tnl_params after a possible skb head reallocation.
Fixes: dd9d598c6657 ("ip_gre: add the support for i/o_flags update via netlink")
Cc: stable@vger.kernel.org
Signed-off-by: Chengfeng Ye <nicoyip.dev@gmail.com>
---
Changes in v2:
- Refresh skb-derived inner_iph pointers after ip_tunnel_encap() and read
frag_off and ttl from tnl_params before ip_tunnel_encap(), because the new
skb_cow_head() in the GUE builder can move skb->head.
Link: https://lore.kernel.org/netdev/20260801060115.3538849-1-nicoyip.dev@gmail.com/ [v1]
net/ipv4/fou_core.c | 2 ++
net/ipv4/ip_tunnel.c | 7 +++++--
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/net/ipv4/fou_core.c b/net/ipv4/fou_core.c
index ab09dfcdecbd..8cf0d43acb41 100644
--- a/net/ipv4/fou_core.c
+++ b/net/ipv4/fou_core.c
@@ -980,6 +980,8 @@ int __gue_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e,
skb, 0, 0, false);
hdrlen = sizeof(struct guehdr) + optlen;
+ if (skb_cow_head(skb, hdrlen + sizeof(struct udphdr)))
+ return -ENOMEM;
skb_push(skb, hdrlen);
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c
index 9d114bd575f9..2bd684eb2ba2 100644
--- a/net/ipv4/ip_tunnel.c
+++ b/net/ipv4/ip_tunnel.c
@@ -606,6 +606,7 @@ void ip_md_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
if (ip_tunnel_encap(skb, &tun_info->encap, &proto, &fl4) < 0)
goto tx_error;
+ inner_iph = (const struct iphdr *)skb_inner_network_header(skb);
use_cache = ip_tunnel_dst_cache_usable(skb, tun_info);
if (use_cache)
@@ -765,8 +766,12 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
tunnel->net, READ_ONCE(tunnel->parms.link),
tunnel->fwmark, skb_get_hash(skb), 0);
+ df = tnl_params->frag_off;
+ ttl = tnl_params->ttl;
+
if (ip_tunnel_encap(skb, &tunnel->encap, &protocol, &fl4) < 0)
goto tx_error;
+ inner_iph = (const struct iphdr *)skb_inner_network_header(skb);
if (connected && md) {
use_cache = ip_tunnel_dst_cache_usable(skb, tun_info);
@@ -799,7 +804,6 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
goto tx_error;
}
- df = tnl_params->frag_off;
if (payload_protocol == htons(ETH_P_IP) && !tunnel->ignore_df)
df |= (inner_iph->frag_off & htons(IP_DF));
@@ -821,7 +825,6 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
}
tos = ip_tunnel_ecn_encap(tos, inner_iph, skb);
- ttl = tnl_params->ttl;
if (ttl == 0) {
if (payload_protocol == htons(ETH_P_IP))
ttl = inner_iph->ttl;
--
2.43.0
next prev parent reply other threads:[~2026-08-21 14:59 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-01 6:01 [PATCH net] fou: ensure GUE headers have enough headroom Chengfeng Ye
2026-08-04 12:22 ` Antoine Tenart
2026-08-21 14:59 ` Chengfeng Ye [this message]
2026-08-24 7:50 ` [PATCH net v2] " Ido Schimmel
2026-08-24 11:20 ` Chengfeng Ye
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=20260821145908.2829132-1-nicoyip.dev@gmail.com \
--to=nicoyip.dev@gmail.com \
--cc=atenart@kernel.org \
--cc=davem@davemloft.net \
--cc=dsahern@kernel.org \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=idosch@nvidia.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--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.