• Eric Dumazet's avatar
    tcp: better validation of received ack sequences · d0e1a1b5
    Eric Dumazet authored
    Paul Fiterau Brostean reported :
    
    <quote>
    Linux TCP stack we analyze exhibits behavior that seems odd to me.
    The scenario is as follows (all packets have empty payloads, no window
    scaling, rcv/snd window size should not be a factor):
    
           TEST HARNESS (CLIENT)                        LINUX SERVER
    
       1.  -                                          LISTEN (server listen,
    then accepts)
    
       2.  - --> <SEQ=100><CTL=SYN>               --> SYN-RECEIVED
    
       3.  - <-- <SEQ=300><ACK=101><CTL=SYN,ACK>  <-- SYN-RECEIVED
    
       4.  - --> <SEQ=101><ACK=301><CTL=ACK>      --> ESTABLISHED
    
       5.  - <-- <SEQ=301><ACK=101><CTL=FIN,ACK>  <-- FIN WAIT-1 (server
    opts to close the data connection calling "close" on the connection
    socket)
    
       6.  - --> <SEQ=101><ACK=99999><CTL=FIN,ACK> --> CLOSING (client sends
    FIN,ACK with not yet sent acknowledgement number)
    
       7.  - <-- <SEQ=302><ACK=102><CTL=ACK>      <-- CLOSING (ACK is 102
    instead of 101, why?)
    
    ... (silence from CLIENT)
    
       8.  - <-- <SEQ=301><ACK=102><CTL=FIN,ACK>  <-- CLOSING
    (retransmission, again ACK is 102)
    
    Now, note that packet 6 while having the expected sequence number,
    acknowledges something that wasn't sent by the server. So I would
    expect
    the packet to maybe prompt an ACK response from the server, and then be
    ignored. Yet it is not ignored and actually leads to an increase of the
    acknowledgement number in the server's retransmission of the FIN,ACK
    packet. The explanation I found is that the FIN  in packet 6 was
    processed, despite the acknowledgement number being unacceptable.
    Further experiments indeed show that the server processes this FIN,
    transitioning to CLOSING, then on receiving an ACK for the FIN it had
    send in packet 5, the server (or better said connection) transitions
    from CLOSING to TIME_WAIT (as signaled by netstat).
    
    </quote>
    
    Indeed, tcp_rcv_state_process() calls tcp_ack() but
    does not exploit the @acceptable status but for TCP_SYN_RECV
    state.
    
    What we want here is to send a challenge ACK, if not in TCP_SYN_RECV
    state. TCP_FIN_WAIT1 state is not the only state we should fix.
    
    Add a FLAG_NO_CHALLENGE_ACK so that tcp_rcv_state_process()
    can choose to send a challenge ACK and discard the packet instead
    of wrongly change socket state.
    
    With help from Neal Cardwell.
    Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
    Reported-by: default avatarPaul Fiterau Brostean <p.fiterau-brostean@science.ru.nl>
    Cc: Neal Cardwell <ncardwell@google.com>
    Cc: Yuchung Cheng <ycheng@google.com>
    Cc: Soheil Hassas Yeganeh <soheil@google.com>
    Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
    d0e1a1b5
tcp_input.c 183 KB