The IPv6 stack labels incoming packets with an m_tag whose payload

is a struct ip6aux.  A struct ip6aux used to contain a pointer to
an in6_ifaddr, but that pointer could become a dangling reference
in the lifetime of the m_tag, because ip6_setdstifaddr() did not
increase the in6_ifaddr's reference count.  I have removed the
pointer from ip6aux.  I load it with the interesting fields from
the in6_ifaddr (an IPv6 address, a scope ID, and some flags),
instead.
This commit is contained in:
dyoung 2007-10-29 16:54:42 +00:00
parent 40ffc8b91f
commit 6709ce7762
4 changed files with 51 additions and 40 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: icmp6.c,v 1.138 2007/10/24 06:37:20 dyoung Exp $ */
/* $NetBSD: icmp6.c,v 1.139 2007/10/29 16:54:42 dyoung Exp $ */
/* $KAME: icmp6.c,v 1.217 2001/06/20 15:03:29 jinmei Exp $ */
/*
@ -62,7 +62,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: icmp6.c,v 1.138 2007/10/24 06:37:20 dyoung Exp $");
__KERNEL_RCSID(0, "$NetBSD: icmp6.c,v 1.139 2007/10/29 16:54:42 dyoung Exp $");
#include "opt_inet.h"
#include "opt_ipsec.h"
@ -1926,11 +1926,13 @@ icmp6_reflect(struct mbuf *m, size_t off)
{
struct ip6_hdr *ip6;
struct icmp6_hdr *icmp6;
struct in6_ifaddr *ia;
const struct in6_ifaddr *ia;
const struct ip6aux *ip6a;
int plen;
int type, code;
struct ifnet *outif = NULL;
struct in6_addr origdst, *src = NULL;
struct in6_addr origdst;
const struct in6_addr *src = NULL;
/* too short to reflect */
if (off < sizeof(struct ip6_hdr)) {
@ -1994,26 +1996,27 @@ icmp6_reflect(struct mbuf *m, size_t off)
* procedure of an outgoing packet of our own, in which case we need
* to search in the ifaddr list.
*/
if (!IN6_IS_ADDR_MULTICAST(&origdst)) {
if ((ia = ip6_getdstifaddr(m))) {
if (!(ia->ia6_flags &
(IN6_IFF_ANYCAST|IN6_IFF_NOTREADY)))
src = &ia->ia_addr.sin6_addr;
} else {
struct sockaddr_in6 d;
if (IN6_IS_ADDR_MULTICAST(&origdst))
;
else if ((ip6a = ip6_getdstifaddr(m)) != NULL) {
if ((ip6a->ip6a_flags &
(IN6_IFF_ANYCAST|IN6_IFF_NOTREADY)) == 0)
src = &ip6a->ip6a_src;
} else {
union {
struct sockaddr_in6 sin6;
struct sockaddr sa;
} u;
bzero(&d, sizeof(d));
d.sin6_family = AF_INET6;
d.sin6_len = sizeof(d);
d.sin6_addr = origdst;
ia = (struct in6_ifaddr *)
ifa_ifwithaddr((struct sockaddr *)&d);
if (ia &&
!(ia->ia6_flags &
(IN6_IFF_ANYCAST|IN6_IFF_NOTREADY))) {
src = &ia->ia_addr.sin6_addr;
}
}
sockaddr_in6_init(&u.sin6, &origdst, 0, 0, 0);
ia = (struct in6_ifaddr *)ifa_ifwithaddr(&u.sa);
if (ia == NULL)
;
else if ((ia->ia6_flags &
(IN6_IFF_ANYCAST|IN6_IFF_NOTREADY)) == 0)
src = &ia->ia_addr.sin6_addr;
}
if (src == NULL) {

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip6_input.c,v 1.111 2007/10/24 06:37:22 dyoung Exp $ */
/* $NetBSD: ip6_input.c,v 1.112 2007/10/29 16:54:42 dyoung Exp $ */
/* $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $ */
/*
@ -62,7 +62,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ip6_input.c,v 1.111 2007/10/24 06:37:22 dyoung Exp $");
__KERNEL_RCSID(0, "$NetBSD: ip6_input.c,v 1.112 2007/10/29 16:54:42 dyoung Exp $");
#include "opt_inet.h"
#include "opt_inet6.h"
@ -149,7 +149,7 @@ struct pfil_head inet6_pfil_hook;
struct ip6stat ip6stat;
static void ip6_init2(void *);
static struct m_tag *ip6_setdstifaddr __P((struct mbuf *, struct in6_ifaddr *));
static struct m_tag *ip6_setdstifaddr(struct mbuf *, const struct in6_ifaddr *);
static int ip6_hopopts_input(u_int32_t *, u_int32_t *, struct mbuf **, int *);
static struct mbuf *ip6_pullexthdr(struct mbuf *, size_t, int);
@ -827,24 +827,30 @@ ip6_input(struct mbuf *m)
* set/grab in6_ifaddr correspond to IPv6 destination address.
*/
static struct m_tag *
ip6_setdstifaddr(struct mbuf *m, struct in6_ifaddr *ia6)
ip6_setdstifaddr(struct mbuf *m, const struct in6_ifaddr *ia)
{
struct m_tag *mtag;
mtag = ip6_addaux(m);
if (mtag)
((struct ip6aux *)(mtag + 1))->ip6a_dstia6 = ia6;
if (mtag != NULL) {
struct ip6aux *ip6a;
ip6a = (struct ip6aux *)(mtag + 1);
in6_setscope(&ip6a->ip6a_src, ia->ia_ifp, &ip6a->ip6a_scope_id);
ip6a->ip6a_src = ia->ia_addr.sin6_addr;
ip6a->ip6a_flags = ia->ia6_flags;
}
return mtag; /* NULL if failed to set */
}
struct in6_ifaddr *
const struct ip6aux *
ip6_getdstifaddr(struct mbuf *m)
{
struct m_tag *mtag;
mtag = ip6_findaux(m);
if (mtag)
return ((struct ip6aux *)(mtag + 1))->ip6a_dstia6;
if (mtag != NULL)
return (struct ip6aux *)(mtag + 1);
else
return NULL;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip6_var.h,v 1.45 2007/07/19 20:48:57 dyoung Exp $ */
/* $NetBSD: ip6_var.h,v 1.46 2007/10/29 16:54:43 dyoung Exp $ */
/* $KAME: ip6_var.h,v 1.33 2000/06/11 14:59:20 jinmei Exp $ */
/*
@ -248,7 +248,9 @@ struct ip6flow {
*/
struct ip6aux {
/* ip6.ip6_dst */
struct in6_ifaddr *ip6a_dstia6; /* my ifaddr that matches ip6_dst */
struct in6_addr ip6a_src;
uint32_t ip6a_scope_id;
int ip6a_flags;
};
/* flags passed to ip6_output as last parameter */
@ -314,7 +316,7 @@ int icmp6_ctloutput(int, struct socket *, int, int, struct mbuf **);
void ip6_init(void);
void ip6intr(void);
void ip6_input(struct mbuf *);
struct in6_ifaddr *ip6_getdstifaddr(struct mbuf *);
const struct ip6aux *ip6_getdstifaddr(struct mbuf *);
void ip6_freepcbopts(struct ip6_pktopts *);
void ip6_freemoptions(struct ip6_moptions *);
int ip6_unknown_opt(u_int8_t *, struct mbuf *, int);

View File

@ -1,4 +1,4 @@
/* $NetBSD: route6.c,v 1.20 2007/05/23 17:15:04 christos Exp $ */
/* $NetBSD: route6.c,v 1.21 2007/10/29 16:54:43 dyoung Exp $ */
/* $KAME: route6.c,v 1.22 2000/12/03 00:54:00 itojun Exp $ */
/*
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: route6.c,v 1.20 2007/05/23 17:15:04 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: route6.c,v 1.21 2007/10/29 16:54:43 dyoung Exp $");
#include <sys/param.h>
#include <sys/mbuf.h>
@ -133,7 +133,7 @@ ip6_rthdr0(struct mbuf *m, struct ip6_hdr *ip6,
{
int addrs, index;
struct in6_addr *nextaddr, tmpaddr;
struct in6_ifaddr *ifa;
const struct ip6aux *ip6a;
if (rh0->ip6r0_segleft == 0)
return (0);
@ -190,9 +190,9 @@ ip6_rthdr0(struct mbuf *m, struct ip6_hdr *ip6,
* of the current hop. [RFC4007, Section 9]
* Then disambiguate the scope zone for the next hop (if necessary).
*/
if ((ifa = ip6_getdstifaddr(m)) == NULL)
if ((ip6a = ip6_getdstifaddr(m)) == NULL)
goto bad;
if (in6_setscope(nextaddr, ifa->ia_ifp, NULL) != 0) {
if (in6_setzoneid(nextaddr, ip6a->ip6a_scope_id) != 0) {
ip6stat.ip6s_badscope++;
goto bad;
}