aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2010-02-08 14:16:26 -0500
committerDavid S. Miller <davem@davemloft.net>2010-02-08 14:16:26 -0500
commit9edd7ca0a3e3999c260642c92fa008892d82ca6e (patch)
tree87585b10617d47a9eba9f6b9daf5e47f2f0b70e7 /net
parent1b3f720bf033fde1fbb6231f9b156b918c5f68d8 (diff)
netfilter: nf_conntrack: fix memory corruption with multiple namespaces
As discovered by Jon Masters <jonathan@jonmasters.org>, the "untracked" conntrack, which is located in the data section, might be accidentally freed when a new namespace is instantiated while the untracked conntrack is attached to a skb because the reference count it re-initialized. The best fix would be to use a seperate untracked conntrack per namespace since it includes a namespace pointer. Unfortunately this is not possible without larger changes since the namespace is not easily available everywhere we need it. For now move the untracked conntrack initialization to the init_net setup function to make sure the reference count is not re-initialized and handle cleanup in the init_net cleanup function to make sure namespaces can exit properly while the untracked conntrack is in use in other namespaces. Cc: stable@kernel.org Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/nf_conntrack_core.c24
1 files changed, 12 insertions, 12 deletions
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 0e98c3282d42..37e2b88313f2 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -1113,6 +1113,10 @@ static void nf_ct_release_dying_list(struct net *net)
1113 1113
1114static void nf_conntrack_cleanup_init_net(void) 1114static void nf_conntrack_cleanup_init_net(void)
1115{ 1115{
1116 /* wait until all references to nf_conntrack_untracked are dropped */
1117 while (atomic_read(&nf_conntrack_untracked.ct_general.use) > 1)
1118 schedule();
1119
1116 nf_conntrack_helper_fini(); 1120 nf_conntrack_helper_fini();
1117 nf_conntrack_proto_fini(); 1121 nf_conntrack_proto_fini();
1118 kmem_cache_destroy(nf_conntrack_cachep); 1122 kmem_cache_destroy(nf_conntrack_cachep);
@@ -1127,9 +1131,6 @@ static void nf_conntrack_cleanup_net(struct net *net)
1127 schedule(); 1131 schedule();
1128 goto i_see_dead_people; 1132 goto i_see_dead_people;
1129 } 1133 }
1130 /* wait until all references to nf_conntrack_untracked are dropped */
1131 while (atomic_read(&nf_conntrack_untracked.ct_general.use) > 1)
1132 schedule();
1133 1134
1134 nf_ct_free_hashtable(net->ct.hash, net->ct.hash_vmalloc, 1135 nf_ct_free_hashtable(net->ct.hash, net->ct.hash_vmalloc,
1135 nf_conntrack_htable_size); 1136 nf_conntrack_htable_size);
@@ -1288,6 +1289,14 @@ static int nf_conntrack_init_init_net(void)
1288 if (ret < 0) 1289 if (ret < 0)
1289 goto err_helper; 1290 goto err_helper;
1290 1291
1292 /* Set up fake conntrack: to never be deleted, not in any hashes */
1293#ifdef CONFIG_NET_NS
1294 nf_conntrack_untracked.ct_net = &init_net;
1295#endif
1296 atomic_set(&nf_conntrack_untracked.ct_general.use, 1);
1297 /* - and look it like as a confirmed connection */
1298 set_bit(IPS_CONFIRMED_BIT, &nf_conntrack_untracked.status);
1299
1291 return 0; 1300 return 0;
1292 1301
1293err_helper: 1302err_helper:
@@ -1333,15 +1342,6 @@ static int nf_conntrack_init_net(struct net *net)
1333 if (ret < 0) 1342 if (ret < 0)
1334 goto err_ecache; 1343 goto err_ecache;
1335 1344
1336 /* Set up fake conntrack:
1337 - to never be deleted, not in any hashes */
1338#ifdef CONFIG_NET_NS
1339 nf_conntrack_untracked.ct_net = &init_net;
1340#endif
1341 atomic_set(&nf_conntrack_untracked.ct_general.use, 1);
1342 /* - and look it like as a confirmed connection */
1343 set_bit(IPS_CONFIRMED_BIT, &nf_conntrack_untracked.status);
1344
1345 return 0; 1345 return 0;
1346 1346
1347err_ecache: 1347err_ecache: