aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2010-02-08 14:16:56 -0500
committerDavid S. Miller <davem@davemloft.net>2010-02-08 14:16:56 -0500
commit5b3501faa8741d50617ce4191c20061c6ef36cb3 (patch)
treefd3ac41baea9db5d795144da48cef46aca3e01f6
parent9edd7ca0a3e3999c260642c92fa008892d82ca6e (diff)
netfilter: nf_conntrack: per netns nf_conntrack_cachep
nf_conntrack_cachep is currently shared by all netns instances, but because of SLAB_DESTROY_BY_RCU special semantics, this is wrong. If we use a shared slab cache, one object can instantly flight between one hash table (netns ONE) to another one (netns TWO), and concurrent reader (doing a lookup in netns ONE, 'finding' an object of netns TWO) can be fooled without notice, because no RCU grace period has to be observed between object freeing and its reuse. We dont have this problem with UDP/TCP slab caches because TCP/UDP hashtables are global to the machine (and each object has a pointer to its netns). If we use per netns conntrack hash tables, we also *must* use per netns conntrack slab caches, to guarantee an object can not escape from one namespace to another one. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> [Patrick: added unique slab name allocation] Cc: stable@kernel.org Signed-off-by: Patrick McHardy <kaber@trash.net>
-rw-r--r--include/net/netns/conntrack.h2
-rw-r--r--net/netfilter/nf_conntrack_core.c39
2 files changed, 25 insertions, 16 deletions
diff --git a/include/net/netns/conntrack.h b/include/net/netns/conntrack.h
index ba1ba0c5efd1..aed23b6c8478 100644
--- a/include/net/netns/conntrack.h
+++ b/include/net/netns/conntrack.h
@@ -11,6 +11,7 @@ struct nf_conntrack_ecache;
11struct netns_ct { 11struct netns_ct {
12 atomic_t count; 12 atomic_t count;
13 unsigned int expect_count; 13 unsigned int expect_count;
14 struct kmem_cache *nf_conntrack_cachep;
14 struct hlist_nulls_head *hash; 15 struct hlist_nulls_head *hash;
15 struct hlist_head *expect_hash; 16 struct hlist_head *expect_hash;
16 struct hlist_nulls_head unconfirmed; 17 struct hlist_nulls_head unconfirmed;
@@ -28,5 +29,6 @@ struct netns_ct {
28#endif 29#endif
29 int hash_vmalloc; 30 int hash_vmalloc;
30 int expect_vmalloc; 31 int expect_vmalloc;
32 char *slabname;
31}; 33};
32#endif 34#endif
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 37e2b88313f2..9de4bd4c0dd7 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -63,8 +63,6 @@ EXPORT_SYMBOL_GPL(nf_conntrack_max);
63struct nf_conn nf_conntrack_untracked __read_mostly; 63struct nf_conn nf_conntrack_untracked __read_mostly;
64EXPORT_SYMBOL_GPL(nf_conntrack_untracked); 64EXPORT_SYMBOL_GPL(nf_conntrack_untracked);
65 65
66static struct kmem_cache *nf_conntrack_cachep __read_mostly;
67
68static int nf_conntrack_hash_rnd_initted; 66static int nf_conntrack_hash_rnd_initted;
69static unsigned int nf_conntrack_hash_rnd; 67static unsigned int nf_conntrack_hash_rnd;
70 68
@@ -572,7 +570,7 @@ struct nf_conn *nf_conntrack_alloc(struct net *net,
572 * Do not use kmem_cache_zalloc(), as this cache uses 570 * Do not use kmem_cache_zalloc(), as this cache uses
573 * SLAB_DESTROY_BY_RCU. 571 * SLAB_DESTROY_BY_RCU.
574 */ 572 */
575 ct = kmem_cache_alloc(nf_conntrack_cachep, gfp); 573 ct = kmem_cache_alloc(net->ct.nf_conntrack_cachep, gfp);
576 if (ct == NULL) { 574 if (ct == NULL) {
577 pr_debug("nf_conntrack_alloc: Can't alloc conntrack.\n"); 575 pr_debug("nf_conntrack_alloc: Can't alloc conntrack.\n");
578 atomic_dec(&net->ct.count); 576 atomic_dec(&net->ct.count);
@@ -611,7 +609,7 @@ void nf_conntrack_free(struct nf_conn *ct)
611 nf_ct_ext_destroy(ct); 609 nf_ct_ext_destroy(ct);
612 atomic_dec(&net->ct.count); 610 atomic_dec(&net->ct.count);
613 nf_ct_ext_free(ct); 611 nf_ct_ext_free(ct);
614 kmem_cache_free(nf_conntrack_cachep, ct); 612 kmem_cache_free(net->ct.nf_conntrack_cachep, ct);
615} 613}
616EXPORT_SYMBOL_GPL(nf_conntrack_free); 614EXPORT_SYMBOL_GPL(nf_conntrack_free);
617 615
@@ -1119,7 +1117,6 @@ static void nf_conntrack_cleanup_init_net(void)
1119 1117
1120 nf_conntrack_helper_fini(); 1118 nf_conntrack_helper_fini();
1121 nf_conntrack_proto_fini(); 1119 nf_conntrack_proto_fini();
1122 kmem_cache_destroy(nf_conntrack_cachep);
1123} 1120}
1124 1121
1125static void nf_conntrack_cleanup_net(struct net *net) 1122static void nf_conntrack_cleanup_net(struct net *net)
@@ -1137,6 +1134,8 @@ static void nf_conntrack_cleanup_net(struct net *net)
1137 nf_conntrack_ecache_fini(net); 1134 nf_conntrack_ecache_fini(net);
1138 nf_conntrack_acct_fini(net); 1135 nf_conntrack_acct_fini(net);
1139 nf_conntrack_expect_fini(net); 1136 nf_conntrack_expect_fini(net);
1137 kmem_cache_destroy(net->ct.nf_conntrack_cachep);
1138 kfree(net->ct.slabname);
1140 free_percpu(net->ct.stat); 1139 free_percpu(net->ct.stat);
1141} 1140}
1142 1141
@@ -1272,15 +1271,6 @@ static int nf_conntrack_init_init_net(void)
1272 NF_CONNTRACK_VERSION, nf_conntrack_htable_size, 1271 NF_CONNTRACK_VERSION, nf_conntrack_htable_size,
1273 nf_conntrack_max); 1272 nf_conntrack_max);
1274 1273
1275 nf_conntrack_cachep = kmem_cache_create("nf_conntrack",
1276 sizeof(struct nf_conn),
1277 0, SLAB_DESTROY_BY_RCU, NULL);
1278 if (!nf_conntrack_cachep) {
1279 printk(KERN_ERR "Unable to create nf_conn slab cache\n");
1280 ret = -ENOMEM;
1281 goto err_cache;
1282 }
1283
1284 ret = nf_conntrack_proto_init(); 1274 ret = nf_conntrack_proto_init();
1285 if (ret < 0) 1275 if (ret < 0)
1286 goto err_proto; 1276 goto err_proto;
@@ -1302,8 +1292,6 @@ static int nf_conntrack_init_init_net(void)
1302err_helper: 1292err_helper:
1303 nf_conntrack_proto_fini(); 1293 nf_conntrack_proto_fini();
1304err_proto: 1294err_proto:
1305 kmem_cache_destroy(nf_conntrack_cachep);
1306err_cache:
1307 return ret; 1295 return ret;
1308} 1296}
1309 1297
@@ -1325,6 +1313,21 @@ static int nf_conntrack_init_net(struct net *net)
1325 ret = -ENOMEM; 1313 ret = -ENOMEM;
1326 goto err_stat; 1314 goto err_stat;
1327 } 1315 }
1316
1317 net->ct.slabname = kasprintf(GFP_KERNEL, "nf_conntrack_%p", net);
1318 if (!net->ct.slabname) {
1319 ret = -ENOMEM;
1320 goto err_slabname;
1321 }
1322
1323 net->ct.nf_conntrack_cachep = kmem_cache_create(net->ct.slabname,
1324 sizeof(struct nf_conn), 0,
1325 SLAB_DESTROY_BY_RCU, NULL);
1326 if (!net->ct.nf_conntrack_cachep) {
1327 printk(KERN_ERR "Unable to create nf_conn slab cache\n");
1328 ret = -ENOMEM;
1329 goto err_cache;
1330 }
1328 net->ct.hash = nf_ct_alloc_hashtable(&nf_conntrack_htable_size, 1331 net->ct.hash = nf_ct_alloc_hashtable(&nf_conntrack_htable_size,
1329 &net->ct.hash_vmalloc, 1); 1332 &net->ct.hash_vmalloc, 1);
1330 if (!net->ct.hash) { 1333 if (!net->ct.hash) {
@@ -1352,6 +1355,10 @@ err_expect:
1352 nf_ct_free_hashtable(net->ct.hash, net->ct.hash_vmalloc, 1355 nf_ct_free_hashtable(net->ct.hash, net->ct.hash_vmalloc,
1353 nf_conntrack_htable_size); 1356 nf_conntrack_htable_size);
1354err_hash: 1357err_hash:
1358 kmem_cache_destroy(net->ct.nf_conntrack_cachep);
1359err_cache:
1360 kfree(net->ct.slabname);
1361err_slabname:
1355 free_percpu(net->ct.stat); 1362 free_percpu(net->ct.stat);
1356err_stat: 1363err_stat:
1357 return ret; 1364 return ret;