lkml.org 
[lkml]   [2020]   [Jun]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.4 115/142] xfrm: call xfrm_output_gso when inner_protocol is set in xfrm_output
    Date
    From: Xin Long <lucien.xin@gmail.com>

    commit a204aef9fd77dce1efd9066ca4e44eede99cd858 upstream.

    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: 7862b4058b9f ("esp: Add gso handlers for esp4 and esp6")
    Reported-by: Xiumei Mu <xmu@redhat.com>
    Signed-off-by: Xin Long <lucien.xin@gmail.com>
    Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    net/xfrm/xfrm_output.c | 12 +++++++-----
    1 file changed, 7 insertions(+), 5 deletions(-)

    --- a/net/xfrm/xfrm_output.c
    +++ b/net/xfrm/xfrm_output.c
    @@ -586,18 +586,20 @@ int xfrm_output(struct sock *sk, struct
    xfrm_state_hold(x);

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

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

    if (x->xso.dev && x->xso.dev->features & NETIF_F_HW_ESP_TX_CSUM)
    goto out;
    + } else {
    + if (skb_is_gso(skb))
    + return xfrm_output_gso(net, sk, skb);
    }

    - if (skb_is_gso(skb))
    - return xfrm_output_gso(net, sk, skb);
    -
    if (skb->ip_summed == CHECKSUM_PARTIAL) {
    err = skb_checksum_help(skb);
    if (err) {

    \
     
     \ /
      Last update: 2020-06-01 21:09    [W:4.042 / U:0.184 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site