Skip to content

Commit

Permalink
ipv6: Fix OOPS in ip6_dst_lookup_tail().
Browse files Browse the repository at this point in the history
This fixes kernel bugzilla 11469: "TUN with 1024 neighbours:
ip6_dst_lookup_tail NULL crash"

dst->neighbour is not necessarily hooked up at this point
in the processing path, so blindly dereferencing it is
the wrong thing to do.  This NULL check exists in other
similar paths and this case was just an oversight.

Also fix the completely wrong and confusing indentation
here while we're at it.

Based upon a patch by Evgeniy Polyakov.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
nhorman authored and davem330 committed Sep 9, 2008
1 parent 225f400 commit e550dfb
Showing 1 changed file with 32 additions and 32 deletions.
64 changes: 32 additions & 32 deletions net/ipv6/ip6_output.c
Expand Up @@ -943,39 +943,39 @@ static int ip6_dst_lookup_tail(struct sock *sk,
}

#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
/*
* Here if the dst entry we've looked up
* has a neighbour entry that is in the INCOMPLETE
* state and the src address from the flow is
* marked as OPTIMISTIC, we release the found
* dst entry and replace it instead with the
* dst entry of the nexthop router
*/
if (!((*dst)->neighbour->nud_state & NUD_VALID)) {
struct inet6_ifaddr *ifp;
struct flowi fl_gw;
int redirect;

ifp = ipv6_get_ifaddr(net, &fl->fl6_src,
(*dst)->dev, 1);

redirect = (ifp && ifp->flags & IFA_F_OPTIMISTIC);
if (ifp)
in6_ifa_put(ifp);

if (redirect) {
/*
* We need to get the dst entry for the
* default router instead
*/
dst_release(*dst);
memcpy(&fl_gw, fl, sizeof(struct flowi));
memset(&fl_gw.fl6_dst, 0, sizeof(struct in6_addr));
*dst = ip6_route_output(net, sk, &fl_gw);
if ((err = (*dst)->error))
goto out_err_release;
}
/*
* Here if the dst entry we've looked up
* has a neighbour entry that is in the INCOMPLETE
* state and the src address from the flow is
* marked as OPTIMISTIC, we release the found
* dst entry and replace it instead with the
* dst entry of the nexthop router
*/
if ((*dst)->neighbour && !((*dst)->neighbour->nud_state & NUD_VALID)) {
struct inet6_ifaddr *ifp;
struct flowi fl_gw;
int redirect;

ifp = ipv6_get_ifaddr(net, &fl->fl6_src,
(*dst)->dev, 1);

redirect = (ifp && ifp->flags & IFA_F_OPTIMISTIC);
if (ifp)
in6_ifa_put(ifp);

if (redirect) {
/*
* We need to get the dst entry for the
* default router instead
*/
dst_release(*dst);
memcpy(&fl_gw, fl, sizeof(struct flowi));
memset(&fl_gw.fl6_dst, 0, sizeof(struct in6_addr));
*dst = ip6_route_output(net, sk, &fl_gw);
if ((err = (*dst)->error))
goto out_err_release;
}
}
#endif

return 0;
Expand Down

0 comments on commit e550dfb

Please sign in to comment.