Commit 3d5221af authored by Jianbo Liu's avatar Jianbo Liu Committed by Steffen Klassert
Browse files

xfrm: Fix inner mode lookup in tunnel mode GSO segmentation



Commit 61fafbee ("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: 61fafbee ("xfrm: Determine inner GSO type from packet inner protocol")
Signed-off-by: default avatarJianbo Liu <jianbol@nvidia.com>
Reviewed-by: default avatarSabrina Dubroca <sd@queasysnail.net>
Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
parent 8f7aa3d3
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -122,8 +122,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);

+2 −2
Original line number Diff line number Diff line
@@ -158,8 +158,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);