]> git.baikalelectronics.ru Git - kernel.git/commit
tcp: avoid fastopen API to be used on AF_UNSPEC
authorWei Wang <weiwan@google.com>
Wed, 24 May 2017 16:59:31 +0000 (09:59 -0700)
committerDavid S. Miller <davem@davemloft.net>
Thu, 25 May 2017 17:30:34 +0000 (13:30 -0400)
commit00c00b3683a914fb8f4e27781e327a7e65b520e4
tree36ebb65ec11cd40346645d99844c1475698f4cfe
parentc0677e8e1f8822eff0ddf3854b109cf6bf3e96cb
tcp: avoid fastopen API to be used on AF_UNSPEC

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: e6ce93601acfe ("tcp: Fast Open client - sendmsg(MSG_FASTOPEN)")
Reported-by: Vegard Nossum <vegard.nossum@oracle.com>
Signed-off-by: Wei Wang <weiwan@google.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv4/tcp.c