Skip to content

Commit a204aef

Browse files
lxinklassert
authored andcommitted
xfrm: call xfrm_output_gso when inner_protocol is set in xfrm_output
An use-after-free crash can be triggered when sending big packets over vxlan over esp with esp offload enabled: [] BUG: KASAN: use-after-free in ipv6_gso_pull_exthdrs.part.8+0x32c/0x4e0 [] Call Trace: [] dump_stack+0x75/0xa0 [] kasan_report+0x37/0x50 [] ipv6_gso_pull_exthdrs.part.8+0x32c/0x4e0 [] ipv6_gso_segment+0x2c8/0x13c0 [] skb_mac_gso_segment+0x1cb/0x420 [] skb_udp_tunnel_segment+0x6b5/0x1c90 [] inet_gso_segment+0x440/0x1380 [] skb_mac_gso_segment+0x1cb/0x420 [] esp4_gso_segment+0xae8/0x1709 [esp4_offload] [] inet_gso_segment+0x440/0x1380 [] skb_mac_gso_segment+0x1cb/0x420 [] __skb_gso_segment+0x2d7/0x5f0 [] validate_xmit_skb+0x527/0xb10 [] __dev_queue_xmit+0x10f8/0x2320 <--- [] ip_finish_output2+0xa2e/0x1b50 [] ip_output+0x1a8/0x2f0 [] xfrm_output_resume+0x110e/0x15f0 [] __xfrm4_output+0xe1/0x1b0 [] xfrm4_output+0xa0/0x200 [] iptunnel_xmit+0x5a7/0x920 [] vxlan_xmit_one+0x1658/0x37a0 [vxlan] [] vxlan_xmit+0x5e4/0x3ec8 [vxlan] [] dev_hard_start_xmit+0x125/0x540 [] __dev_queue_xmit+0x17bd/0x2320 <--- [] ip6_finish_output2+0xb20/0x1b80 [] ip6_output+0x1b3/0x390 [] ip6_xmit+0xb82/0x17e0 [] inet6_csk_xmit+0x225/0x3d0 [] __tcp_transmit_skb+0x1763/0x3520 [] tcp_write_xmit+0xd64/0x5fe0 [] __tcp_push_pending_frames+0x8c/0x320 [] tcp_sendmsg_locked+0x2245/0x3500 [] tcp_sendmsg+0x27/0x40 As on the tx path of vxlan over esp, skb->inner_network_header would be set on vxlan_xmit() and xfrm4_tunnel_encap_add(), and the later one can overwrite the former one. It causes skb_udp_tunnel_segment() to use a wrong skb->inner_network_header, then the issue occurs. This patch is to fix it by calling xfrm_output_gso() instead when the inner_protocol is set, in which gso_segment of inner_protocol will be done first. While at it, also improve some code around. Fixes: 7862b40 ("esp: Add gso handlers for esp4 and esp6") Reported-by: Xiumei Mu <[email protected]> Signed-off-by: Xin Long <[email protected]> Signed-off-by: Steffen Klassert <[email protected]>
1 parent 6f29706 commit a204aef

File tree

1 file changed

+7
-5
lines changed

1 file changed

+7
-5
lines changed

net/xfrm/xfrm_output.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -583,18 +583,20 @@ int xfrm_output(struct sock *sk, struct sk_buff *skb)
583583
xfrm_state_hold(x);
584584

585585
if (skb_is_gso(skb)) {
586-
skb_shinfo(skb)->gso_type |= SKB_GSO_ESP;
586+
if (skb->inner_protocol)
587+
return xfrm_output_gso(net, sk, skb);
587588

588-
return xfrm_output2(net, sk, skb);
589+
skb_shinfo(skb)->gso_type |= SKB_GSO_ESP;
590+
goto out;
589591
}
590592

591593
if (x->xso.dev && x->xso.dev->features & NETIF_F_HW_ESP_TX_CSUM)
592594
goto out;
595+
} else {
596+
if (skb_is_gso(skb))
597+
return xfrm_output_gso(net, sk, skb);
593598
}
594599

595-
if (skb_is_gso(skb))
596-
return xfrm_output_gso(net, sk, skb);
597-
598600
if (skb->ip_summed == CHECKSUM_PARTIAL) {
599601
err = skb_checksum_help(skb);
600602
if (err) {

0 commit comments

Comments
 (0)