diff options
| author | Patrick McHardy <kaber@trash.net> | 2007-02-12 14:12:09 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2007-02-12 14:12:09 -0500 |
| commit | a441dfdbb2e54217b8d26a6c129650728d401bf7 (patch) | |
| tree | 49811d9e97eaaee1b10a66a6b5798f2bccc05d39 /net/ipv4 | |
| parent | e92ad99c78de09a5ba0746e1c0ee27cc7450c64d (diff) | |
[NETFILTER]: ip_nat: properly use RCU API for ip_nat_protos array
Replace preempt_{enable,disable} based RCU by proper use of the
RCU API and add missing rcu_read_lock/rcu_read_unlock calls in
paths used outside of packet processing context (nfnetlink_conntrack).
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
| -rw-r--r-- | net/ipv4/netfilter/ip_nat_core.c | 61 |
1 files changed, 29 insertions, 32 deletions
diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c index 275a4d3faf0a..85ae0cabc8b5 100644 --- a/net/ipv4/netfilter/ip_nat_core.c +++ b/net/ipv4/netfilter/ip_nat_core.c | |||
| @@ -50,7 +50,7 @@ static struct ip_nat_protocol *ip_nat_protos[MAX_IP_NAT_PROTO]; | |||
| 50 | static inline struct ip_nat_protocol * | 50 | static inline struct ip_nat_protocol * |
| 51 | __ip_nat_proto_find(u_int8_t protonum) | 51 | __ip_nat_proto_find(u_int8_t protonum) |
| 52 | { | 52 | { |
| 53 | return ip_nat_protos[protonum]; | 53 | return rcu_dereference(ip_nat_protos[protonum]); |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | struct ip_nat_protocol * | 56 | struct ip_nat_protocol * |
| @@ -58,13 +58,11 @@ ip_nat_proto_find_get(u_int8_t protonum) | |||
| 58 | { | 58 | { |
| 59 | struct ip_nat_protocol *p; | 59 | struct ip_nat_protocol *p; |
| 60 | 60 | ||
| 61 | /* we need to disable preemption to make sure 'p' doesn't get | 61 | rcu_read_lock(); |
| 62 | * removed until we've grabbed the reference */ | ||
| 63 | preempt_disable(); | ||
| 64 | p = __ip_nat_proto_find(protonum); | 62 | p = __ip_nat_proto_find(protonum); |
| 65 | if (!try_module_get(p->me)) | 63 | if (!try_module_get(p->me)) |
| 66 | p = &ip_nat_unknown_protocol; | 64 | p = &ip_nat_unknown_protocol; |
| 67 | preempt_enable(); | 65 | rcu_read_unlock(); |
| 68 | 66 | ||
| 69 | return p; | 67 | return p; |
| 70 | } | 68 | } |
| @@ -120,8 +118,8 @@ static int | |||
| 120 | in_range(const struct ip_conntrack_tuple *tuple, | 118 | in_range(const struct ip_conntrack_tuple *tuple, |
| 121 | const struct ip_nat_range *range) | 119 | const struct ip_nat_range *range) |
| 122 | { | 120 | { |
| 123 | struct ip_nat_protocol *proto = | 121 | struct ip_nat_protocol *proto; |
| 124 | __ip_nat_proto_find(tuple->dst.protonum); | 122 | int ret = 0; |
| 125 | 123 | ||
| 126 | /* If we are supposed to map IPs, then we must be in the | 124 | /* If we are supposed to map IPs, then we must be in the |
| 127 | range specified, otherwise let this drag us onto a new src IP. */ | 125 | range specified, otherwise let this drag us onto a new src IP. */ |
| @@ -131,12 +129,15 @@ in_range(const struct ip_conntrack_tuple *tuple, | |||
| 131 | return 0; | 129 | return 0; |
| 132 | } | 130 | } |
| 133 | 131 | ||
| 132 | rcu_read_lock(); | ||
| 133 | proto = __ip_nat_proto_find(tuple->dst.protonum); | ||
| 134 | if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) | 134 | if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) |
| 135 | || proto->in_range(tuple, IP_NAT_MANIP_SRC, | 135 | || proto->in_range(tuple, IP_NAT_MANIP_SRC, |
| 136 | &range->min, &range->max)) | 136 | &range->min, &range->max)) |
| 137 | return 1; | 137 | ret = 1; |
| 138 | rcu_read_unlock(); | ||
| 138 | 139 | ||
| 139 | return 0; | 140 | return ret; |
| 140 | } | 141 | } |
| 141 | 142 | ||
| 142 | static inline int | 143 | static inline int |
| @@ -260,27 +261,25 @@ get_unique_tuple(struct ip_conntrack_tuple *tuple, | |||
| 260 | /* 3) The per-protocol part of the manip is made to map into | 261 | /* 3) The per-protocol part of the manip is made to map into |
| 261 | the range to make a unique tuple. */ | 262 | the range to make a unique tuple. */ |
| 262 | 263 | ||
| 263 | proto = ip_nat_proto_find_get(orig_tuple->dst.protonum); | 264 | rcu_read_lock(); |
| 265 | proto = __ip_nat_proto_find(orig_tuple->dst.protonum); | ||
| 264 | 266 | ||
| 265 | /* Change protocol info to have some randomization */ | 267 | /* Change protocol info to have some randomization */ |
| 266 | if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) { | 268 | if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) { |
| 267 | proto->unique_tuple(tuple, range, maniptype, conntrack); | 269 | proto->unique_tuple(tuple, range, maniptype, conntrack); |
| 268 | ip_nat_proto_put(proto); | 270 | goto out; |
| 269 | return; | ||
| 270 | } | 271 | } |
| 271 | 272 | ||
| 272 | /* Only bother mapping if it's not already in range and unique */ | 273 | /* Only bother mapping if it's not already in range and unique */ |
| 273 | if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) | 274 | if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) |
| 274 | || proto->in_range(tuple, maniptype, &range->min, &range->max)) | 275 | || proto->in_range(tuple, maniptype, &range->min, &range->max)) |
| 275 | && !ip_nat_used_tuple(tuple, conntrack)) { | 276 | && !ip_nat_used_tuple(tuple, conntrack)) |
| 276 | ip_nat_proto_put(proto); | 277 | goto out; |
| 277 | return; | ||
| 278 | } | ||
| 279 | 278 | ||
| 280 | /* Last change: get protocol to try to obtain unique tuple. */ | 279 | /* Last change: get protocol to try to obtain unique tuple. */ |
| 281 | proto->unique_tuple(tuple, range, maniptype, conntrack); | 280 | proto->unique_tuple(tuple, range, maniptype, conntrack); |
| 282 | 281 | out: | |
| 283 | ip_nat_proto_put(proto); | 282 | rcu_read_unlock(); |
| 284 | } | 283 | } |
| 285 | 284 | ||
| 286 | unsigned int | 285 | unsigned int |
| @@ -360,12 +359,11 @@ manip_pkt(u_int16_t proto, | |||
| 360 | iph = (void *)(*pskb)->data + iphdroff; | 359 | iph = (void *)(*pskb)->data + iphdroff; |
| 361 | 360 | ||
| 362 | /* Manipulate protcol part. */ | 361 | /* Manipulate protcol part. */ |
| 363 | p = ip_nat_proto_find_get(proto); | 362 | |
| 364 | if (!p->manip_pkt(pskb, iphdroff, target, maniptype)) { | 363 | /* rcu_read_lock()ed by nf_hook_slow */ |
| 365 | ip_nat_proto_put(p); | 364 | p = __ip_nat_proto_find(proto); |
| 365 | if (!p->manip_pkt(pskb, iphdroff, target, maniptype)) | ||
| 366 | return 0; | 366 | return 0; |
| 367 | } | ||
| 368 | ip_nat_proto_put(p); | ||
| 369 | 367 | ||
| 370 | iph = (void *)(*pskb)->data + iphdroff; | 368 | iph = (void *)(*pskb)->data + iphdroff; |
| 371 | 369 | ||
| @@ -515,7 +513,7 @@ int ip_nat_protocol_register(struct ip_nat_protocol *proto) | |||
| 515 | ret = -EBUSY; | 513 | ret = -EBUSY; |
| 516 | goto out; | 514 | goto out; |
| 517 | } | 515 | } |
| 518 | ip_nat_protos[proto->protonum] = proto; | 516 | rcu_assign_pointer(ip_nat_protos[proto->protonum], proto); |
| 519 | out: | 517 | out: |
| 520 | write_unlock_bh(&ip_nat_lock); | 518 | write_unlock_bh(&ip_nat_lock); |
| 521 | return ret; | 519 | return ret; |
| @@ -526,11 +524,10 @@ EXPORT_SYMBOL(ip_nat_protocol_register); | |||
| 526 | void ip_nat_protocol_unregister(struct ip_nat_protocol *proto) | 524 | void ip_nat_protocol_unregister(struct ip_nat_protocol *proto) |
| 527 | { | 525 | { |
| 528 | write_lock_bh(&ip_nat_lock); | 526 | write_lock_bh(&ip_nat_lock); |
| 529 | ip_nat_protos[proto->protonum] = &ip_nat_unknown_protocol; | 527 | rcu_assign_pointer(ip_nat_protos[proto->protonum], |
| 528 | &ip_nat_unknown_protocol); | ||
| 530 | write_unlock_bh(&ip_nat_lock); | 529 | write_unlock_bh(&ip_nat_lock); |
| 531 | 530 | synchronize_rcu(); | |
| 532 | /* Someone could be still looking at the proto in a bh. */ | ||
| 533 | synchronize_net(); | ||
| 534 | } | 531 | } |
| 535 | EXPORT_SYMBOL(ip_nat_protocol_unregister); | 532 | EXPORT_SYMBOL(ip_nat_protocol_unregister); |
| 536 | 533 | ||
| @@ -594,10 +591,10 @@ static int __init ip_nat_init(void) | |||
| 594 | /* Sew in builtin protocols. */ | 591 | /* Sew in builtin protocols. */ |
| 595 | write_lock_bh(&ip_nat_lock); | 592 | write_lock_bh(&ip_nat_lock); |
| 596 | for (i = 0; i < MAX_IP_NAT_PROTO; i++) | 593 | for (i = 0; i < MAX_IP_NAT_PROTO; i++) |
| 597 | ip_nat_protos[i] = &ip_nat_unknown_protocol; | 594 | rcu_assign_pointer(ip_nat_protos[i], &ip_nat_unknown_protocol); |
| 598 | ip_nat_protos[IPPROTO_TCP] = &ip_nat_protocol_tcp; | 595 | rcu_assign_pointer(ip_nat_protos[IPPROTO_TCP], &ip_nat_protocol_tcp); |
| 599 | ip_nat_protos[IPPROTO_UDP] = &ip_nat_protocol_udp; | 596 | rcu_assign_pointer(ip_nat_protos[IPPROTO_UDP], &ip_nat_protocol_udp); |
| 600 | ip_nat_protos[IPPROTO_ICMP] = &ip_nat_protocol_icmp; | 597 | rcu_assign_pointer(ip_nat_protos[IPPROTO_ICMP], &ip_nat_protocol_icmp); |
| 601 | write_unlock_bh(&ip_nat_lock); | 598 | write_unlock_bh(&ip_nat_lock); |
| 602 | 599 | ||
| 603 | for (i = 0; i < ip_nat_htable_size; i++) { | 600 | for (i = 0; i < ip_nat_htable_size; i++) { |
