]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
xfrm: Fix inner mode lookup in tunnel mode GSO segmentation
authorJianbo Liu <jianbol@nvidia.com>
Thu, 20 Nov 2025 03:56:09 +0000 (05:56 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 6 Feb 2026 15:43:54 +0000 (16:43 +0100)
[ Upstream commit 3d5221af9c7711b7aec8da1298c8fc393ef6183d ]

Commit 61fafbee6cfe ("xfrm: Determine inner GSO type from packet inner
protocol") attempted to fix GSO segmentation by reading the inner
protocol from XFRM_MODE_SKB_CB(skb)->protocol. This was incorrect
because the field holds the inner L4 protocol (TCP/UDP) instead of the
required tunnel protocol. Also, the memory location (shared by
XFRM_SKB_CB(skb) which could be overwritten by xfrm_replay_overflow())
is prone to corruption. This combination caused the kernel to select
the wrong inner mode and get the wrong address family.

The correct value is in xfrm_offload(skb)->proto, which is set from
the outer tunnel header's protocol field by esp[4|6]_gso_encap(). It
is initialized by xfrm[4|6]_tunnel_encap_add() to either IPPROTO_IPIP
or IPPROTO_IPV6, using xfrm_af2proto() and correctly reflects the
inner packet's address family.

Fixes: 61fafbee6cfe ("xfrm: Determine inner GSO type from packet inner protocol")
Signed-off-by: Jianbo Liu <jianbol@nvidia.com>
Reviewed-by: Sabrina Dubroca <sd@queasysnail.net>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
net/ipv4/esp4_offload.c
net/ipv6/esp6_offload.c

index cbfc8b5b15bd23afa6c905397be6cdb564c19f65..8d6a40054eaabd85a15d78c4adb957e211dd2bdb 100644 (file)
@@ -110,8 +110,8 @@ static struct sk_buff *xfrm4_tunnel_gso_segment(struct xfrm_state *x,
                                                struct sk_buff *skb,
                                                netdev_features_t features)
 {
-       const struct xfrm_mode *inner_mode = xfrm_ip2inner_mode(x,
-                                       XFRM_MODE_SKB_CB(skb)->protocol);
+       struct xfrm_offload *xo = xfrm_offload(skb);
+       const struct xfrm_mode *inner_mode = xfrm_ip2inner_mode(x, xo->proto);
        __be16 type = inner_mode->family == AF_INET6 ? htons(ETH_P_IPV6)
                                                     : htons(ETH_P_IP);
 
index 65d628e5000597e3c37be4a470b4290085a3c37d..460cf1dab9da2d040c4ae6f710052c70c26d7a6d 100644 (file)
@@ -145,8 +145,8 @@ static struct sk_buff *xfrm6_tunnel_gso_segment(struct xfrm_state *x,
                                                struct sk_buff *skb,
                                                netdev_features_t features)
 {
-       const struct xfrm_mode *inner_mode = xfrm_ip2inner_mode(x,
-                                       XFRM_MODE_SKB_CB(skb)->protocol);
+       struct xfrm_offload *xo = xfrm_offload(skb);
+       const struct xfrm_mode *inner_mode = xfrm_ip2inner_mode(x, xo->proto);
        __be16 type = inner_mode->family == AF_INET ? htons(ETH_P_IP)
                                                    : htons(ETH_P_IPV6);