Clear 'ia' after iterating if_addrhead for unicast address matching: since

'ifa' was used as the TAILQ_FOREACH() iterator argument, and 'ia' was just
derived form it, it could be left non-NULL which confused later
conditional freeing code.  This could cause kernel panics if multicast IP
packets were received.  [1]

Call 'struct in_ifaddr *' in ip_rtaddr() 'ia', not 'ifa' in keeping with
normal conventions.

When 'ipstealth' is enabled returns from ip_input early, properly release
the 'ia' reference.

Reported by:	lstewart, sam [1]
MFC after:	6 weeks
This commit is contained in:
Robert Watson 2009-06-24 14:29:40 +00:00
parent 3c366f1f14
commit 19e5b0a797

View File

@ -661,6 +661,7 @@ passin:
#endif #endif
} }
IF_ADDR_UNLOCK(ifp); IF_ADDR_UNLOCK(ifp);
ia = NULL;
} }
/* RFC 3927 2.7: Do not forward datagrams for 169.254.0.0/16. */ /* RFC 3927 2.7: Do not forward datagrams for 169.254.0.0/16. */
if (IN_LINKLOCAL(ntohl(ip->ip_dst.s_addr))) { if (IN_LINKLOCAL(ntohl(ip->ip_dst.s_addr))) {
@ -738,9 +739,11 @@ ours:
* IPSTEALTH: Process non-routing options only * IPSTEALTH: Process non-routing options only
* if the packet is destined for us. * if the packet is destined for us.
*/ */
if (V_ipstealth && hlen > sizeof (struct ip) && if (V_ipstealth && hlen > sizeof (struct ip) && ip_dooptions(m, 1)) {
ip_dooptions(m, 1)) if (ia != NULL)
ifa_free(&ia->ia_ifa);
return; return;
}
#endif /* IPSTEALTH */ #endif /* IPSTEALTH */
/* Count the packet in the ip address stats */ /* Count the packet in the ip address stats */
@ -1349,7 +1352,7 @@ ip_rtaddr(struct in_addr dst, u_int fibnum)
{ {
struct route sro; struct route sro;
struct sockaddr_in *sin; struct sockaddr_in *sin;
struct in_ifaddr *ifa; struct in_ifaddr *ia;
bzero(&sro, sizeof(sro)); bzero(&sro, sizeof(sro));
sin = (struct sockaddr_in *)&sro.ro_dst; sin = (struct sockaddr_in *)&sro.ro_dst;
@ -1361,10 +1364,10 @@ ip_rtaddr(struct in_addr dst, u_int fibnum)
if (sro.ro_rt == NULL) if (sro.ro_rt == NULL)
return (NULL); return (NULL);
ifa = ifatoia(sro.ro_rt->rt_ifa); ia = ifatoia(sro.ro_rt->rt_ifa);
ifa_ref(&ifa->ia_ifa); ifa_ref(&ia->ia_ifa);
RTFREE(sro.ro_rt); RTFREE(sro.ro_rt);
return (ifa); return (ia);
} }
u_char inetctlerrmap[PRC_NCMDS] = { u_char inetctlerrmap[PRC_NCMDS] = {