• Yuchung Cheng's avatar
    tcp: fix zero cwnd in tcp_cwnd_reduction · 8b8a321f
    Yuchung Cheng authored
    Patch 3759824d ("tcp: PRR uses CRB mode by default and SS mode
    conditionally") introduced a bug that cwnd may become 0 when both
    inflight and sndcnt are 0 (cwnd = inflight + sndcnt). This may lead
    to a div-by-zero if the connection starts another cwnd reduction
    phase by setting tp->prior_cwnd to the current cwnd (0) in
    tcp_init_cwnd_reduction().
    
    To prevent this we skip PRR operation when nothing is acked or
    sacked. Then cwnd must be positive in all cases as long as ssthresh
    is positive:
    
    1) The proportional reduction mode
       inflight > ssthresh > 0
    
    2) The reduction bound mode
      a) inflight == ssthresh > 0
    
      b) inflight < ssthresh
         sndcnt > 0 since newly_acked_sacked > 0 and inflight < ssthresh
    
    Therefore in all cases inflight and sndcnt can not both be 0.
    We check invalid tp->prior_cwnd to avoid potential div0 bugs.
    
    In reality this bug is triggered only with a sequence of less common
    events.  For example, the connection is terminating an ECN-triggered
    cwnd reduction with an inflight 0, then it receives reordered/old
    ACKs or DSACKs from prior transmission (which acks nothing). Or the
    connection is in fast recovery stage that marks everything lost,
    but fails to retransmit due to local issues, then receives data
    packets from other end which acks nothing.
    
    Fixes: 3759824d ("tcp: PRR uses CRB mode by default and SS mode conditionally")
    Reported-by: default avatarOleksandr Natalenko <oleksandr@natalenko.name>
    Signed-off-by: default avatarYuchung Cheng <ycheng@google.com>
    Signed-off-by: default avatarNeal Cardwell <ncardwell@google.com>
    Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
    Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
    8b8a321f
tcp_input.c 179 KB