aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Chion Tang <sdspeedonion@gmail.com> 2018-03-13 18:15:11 +0000
committerGravatar Chion Tang <sdspeedonion@gmail.com> 2018-03-13 18:15:11 +0000
commit1dccfd7d0a5ff8a56258c65fbeb4db2e5679c881 (patch)
tree66a191dc506a1676582e1f032b2ae4d53222c2c4
parentfeature: support for multiple external interfaces (diff)
downloadnetfilter-full-cone-nat-1dccfd7d0a5ff8a56258c65fbeb4db2e5679c881.tar.gz
netfilter-full-cone-nat-1dccfd7d0a5ff8a56258c65fbeb4db2e5679c881.tar.bz2
netfilter-full-cone-nat-1dccfd7d0a5ff8a56258c65fbeb4db2e5679c881.zip
fix: nf_ct_event register lock bug
-rw-r--r--xt_FULLCONENAT.c33
1 files changed, 20 insertions, 13 deletions
diff --git a/xt_FULLCONENAT.c b/xt_FULLCONENAT.c
index d724b24..54e8c97 100644
--- a/xt_FULLCONENAT.c
+++ b/xt_FULLCONENAT.c
@@ -48,6 +48,7 @@ struct nat_mapping {
struct nf_ct_net_event {
struct net *net;
+ u8 family;
struct nf_ct_event_notifier ct_event_notifier;
int refer_count;
@@ -56,6 +57,8 @@ struct nf_ct_net_event {
static LIST_HEAD(nf_ct_net_event_list);
+static DEFINE_MUTEX(nf_ct_net_event_lock);
+
static DEFINE_HASHTABLE(mapping_table, 10);
static DEFINE_SPINLOCK(fullconenat_lock);
@@ -413,33 +416,38 @@ static int fullconenat_tg_check(const struct xt_tgchk_param *par)
struct net *net = par->net;
- spin_lock(&fullconenat_lock);
+ mutex_lock(&nf_ct_net_event_lock);
list_for_each(iter, &nf_ct_net_event_list) {
net_event = list_entry(iter, struct nf_ct_net_event, node);
if (net_event->net == net) {
(net_event->refer_count)++;
- pr_debug("xt_FULLCONENAT: refer_count for net addr %p is now %d\n", (void*) net, net_event->refer_count);
+ pr_debug("xt_FULLCONENAT: refer_count for net addr %p is now %d\n", (void*) (net_event->net), net_event->refer_count);
goto out;
}
}
- net_event = kmalloc(sizeof(struct nf_ct_net_event), GFP_ATOMIC);
+ net_event = kmalloc(sizeof(struct nf_ct_net_event), GFP_KERNEL);
if (net_event == NULL) {
pr_debug("xt_FULLCONENAT: ERROR: kmalloc() for net_event failed.\n");
goto out;
}
net_event->net = net;
+ net_event->family = par->family;
(net_event->ct_event_notifier).fcn = ct_event_cb;
net_event->refer_count = 1;
list_add(&net_event->node, &nf_ct_net_event_list);
+
+ nf_ct_netns_get(net_event->net, net_event->family);
nf_conntrack_register_notifier(net_event->net, &(net_event->ct_event_notifier));
- pr_debug("xt_FULLCONENAT: ct_event_notifier registered for net addr %p\n", (void*) net);
+ pr_debug("xt_FULLCONENAT: refer_count for net addr %p is now %d\n", (void*) (net_event->net), net_event->refer_count);
+ pr_debug("xt_FULLCONENAT: ct_event_notifier registered for net addr %p\n", (void*) (net_event->net));
+
out:
- spin_unlock(&fullconenat_lock);
+ mutex_unlock(&nf_ct_net_event_lock);
- return nf_ct_netns_get(par->net, par->family);
+ return 0;
}
static void fullconenat_tg_destroy(const struct xt_tgdtor_param *par)
@@ -449,27 +457,26 @@ static void fullconenat_tg_destroy(const struct xt_tgdtor_param *par)
struct net *net = par->net;
- spin_lock(&fullconenat_lock);
+ mutex_lock(&nf_ct_net_event_lock);
list_for_each_safe(iter, tmp_iter, &nf_ct_net_event_list) {
net_event = list_entry(iter, struct nf_ct_net_event, node);
if (net_event->net == net) {
(net_event->refer_count)--;
- pr_debug("xt_FULLCONENAT: refer_count for net addr %p is now %d\n", (void*)net, net_event->refer_count);
+ pr_debug("xt_FULLCONENAT: refer_count for net addr %p is now %d\n", (void*) (net_event->net), net_event->refer_count);
if (net_event->refer_count <= 0) {
nf_conntrack_unregister_notifier(net_event->net, &(net_event->ct_event_notifier));
-
- pr_debug("xt_FULLCONENAT: unregistered ct_net_event for net addr %p\n", (void*)net);
+ nf_ct_netns_put(net_event->net, net_event->family);
+
+ pr_debug("xt_FULLCONENAT: unregistered ct_net_event for net addr %p\n", (void*) (net_event->net));
list_del(&net_event->node);
kfree(net_event);
}
}
}
- spin_unlock(&fullconenat_lock);
-
- nf_ct_netns_put(par->net, par->family);
+ mutex_unlock(&nf_ct_net_event_lock);
}
static struct xt_target tg_reg[] __read_mostly = {