aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorMartin KaFai Lau <kafai@fb.com>2019-04-30 13:45:12 -0400
committerDavid S. Miller <davem@davemloft.net>2019-05-01 17:17:54 -0400
commit886b7a50100a50f1cbd08a6f8ec5884dfbe082dc (patch)
treef18e97f6f5ac9054af65539f00e52c6160470a20 /net/ipv6
parentf3505745c07ff50c22aeca9dde98762d1c8b5898 (diff)
ipv6: A few fixes on dereferencing rt->from
It is a followup after the fix in commit 9c69a1320515 ("route: Avoid crash from dereferencing NULL rt->from") rt6_do_redirect(): 1. NULL checking is needed on rt->from because a parallel fib6_info delete could happen that sets rt->from to NULL. (e.g. rt6_remove_exception() and fib6_drop_pcpu_from()). 2. fib6_info_hold() is not enough. Same reason as (1). Meaning, holding dst->__refcnt cannot ensure rt->from is not NULL or rt->from->fib6_ref is not 0. Instead of using fib6_info_hold_safe() which ip6_rt_cache_alloc() is already doing, this patch chooses to extend the rcu section to keep "from" dereference-able after checking for NULL. inet6_rtm_getroute(): 1. NULL checking is also needed on rt->from for a similar reason. Note that inet6_rtm_getroute() is using RTNL_FLAG_DOIT_UNLOCKED. Fixes: a68886a69180 ("net/ipv6: Make from in rt6_info rcu protected") Signed-off-by: Martin KaFai Lau <kafai@fb.com> Acked-by: Wei Wang <weiwan@google.com> Reviewed-by: David Ahern <dsahern@gmail.com> Reviewed-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/route.c38
1 files changed, 18 insertions, 20 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 2cc166bc978d..0520aca3354b 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -3392,11 +3392,8 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
3392 3392
3393 rcu_read_lock(); 3393 rcu_read_lock();
3394 from = rcu_dereference(rt->from); 3394 from = rcu_dereference(rt->from);
3395 /* This fib6_info_hold() is safe here because we hold reference to rt 3395 if (!from)
3396 * and rt already holds reference to fib6_info. 3396 goto out;
3397 */
3398 fib6_info_hold(from);
3399 rcu_read_unlock();
3400 3397
3401 nrt = ip6_rt_cache_alloc(from, &msg->dest, NULL); 3398 nrt = ip6_rt_cache_alloc(from, &msg->dest, NULL);
3402 if (!nrt) 3399 if (!nrt)
@@ -3408,10 +3405,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
3408 3405
3409 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key; 3406 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
3410 3407
3411 /* No need to remove rt from the exception table if rt is 3408 /* rt6_insert_exception() will take care of duplicated exceptions */
3412 * a cached route because rt6_insert_exception() will
3413 * takes care of it
3414 */
3415 if (rt6_insert_exception(nrt, from)) { 3409 if (rt6_insert_exception(nrt, from)) {
3416 dst_release_immediate(&nrt->dst); 3410 dst_release_immediate(&nrt->dst);
3417 goto out; 3411 goto out;
@@ -3424,7 +3418,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
3424 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent); 3418 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
3425 3419
3426out: 3420out:
3427 fib6_info_release(from); 3421 rcu_read_unlock();
3428 neigh_release(neigh); 3422 neigh_release(neigh);
3429} 3423}
3430 3424
@@ -5023,16 +5017,20 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
5023 5017
5024 rcu_read_lock(); 5018 rcu_read_lock();
5025 from = rcu_dereference(rt->from); 5019 from = rcu_dereference(rt->from);
5026 5020 if (from) {
5027 if (fibmatch) 5021 if (fibmatch)
5028 err = rt6_fill_node(net, skb, from, NULL, NULL, NULL, iif, 5022 err = rt6_fill_node(net, skb, from, NULL, NULL, NULL,
5029 RTM_NEWROUTE, NETLINK_CB(in_skb).portid, 5023 iif, RTM_NEWROUTE,
5030 nlh->nlmsg_seq, 0); 5024 NETLINK_CB(in_skb).portid,
5031 else 5025 nlh->nlmsg_seq, 0);
5032 err = rt6_fill_node(net, skb, from, dst, &fl6.daddr, 5026 else
5033 &fl6.saddr, iif, RTM_NEWROUTE, 5027 err = rt6_fill_node(net, skb, from, dst, &fl6.daddr,
5034 NETLINK_CB(in_skb).portid, nlh->nlmsg_seq, 5028 &fl6.saddr, iif, RTM_NEWROUTE,
5035 0); 5029 NETLINK_CB(in_skb).portid,
5030 nlh->nlmsg_seq, 0);
5031 } else {
5032 err = -ENETUNREACH;
5033 }
5036 rcu_read_unlock(); 5034 rcu_read_unlock();
5037 5035
5038 if (err < 0) { 5036 if (err < 0) {