netfilter: ctnetlink: fix racy timer in the creation path If we set a very small timer for new conntrack created via ctnetlink, the entry may expire before it is in the hashes, resulting in a crash. To fix this problem, the timer addition and the insertion into the hashes is done holding the nf_conntrack spin lock bh. Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_conntrack.h | 2 +- net/netfilter/nf_conntrack_core.c | 7 ++----- net/netfilter/nf_conntrack_netlink.c | 4 +++- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index b76a868..a05e2e2 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -197,7 +197,7 @@ extern void nf_ct_free_hashtable(struct hlist_head *hash, int vmalloced, extern struct nf_conntrack_tuple_hash * __nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple); -extern void nf_conntrack_hash_insert(struct nf_conn *ct); +extern void __nf_conntrack_insert(struct nf_conn *ct); extern void nf_conntrack_flush(struct net *net); diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 622d7c6..22246ec 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -298,18 +298,15 @@ static void __nf_conntrack_hash_insert(struct nf_conn *ct, &net->ct.hash[repl_hash]); } -void nf_conntrack_hash_insert(struct nf_conn *ct) +void __nf_conntrack_insert(struct nf_conn *ct) { unsigned int hash, repl_hash; hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); repl_hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); - - spin_lock_bh(&nf_conntrack_lock); __nf_conntrack_hash_insert(ct, hash, repl_hash); - spin_unlock_bh(&nf_conntrack_lock); } -EXPORT_SYMBOL_GPL(nf_conntrack_hash_insert); +EXPORT_SYMBOL_GPL(__nf_conntrack_insert); /* Confirm a connection given skb; places it in hash table */ int diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index b132124..2eb8fd3 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1151,8 +1151,10 @@ ctnetlink_create_conntrack(struct nlattr *cda[], ct->master = master_ct; } + spin_lock_bh(&nf_conntrack_lock); add_timer(&ct->timeout); - nf_conntrack_hash_insert(ct); + __nf_conntrack_insert(ct); + spin_unlock_bh(&nf_conntrack_lock); rcu_read_unlock(); return 0;