aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/netfilter/ip_conntrack_core.c26
-rw-r--r--net/ipv4/netfilter/ip_conntrack_standalone.c9
-rw-r--r--net/ipv4/netfilter/ip_nat_core.c6
3 files changed, 26 insertions, 15 deletions
diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c
index 508e6007a191..e7de6d31b853 100644
--- a/net/ipv4/netfilter/ip_conntrack_core.c
+++ b/net/ipv4/netfilter/ip_conntrack_core.c
@@ -318,9 +318,11 @@ destroy_conntrack(struct nf_conntrack *nfct)
318 /* To make sure we don't get any weird locking issues here: 318 /* To make sure we don't get any weird locking issues here:
319 * destroy_conntrack() MUST NOT be called with a write lock 319 * destroy_conntrack() MUST NOT be called with a write lock
320 * to ip_conntrack_lock!!! -HW */ 320 * to ip_conntrack_lock!!! -HW */
321 rcu_read_lock();
321 proto = __ip_conntrack_proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum); 322 proto = __ip_conntrack_proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
322 if (proto && proto->destroy) 323 if (proto && proto->destroy)
323 proto->destroy(ct); 324 proto->destroy(ct);
325 rcu_read_unlock();
324 326
325 if (ip_conntrack_destroyed) 327 if (ip_conntrack_destroyed)
326 ip_conntrack_destroyed(ct); 328 ip_conntrack_destroyed(ct);
@@ -595,13 +597,13 @@ ip_conntrack_proto_find_get(u_int8_t protocol)
595{ 597{
596 struct ip_conntrack_protocol *p; 598 struct ip_conntrack_protocol *p;
597 599
598 preempt_disable(); 600 rcu_read_lock();
599 p = __ip_conntrack_proto_find(protocol); 601 p = __ip_conntrack_proto_find(protocol);
600 if (p) { 602 if (p) {
601 if (!try_module_get(p->me)) 603 if (!try_module_get(p->me))
602 p = &ip_conntrack_generic_protocol; 604 p = &ip_conntrack_generic_protocol;
603 } 605 }
604 preempt_enable(); 606 rcu_read_unlock();
605 607
606 return p; 608 return p;
607} 609}
@@ -830,6 +832,7 @@ unsigned int ip_conntrack_in(unsigned int hooknum,
830 } 832 }
831#endif 833#endif
832 834
835 /* rcu_read_lock()ed by nf_hook_slow */
833 proto = __ip_conntrack_proto_find((*pskb)->nh.iph->protocol); 836 proto = __ip_conntrack_proto_find((*pskb)->nh.iph->protocol);
834 837
835 /* It may be an special packet, error, unclean... 838 /* It may be an special packet, error, unclean...
@@ -875,8 +878,15 @@ unsigned int ip_conntrack_in(unsigned int hooknum,
875int invert_tuplepr(struct ip_conntrack_tuple *inverse, 878int invert_tuplepr(struct ip_conntrack_tuple *inverse,
876 const struct ip_conntrack_tuple *orig) 879 const struct ip_conntrack_tuple *orig)
877{ 880{
878 return ip_ct_invert_tuple(inverse, orig, 881 struct ip_conntrack_protocol *proto;
879 __ip_conntrack_proto_find(orig->dst.protonum)); 882 int ret;
883
884 rcu_read_lock();
885 proto = __ip_conntrack_proto_find(orig->dst.protonum);
886 ret = ip_ct_invert_tuple(inverse, orig, proto);
887 rcu_read_unlock();
888
889 return ret;
880} 890}
881 891
882/* Would two expected things clash? */ 892/* Would two expected things clash? */
@@ -1507,11 +1517,11 @@ int __init ip_conntrack_init(void)
1507 /* Don't NEED lock here, but good form anyway. */ 1517 /* Don't NEED lock here, but good form anyway. */
1508 write_lock_bh(&ip_conntrack_lock); 1518 write_lock_bh(&ip_conntrack_lock);
1509 for (i = 0; i < MAX_IP_CT_PROTO; i++) 1519 for (i = 0; i < MAX_IP_CT_PROTO; i++)
1510 ip_ct_protos[i] = &ip_conntrack_generic_protocol; 1520 rcu_assign_pointer(ip_ct_protos[i], &ip_conntrack_generic_protocol);
1511 /* Sew in builtin protocols. */ 1521 /* Sew in builtin protocols. */
1512 ip_ct_protos[IPPROTO_TCP] = &ip_conntrack_protocol_tcp; 1522 rcu_assign_pointer(ip_ct_protos[IPPROTO_TCP], &ip_conntrack_protocol_tcp);
1513 ip_ct_protos[IPPROTO_UDP] = &ip_conntrack_protocol_udp; 1523 rcu_assign_pointer(ip_ct_protos[IPPROTO_UDP], &ip_conntrack_protocol_udp);
1514 ip_ct_protos[IPPROTO_ICMP] = &ip_conntrack_protocol_icmp; 1524 rcu_assign_pointer(ip_ct_protos[IPPROTO_ICMP], &ip_conntrack_protocol_icmp);
1515 write_unlock_bh(&ip_conntrack_lock); 1525 write_unlock_bh(&ip_conntrack_lock);
1516 1526
1517 /* For use by ipt_REJECT */ 1527 /* For use by ipt_REJECT */
diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c
index 300ccbbbdac9..c7c1ec61b0f5 100644
--- a/net/ipv4/netfilter/ip_conntrack_standalone.c
+++ b/net/ipv4/netfilter/ip_conntrack_standalone.c
@@ -796,7 +796,7 @@ int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto)
796 ret = -EBUSY; 796 ret = -EBUSY;
797 goto out; 797 goto out;
798 } 798 }
799 ip_ct_protos[proto->proto] = proto; 799 rcu_assign_pointer(ip_ct_protos[proto->proto], proto);
800 out: 800 out:
801 write_unlock_bh(&ip_conntrack_lock); 801 write_unlock_bh(&ip_conntrack_lock);
802 return ret; 802 return ret;
@@ -805,11 +805,10 @@ int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto)
805void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto) 805void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto)
806{ 806{
807 write_lock_bh(&ip_conntrack_lock); 807 write_lock_bh(&ip_conntrack_lock);
808 ip_ct_protos[proto->proto] = &ip_conntrack_generic_protocol; 808 rcu_assign_pointer(ip_ct_protos[proto->proto],
809 &ip_conntrack_generic_protocol);
809 write_unlock_bh(&ip_conntrack_lock); 810 write_unlock_bh(&ip_conntrack_lock);
810 811 synchronize_rcu();
811 /* Somebody could be still looking at the proto in bh. */
812 synchronize_net();
813 812
814 /* Remove all contrack entries for this protocol */ 813 /* Remove all contrack entries for this protocol */
815 ip_ct_iterate_cleanup(kill_proto, &proto->proto); 814 ip_ct_iterate_cleanup(kill_proto, &proto->proto);
diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c
index 85ae0cabc8b5..18daabc22069 100644
--- a/net/ipv4/netfilter/ip_nat_core.c
+++ b/net/ipv4/netfilter/ip_nat_core.c
@@ -420,6 +420,7 @@ int ip_nat_icmp_reply_translation(struct ip_conntrack *ct,
420 struct icmphdr icmp; 420 struct icmphdr icmp;
421 struct iphdr ip; 421 struct iphdr ip;
422 } *inside; 422 } *inside;
423 struct ip_conntrack_protocol *proto;
423 struct ip_conntrack_tuple inner, target; 424 struct ip_conntrack_tuple inner, target;
424 int hdrlen = (*pskb)->nh.iph->ihl * 4; 425 int hdrlen = (*pskb)->nh.iph->ihl * 4;
425 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 426 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
@@ -455,10 +456,11 @@ int ip_nat_icmp_reply_translation(struct ip_conntrack *ct,
455 DEBUGP("icmp_reply_translation: translating error %p manp %u dir %s\n", 456 DEBUGP("icmp_reply_translation: translating error %p manp %u dir %s\n",
456 *pskb, manip, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY"); 457 *pskb, manip, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY");
457 458
459 /* rcu_read_lock()ed by nf_hook_slow */
460 proto = __ip_conntrack_proto_find(inside->ip.protocol);
458 if (!ip_ct_get_tuple(&inside->ip, *pskb, (*pskb)->nh.iph->ihl*4 + 461 if (!ip_ct_get_tuple(&inside->ip, *pskb, (*pskb)->nh.iph->ihl*4 +
459 sizeof(struct icmphdr) + inside->ip.ihl*4, 462 sizeof(struct icmphdr) + inside->ip.ihl*4,
460 &inner, 463 &inner, proto))
461 __ip_conntrack_proto_find(inside->ip.protocol)))
462 return 0; 464 return 0;
463 465
464 /* Change inner back to look like incoming packet. We do the 466 /* Change inner back to look like incoming packet. We do the