diff options
-rw-r--r-- | include/net/netfilter/nf_conntrack_l3proto.h | 2 | ||||
-rw-r--r-- | net/ipv4/netfilter/nf_conntrack_proto_icmp.c | 2 | ||||
-rw-r--r-- | net/ipv4/netfilter/nf_nat_core.c | 9 | ||||
-rw-r--r-- | net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | 1 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_core.c | 27 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_proto.c | 33 |
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 | } |
654 | EXPORT_SYMBOL_GPL(nf_conntrack_alloc); | 662 | EXPORT_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); | |||
872 | int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse, | 882 | int 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 | } |
880 | EXPORT_SYMBOL_GPL(nf_ct_invert_tuplepr); | 895 | EXPORT_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 | } |
71 | EXPORT_SYMBOL_GPL(__nf_ct_l4proto_find); | 71 | EXPORT_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 | } |
146 | EXPORT_SYMBOL_GPL(nf_ct_l3proto_module_put); | 144 | EXPORT_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 | ||