From: Jianbo Liu Date: Thu, 20 Nov 2025 03:56:09 +0000 (+0200) Subject: xfrm: Fix inner mode lookup in tunnel mode GSO segmentation X-Git-Tag: v6.1.162~270 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1751d34fca4e9759a8356f6824d06e6179f9567e;p=thirdparty%2Fkernel%2Fstable.git xfrm: Fix inner mode lookup in tunnel mode GSO segmentation [ 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 Reviewed-by: Sabrina Dubroca Signed-off-by: Steffen Klassert Signed-off-by: Sasha Levin --- diff --git a/net/ipv4/esp4_offload.c b/net/ipv4/esp4_offload.c index cbfc8b5b15bd2..8d6a40054eaab 100644 --- a/net/ipv4/esp4_offload.c +++ b/net/ipv4/esp4_offload.c @@ -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); diff --git a/net/ipv6/esp6_offload.c b/net/ipv6/esp6_offload.c index 65d628e500059..460cf1dab9da2 100644 --- a/net/ipv6/esp6_offload.c +++ b/net/ipv6/esp6_offload.c @@ -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);