From: Ido Schimmel <idosch@nvidia.com>
To: Ren Wei <enjou1224z@gmail.com>
Cc: netdev@vger.kernel.org, dsahern@kernel.org, davem@davemloft.net,
edumazet@google.com, pabeni@redhat.com, horms@kernel.org,
tom@herbertland.com, vega@nebusec.ai, petalzu987@gmail.com
Subject: Re: [PATCH net 1/1] ip6_tunnel: avoid racing encap setup in changelink
Date: Sun, 2 Aug 2026 21:33:00 +0300 [thread overview]
Message-ID: <20260802183300.GA481323@shredder> (raw)
In-Reply-To: <f4a1f215a63268d5b1028521537e8f292d5f41a6.1785221754.git.petalzu987@gmail.com>
On Tue, Jul 28, 2026 at 11:17:13PM +0800, Ren Wei wrote:
> From: Chai Zixuan <petalzu987@gmail.com>
>
> ip6_tnl_changelink() can change encapsulation parameters while the
> tunnel device is still accepting transmitters. A transmitter can
> reserve headroom using the old encapsulation header length and then
> build the packet after the live encapsulation state has changed. This
> can cause skb_push() to underflow the skb head.
>
> Validate new encapsulation parameters on a temporary tunnel object
> first. During live updates on running tunnel devices, stop the TX
> queues before waiting for existing transmitters with synchronize_net().
> Then apply the new encapsulation state and tunnel parameters before
> waking the queues again. This prevents both rejected changelink
> requests from mutating the live tunnel and new transmitters from
> entering after the synchronization point with mismatched state, without
> leaving stopped TX queues on down devices.
>
> Fixes: b3a27b519b22 ("ip6_tunnel: Add support for fou/gue encapsulation")
> Cc: stable@vger.kernel.org
> Reported-by: Vega <vega@nebusec.ai>
> Assisted-by: Codex:gpt-5.4
> Signed-off-by: Chai Zixuan <petalzu987@gmail.com>
> Signed-off-by: Ren Wei <enjou1224z@gmail.com>
There are many issues with this patch. Please check:
https://sashiko.dev/#/patchset/f4a1f215a63268d5b1028521537e8f292d5f41a6.1785221754.git.petalzu987%40gmail.com
https://netdev-ai.bots.linux.dev/sashiko/#/patchset/f4a1f215a63268d5b1028521537e8f292d5f41a6.1785221754.git.petalzu987%40gmail.com
And:
https://lore.kernel.org/all/83360de7addb13a3b5f4d5e722148f248fdb2ae0.1784884817.git.pabeni@redhat.com/
Too tired from reading walls of texts all day to give you a summary.
I think that taking a snapshot of t->encap and calculating encap_hlen
based on it should fix it. Something like [1] (not compile tested).
I'm pretty sure that IPv4 has a similar problem and that we also have
the same issue with the headers pushed by GRE / ERSPAN, but these should
be solved by other patches.
[1]
diff --git a/include/net/ip6_tunnel.h b/include/net/ip6_tunnel.h
index b99805ee2fd1..6e76e50a4406 100644
--- a/include/net/ip6_tunnel.h
+++ b/include/net/ip6_tunnel.h
@@ -106,22 +106,22 @@ static inline int ip6_encap_hlen(struct ip_tunnel_encap *e)
return hlen;
}
-static inline int ip6_tnl_encap(struct sk_buff *skb, struct ip6_tnl *t,
+static inline int ip6_tnl_encap(struct sk_buff *skb, struct ip_tunnel_encap *e,
u8 *protocol, struct flowi6 *fl6)
{
const struct ip6_tnl_encap_ops *ops;
int ret = -EINVAL;
- if (t->encap.type == TUNNEL_ENCAP_NONE)
+ if (e->type == TUNNEL_ENCAP_NONE)
return 0;
- if (t->encap.type >= MAX_IPTUN_ENCAP_OPS)
+ if (e->type >= MAX_IPTUN_ENCAP_OPS)
return -EINVAL;
rcu_read_lock();
- ops = rcu_dereference(ip6tun_encaps[t->encap.type]);
+ ops = rcu_dereference(ip6tun_encaps[e->type]);
if (likely(ops && ops->build_header))
- ret = ops->build_header(skb, &t->encap, protocol, fl6);
+ ret = ops->build_header(skb, e, protocol, fl6);
rcu_read_unlock();
return ret;
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 97c3f61d627b..7764442fed4e 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -1099,6 +1099,7 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
__u8 proto)
{
struct ip6_tnl *t = netdev_priv(dev);
+ struct ip_tunnel_encap ipencap;
struct net *net = t->net;
struct ipv6hdr *ipv6h;
struct ipv6_tel_txoption opt;
@@ -1106,10 +1107,11 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
struct net_device *tdev;
int err_count, mtu;
unsigned int eth_hlen = t->dev->type == ARPHRD_ETHER ? ETH_HLEN : 0;
- unsigned int psh_hlen = sizeof(struct ipv6hdr) + t->encap_hlen;
- unsigned int max_headroom = psh_hlen;
+ unsigned int max_headroom;
__be16 payload_protocol;
bool use_cache = false;
+ unsigned int psh_hlen;
+ int encap_hlen;
u8 hop_limit;
int err = -1;
@@ -1199,6 +1201,15 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
t->parms.name);
goto tx_err_dst_release;
}
+
+ /* Can tear, but better than skb_under_panic. */
+ ipencap = t->encap;
+ encap_hlen = ip6_encap_hlen(&ipencap);
+ if (unlikely(encap_hlen < 0))
+ goto tx_err_dst_release;
+ psh_hlen = sizeof(struct ipv6hdr) + encap_hlen;
+ max_headroom = psh_hlen;
+
mtu = dst6_mtu(dst) - eth_hlen - psh_hlen - t->tun_hlen;
if (encap_limit >= 0) {
max_headroom += 8;
@@ -1248,7 +1259,7 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
}
if (t->parms.collect_md) {
- if (t->encap.type != TUNNEL_ENCAP_NONE)
+ if (ipencap.type != TUNNEL_ENCAP_NONE)
goto tx_err_dst_release;
} else {
if (use_cache && ndst)
@@ -1269,10 +1280,10 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
* needed_headroom if necessary.
*/
max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(struct ipv6hdr)
- + dst->header_len + t->hlen;
+ + dst->header_len + t->tun_hlen + encap_hlen;
ip_tunnel_adj_headroom(dev, max_headroom);
- err = ip6_tnl_encap(skb, t, &proto, fl6);
+ err = ip6_tnl_encap(skb, &ipencap, &proto, fl6);
if (err)
return err;
prev parent reply other threads:[~2026-08-02 18:33 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-28 15:17 [PATCH net 0/1] ip6_tunnel: avoid racing encap setup Ren Wei
2026-07-28 15:17 ` [PATCH net 1/1] ip6_tunnel: avoid racing encap setup in changelink Ren Wei
2026-08-02 18:33 ` Ido Schimmel [this message]
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=20260802183300.GA481323@shredder \
--to=idosch@nvidia.com \
--cc=davem@davemloft.net \
--cc=dsahern@kernel.org \
--cc=edumazet@google.com \
--cc=enjou1224z@gmail.com \
--cc=horms@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=petalzu987@gmail.com \
--cc=tom@herbertland.com \
--cc=vega@nebusec.ai \
/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.