On Tue, Mar 19, 2019 at 11:45 PM Xin Long <lucien....@gmail.com> wrote: > > Jianlin reported a crash: > > [ 381.484332] BUG: unable to handle kernel NULL pointer dereference at > 0000000000000068 > [ 381.619802] RIP: 0010:fib6_rule_lookup+0xa3/0x160 > [ 382.009615] Call Trace: > [ 382.020762] <IRQ> > [ 382.030174] ip6_route_redirect.isra.52+0xc9/0xf0 > [ 382.050984] ip6_redirect+0xb6/0xf0 > [ 382.066731] icmpv6_notify+0xca/0x190 > [ 382.083185] ndisc_redirect_rcv+0x10f/0x160 > [ 382.102569] ndisc_rcv+0xfb/0x100 > [ 382.117725] icmpv6_rcv+0x3f2/0x520 > [ 382.133637] ip6_input_finish+0xbf/0x460 > [ 382.151634] ip6_input+0x3b/0xb0 > [ 382.166097] ipv6_rcv+0x378/0x4e0 > > It was caused by the lookup function __ip6_route_redirect() returns NULL in > fib6_rule_lookup() when ip6_create_rt_rcu() returns NULL. > > So we fix it by simply making ip6_create_rt_rcu() return ip6_null_entry > instead of NULL. > > v1->v2: > - move down 'fallback:' to make it more readable. > > Fixes: e873e4b9cc7e ("ipv6: use fib6_info_hold_safe() when necessary") > Reported-by: Jianlin Shi <ji...@redhat.com> > Suggested-by: Paolo Abeni <pab...@redhat.com> > Signed-off-by: Xin Long <lucien....@gmail.com> > --- Acked-by: Wei Wang <wei...@google.com>
Thanks for the fix. > net/ipv6/route.c | 18 ++++++++++-------- > 1 file changed, 10 insertions(+), 8 deletions(-) > > diff --git a/net/ipv6/route.c b/net/ipv6/route.c > index 4ef4bbd..0302e0eb 100644 > --- a/net/ipv6/route.c > +++ b/net/ipv6/route.c > @@ -1040,14 +1040,20 @@ static struct rt6_info *ip6_create_rt_rcu(struct > fib6_info *rt) > struct rt6_info *nrt; > > if (!fib6_info_hold_safe(rt)) > - return NULL; > + goto fallback; > > nrt = ip6_dst_alloc(dev_net(dev), dev, flags); > - if (nrt) > - ip6_rt_copy_init(nrt, rt); > - else > + if (!nrt) { > fib6_info_release(rt); > + goto fallback; > + } > > + ip6_rt_copy_init(nrt, rt); > + return nrt; > + > +fallback: > + nrt = dev_net(dev)->ipv6.ip6_null_entry; > + dst_hold(&nrt->dst); > return nrt; > } > > @@ -1096,10 +1102,6 @@ static struct rt6_info *ip6_pol_route_lookup(struct > net *net, > dst_hold(&rt->dst); > } else { > rt = ip6_create_rt_rcu(f6i); > - if (!rt) { > - rt = net->ipv6.ip6_null_entry; > - dst_hold(&rt->dst); > - } > } > > rcu_read_unlock(); > -- > 2.1.0 >