diff options
author | Jun-ichiro itojun Hagino <itojun@cvs.openbsd.org> | 2004-02-10 20:20:02 +0000 |
---|---|---|
committer | Jun-ichiro itojun Hagino <itojun@cvs.openbsd.org> | 2004-02-10 20:20:02 +0000 |
commit | acc96c29c62035d38bea930d9f6669be56064bdd (patch) | |
tree | c0e770f443b9b17cb622102ac6468aa461c5d362 | |
parent | 059f45599ccaca843e9879cc92e16655bec5ff62 (diff) |
plug mbuf leak (ip_fragment() always free mbuf on error). tested by cedric,
dhartmei ok
-rw-r--r-- | sys/net/if_bridge.c | 6 | ||||
-rw-r--r-- | sys/net/pf.c | 6 | ||||
-rw-r--r-- | sys/netinet/ip_output.c | 44 |
3 files changed, 45 insertions, 11 deletions
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c index 4488fea6da0..f2798157ea2 100644 --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_bridge.c,v 1.130 2004/02/02 19:56:23 cedric Exp $ */ +/* $OpenBSD: if_bridge.c,v 1.131 2004/02/10 20:20:01 itojun Exp $ */ /* * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net) @@ -2577,8 +2577,10 @@ bridge_fragment(struct bridge_softc *sc, struct ifnet *ifp, } error = ip_fragment(m, ifp, ifp->if_mtu); - if (error) + if (error) { + m = NULL; goto dropit; + } for (; m; m = m0) { m0 = m->m_nextpkt; diff --git a/sys/net/pf.c b/sys/net/pf.c index 4d2ab09b455..2ff09f04c04 100644 --- a/sys/net/pf.c +++ b/sys/net/pf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf.c,v 1.422 2004/02/10 18:49:10 henning Exp $ */ +/* $OpenBSD: pf.c,v 1.423 2004/02/10 20:20:01 itojun Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -5006,8 +5006,10 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, m1 = m0; error = ip_fragment(m0, ifp, ifp->if_mtu); - if (error) + if (error) { + m0 = NULL; goto bad; + } for (m0 = m1; m0; m0 = m1) { m1 = m0->m_nextpkt; diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index 5a8680e8d0b..9cc42341943 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_output.c,v 1.159 2003/11/06 16:57:41 dhartmei Exp $ */ +/* $OpenBSD: ip_output.c,v 1.160 2004/02/10 20:20:01 itojun Exp $ */ /* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */ /* @@ -717,8 +717,10 @@ sendit: } error = ip_fragment(m, ifp, mtu); - if (error) + if (error) { + m = m0 = NULL; goto bad; + } for (; m; m = m0) { m0 = m->m_nextpkt; @@ -739,7 +741,7 @@ done: return (error); bad: #ifdef IPSEC - if (error == EMSGSIZE && ip_mtudisc && icmp_mtu != 0) + if (error == EMSGSIZE && ip_mtudisc && icmp_mtu != 0 && m != NULL) ipsec_adjust_mtu(m, icmp_mtu); #endif m_freem(m0); @@ -754,13 +756,18 @@ ip_fragment(struct mbuf *m, struct ifnet *ifp, u_long mtu) int len, hlen, off; int mhlen, firstlen; struct mbuf **mnext; + int fragments = 0; + int s; + int error = 0; ip = mtod(m, struct ip *); hlen = ip->ip_hl << 2; len = (mtu - hlen) &~ 7; - if (len < 8) + if (len < 8) { + m_freem(m); return (EMSGSIZE); + } /* * If we are doing fragmentation, we can't defer TCP/UDP @@ -784,7 +791,8 @@ ip_fragment(struct mbuf *m, struct ifnet *ifp, u_long mtu) MGETHDR(m, M_DONTWAIT, MT_HEADER); if (m == 0) { ipstat.ips_odropped++; - return (ENOBUFS); + error = ENOBUFS; + goto sendorfree; } *mnext = m; mnext = &m->m_nextpkt; @@ -810,7 +818,8 @@ ip_fragment(struct mbuf *m, struct ifnet *ifp, u_long mtu) m->m_next = m_copy(m0, off, len); if (m->m_next == 0) { ipstat.ips_odropped++; - return (ENOBUFS); /* ??? */ + error = ENOBUFS; + goto sendorfree; } m->m_pkthdr.len = mhlen + len; m->m_pkthdr.rcvif = (struct ifnet *)0; @@ -824,6 +833,7 @@ ip_fragment(struct mbuf *m, struct ifnet *ifp, u_long mtu) mhip->ip_sum = in_cksum(m, mhlen); } ipstat.ips_ofragments++; + fragments++; } /* * Update first fragment by trimming what's been copied out @@ -842,8 +852,28 @@ ip_fragment(struct mbuf *m, struct ifnet *ifp, u_long mtu) ip->ip_sum = 0; ip->ip_sum = in_cksum(m, hlen); } +sendorfree: + /* + * If there is no room for all the fragments, don't queue + * any of them. + */ + s = splnet(); + if (ifp->if_snd.ifq_maxlen - ifp->if_snd.ifq_len < fragments && + error == 0) { + error = ENOBUFS; + ipstat.ips_odropped++; + IFQ_INC_DROPS(&ifp->if_snd); + } + splx(s); + if (error) { + for (m = m0; m; m = m0) { + m0 = m->m_nextpkt; + m->m_nextpkt = NULL; + m_freem(m); + } + } - return (0); + return (error); } /* |