aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c13
-rw-r--r--net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c9
-rw-r--r--net/netfilter/nf_conntrack_core.c26
-rw-r--r--net/netfilter/nf_conntrack_expect.c4
-rw-r--r--net/netfilter/nf_conntrack_helper.c2
-rw-r--r--net/netfilter/nf_conntrack_netlink.c34
-rw-r--r--net/netfilter/nf_conntrack_proto_gre.c2
7 files changed, 61 insertions, 29 deletions
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index fd62a41d69..6dc72a815f 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -133,6 +133,7 @@ static unsigned int ipv4_conntrack_help(unsigned int hooknum,
133 struct nf_conn *ct; 133 struct nf_conn *ct;
134 enum ip_conntrack_info ctinfo; 134 enum ip_conntrack_info ctinfo;
135 struct nf_conn_help *help; 135 struct nf_conn_help *help;
136 struct nf_conntrack_helper *helper;
136 137
137 /* This is where we call the helper: as the packet goes out. */ 138 /* This is where we call the helper: as the packet goes out. */
138 ct = nf_ct_get(*pskb, &ctinfo); 139 ct = nf_ct_get(*pskb, &ctinfo);
@@ -140,12 +141,14 @@ static unsigned int ipv4_conntrack_help(unsigned int hooknum,
140 return NF_ACCEPT; 141 return NF_ACCEPT;
141 142
142 help = nfct_help(ct); 143 help = nfct_help(ct);
143 if (!help || !help->helper) 144 if (!help)
144 return NF_ACCEPT; 145 return NF_ACCEPT;
145 146 /* rcu_read_lock()ed by nf_hook_slow */
146 return help->helper->help(pskb, 147 helper = rcu_dereference(help->helper);
147 skb_network_offset(*pskb) + ip_hdrlen(*pskb), 148 if (!helper)
148 ct, ctinfo); 149 return NF_ACCEPT;
150 return helper->help(pskb, skb_network_offset(*pskb) + ip_hdrlen(*pskb),
151 ct, ctinfo);
149} 152}
150 153
151static unsigned int ipv4_conntrack_defrag(unsigned int hooknum, 154static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index dc442fb791..1b1797f1f3 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -160,6 +160,7 @@ static unsigned int ipv6_confirm(unsigned int hooknum,
160{ 160{
161 struct nf_conn *ct; 161 struct nf_conn *ct;
162 struct nf_conn_help *help; 162 struct nf_conn_help *help;
163 struct nf_conntrack_helper *helper;
163 enum ip_conntrack_info ctinfo; 164 enum ip_conntrack_info ctinfo;
164 unsigned int ret, protoff; 165 unsigned int ret, protoff;
165 unsigned int extoff = (u8 *)(ipv6_hdr(*pskb) + 1) - (*pskb)->data; 166 unsigned int extoff = (u8 *)(ipv6_hdr(*pskb) + 1) - (*pskb)->data;
@@ -172,7 +173,11 @@ static unsigned int ipv6_confirm(unsigned int hooknum,
172 goto out; 173 goto out;
173 174
174 help = nfct_help(ct); 175 help = nfct_help(ct);
175 if (!help || !help->helper) 176 if (!help)
177 goto out;
178 /* rcu_read_lock()ed by nf_hook_slow */
179 helper = rcu_dereference(help->helper);
180 if (!helper)
176 goto out; 181 goto out;
177 182
178 protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum, 183 protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum,
@@ -182,7 +187,7 @@ static unsigned int ipv6_confirm(unsigned int hooknum,
182 return NF_ACCEPT; 187 return NF_ACCEPT;
183 } 188 }
184 189
185 ret = help->helper->help(pskb, protoff, ct, ctinfo); 190 ret = helper->help(pskb, protoff, ct, ctinfo);
186 if (ret != NF_ACCEPT) 191 if (ret != NF_ACCEPT)
187 return ret; 192 return ret;
188out: 193out:
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 483e927a9c..7a15e30356 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -350,9 +350,15 @@ static void death_by_timeout(unsigned long ul_conntrack)
350{ 350{
351 struct nf_conn *ct = (void *)ul_conntrack; 351 struct nf_conn *ct = (void *)ul_conntrack;
352 struct nf_conn_help *help = nfct_help(ct); 352 struct nf_conn_help *help = nfct_help(ct);
353 struct nf_conntrack_helper *helper;
353 354
354 if (help && help->helper && help->helper->destroy) 355 if (help) {
355 help->helper->destroy(ct); 356 rcu_read_lock();
357 helper = rcu_dereference(help->helper);
358 if (helper && helper->destroy)
359 helper->destroy(ct);
360 rcu_read_unlock();
361 }
356 362
357 write_lock_bh(&nf_conntrack_lock); 363 write_lock_bh(&nf_conntrack_lock);
358 /* Inside lock so preempt is disabled on module removal path. 364 /* Inside lock so preempt is disabled on module removal path.
@@ -661,6 +667,7 @@ init_conntrack(const struct nf_conntrack_tuple *tuple,
661 unsigned int dataoff) 667 unsigned int dataoff)
662{ 668{
663 struct nf_conn *conntrack; 669 struct nf_conn *conntrack;
670 struct nf_conn_help *help;
664 struct nf_conntrack_tuple repl_tuple; 671 struct nf_conntrack_tuple repl_tuple;
665 struct nf_conntrack_expect *exp; 672 struct nf_conntrack_expect *exp;
666 u_int32_t features = 0; 673 u_int32_t features = 0;
@@ -691,6 +698,7 @@ init_conntrack(const struct nf_conntrack_tuple *tuple,
691 write_lock_bh(&nf_conntrack_lock); 698 write_lock_bh(&nf_conntrack_lock);
692 exp = find_expectation(tuple); 699 exp = find_expectation(tuple);
693 700
701 help = nfct_help(conntrack);
694 if (exp) { 702 if (exp) {
695 DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n", 703 DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
696 conntrack, exp); 704 conntrack, exp);
@@ -698,7 +706,7 @@ init_conntrack(const struct nf_conntrack_tuple *tuple,
698 __set_bit(IPS_EXPECTED_BIT, &conntrack->status); 706 __set_bit(IPS_EXPECTED_BIT, &conntrack->status);
699 conntrack->master = exp->master; 707 conntrack->master = exp->master;
700 if (exp->helper) 708 if (exp->helper)
701 nfct_help(conntrack)->helper = exp->helper; 709 rcu_assign_pointer(help->helper, exp->helper);
702#ifdef CONFIG_NF_CONNTRACK_MARK 710#ifdef CONFIG_NF_CONNTRACK_MARK
703 conntrack->mark = exp->master->mark; 711 conntrack->mark = exp->master->mark;
704#endif 712#endif
@@ -708,10 +716,11 @@ init_conntrack(const struct nf_conntrack_tuple *tuple,
708 nf_conntrack_get(&conntrack->master->ct_general); 716 nf_conntrack_get(&conntrack->master->ct_general);
709 NF_CT_STAT_INC(expect_new); 717 NF_CT_STAT_INC(expect_new);
710 } else { 718 } else {
711 struct nf_conn_help *help = nfct_help(conntrack); 719 if (help) {
712 720 /* not in hash table yet, so not strictly necessary */
713 if (help) 721 rcu_assign_pointer(help->helper,
714 help->helper = __nf_ct_helper_find(&repl_tuple); 722 __nf_ct_helper_find(&repl_tuple));
723 }
715 NF_CT_STAT_INC(new); 724 NF_CT_STAT_INC(new);
716 } 725 }
717 726
@@ -893,7 +902,8 @@ void nf_conntrack_alter_reply(struct nf_conn *ct,
893 helper = __nf_ct_helper_find(newreply); 902 helper = __nf_ct_helper_find(newreply);
894 if (helper) 903 if (helper)
895 memset(&help->help, 0, sizeof(help->help)); 904 memset(&help->help, 0, sizeof(help->help));
896 help->helper = helper; 905 /* not in hash table yet, so not strictly necessary */
906 rcu_assign_pointer(help->helper, helper);
897 } 907 }
898 write_unlock_bh(&nf_conntrack_lock); 908 write_unlock_bh(&nf_conntrack_lock);
899} 909}
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index 117cbfdb91..504fb6c083 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -337,6 +337,10 @@ int nf_conntrack_expect_related(struct nf_conntrack_expect *expect)
337 NF_CT_ASSERT(master_help); 337 NF_CT_ASSERT(master_help);
338 338
339 write_lock_bh(&nf_conntrack_lock); 339 write_lock_bh(&nf_conntrack_lock);
340 if (!master_help->helper) {
341 ret = -ESHUTDOWN;
342 goto out;
343 }
340 list_for_each_entry(i, &nf_conntrack_expect_list, list) { 344 list_for_each_entry(i, &nf_conntrack_expect_list, list) {
341 if (expect_matches(i, expect)) { 345 if (expect_matches(i, expect)) {
342 /* Refresh timer: if it's dying, ignore.. */ 346 /* Refresh timer: if it's dying, ignore.. */
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
index 0743be4434..f868b7fbd9 100644
--- a/net/netfilter/nf_conntrack_helper.c
+++ b/net/netfilter/nf_conntrack_helper.c
@@ -93,7 +93,7 @@ static inline int unhelp(struct nf_conntrack_tuple_hash *i,
93 93
94 if (help && help->helper == me) { 94 if (help && help->helper == me) {
95 nf_conntrack_event(IPCT_HELPER, ct); 95 nf_conntrack_event(IPCT_HELPER, ct);
96 help->helper = NULL; 96 rcu_assign_pointer(help->helper, NULL);
97 } 97 }
98 return 0; 98 return 0;
99} 99}
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index d6d39e2413..3f73327794 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -171,21 +171,29 @@ ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct)
171{ 171{
172 struct nfattr *nest_helper; 172 struct nfattr *nest_helper;
173 const struct nf_conn_help *help = nfct_help(ct); 173 const struct nf_conn_help *help = nfct_help(ct);
174 struct nf_conntrack_helper *helper;
174