aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiping Zhang <zlpnobody@gmail.com>2017-05-07 10:01:56 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2017-05-15 06:42:29 -0400
commit9338d7b4418e9996a7642867d8f6b482a6040ed6 (patch)
tree5bf37ab11070434ed04c1bcfe12194925bfffd25
parentd91fc59cd77c719f33eda65c194ad8f95a055190 (diff)
netfilter: nfnl_cthelper: reject del request if helper obj is in use
We can still delete the ct helper even if it is in use, this will cause a use-after-free error. In more detail, I mean: # nfct helper add ssdp inet udp # iptables -t raw -A OUTPUT -p udp -j CT --helper ssdp # nfct helper delete ssdp //--> oops, succeed! BUG: unable to handle kernel paging request at 000026ca IP: 0x26ca [...] Call Trace: ? ipv4_helper+0x62/0x80 [nf_conntrack_ipv4] nf_hook_slow+0x21/0xb0 ip_output+0xe9/0x100 ? ip_fragment.constprop.54+0xc0/0xc0 ip_local_out+0x33/0x40 ip_send_skb+0x16/0x80 udp_send_skb+0x84/0x240 udp_sendmsg+0x35d/0xa50 So add reference count to fix this issue, if ct helper is used by others, reject the delete request. Apply this patch: # nfct helper delete ssdp nfct v1.4.3: netlink error: Device or resource busy Signed-off-by: Liping Zhang <zlpnobody@gmail.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r--include/net/netfilter/nf_conntrack_helper.h2
-rw-r--r--net/netfilter/nf_conntrack_helper.c6
-rw-r--r--net/netfilter/nfnetlink_cthelper.c17
3 files changed, 19 insertions, 6 deletions
diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h
index c1c12411103a..c519bb5b5bb8 100644
--- a/include/net/netfilter/nf_conntrack_helper.h
+++ b/include/net/netfilter/nf_conntrack_helper.h
@@ -9,6 +9,7 @@
9 9
10#ifndef _NF_CONNTRACK_HELPER_H 10#ifndef _NF_CONNTRACK_HELPER_H
11#define _NF_CONNTRACK_HELPER_H 11#define _NF_CONNTRACK_HELPER_H
12#include <linux/refcount.h>
12#include <net/netfilter/nf_conntrack.h> 13#include <net/netfilter/nf_conntrack.h>
13#include <net/netfilter/nf_conntrack_extend.h> 14#include <net/netfilter/nf_conntrack_extend.h>
14#include <net/netfilter/nf_conntrack_expect.h> 15#include <net/netfilter/nf_conntrack_expect.h>
@@ -26,6 +27,7 @@ struct nf_conntrack_helper {
26 struct hlist_node hnode; /* Internal use. */ 27 struct hlist_node hnode; /* Internal use. */
27 28
28 char name[NF_CT_HELPER_NAME_LEN]; /* name of the module */ 29 char name[NF_CT_HELPER_NAME_LEN]; /* name of the module */
30 refcount_t refcnt;
29 struct module *me; /* pointer to self */ 31 struct module *me; /* pointer to self */
30 const struct nf_conntrack_expect_policy *expect_policy; 32 const struct nf_conntrack_expect_policy *expect_policy;
31 33
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
index e17006b6e434..7f6100ca63be 100644
--- a/net/netfilter/nf_conntrack_helper.c
+++ b/net/netfilter/nf_conntrack_helper.c
@@ -174,6 +174,10 @@ nf_conntrack_helper_try_module_get(const char *name, u16 l3num, u8 protonum)
174#endif 174#endif
175 if (h != NULL && !try_module_get(h->me)) 175 if (h != NULL && !try_module_get(h->me))
176 h = NULL; 176 h = NULL;
177 if (h != NULL && !refcount_inc_not_zero(&h->refcnt)) {
178 module_put(h->me);
179 h = NULL;
180 }
177 181
178 rcu_read_unlock(); 182 rcu_read_unlock();
179 183
@@ -183,6 +187,7 @@ EXPORT_SYMBOL_GPL(nf_conntrack_helper_try_module_get);
183 187
184void nf_conntrack_helper_put(struct nf_conntrack_helper *helper) 188void nf_conntrack_helper_put(struct nf_conntrack_helper *helper)
185{ 189{
190 refcount_dec(&helper->refcnt);
186 module_put(helper->me); 191 module_put(helper->me);
187} 192}
188EXPORT_SYMBOL_GPL(nf_conntrack_helper_put); 193EXPORT_SYMBOL_GPL(nf_conntrack_helper_put);
@@ -423,6 +428,7 @@ int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
423 } 428 }
424 } 429 }
425 } 430 }
431 refcount_set(&me->refcnt, 1);
426 hlist_add_head_rcu(&me->hnode, &nf_ct_helper_hash[h]); 432 hlist_add_head_rcu(&me->hnode, &nf_ct_helper_hash[h]);
427 nf_ct_helper_count++; 433 nf_ct_helper_count++;
428out: 434out:
diff --git a/net/netfilter/nfnetlink_cthelper.c b/net/netfilter/nfnetlink_cthelper.c
index 950bf6eadc65..be678a323598 100644
--- a/net/netfilter/nfnetlink_cthelper.c
+++ b/net/netfilter/nfnetlink_cthelper.c
@@ -686,6 +686,7 @@ static int nfnl_cthelper_del(struct net *net, struct sock *nfnl,
686 tuple_set = true; 686 tuple_set = true;
687 } 687 }
688 688
689 ret = -ENOENT;
689 list_for_each_entry_safe(nlcth, n, &nfnl_cthelper_list, list) { 690 list_for_each_entry_safe(nlcth, n, &nfnl_cthelper_list, list) {
690 cur = &nlcth->helper; 691 cur = &nlcth->helper;
691 j++; 692 j++;
@@ -699,16 +700,20 @@ static int nfnl_cthelper_del(struct net *net, struct sock *nfnl,
699 tuple.dst.protonum != cur->tuple.dst.protonum)) 700 tuple.dst.protonum != cur->tuple.dst.protonum))
700 continue; 701 continue;
701 702
702 found = true; 703 if (refcount_dec_if_one(&cur->refcnt)) {
703 nf_conntrack_helper_unregister(cur); 704 found = true;
704 kfree(cur->expect_policy); 705 nf_conntrack_helper_unregister(cur);
706 kfree(cur->expect_policy);
705 707
706 list_del(&nlcth->list); 708 list_del(&nlcth->list);
707 kfree(nlcth); 709 kfree(nlcth);
710 } else {
711 ret = -EBUSY;
712 }
708 } 713 }
709 714
710 /* Make sure we return success if we flush and there is no helpers */ 715 /* Make sure we return success if we flush and there is no helpers */
711 return (found || j == 0) ? 0 : -ENOENT; 716 return (found || j == 0) ? 0 : ret;
712} 717}
713 718
714static const struct nla_policy nfnl_cthelper_policy[NFCTH_MAX+1] = { 719static const struct nla_policy nfnl_cthelper_policy[NFCTH_MAX+1] = {