aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2007-02-12 14:12:26 -0500
committerDavid S. Miller <davem@davemloft.net>2007-02-12 14:12:26 -0500
commite22a05486913ccb959281cd6370593bd8e197fa9 (patch)
tree7aa413f110ea04eee3ea98a10ad8e9cda7e989ca
parenta441dfdbb2e54217b8d26a6c129650728d401bf7 (diff)
[NETFILTER]: nf_nat: properly use RCU API for nf_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>
-rw-r--r--net/ipv4/netfilter/nf_nat_core.c59
1 files changed, 28 insertions, 31 deletions
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c
index cf1010827be1..6d0061f05810 100644
--- a/net/ipv4/netfilter/nf_nat_core.c
+++ b/net/ipv4/netfilter/nf_nat_core.c
@@ -53,7 +53,7 @@ static struct nf_nat_protocol *nf_nat_protos[MAX_IP_NAT_PROTO];
53static inline struct nf_nat_protocol * 53static inline struct nf_nat_protocol *
54__nf_nat_proto_find(u_int8_t protonum) 54__nf_nat_proto_find(u_int8_t protonum)
55{ 55{
56 return nf_nat_protos[protonum]; 56 return rcu_dereference(nf_nat_protos[protonum]);
57} 57}
58 58
59struct nf_nat_protocol * 59struct nf_nat_protocol *
@@ -61,13 +61,11 @@ nf_nat_proto_find_get(u_int8_t protonum)
61{ 61{
62 struct nf_nat_protocol *p; 62 struct nf_nat_protocol *p;
63 63
64 /* we need to disable preemption to make sure 'p' doesn't get 64 rcu_read_lock();
65 * removed until we've grabbed the reference */
66 preempt_disable();
67 p = __nf_nat_proto_find(protonum); 65 p = __nf_nat_proto_find(protonum);
68 if (!try_module_get(p->me)) 66 if (!try_module_get(p->me))
69 p = &nf_nat_unknown_protocol; 67 p = &nf_nat_unknown_protocol;
70 preempt_enable(); 68 rcu_read_unlock();
71 69
72 return p; 70 return p;
73} 71}
@@ -126,8 +124,8 @@ in_range(const struct nf_conntrack_tuple *tuple,
126 const struct nf_nat_range *range) 124 const struct nf_nat_range *range)
127{ 125{
128 struct nf_nat_protocol *proto; 126 struct nf_nat_protocol *proto;
127 int ret = 0;
129 128
130 proto = __nf_nat_proto_find(tuple->dst.protonum);
131 /* If we are supposed to map IPs, then we must be in the 129 /* If we are supposed to map IPs, then we must be in the
132 range specified, otherwise let this drag us onto a new src IP. */ 130 range specified, otherwise let this drag us onto a new src IP. */
133 if (range->flags & IP_NAT_RANGE_MAP_IPS) { 131 if (range->flags & IP_NAT_RANGE_MAP_IPS) {
@@ -136,12 +134,15 @@ in_range(const struct nf_conntrack_tuple *tuple,
136 return 0; 134 return 0;
137 } 135 }
138 136
137 rcu_read_lock();
138 proto = __nf_nat_proto_find(tuple->dst.protonum);
139 if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) || 139 if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) ||
140 proto->in_range(tuple, IP_NAT_MANIP_SRC, 140 proto->in_range(tuple, IP_NAT_MANIP_SRC,
141 &range->min, &range->max)) 141 &range->min, &range->max))
142 return 1; 142 ret = 1;
143 rcu_read_unlock();
143 144
144 return 0; 145 return ret;
145} 146}
146 147
147static inline int 148static inline int
@@ -268,27 +269,25 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
268 /* 3) The per-protocol part of the manip is made to map into 269 /* 3) The per-protocol part of the manip is made to map into
269 the range to make a unique tuple. */ 270 the range to make a unique tuple. */
270 271
271 proto = nf_nat_proto_find_get(orig_tuple->dst.protonum); 272 rcu_read_lock();
273 proto = __nf_nat_proto_find(orig_tuple->dst.protonum);
272 274
273 /* Change protocol info to have some randomization */ 275 /* Change protocol info to have some randomization */
274 if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) { 276 if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) {
275 proto->unique_tuple(tuple, range, maniptype, ct); 277 proto->unique_tuple(tuple, range, maniptype, ct);
276 nf_nat_proto_put(proto); 278 goto out;
277 return;
278 } 279 }
279 280
280 /* Only bother mapping if it's not already in range and unique */ 281 /* Only bother mapping if it's not already in range and unique */
281 if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) || 282 if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) ||
282 proto->in_range(tuple, maniptype, &range->min, &range->max)) && 283 proto->in_range(tuple, maniptype, &range->min, &range->max)) &&
283 !nf_nat_used_tuple(tuple, ct)) { 284 !nf_nat_used_tuple(tuple, ct))
284 nf_nat_proto_put(proto); 285 goto out;
285 return;
286 }
287 286
288 /* Last change: get protocol to try to obtain unique tuple. */ 287 /* Last change: get protocol to try to obtain unique tuple. */
289 proto->unique_tuple(tuple, range, maniptype, ct); 288 proto->unique_tuple(tuple, range, maniptype, ct);
290 289out:
291 nf_nat_proto_put(proto); 290 rcu_read_unlock();
292} 291}
293 292
294unsigned int 293unsigned int
@@ -369,12 +368,11 @@ manip_pkt(u_int16_t proto,
369 iph = (void *)(*pskb)->data + iphdroff; 368 iph = (void *)(*pskb)->data + iphdroff;
370 369
371 /* Manipulate protcol part. */ 370 /* Manipulate protcol part. */
372 p = nf_nat_proto_find_get(proto); 371
373 if (!p->manip_pkt(pskb, iphdroff, target, maniptype)) { 372 /* rcu_read_lock()ed by nf_hook_slow */
374 nf_nat_proto_put(p); 373 p = __nf_nat_proto_find(proto);
374 if (!p->manip_pkt(pskb, iphdroff, target, maniptype))
375 return 0; 375 return 0;
376 }
377 nf_nat_proto_put(p);
378 376
379 iph = (void *)(*pskb)->data + iphdroff; 377 iph = (void *)(*pskb)->data + iphdroff;
380 378
@@ -529,7 +527,7 @@ int nf_nat_protocol_register(struct nf_nat_protocol *proto)
529 ret = -EBUSY; 527 ret = -EBUSY;
530 goto out; 528 goto out;
531 } 529 }
532 nf_nat_protos[proto->protonum] = proto; 530 rcu_assign_pointer(nf_nat_protos[proto->protonum], proto);
533 out: 531 out:
534 write_unlock_bh(&nf_nat_lock); 532 write_unlock_bh(&nf_nat_lock);
535 return ret; 533 return ret;
@@ -540,11 +538,10 @@ EXPORT_SYMBOL(nf_nat_protocol_register);
540void nf_nat_protocol_unregister(struct nf_nat_protocol *proto) 538void nf_nat_protocol_unregister(struct nf_nat_protocol *proto)
541{ 539{
542 write_lock_bh(&nf_nat_lock); 540 write_lock_bh(&nf_nat_lock);
543 nf_nat_protos[proto->protonum] = &nf_nat_unknown_protocol; 541 rcu_assign_pointer(nf_nat_protos[proto->protonum],
542 &nf_nat_unknown_protocol);
544 write_unlock_bh(&nf_nat_lock); 543 write_unlock_bh(&nf_nat_lock);
545 544 synchronize_rcu();
546 /* Someone could be still looking at the proto in a bh. */
547 synchronize_net();
548} 545}
549EXPORT_SYMBOL(nf_nat_protocol_unregister); 546EXPORT_SYMBOL(nf_nat_protocol_unregister);
550 547
@@ -608,10 +605,10 @@ static int __init nf_nat_init(void)
608 /* Sew in builtin protocols. */ 605 /* Sew in builtin protocols. */
609 write_lock_bh(&nf_nat_lock); 606 write_lock_bh(&nf_nat_lock);
610 for (i = 0; i < MAX_IP_NAT_PROTO; i++) 607 for (i = 0; i < MAX_IP_NAT_PROTO; i++)
611 nf_nat_protos[i] = &nf_nat_unknown_protocol; 608 rcu_assign_pointer(nf_nat_protos[i], &nf_nat_unknown_protocol);
612 nf_nat_protos[IPPROTO_TCP] = &nf_nat_protocol_tcp; 609 rcu_assign_pointer(nf_nat_protos[IPPROTO_TCP], &nf_nat_protocol_tcp);
613 nf_nat_protos[IPPROTO_UDP] = &nf_nat_protocol_udp; 610 rcu_assign_pointer(nf_nat_protos[IPPROTO_UDP], &nf_nat_protocol_udp);
614 nf_nat_protos[IPPROTO_ICMP] = &nf_nat_protocol_icmp; 611 rcu_assign_pointer(nf_nat_protos[IPPROTO_ICMP], &nf_nat_protocol_icmp);
615 write_unlock_bh(&nf_nat_lock); 612 write_unlock_bh(&nf_nat_lock);
616 613
617 for (i = 0; i < nf_nat_htable_size; i++) { 614 for (i = 0; i < nf_nat_htable_size; i++) {