]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
netfilter: nf_conntrack: fix confirmation race condition
authorPatrick McHardy <kaber@trash.net>
Mon, 22 Jun 2009 12:14:16 +0000 (14:14 +0200)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 30 Jul 2009 21:40:21 +0000 (14:40 -0700)
commit 5c8ec910e789a92229978d8fd1fce7b62e8ac711 upstream.

New connection tracking entries are inserted into the hash before they
are fully set up, namely the CONFIRMED bit is not set and the timer not
started yet. This can theoretically lead to a race with timer, which
would set the timeout value to a relative value, most likely already in
the past.

Perform hash insertion as the final step to fix this.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
net/netfilter/nf_conntrack_core.c

index 8020db6274b86471149533b40eecd89c496c24d5..c8bd559bbf8b4a13731b0a274d81220531544d92 100644 (file)
@@ -385,7 +385,6 @@ __nf_conntrack_confirm(struct sk_buff *skb)
        /* Remove from unconfirmed list */
        hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode);
 
-       __nf_conntrack_hash_insert(ct, hash, repl_hash);
        /* Timer relative to confirmation time, not original
           setting time, otherwise we'd get timer wrap in
           weird delay cases. */
@@ -393,8 +392,16 @@ __nf_conntrack_confirm(struct sk_buff *skb)
        add_timer(&ct->timeout);
        atomic_inc(&ct->ct_general.use);
        set_bit(IPS_CONFIRMED_BIT, &ct->status);
+
+       /* Since the lookup is lockless, hash insertion must be done after
+        * starting the timer and setting the CONFIRMED bit. The RCU barriers
+        * guarantee that no other CPU can find the conntrack before the above
+        * stores are visible.
+        */
+       __nf_conntrack_hash_insert(ct, hash, repl_hash);
        NF_CT_STAT_INC(net, insert);
        spin_unlock_bh(&nf_conntrack_lock);
+
        help = nfct_help(ct);
        if (help && help->helper)
                nf_conntrack_event_cache(IPCT_HELPER, ct);