• Wei Wang's avatar
    tcp: avoid fastopen API to be used on AF_UNSPEC · 4b81271e
    Wei Wang authored
    
    [ Upstream commit ba615f67 ]
    
    Fastopen API should be used to perform fastopen operations on the TCP
    socket. It does not make sense to use fastopen API to perform disconnect
    by calling it with AF_UNSPEC. The fastopen data path is also prone to
    race conditions and bugs when using with AF_UNSPEC.
    
    One issue reported and analyzed by Vegard Nossum is as follows:
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    Thread A:                            Thread B:
    ------------------------------------------------------------------------
    sendto()
     - tcp_sendmsg()
         - sk_stream_memory_free() = 0
             - goto wait_for_sndbuf
    	     - sk_stream_wait_memory()
    	        - sk_wait_event() // sleep
              |                          sendto(flags=MSG_FASTOPEN, dest_addr=AF_UNSPEC)
    	  |                           - tcp_sendmsg()
    	  |                              - tcp_sendmsg_fastopen()
    	  |                                 - __inet_stream_connect()
    	  |                                    - tcp_disconnect() //because of AF_UNSPEC
    	  |                                       - tcp_transmit_skb()// send RST
    	  |                                    - return 0; // no reconnect!
    	  |                           - sk_stream_wait_connect()
    	  |                                 - sock_error()
    	  |                                    - xchg(&sk->sk_err, 0)
    	  |                                    - return -ECONNRESET
    	- ... // wake up, see sk->sk_err == 0
        - skb_entail() on TCP_CLOSE socket
    
    If the connection is reopened then we will send a brand new SYN packet
    after thread A has already queued a buffer. At this point I think the
    socket internal state (sequence numbers etc.) becomes messed up.
    
    When the new connection is closed, the FIN-ACK is rejected because the
    sequence number is outside the window. The other side tries to
    retransmit,
    but __tcp_retransmit_skb() calls tcp_trim_head() on an empty skb which
    corrupts the skb data length and hits a BUG() in copy_and_csum_bits().
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    
    Hence, this patch adds a check for AF_UNSPEC in the fastopen data path
    and return EOPNOTSUPP to user if such case happens.
    
    Fixes: cf60af03 ("tcp: Fast Open client - sendmsg(MSG_FASTOPEN)")
    Reported-by: default avatarVegard Nossum <vegard.nossum@oracle.com>
    Signed-off-by: default avatarWei Wang <weiwan@google.com>
    Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
    Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    4b81271e
tcp.c 86.6 KB