• Eric Dumazet's avatar
    tcp/dccp: fix timewait races in timer handling · ed2e9239
    Eric Dumazet authored
    When creating a timewait socket, we need to arm the timer before
    allowing other cpus to find it. The signal allowing cpus to find
    the socket is setting tw_refcnt to non zero value.
    
    As we set tw_refcnt in __inet_twsk_hashdance(), we therefore need to
    call inet_twsk_schedule() first.
    
    This also means we need to remove tw_refcnt changes from
    inet_twsk_schedule() and let the caller handle it.
    
    Note that because we use mod_timer_pinned(), we have the guarantee
    the timer wont expire before we set tw_refcnt as we run in BH context.
    
    To make things more readable I introduced inet_twsk_reschedule() helper.
    
    When rearming the timer, we can use mod_timer_pending() to make sure
    we do not rearm a canceled timer.
    
    Note: This bug can possibly trigger if packets of a flow can hit
    multiple cpus. This does not normally happen, unless flow steering
    is broken somehow. This explains this bug was spotted ~5 months after
    its introduction.
    
    A similar fix is needed for SYN_RECV sockets in reqsk_queue_hash_req(),
    but will be provided in a separate patch for proper tracking.
    
    Fixes: 789f558c ("tcp/dccp: get rid of central timewait timer")
    Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
    Reported-by: default avatarYing Cai <ycai@google.com>
    Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
    ed2e9239
inet_timewait_sock.h 4.11 KB