Fix the memory leak reported in kern/36337. Thanks Matthias Scheler

for the heads-up.  My fix is based on the following patches from
FreeBSD, however, I extracted the code into a subroutine,
nd6_llinfo_release_pkts():

http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/netinet6/nd6.c.diff?r1=1.48.2.18;r2=1.48.2.19
http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/netinet6/nd6_nbr.c.diff?r1=1.29.2.8;r2=1.29.2.9
This commit is contained in:
dyoung 2007-05-17 00:53:26 +00:00
parent 50ab9d6934
commit 1db31a59af
3 changed files with 30 additions and 52 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: nd6.c,v 1.114 2007/05/02 20:40:27 dyoung Exp $ */
/* $NetBSD: nd6.c,v 1.115 2007/05/17 00:53:26 dyoung Exp $ */
/* $KAME: nd6.c,v 1.279 2002/06/08 11:16:51 itojun Exp $ */
/*
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.114 2007/05/02 20:40:27 dyoung Exp $");
__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.115 2007/05/17 00:53:26 dyoung Exp $");
#include "opt_ipsec.h"
@ -1584,6 +1584,27 @@ nd6_ioctl(u_long cmd, void *data, struct ifnet *ifp)
return error;
}
void
nd6_llinfo_release_pkts(struct llinfo_nd6 *ln, struct ifnet *ifp,
struct rtentry *rt)
{
struct mbuf *m_hold, *m_hold_next;
for (m_hold = ln->ln_hold, ln->ln_hold = NULL;
m_hold != NULL;
m_hold = m_hold_next) {
m_hold_next = m_hold->m_nextpkt;
m_hold->m_nextpkt = NULL;
/*
* we assume ifp is not a p2p here, so
* just set the 2nd argument as the
* 1st one.
*/
nd6_output(ifp, ifp, m_hold, satocsin6(rt_key(rt)), rt);
}
}
/*
* Create neighbor cache entry and cache link-layer address,
* on reception of inbound ND6 packets. (RS/RA/NS/redirect)
@ -1718,31 +1739,7 @@ fail:
*/
nd6_llinfo_settimer(ln, (long)nd6_gctimer * hz);
if (ln->ln_hold) {
struct mbuf *m_hold, *m_hold_next;
for (m_hold = ln->ln_hold; m_hold;
m_hold = m_hold_next) {
struct mbuf *mpkt = NULL;
m_hold_next = m_hold->m_nextpkt;
mpkt = m_copym(m_hold, 0, M_COPYALL, M_DONTWAIT);
if (mpkt == NULL) {
m_freem(m_hold);
break;
}
mpkt->m_nextpkt = NULL;
/*
* we assume ifp is not a p2p here, so
* just set the 2nd argument as the
* 1st one.
*/
nd6_output(ifp, ifp, mpkt,
(struct sockaddr_in6 *)rt_key(rt),
rt);
}
ln->ln_hold = NULL;
}
nd6_llinfo_release_pkts(ln, ifp, rt);
} else if (ln->ln_state == ND6_LLINFO_INCOMPLETE) {
/* probe right away */
nd6_llinfo_settimer((void *)ln, 0);

View File

@ -1,4 +1,4 @@
/* $NetBSD: nd6.h,v 1.46 2007/05/02 20:40:28 dyoung Exp $ */
/* $NetBSD: nd6.h,v 1.47 2007/05/17 00:53:26 dyoung Exp $ */
/* $KAME: nd6.h,v 1.95 2002/06/08 11:31:06 itojun Exp $ */
/*
@ -402,6 +402,8 @@ int nd6_storelladdr(const struct ifnet *, const struct rtentry *, struct mbuf *,
const struct sockaddr *, uint8_t *, size_t);
int nd6_sysctl(int, void *, size_t *, void *, size_t);
int nd6_need_cache(struct ifnet *);
void nd6_llinfo_release_pkts(struct llinfo_nd6 *, struct ifnet *,
struct rtentry *);
/* nd6_nbr.c */
void nd6_na_input(struct mbuf *, int, int);

View File

@ -1,4 +1,4 @@
/* $NetBSD: nd6_nbr.c,v 1.73 2007/05/02 20:40:28 dyoung Exp $ */
/* $NetBSD: nd6_nbr.c,v 1.74 2007/05/17 00:53:26 dyoung Exp $ */
/* $KAME: nd6_nbr.c,v 1.61 2001/02/10 16:06:14 jinmei Exp $ */
/*
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v 1.73 2007/05/02 20:40:28 dyoung Exp $");
__KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v 1.74 2007/05/17 00:53:26 dyoung Exp $");
#include "opt_inet.h"
#include "opt_ipsec.h"
@ -806,28 +806,7 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
}
rt->rt_flags &= ~RTF_REJECT;
ln->ln_asked = 0;
if (ln->ln_hold) {
struct mbuf *m_hold, *m_hold_next;
for (m_hold = ln->ln_hold; m_hold; m_hold = m_hold_next) {
struct mbuf *mpkt = NULL;
m_hold_next = m_hold->m_nextpkt;
mpkt = m_copym(m_hold, 0, M_COPYALL, M_DONTWAIT);
if (mpkt == NULL) {
m_freem(m_hold);
break;
}
mpkt->m_nextpkt = NULL;
/*
* we assume ifp is not a loopback here, so just set
* the 2nd argument as the 1st one.
*/
nd6_output(ifp, ifp, mpkt,
(struct sockaddr_in6 *)rt_key(rt), rt);
}
ln->ln_hold = NULL;
}
nd6_llinfo_release_pkts(ln, ifp, rt);
freeit:
m_freem(m);