diff options
author | David S. Miller <davem@davemloft.net> | 2018-04-23 16:12:55 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-04-23 16:12:55 -0400 |
commit | f7c3b12cec09ad487d343fc940f606d17157d047 (patch) | |
tree | a25f9508243656db0d31f15c1dde671845ba23e1 | |
parent | 40cde8249a8280e4e24b42a4e20813ac4c1368e9 (diff) | |
parent | 8a14e46f140230ca889c2b0a4753ae8ea45fd770 (diff) |
Merge branch 'ipv6-couple-of-fixes-for-rcu-change-to-from'
David Ahern says:
====================
net/ipv6: couple of fixes for rcu change to from
So many details... I am thankful for all the robots running the
permutations and tools.
Two bug fixes from the rcu change to rt->from:
1. missing rcu lock in ip6_negative_advice
2. rcu dereferences in 2 sites
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/ipv6/route.c | 17 |
1 files changed, 12 insertions, 5 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 0407bbc5a028..ac3e51631c65 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1541,11 +1541,13 @@ static struct rt6_info *rt6_find_cached_rt(struct fib6_info *rt, static int rt6_remove_exception_rt(struct rt6_info *rt) { struct rt6_exception_bucket *bucket; - struct fib6_info *from = rt->from; struct in6_addr *src_key = NULL; struct rt6_exception *rt6_ex; + struct fib6_info *from; int err; + from = rcu_dereference_protected(rt->from, + lockdep_is_held(&rt6_exception_lock)); if (!from || !(rt->rt6i_flags & RTF_CACHE)) return -EINVAL; @@ -2201,10 +2203,12 @@ static struct dst_entry *ip6_negative_advice(struct dst_entry *dst) if (rt) { if (rt->rt6i_flags & RTF_CACHE) { + rcu_read_lock(); if (rt6_check_expired(rt)) { rt6_remove_exception_rt(rt); dst = NULL; } + rcu_read_unlock(); } else { dst_release(dst); dst = NULL; @@ -2221,6 +2225,7 @@ static void ip6_link_failure(struct sk_buff *skb) rt = (struct rt6_info *) skb_dst(skb); if (rt) { + rcu_read_lock(); if (rt->rt6i_flags & RTF_CACHE) { if (dst_hold_safe(&rt->dst)) rt6_remove_exception_rt(rt); @@ -2228,15 +2233,14 @@ static void ip6_link_failure(struct sk_buff *skb) struct fib6_info *from; struct fib6_node *fn; - rcu_read_lock(); from = rcu_dereference(rt->from); if (from) { fn = rcu_dereference(from->fib6_node); if (fn && (rt->rt6i_flags & RTF_DEFAULT)) fn->fn_sernum = -1; } - rcu_read_unlock(); } + rcu_read_unlock(); } } @@ -3338,8 +3342,10 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu rcu_read_lock(); from = rcu_dereference(rt->from); - nrt = ip6_rt_cache_alloc(from, &msg->dest, NULL); + fib6_info_hold(from); rcu_read_unlock(); + + nrt = ip6_rt_cache_alloc(from, &msg->dest, NULL); if (!nrt) goto out; @@ -3353,7 +3359,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu * a cached route because rt6_insert_exception() will * takes care of it */ - if (rt6_insert_exception(nrt, rt->from)) { + if (rt6_insert_exception(nrt, from)) { dst_release_immediate(&nrt->dst); goto out; } @@ -3365,6 +3371,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu call_netevent_notifiers(NETEVENT_REDIRECT, &netevent); out: + fib6_info_release(from); neigh_release(neigh); } |