summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>2004-02-10 20:20:02 +0000
committerJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>2004-02-10 20:20:02 +0000
commitacc96c29c62035d38bea930d9f6669be56064bdd (patch)
treec0e770f443b9b17cb622102ac6468aa461c5d362
parent059f45599ccaca843e9879cc92e16655bec5ff62 (diff)
plug mbuf leak (ip_fragment() always free mbuf on error). tested by cedric,
dhartmei ok
-rw-r--r--sys/net/if_bridge.c6
-rw-r--r--sys/net/pf.c6
-rw-r--r--sys/netinet/ip_output.c44
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);
}
/*