summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2014-01-21 10:18:27 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2014-01-21 10:18:27 +0000
commitafabf447e8168a34694f0eca272e80e7fc416c39 (patch)
treeb6d289ad055b7220f002e24aa0db83837cc1354d
parent492bb95e09ccd5e49a21417ea42f9dd979a37939 (diff)
Do not clean the multicast records of an interface when it is destroyed
(unplugged). Even if it makes no sense to keep them around if the interface is no more, we cannot safely remove them since pcb multicast options might keep a pointer to them. Fixes a user after free introduced by the multicast address linking rewrite and reported by Alexey Suslikov, thanks! ok claudio@
-rw-r--r--sys/net/if_var.h4
-rw-r--r--sys/netinet/igmp.c25
-rw-r--r--sys/netinet/in.c35
-rw-r--r--sys/netinet/in_var.h4
-rw-r--r--sys/netinet/ip_output.c8
-rw-r--r--sys/netinet6/in6.c27
-rw-r--r--sys/netinet6/in6_ifattach.c12
-rw-r--r--sys/netinet6/in6_var.h4
-rw-r--r--sys/netinet6/ip6_output.c7
-rw-r--r--sys/netinet6/mld6.c16
10 files changed, 70 insertions, 72 deletions
diff --git a/sys/net/if_var.h b/sys/net/if_var.h
index c2e95ad3b38..27403cfc6da 100644
--- a/sys/net/if_var.h
+++ b/sys/net/if_var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_var.h,v 1.3 2013/11/28 11:05:18 mpi Exp $ */
+/* $OpenBSD: if_var.h,v 1.4 2014/01/21 10:18:26 mpi Exp $ */
/* $NetBSD: if.h,v 1.23 1996/05/07 02:40:27 thorpej Exp $ */
/*
@@ -310,7 +310,7 @@ struct ifaddr_item {
*/
struct ifmaddr {
struct sockaddr *ifma_addr; /* Protocol address */
- struct ifnet *ifma_ifp; /* Back pointer to ifnet */
+ unsigned short ifma_ifidx; /* Index of the interface */
unsigned int ifma_refcnt; /* Count of references */
TAILQ_ENTRY(ifmaddr) ifma_list; /* Per-interface list */
};
diff --git a/sys/netinet/igmp.c b/sys/netinet/igmp.c
index 51fbb15fc38..2babdd30dfd 100644
--- a/sys/netinet/igmp.c
+++ b/sys/netinet/igmp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: igmp.c,v 1.36 2013/11/28 10:16:44 mpi Exp $ */
+/* $OpenBSD: igmp.c,v 1.37 2014/01/21 10:18:26 mpi Exp $ */
/* $NetBSD: igmp.c,v 1.15 1996/02/13 23:41:25 christos Exp $ */
/*
@@ -128,7 +128,7 @@ rti_fill(struct in_multi *inm)
struct router_info *rti;
for (rti = rti_head; rti != 0; rti = rti->rti_next) {
- if (rti->rti_ifp == inm->inm_ifp) {
+ if (rti->rti_ifp->if_index == inm->inm_ifidx) {
inm->inm_rti = rti;
if (rti->rti_type == IGMP_v1_ROUTER)
return (IGMP_v1_HOST_MEMBERSHIP_REPORT);
@@ -141,7 +141,7 @@ rti_fill(struct in_multi *inm)
M_MRTABLE, M_NOWAIT);
if (rti == NULL)
return (-1);
- rti->rti_ifp = inm->inm_ifp;
+ rti->rti_ifp = if_get(inm->inm_ifidx);
rti->rti_type = IGMP_v2_ROUTER;
rti->rti_next = rti_head;
rti_head = rti;
@@ -462,13 +462,16 @@ igmp_input(struct mbuf *m, ...)
void
igmp_joingroup(struct in_multi *inm)
{
- int i, s = splsoftnet();
+ struct ifnet* ifp;
+ int i, s;
+
+ ifp = if_get(inm->inm_ifidx);
+ s = splsoftnet();
inm->inm_state = IGMP_IDLE_MEMBER;
if (!IN_LOCAL_GROUP(inm->inm_addr.s_addr) &&
- inm->inm_ifp &&
- (inm->inm_ifp->if_flags & IFF_LOOPBACK) == 0) {
+ ifp && (ifp->if_flags & IFF_LOOPBACK) == 0) {
if ((i = rti_fill(inm)) == -1) {
splx(s);
return;
@@ -486,15 +489,17 @@ igmp_joingroup(struct in_multi *inm)
void
igmp_leavegroup(struct in_multi *inm)
{
+ struct ifnet* ifp;
+ int s;
- int s = splsoftnet();
+ ifp = if_get(inm->inm_ifidx);
+ s = splsoftnet();
switch (inm->inm_state) {
case IGMP_DELAYING_MEMBER:
case IGMP_IDLE_MEMBER:
if (!IN_LOCAL_GROUP(inm->inm_addr.s_addr) &&
- inm->inm_ifp &&
- (inm->inm_ifp->if_flags & IFF_LOOPBACK) == 0)
+ ifp && (ifp->if_flags & IFF_LOOPBACK) == 0)
if (inm->inm_rti->rti_type != IGMP_v1_ROUTER)
igmp_sendpkt(inm, IGMP_HOST_LEAVE_MESSAGE,
INADDR_ALLROUTERS_GROUP);
@@ -616,7 +621,7 @@ igmp_sendpkt(struct in_multi *inm, int type, in_addr_t addr)
m->m_data -= sizeof(struct ip);
m->m_len += sizeof(struct ip);
- imo.imo_multicast_ifp = inm->inm_ifp;
+ imo.imo_multicast_ifp = if_get(inm->inm_ifidx);
imo.imo_multicast_ttl = 1;
/*
diff --git a/sys/netinet/in.c b/sys/netinet/in.c
index a12b241d27a..d552303747d 100644
--- a/sys/netinet/in.c
+++ b/sys/netinet/in.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: in.c,v 1.90 2013/12/31 03:24:44 tedu Exp $ */
+/* $OpenBSD: in.c,v 1.91 2014/01/21 10:18:26 mpi Exp $ */
/* $NetBSD: in.c,v 1.26 1996/02/13 23:41:39 christos Exp $ */
/*
@@ -949,7 +949,7 @@ in_addmulti(struct in_addr *ap, struct ifnet *ifp)
inm->inm_sin.sin_family = AF_INET;
inm->inm_sin.sin_addr = *ap;
inm->inm_refcnt = 1;
- inm->inm_ifp = ifp;
+ inm->inm_ifidx = ifp->if_index;
inm->inm_ifma.ifma_addr = sintosa(&inm->inm_sin);
/*
@@ -992,20 +992,24 @@ in_delmulti(struct in_multi *inm)
* we are leaving the multicast group.
*/
igmp_leavegroup(inm);
- ifp = inm->inm_ifp;
+ ifp = if_get(inm->inm_ifidx);
/*
* Notify the network driver to update its multicast
* reception filter.
*/
- satosin(&ifr.ifr_addr)->sin_len = sizeof(struct sockaddr_in);
- satosin(&ifr.ifr_addr)->sin_family = AF_INET;
- satosin(&ifr.ifr_addr)->sin_addr = inm->inm_addr;
- (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
-
- s = splsoftnet();
- TAILQ_REMOVE(&ifp->if_maddrlist, &inm->inm_ifma, ifma_list);
- splx(s);
+ if (ifp != NULL) {
+ satosin(&ifr.ifr_addr)->sin_len =
+ sizeof(struct sockaddr_in);
+ satosin(&ifr.ifr_addr)->sin_family = AF_INET;
+ satosin(&ifr.ifr_addr)->sin_addr = inm->inm_addr;
+ (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
+
+ s = splsoftnet();
+ TAILQ_REMOVE(&ifp->if_maddrlist, &inm->inm_ifma,
+ ifma_list);
+ splx(s);
+ }
free(inm, M_IPMADDR);
}
@@ -1017,7 +1021,6 @@ void
in_ifdetach(struct ifnet *ifp)
{
struct ifaddr *ifa, *next;
- struct ifmaddr *ifma, *mnext;
/* nuke any of IPv4 addresses we have */
TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrlist, ifa_list, next) {
@@ -1025,12 +1028,4 @@ in_ifdetach(struct ifnet *ifp)
continue;
in_purgeaddr(ifa);
}
-
- TAILQ_FOREACH_SAFE(ifma, &ifp->if_maddrlist, ifma_list, mnext) {
- if (ifma->ifma_addr->sa_family != AF_INET)
- continue;
-
- ifma->ifma_refcnt = 1;
- in_delmulti(ifmatoinm(ifma));
- }
}
diff --git a/sys/netinet/in_var.h b/sys/netinet/in_var.h
index 91a233a1bab..a3c388fe3e1 100644
--- a/sys/netinet/in_var.h
+++ b/sys/netinet/in_var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: in_var.h,v 1.32 2014/01/13 09:48:12 mpi Exp $ */
+/* $OpenBSD: in_var.h,v 1.33 2014/01/21 10:18:26 mpi Exp $ */
/* $NetBSD: in_var.h,v 1.16 1996/02/13 23:42:15 christos Exp $ */
/*
@@ -115,7 +115,7 @@ struct router_info {
struct in_multi {
struct ifmaddr inm_ifma; /* Protocol-independent info */
#define inm_refcnt inm_ifma.ifma_refcnt
-#define inm_ifp inm_ifma.ifma_ifp
+#define inm_ifidx inm_ifma.ifma_ifidx
struct sockaddr_in inm_sin; /* IPv4 multicast address */
#define inm_addr inm_sin.sin_addr
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index 1c1c0b534a7..ffd49ec9ba5 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_output.c,v 1.254 2014/01/09 06:29:06 tedu Exp $ */
+/* $OpenBSD: ip_output.c,v 1.255 2014/01/21 10:18:26 mpi Exp $ */
/* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */
/*
@@ -1833,7 +1833,8 @@ ip_setmoptions(int optname, struct ip_moptions **imop, struct mbuf *m,
* membership slots are full.
*/
for (i = 0; i < imo->imo_num_memberships; ++i) {
- if (imo->imo_membership[i]->inm_ifp == ifp &&
+ if (imo->imo_membership[i]->inm_ifidx
+ == ifp->if_index &&
imo->imo_membership[i]->inm_addr.s_addr
== mreq->imr_multiaddr.s_addr)
break;
@@ -1916,7 +1917,8 @@ ip_setmoptions(int optname, struct ip_moptions **imop, struct mbuf *m,
*/
for (i = 0; i < imo->imo_num_memberships; ++i) {
if ((ifp == NULL ||
- imo->imo_membership[i]->inm_ifp == ifp) &&
+ imo->imo_membership[i]->inm_ifidx ==
+ ifp->if_index) &&
imo->imo_membership[i]->inm_addr.s_addr ==
mreq->imr_multiaddr.s_addr)
break;
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index 2a4976c74fd..d4a60b432df 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: in6.c,v 1.129 2014/01/15 09:25:38 mpi Exp $ */
+/* $OpenBSD: in6.c,v 1.130 2014/01/21 10:18:26 mpi Exp $ */
/* $KAME: in6.c,v 1.372 2004/06/14 08:14:21 itojun Exp $ */
/*
@@ -1592,7 +1592,7 @@ in6_addmulti(struct in6_addr *maddr6, struct ifnet *ifp, int *errorp)
in6m->in6m_sin.sin6_family = AF_INET6;
in6m->in6m_sin.sin6_addr = *maddr6;
in6m->in6m_refcnt = 1;
- in6m->in6m_ifp = ifp;
+ in6m->in6m_ifidx = ifp->if_index;
in6m->in6m_ifma.ifma_addr = sin6tosa(&in6m->in6m_sin);
/*
@@ -1637,21 +1637,24 @@ in6_delmulti(struct in6_multi *in6m)
* that we are leaving the multicast group.
*/
mld6_stop_listening(in6m);
- ifp = in6m->in6m_ifp;
+ ifp = if_get(in6m->in6m_ifidx);
/*
* Notify the network driver to update its multicast
* reception filter.
*/
- bzero(&ifr.ifr_addr, sizeof(struct sockaddr_in6));
- ifr.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
- ifr.ifr_addr.sin6_family = AF_INET6;
- ifr.ifr_addr.sin6_addr = in6m->in6m_addr;
- (*ifp->if_ioctl)(in6m->in6m_ifp, SIOCDELMULTI, (caddr_t)&ifr);
-
- s = splsoftnet();
- TAILQ_REMOVE(&ifp->if_maddrlist, &in6m->in6m_ifma, ifma_list);
- splx(s);
+ if (ifp != NULL) {
+ bzero(&ifr.ifr_addr, sizeof(struct sockaddr_in6));
+ ifr.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
+ ifr.ifr_addr.sin6_family = AF_INET6;
+ ifr.ifr_addr.sin6_addr = in6m->in6m_addr;
+ (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
+
+ s = splsoftnet();
+ TAILQ_REMOVE(&ifp->if_maddrlist, &in6m->in6m_ifma,
+ ifma_list);
+ splx(s);
+ }
free(in6m, M_IPMADDR);
}
diff --git a/sys/netinet6/in6_ifattach.c b/sys/netinet6/in6_ifattach.c
index 567caa0b219..f1757337b6f 100644
--- a/sys/netinet6/in6_ifattach.c
+++ b/sys/netinet6/in6_ifattach.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: in6_ifattach.c,v 1.67 2014/01/13 23:03:52 bluhm Exp $ */
+/* $OpenBSD: in6_ifattach.c,v 1.68 2014/01/21 10:18:26 mpi Exp $ */
/* $KAME: in6_ifattach.c,v 1.124 2001/07/18 08:32:51 jinmei Exp $ */
/*
@@ -646,7 +646,6 @@ void
in6_ifdetach(struct ifnet *ifp)
{
struct ifaddr *ifa, *next;
- struct ifmaddr *ifma, *mnext;
struct rtentry *rt;
struct sockaddr_in6 sin6;
@@ -665,15 +664,6 @@ in6_ifdetach(struct ifnet *ifp)
in6_purgeaddr(ifa);
}
-
- TAILQ_FOREACH_SAFE(ifma, &ifp->if_maddrlist, ifma_list, mnext) {
- if (ifma->ifma_addr->sa_family != AF_INET6)
- continue;
-
- ifma->ifma_refcnt = 1;
- in6_delmulti(ifmatoin6m(ifma));
- }
-
/*
* remove neighbor management table. we call it twice just to make
* sure we nuke everything. maybe we need just one call.
diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h
index 4b504494a20..56eef418e44 100644
--- a/sys/netinet6/in6_var.h
+++ b/sys/netinet6/in6_var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: in6_var.h,v 1.46 2013/11/28 10:16:44 mpi Exp $ */
+/* $OpenBSD: in6_var.h,v 1.47 2014/01/21 10:18:26 mpi Exp $ */
/* $KAME: in6_var.h,v 1.55 2001/02/16 12:49:45 itojun Exp $ */
/*
@@ -467,7 +467,7 @@ struct in6_multi_mship {
struct in6_multi {
struct ifmaddr in6m_ifma; /* Protocol-independent info */
#define in6m_refcnt in6m_ifma.ifma_refcnt
-#define in6m_ifp in6m_ifma.ifma_ifp
+#define in6m_ifidx in6m_ifma.ifma_ifidx
struct sockaddr_in6 in6m_sin; /* IPv6 multicast address */
#define in6m_addr in6m_sin.sin6_addr
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
index b2f11f617fb..f547e635db8 100644
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip6_output.c,v 1.149 2014/01/13 23:03:52 bluhm Exp $ */
+/* $OpenBSD: ip6_output.c,v 1.150 2014/01/21 10:18:26 mpi Exp $ */
/* $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $ */
/*
@@ -2514,7 +2514,7 @@ ip6_setmoptions(int optname, struct ip6_moptions **im6op, struct mbuf *m)
* See if the membership already exists.
*/
LIST_FOREACH(imm, &im6o->im6o_memberships, i6mm_chain)
- if (imm->i6mm_maddr->in6m_ifp == ifp &&
+ if (imm->i6mm_maddr->in6m_ifidx == ifp->if_index &&
IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr,
&mreq->ipv6mr_multiaddr))
break;
@@ -2578,7 +2578,8 @@ ip6_setmoptions(int optname, struct ip6_moptions **im6op, struct mbuf *m)
* Find the membership in the membership list.
*/
LIST_FOREACH(imm, &im6o->im6o_memberships, i6mm_chain) {
- if ((ifp == NULL || imm->i6mm_maddr->in6m_ifp == ifp) &&
+ if ((ifp == NULL ||
+ imm->i6mm_maddr->in6m_ifidx == ifp->if_index) &&
IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr,
&mreq->ipv6mr_multiaddr))
break;
diff --git a/sys/netinet6/mld6.c b/sys/netinet6/mld6.c
index 95648c14080..d0058336823 100644
--- a/sys/netinet6/mld6.c
+++ b/sys/netinet6/mld6.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mld6.c,v 1.35 2014/01/13 23:03:52 bluhm Exp $ */
+/* $OpenBSD: mld6.c,v 1.36 2014/01/21 10:18:26 mpi Exp $ */
/* $KAME: mld6.c,v 1.26 2001/02/16 14:50:35 itojun Exp $ */
/*
@@ -127,8 +127,7 @@ mld6_start_listening(struct in6_multi *in6m)
* MLD messages are never sent for multicast addresses whose scope is 0
* (reserved) or 1 (node-local).
*/
- mld_all_nodes_linklocal.s6_addr16[1] =
- htons(in6m->in6m_ifp->if_index); /* XXX */
+ mld_all_nodes_linklocal.s6_addr16[1] = htons(in6m->in6m_ifidx);/* XXX */
if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &mld_all_nodes_linklocal) ||
__IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) < __IPV6_ADDR_SCOPE_LINKLOCAL) {
in6m->in6m_timer = 0;
@@ -149,10 +148,9 @@ mld6_stop_listening(struct in6_multi *in6m)
{
int s = splsoftnet();
- mld_all_nodes_linklocal.s6_addr16[1] =
- htons(in6m->in6m_ifp->if_index); /* XXX */
+ mld_all_nodes_linklocal.s6_addr16[1] = htons(in6m->in6m_ifidx);/* XXX */
mld_all_routers_linklocal.s6_addr16[1] =
- htons(in6m->in6m_ifp->if_index); /* XXX: necessary when mrouting */
+ htons(in6m->in6m_ifidx); /* XXX: necessary when mrouting */
if (in6m->in6m_state == MLD_IREPORTEDLAST &&
(!IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &mld_all_nodes_linklocal)) &&
@@ -374,9 +372,13 @@ mld6_sendpkt(struct in6_multi *in6m, int type, const struct in6_addr *dst)
struct ip6_hdr *ip6;
struct ip6_moptions im6o;
struct in6_ifaddr *ia6;
- struct ifnet *ifp = in6m->in6m_ifp;
+ struct ifnet *ifp;
int ignflags;
+ ifp = if_get(in6m->in6m_ifidx);
+ if (ifp == NULL)
+ return;
+
/*
* At first, find a link local address on the outgoing interface
* to use as the source address of the MLD packet.