aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2014-09-04 01:21:56 -0400
committerDavid S. Miller <davem@davemloft.net>2014-09-05 20:15:50 -0400
commitcaa415270c732505240bb60171c44a7838c555e8 (patch)
treecd44cd81f85c3904340f5cef1a359e2ae97a0c20 /net/ipv4
parent29abe2fda54f8e16ecff5d76d96325f31508d5ba (diff)
ipv4: fix a race in update_or_create_fnhe()
nh_exceptions is effectively used under rcu, but lacks proper barriers. Between kzalloc() and setting of nh->nh_exceptions(), we need a proper memory barrier. Signed-off-by: Eric Dumazet <edumazet@google.com> Fixes: 4895c771c7f00 ("ipv4: Add FIB nexthop exceptions.") Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/fib_semantics.c8
-rw-r--r--net/ipv4/route.c6
2 files changed, 8 insertions, 6 deletions
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index b10cd43a4722..5b6efb3d2308 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -157,9 +157,12 @@ static void rt_fibinfo_free(struct rtable __rcu **rtp)
157 157
158static void free_nh_exceptions(struct fib_nh *nh) 158static void free_nh_exceptions(struct fib_nh *nh)
159{ 159{
160 struct fnhe_hash_bucket *hash = nh->nh_exceptions; 160 struct fnhe_hash_bucket *hash;
161 int i; 161 int i;
162 162
163 hash = rcu_dereference_protected(nh->nh_exceptions, 1);
164 if (!hash)
165 return;
163 for (i = 0; i < FNHE_HASH_SIZE; i++) { 166 for (i = 0; i < FNHE_HASH_SIZE; i++) {
164 struct fib_nh_exception *fnhe; 167 struct fib_nh_exception *fnhe;
165 168
@@ -205,8 +208,7 @@ static void free_fib_info_rcu(struct rcu_head *head)
205 change_nexthops(fi) { 208 change_nexthops(fi) {
206 if (nexthop_nh->nh_dev) 209 if (nexthop_nh->nh_dev)
207 dev_put(nexthop_nh->nh_dev); 210 dev_put(nexthop_nh->nh_dev);
208 if (nexthop_nh->nh_exceptions) 211 free_nh_exceptions(nexthop_nh);
209 free_nh_exceptions(nexthop_nh);
210 rt_fibinfo_free_cpus(nexthop_nh->nh_pcpu_rth_output); 212 rt_fibinfo_free_cpus(nexthop_nh->nh_pcpu_rth_output);
211 rt_fibinfo_free(&nexthop_nh->nh_rth_input); 213 rt_fibinfo_free(&nexthop_nh->nh_rth_input);
212 } endfor_nexthops(fi); 214 } endfor_nexthops(fi);
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index eaa4b000c7b4..44b0cbdd76f1 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -628,12 +628,12 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw,
628 628
629 spin_lock_bh(&fnhe_lock); 629 spin_lock_bh(&fnhe_lock);
630 630
631 hash = nh->nh_exceptions; 631 hash = rcu_dereference(nh->nh_exceptions);
632 if (!hash) { 632 if (!hash) {
633 hash = kzalloc(FNHE_HASH_SIZE * sizeof(*hash), GFP_ATOMIC); 633 hash = kzalloc(FNHE_HASH_SIZE * sizeof(*hash), GFP_ATOMIC);
634 if (!hash) 634 if (!hash)
635 goto out_unlock; 635 goto out_unlock;
636 nh->nh_exceptions = hash; 636 rcu_assign_pointer(nh->nh_exceptions, hash);
637 } 637 }
638 638
639 hash += hval; 639 hash += hval;
@@ -1242,7 +1242,7 @@ static unsigned int ipv4_mtu(const struct dst_entry *dst)
1242 1242
1243static struct fib_nh_exception *find_exception(struct fib_nh *nh, __be32 daddr) 1243static struct fib_nh_exception *find_exception(struct fib_nh *nh, __be32 daddr)
1244{ 1244{
1245 struct fnhe_hash_bucket *hash = nh->nh_exceptions; 1245 struct fnhe_hash_bucket *hash = rcu_dereference(nh->nh_exceptions);
1246 struct fib_nh_exception *fnhe; 1246 struct fib_nh_exception *fnhe;
1247 u32 hval; 1247 u32 hval;
1248 1248