• Eric Dumazet's avatar
    tcp: replace TCP_SKB_CB(skb)->tcp_tw_isn with a per-cpu field · 41eecbd7
    Eric Dumazet authored
    TCP can transform a TIMEWAIT socket into a SYN_RECV one from
    a SYN packet, and the ISN of the SYNACK packet is normally
    generated using TIMEWAIT tw_snd_nxt :
    
    tcp_timewait_state_process()
    ...
        u32 isn = tcptw->tw_snd_nxt + 65535 + 2;
        if (isn == 0)
            isn++;
        TCP_SKB_CB(skb)->tcp_tw_isn = isn;
        return TCP_TW_SYN;
    
    This SYN packet also bypasses normal checks against listen queue
    being full or not.
    
    tcp_conn_request()
    ...
           __u32 isn = TCP_SKB_CB(skb)->tcp_tw_isn;
    ...
            /* TW buckets are converted to open requests without
             * limitations, they conserve resources and peer is
             * evidently real one.
             */
            if ((syncookies == 2 || inet_csk_reqsk_queue_is_full(sk)) && !isn) {
                    want_cookie = tcp_syn_flood_action(sk, rsk_ops->slab_name);
                    if (!want_cookie)
                            goto drop;
            }
    
    This was using TCP_SKB_CB(skb)->tcp_tw_isn field in skb.
    
    Unfortunately this field has been accidentally cleared
    after the call to tcp_timewait_state_process() returning
    TCP_TW_SYN.
    
    Using a field in TCP_SKB_CB(skb) for a temporary state
    is overkill.
    
    Switch instead to a per-cpu variable.
    
    As a bonus, we do not have to clear tcp_tw_isn in TCP receive
    fast path.
    It is temporarily set then cleared only in the TCP_TW_SYN dance.
    
    Fixes: 4ad19de8 ("net: tcp6: fix double call of tcp_v6_fill_cb()")
    Fixes: eeea10b8 ("tcp: add tcp_v4_fill_cb()/tcp_v4_restore_cb()")
    Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
    Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
    41eecbd7
tcp_input.c 208 KB