Fix in6_pcbrtentry() for the case of IPv6-mapped IPv4 addresses:

don't assume that the cached route is a sockaddr_in6, and do the
right comparisions so that no out-of-bounds memory is accessed.

btw, the use of "#ifdef INET" throughout the source doesn't look clean
to me: There are 2 cases -- whether AF_INET is usable by userland
programs, and whether IPv4 is supported as on-wire protocol.
This commit is contained in:
drochner 2007-11-21 21:18:25 +00:00
parent 72ff826442
commit e3e9b75351
1 changed files with 27 additions and 9 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: in6_pcb.c,v 1.89 2007/11/10 00:14:31 dyoung Exp $ */
/* $NetBSD: in6_pcb.c,v 1.90 2007/11/21 21:18:25 drochner Exp $ */
/* $KAME: in6_pcb.c,v 1.84 2001/02/08 18:02:08 itojun Exp $ */
/*
@ -62,7 +62,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: in6_pcb.c,v 1.89 2007/11/10 00:14:31 dyoung Exp $");
__KERNEL_RCSID(0, "$NetBSD: in6_pcb.c,v 1.90 2007/11/21 21:18:25 drochner Exp $");
#include "opt_inet.h"
#include "opt_ipsec.h"
@ -903,20 +903,38 @@ struct rtentry *
in6_pcbrtentry(struct in6pcb *in6p)
{
struct route *ro;
const struct sockaddr_in6 *cdst;
union {
const struct sockaddr *sa;
const struct sockaddr_in6 *sa6;
#ifdef INET
const struct sockaddr_in *sa4;
#endif
} cdst;
ro = &in6p->in6p_route;
if (in6p->in6p_af != AF_INET6)
return (NULL);
cdst = (const struct sockaddr_in6 *)rtcache_getdst(ro);
if (cdst == NULL)
cdst.sa = rtcache_getdst(ro);
if (cdst.sa == NULL)
;
else if (!IN6_ARE_ADDR_EQUAL(&cdst->sin6_addr, &in6p->in6p_faddr))
rtcache_free(ro);
else
rtcache_check(ro);
#ifdef INET
else if (cdst.sa->sa_family == AF_INET) {
KASSERT(IN6_IS_ADDR_V4MAPPED(&in6p->in6p_faddr));
if (cdst.sa4->sin_addr.s_addr != in6p->in6p_faddr.s6_addr32[3])
rtcache_free(ro);
else
rtcache_check(ro);
}
#endif
else {
if (!IN6_ARE_ADDR_EQUAL(&cdst.sa6->sin6_addr,
&in6p->in6p_faddr))
rtcache_free(ro);
else
rtcache_check(ro);
}
#ifdef INET
if (ro->ro_rt == NULL && IN6_IS_ADDR_V4MAPPED(&in6p->in6p_faddr)) {
union {