From: Rustam Mustafin <rmustafin@cloudlinux.com>
To: Steffen Klassert <steffen.klassert@secunet.com>,
Herbert Xu <herbert@gondor.apana.org.au>,
"David S. Miller" <davem@davemloft.net>
Cc: Eric Dumazet <edumazet@kernel.org>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Simon Horman <horms@kernel.org>,
netdev@vger.kernel.org, ipsec@lists.linux.dev,
linux-kernel@vger.kernel.org,
Rustam Mustafin <rmustafin@cloudlinux.com>,
stable@vger.kernel.org
Subject: [PATCH ipsec] xfrm6: gate the local error on the frame's own socket
Date: Sat, 14 Nov 2026 19:55:52 +0700 [thread overview]
Message-ID: <20261114125552.1319352-1-rmustafin@cloudlinux.com> (raw)
__xfrm6_output() decides to report a too big frame as a local error by
looking at its sk argument, but xfrm_local_error() reports to skb->sk
and dereferences it unchecked. The two differ for a UDP tunnel: vxlan,
geneve and other udp_tunnel6_xmit_skb() users pass the tunnel socket as
sk, while a frame they forward has no skb->sk. When such a frame takes
an IPv6 tunnel mode xfrm bundle and exceeds its MTU, xfrm_local_error()
oopses on skb->sk->sk_family in softirq context:
KASAN: null-ptr-deref in range [0x0000000000000010-0x0000000000000017]
RIP: 0010:xfrm_local_error+0x92/0x190
Call Trace:
<IRQ>
xfrm6_output+0x599/0xae0
udp_tunnel6_xmit_skb+0x713/0xd90
vxlan_xmit_one+0x1ebc/0x3490
vxlan_xmit+0x1369/0x6540
dev_hard_start_xmit+0xe3/0x5b0
__dev_queue_xmit+0x18e7/0x3550
ip6_output+0x360/0xec0
ip6_forward+0x1573/0x35c0
Commit 1620c88887b1 ("xfrm: Fix the usage of skb->sk") changed this
test from skb->sk to sk. Test skb_to_full_sk(skb) instead, as
xfrm6_tunnel_check_size() already does; commit 6973a21ee73c
("ipv6: xfrm: use full sockets in local error paths") made the IPv6
callees use full sockets the same way.
A frame without a socket then goes to ip6_fragment(), which sends an
ICMPv6 Packet Too Big to the source address of the outer header, the
local tunnel endpoint, and drops the frame, as before 1620c88887b1. A
caller that passes a NULL sk while skb->sk is set, such as
ip6tunnel_xmit(NULL, ...) in ip6_tunnel.c, takes the local error path
again, also as before that commit.
Fixes: 1620c88887b1 ("xfrm: Fix the usage of skb->sk")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Rustam Mustafin <rmustafin@cloudlinux.com>
---
Notes:
Tested in virtme-ng on 7e1392a42ea2 (v7.4-rc2+) with KASAN: vxlan over
an IPv6 ESP tunnel, a forwarded frame above the bundle MTU.
Unpatched: the oops above.
Patched: no oops in 3 runs. A separate run with nstat in the
forwarding netns shows Ip6FragFails 0->2, Icmp6OutPktTooBigs 0->2 and
Ip6FragCreates 0->0.
The reproducer script is available on request.
Not changed here:
- The xfrm6_local_dontfrag(sk) test in the same function still uses the
argument. Its callee xfrm6_local_rxpmtu() returns on a NULL skb->sk
since 6973a21ee73c, so that mismatch does not oops.
- iptfs_is_too_big() has the same sk vs skb->sk mismatch (IPv6 oops,
IPv4 silent drop). It is left for a separate patch; it was already
pointed out in two reviews:
https://lore.kernel.org/r/20260908224856.1591189-1-kuba@kernel.org
https://lore.kernel.org/r/179369310739.488856.16665150928122536725@kernel.org
net/ipv6/xfrm6_output.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
index 44b221a09a0c..54fcf4b43091 100644
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -95,7 +95,10 @@ static int __xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
} else if (toobig && xfrm6_noneed_fragment(skb)) {
skb->ignore_df = 1;
goto skip_frag;
- } else if (!skb->ignore_df && toobig && sk) {
+ } else if (!skb->ignore_df && toobig && skb_to_full_sk(skb)) {
+ /* xfrm_local_error() reports to skb->sk; a forwarded frame
+ * sent through a UDP tunnel has none, sk is the tunnel's.
+ */
xfrm_local_error(skb, mtu);
kfree_skb(skb);
return -EMSGSIZE;
base-commit: 7e1392a42ea288d70a266f6553fe06f57f8647ea
--
2.52.0
reply other threads:[~2026-11-14 12:56 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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=20261114125552.1319352-1-rmustafin@cloudlinux.com \
--to=rmustafin@cloudlinux.com \
--cc=davem@davemloft.net \
--cc=edumazet@kernel.org \
--cc=herbert@gondor.apana.org.au \
--cc=horms@kernel.org \
--cc=ipsec@lists.linux.dev \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=stable@vger.kernel.org \
--cc=steffen.klassert@secunet.com \
/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.