aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/netfilter/nf_conntrack_l3proto.h2
-rw-r--r--net/ipv4/netfilter/nf_conntrack_proto_icmp.c2
-rw-r--r--net/ipv4/netfilter/nf_nat_core.c9
-rw-r--r--net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c1
-rw-r--r--net/netfilter/nf_conntrack_core.c27
-rw-r--r--net/netfilter/nf_conntrack_proto.c33
6 files changed, 44 insertions, 30 deletions
diff --git a/include/net/netfilter/nf_conntrack_l3proto.h b/include/net/netfilter/nf_conntrack_l3proto.h
index 664ddcffe00d..ba760fe09b8a 100644
--- a/include/net/netfilter/nf_conntrack_l3proto.h
+++ b/include/net/netfilter/nf_conntrack_l3proto.h
@@ -106,7 +106,7 @@ __nf_ct_l3proto_find(u_int16_t l3proto)
106{ 106{
107 if (unlikely(l3proto >= AF_MAX)) 107 if (unlikely(l3proto >= AF_MAX))
108 return &nf_conntrack_l3proto_generic; 108 return &nf_conntrack_l3proto_generic;
109 return nf_ct_l3protos[l3proto]; 109 return rcu_dereference(nf_ct_l3protos[l3proto]);
110} 110}
111 111
112#endif /*_NF_CONNTRACK_L3PROTO_H*/ 112#endif /*_NF_CONNTRACK_L3PROTO_H*/
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
index 677b6c80c618..e5aa4d849b00 100644
--- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
@@ -170,7 +170,9 @@ icmp_error_message(struct sk_buff *skb,
170 return -NF_ACCEPT; 170 return -NF_ACCEPT;
171 } 171 }
172 172
173 /* rcu_read_lock()ed by nf_hook_slow */
173 innerproto = __nf_ct_l4proto_find(PF_INET, inside->ip.protocol); 174 innerproto = __nf_ct_l4proto_find(PF_INET, inside->ip.protocol);
175
174 dataoff = skb->nh.iph->ihl*4 + sizeof(inside->icmp); 176 dataoff = skb->nh.iph->ihl*4 + sizeof(inside->icmp);
175 /* Are they talking about one of our connections? */ 177 /* Are they talking about one of our connections? */
176 if (!nf_ct_get_tuple(skb, dataoff, dataoff + inside->ip.ihl*4, PF_INET, 178 if (!nf_ct_get_tuple(skb, dataoff, dataoff + inside->ip.ihl*4, PF_INET,
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c
index 6d0061f05810..5156d5d6c3b8 100644
--- a/net/ipv4/netfilter/nf_nat_core.c
+++ b/net/ipv4/netfilter/nf_nat_core.c
@@ -429,6 +429,7 @@ int nf_nat_icmp_reply_translation(struct nf_conn *ct,
429 struct icmphdr icmp; 429 struct icmphdr icmp;
430 struct iphdr ip; 430 struct iphdr ip;
431 } *inside; 431 } *inside;
432 struct nf_conntrack_l4proto *l4proto;
432 struct nf_conntrack_tuple inner, target; 433 struct nf_conntrack_tuple inner, target;
433 int hdrlen = (*pskb)->nh.iph->ihl * 4; 434 int hdrlen = (*pskb)->nh.iph->ihl * 4;
434 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 435 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
@@ -464,16 +465,16 @@ int nf_nat_icmp_reply_translation(struct nf_conn *ct,
464 DEBUGP("icmp_reply_translation: translating error %p manp %u dir %s\n", 465 DEBUGP("icmp_reply_translation: translating error %p manp %u dir %s\n",
465 *pskb, manip, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY"); 466 *pskb, manip, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY");
466 467
468 /* rcu_read_lock()ed by nf_hook_slow */
469 l4proto = __nf_ct_l4proto_find(PF_INET, inside->ip.protocol);
470
467 if (!nf_ct_get_tuple(*pskb, 471 if (!nf_ct_get_tuple(*pskb,
468 (*pskb)->nh.iph->ihl*4 + sizeof(struct icmphdr), 472 (*pskb)->nh.iph->ihl*4 + sizeof(struct icmphdr),
469 (*pskb)->nh.iph->ihl*4 + 473 (*pskb)->nh.iph->ihl*4 +
470 sizeof(struct icmphdr) + inside->ip.ihl*4, 474 sizeof(struct icmphdr) + inside->ip.ihl*4,
471 (u_int16_t)AF_INET, 475 (u_int16_t)AF_INET,
472 inside->ip.protocol, 476 inside->ip.protocol,
473 &inner, 477 &inner, l3proto, l4proto))
474 l3proto,
475 __nf_ct_l4proto_find((u_int16_t)PF_INET,
476 inside->ip.protocol)))
477 return 0; 478 return 0;
478 479
479 /* Change inner back to look like incoming packet. We do the 480 /* Change inner back to look like incoming packet. We do the
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
index b08622c992b2..19bdb7cb8ff3 100644
--- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
@@ -182,6 +182,7 @@ icmpv6_error_message(struct sk_buff *skb,
182 return -NF_ACCEPT; 182 return -NF_ACCEPT;
183 } 183 }
184 184
185 /* rcu_read_lock()ed by nf_hook_slow */
185 inproto = __nf_ct_l4proto_find(PF_INET6, inprotonum); 186 inproto = __nf_ct_l4proto_find(PF_INET6, inprotonum);
186 187
187 /* Are they talking about one of our connections? */ 188 /* Are they talking about one of our connections? */
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 59bcab1d1084..3deeb900263b 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -332,13 +332,16 @@ destroy_conntrack(struct nf_conntrack *nfct)
332 /* To make sure we don't get any weird locking issues here: 332 /* To make sure we don't get any weird locking issues here:
333 * destroy_conntrack() MUST NOT be called with a write lock 333 * destroy_conntrack() MUST NOT be called with a write lock
334 * to nf_conntrack_lock!!! -HW */ 334 * to nf_conntrack_lock!!! -HW */
335 rcu_read_lock();
335 l3proto = __nf_ct_l3proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num); 336 l3proto = __nf_ct_l3proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num);
336 if (l3proto && l3proto->destroy) 337 if (l3proto && l3proto->destroy)
337 l3proto->destroy(ct); 338 l3proto->destroy(ct);
338 339
339 l4proto = __nf_ct_l4proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num, ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum); 340 l4proto = __nf_ct_l4proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num,
341 ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
340 if (l4proto && l4proto->destroy) 342 if (l4proto && l4proto->destroy)
341 l4proto->destroy(ct); 343 l4proto->destroy(ct);
344 rcu_read_unlock();
342 345
343 if (nf_conntrack_destroyed) 346 if (nf_conntrack_destroyed)
344 nf_conntrack_destroyed(ct); 347 nf_conntrack_destroyed(ct);
@@ -647,9 +650,14 @@ struct nf_conn *nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
647 const struct nf_conntrack_tuple *repl) 650 const struct nf_conntrack_tuple *repl)
648{ 651{
649 struct nf_conntrack_l3proto *l3proto; 652 struct nf_conntrack_l3proto *l3proto;
653 struct nf_conn *ct;
650 654
655 rcu_read_lock();
651 l3proto = __nf_ct_l3proto_find(orig->src.l3num); 656 l3proto = __nf_ct_l3proto_find(orig->src.l3num);
652 return __nf_conntrack_alloc(orig, repl, l3proto, 0); 657 ct = __nf_conntrack_alloc(orig, repl, l3proto, 0);
658 rcu_read_unlock();
659
660 return ct;
653} 661}
654EXPORT_SYMBOL_GPL(nf_conntrack_alloc); 662EXPORT_SYMBOL_GPL(nf_conntrack_alloc);
655 663
@@ -817,7 +825,9 @@ nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff **pskb)
817 return NF_ACCEPT; 825 return NF_ACCEPT;
818 } 826 }
819 827
828 /* rcu_read_lock()ed by nf_hook_slow */
820 l3proto = __nf_ct_l3proto_find((u_int16_t)pf); 829 l3proto = __nf_ct_l3proto_find((u_int16_t)pf);
830
821 if ((ret = l3proto->prepare(pskb, hooknum, &dataoff, &protonum)) <= 0) { 831 if ((ret = l3proto->prepare(pskb, hooknum, &dataoff, &protonum)) <= 0) {
822 DEBUGP("not prepared to track yet or error occured\n"); 832 DEBUGP("not prepared to track yet or error occured\n");
823 return -ret; 833 return -ret;
@@ -872,10 +882,15 @@ EXPORT_SYMBOL_GPL(nf_conntrack_in);
872int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse, 882int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse,
873 const struct nf_conntrack_tuple *orig) 883 const struct nf_conntrack_tuple *orig)
874{ 884{
875 return nf_ct_invert_tuple(inverse, orig, 885 int ret;
876 __nf_ct_l3proto_find(orig->src.l3num), 886
877 __nf_ct_l4proto_find(orig->src.l3num, 887 rcu_read_lock();
878 orig->dst.protonum)); 888 ret = nf_ct_invert_tuple(inverse, orig,
889 __nf_ct_l3proto_find(orig->src.l3num),
890 __nf_ct_l4proto_find(orig->src.l3num,
891 orig->dst.protonum));
892 rcu_read_unlock();
893 return ret;
879} 894}
880EXPORT_SYMBOL_GPL(nf_ct_invert_tuplepr); 895EXPORT_SYMBOL_GPL(nf_ct_invert_tuplepr);
881 896
diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c
index 1a61b72712cd..4dab3fa6e2bc 100644
--- a/net/netfilter/nf_conntrack_proto.c
+++ b/net/netfilter/nf_conntrack_proto.c
@@ -66,7 +66,7 @@ __nf_ct_l4proto_find(u_int16_t l3proto, u_int8_t l4proto)
66 if (unlikely(l3proto >= AF_MAX || nf_ct_protos[l3proto] == NULL)) 66 if (unlikely(l3proto >= AF_MAX || nf_ct_protos[l3proto] == NULL))
67 return &nf_conntrack_l4proto_generic; 67 return &nf_conntrack_l4proto_generic;
68 68
69 return nf_ct_protos[l3proto][l4proto]; 69 return rcu_dereference(nf_ct_protos[l3proto][l4proto]);
70} 70}
71EXPORT_SYMBOL_GPL(__nf_ct_l4proto_find); 71EXPORT_SYMBOL_GPL(__nf_ct_l4proto_find);
72 72
@@ -77,11 +77,11 @@ nf_ct_l4proto_find_get(u_int16_t l3proto, u_int8_t l4proto)
77{ 77{
78 struct nf_conntrack_l4proto *p; 78 struct nf_conntrack_l4proto *p;
79 79
80 preempt_disable(); 80 rcu_read_lock();
81 p = __nf_ct_l4proto_find(l3proto, l4proto); 81 p = __nf_ct_l4proto_find(l3proto, l4proto);
82 if (!try_module_get(p->me)) 82 if (!try_module_get(p->me))
83 p = &nf_conntrack_l4proto_generic; 83 p = &nf_conntrack_l4proto_generic;
84 preempt_enable(); 84 rcu_read_unlock();
85 85
86 return p; 86 return p;
87} 87}
@@ -98,11 +98,11 @@ nf_ct_l3proto_find_get(u_int16_t l3proto)
98{ 98{
99 struct nf_conntrack_l3proto *p; 99 struct nf_conntrack_l3proto *p;
100 100
101 preempt_disable(); 101 rcu_read_lock();
102 p = __nf_ct_l3proto_find(l3proto); 102 p = __nf_ct_l3proto_find(l3proto);
103 if (!try_module_get(p->me)) 103 if (!try_module_get(p->me))
104 p = &nf_conntrack_l3proto_generic; 104 p = &nf_conntrack_l3proto_generic;
105 preempt_enable(); 105 rcu_read_unlock();
106 106
107 return p; 107 return p;
108} 108}
@@ -137,10 +137,8 @@ void nf_ct_l3proto_module_put(unsigned short l3proto)
137{ 137{
138 struct nf_conntrack_l3proto *p; 138 struct nf_conntrack_l3proto *p;
139 139
140 preempt_disable(); 140 /* rcu_read_lock not necessary since the caller holds a reference */
141 p = __nf_ct_l3proto_find(l3proto); 141 p = __nf_ct_l3proto_find(l3proto);
142 preempt_enable();
143
144 module_put(p->me); 142 module_put(p->me);
145} 143}
146EXPORT_SYMBOL_GPL(nf_ct_l3proto_module_put); 144EXPORT_SYMBOL_GPL(nf_ct_l3proto_module_put);
@@ -202,7 +200,7 @@ int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto)
202 ret = -EBUSY; 200 ret = -EBUSY;
203 goto out_unlock; 201 goto out_unlock;
204 } 202 }
205 nf_ct_l3protos[proto->l3proto] = proto; 203 rcu_assign_pointer(nf_ct_l3protos[proto->l3proto], proto);
206 write_unlock_bh(&nf_conntrack_lock); 204 write_unlock_bh(&nf_conntrack_lock);
207 205
208 ret = nf_ct_l3proto_register_sysctl(proto); 206 ret = nf_ct_l3proto_register_sysctl(proto);
@@ -233,14 +231,13 @@ int nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto)
233 goto out; 231 goto out;
234 } 232 }
235 233
236 nf_ct_l3protos[proto->l3proto] = &nf_conntrack_l3proto_generic; 234 rcu_assign_pointer(nf_ct_l3protos[proto->l3proto],
235 &nf_conntrack_l3proto_generic);
237 write_unlock_bh(&nf_conntrack_lock); 236 write_unlock_bh(&nf_conntrack_lock);
237 synchronize_rcu();
238 238
239 nf_ct_l3proto_unregister_sysctl(proto); 239 nf_ct_l3proto_unregister_sysctl(proto);
240 240
241 /* Somebody could be still looking at the proto in bh. */
242 synchronize_net();
243
244 /* Remove all contrack entries for this protocol */ 241 /* Remove all contrack entries for this protocol */
245 nf_ct_iterate_cleanup(kill_l3proto, proto); 242 nf_ct_iterate_cleanup(kill_l3proto, proto);
246 243
@@ -356,7 +353,7 @@ retry:
356 goto retry; 353 goto retry;
357 } 354 }
358 355
359 nf_ct_protos[l4proto->l3proto][l4proto->l4proto] = l4proto; 356 rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto], l4proto);
360 write_unlock_bh(&nf_conntrack_lock); 357 write_unlock_bh(&nf_conntrack_lock);
361 358
362 ret = nf_ct_l4proto_register_sysctl(l4proto); 359 ret = nf_ct_l4proto_register_sysctl(l4proto);
@@ -392,15 +389,13 @@ int nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *l4proto)
392 ret = -EBUSY; 389 ret = -EBUSY;
393 goto out; 390 goto out;
394 } 391 }
395 nf_ct_protos[l4proto->l3proto][l4proto->l4proto] 392 rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto],
396 = &nf_conntrack_l4proto_generic; 393 &nf_conntrack_l4proto_generic);
397 write_unlock_bh(&nf_conntrack_lock); 394 write_unlock_bh(&nf_conntrack_lock);
395 synchronize_rcu();
398 396
399 nf_ct_l4proto_unregister_sysctl(l4proto); 397 nf_ct_l4proto_unregister_sysctl(l4proto);
400 398
401 /* Somebody could be still looking at the proto in bh. */
402 synchronize_net();
403
404 /* Remove all contrack entries for this protocol */ 399 /* Remove all contrack entries for this protocol */
405 nf_ct_iterate_cleanup(kill_l4proto, l4proto); 400 nf_ct_iterate_cleanup(kill_l4proto, l4proto);
406 401