aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2009-06-22 08:13:55 -0400
committerPatrick McHardy <kaber@trash.net>2009-06-22 08:13:55 -0400
commit8cc20198cfccd06cef705c14fd50bde603e2e306 (patch)
tree95934002dceac963afa7b135b39a9b2b6bdce368 /net
parentf6b24caaf933a466397915a08e30e885a32f905a (diff)
netfilter: nf_conntrack: death_by_timeout() fix
death_by_timeout() might delete a conntrack from hash list and insert it in dying list. nf_ct_delete_from_lists(ct); nf_ct_insert_dying_list(ct); I believe a (lockless) reader could *catch* ct while doing a lookup and miss the end of its chain. (nulls lookup algo must check the null value at the end of lookup and should restart if the null value is not the expected one. cf Documentation/RCU/rculist_nulls.txt for details) We need to change nf_conntrack_init_net() and use a different "null" value, guaranteed not being used in regular lists. Choose very large values, since hash table uses [0..size-1] null values. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Acked-by: Pablo Neira Ayuso <pablo@netfilter.org> Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/nf_conntrack_core.c10
1 files changed, 8 insertions, 2 deletions
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 5f72b94b4918..5276a2dd56fe 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -1267,13 +1267,19 @@ err_cache:
1267 return ret; 1267 return ret;
1268} 1268}
1269 1269
1270/*
1271 * We need to use special "null" values, not used in hash table
1272 */
1273#define UNCONFIRMED_NULLS_VAL ((1<<30)+0)
1274#define DYING_NULLS_VAL ((1<<30)+1)
1275
1270static int nf_conntrack_init_net(struct net *net) 1276static int nf_conntrack_init_net(struct net *net)
1271{ 1277{
1272 int ret; 1278 int ret;
1273 1279
1274 atomic_set(&net->ct.count, 0); 1280 atomic_set(&net->ct.count, 0);
1275 INIT_HLIST_NULLS_HEAD(&net->ct.unconfirmed, 0); 1281 INIT_HLIST_NULLS_HEAD(&net->ct.unconfirmed, UNCONFIRMED_NULLS_VAL);
1276 INIT_HLIST_NULLS_HEAD(&net->ct.dying, 0); 1282 INIT_HLIST_NULLS_HEAD(&net->ct.dying, DYING_NULLS_VAL);
1277 net->ct.stat = alloc_percpu(struct ip_conntrack_stat); 1283 net->ct.stat = alloc_percpu(struct ip_conntrack_stat);
1278 if (!net->ct.stat) { 1284 if (!net->ct.stat) {
1279 ret = -ENOMEM; 1285 ret = -ENOMEM;