summaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
authorJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>2001-02-14 17:04:35 +0000
committerJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>2001-02-14 17:04:35 +0000
commit146aaca1e9e7e36d07238d7ae71096ed0add2016 (patch)
tree0483402e77e5c500f51f1410ec912e513fbafadf /sys/kern
parent53195031cd73d83cb0a0183780f9151305fe18db (diff)
make sure we do not pass shared M_EXT mbuf. will avoid
possible shared mbuf overwrite if we use bridge/multicast/loopback/whatever. sync with kame
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/uipc_mbuf2.c110
1 files changed, 63 insertions, 47 deletions
diff --git a/sys/kern/uipc_mbuf2.c b/sys/kern/uipc_mbuf2.c
index 3290b524e51..2725dc389bc 100644
--- a/sys/kern/uipc_mbuf2.c
+++ b/sys/kern/uipc_mbuf2.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: uipc_mbuf2.c,v 1.4 2000/07/12 16:41:30 itojun Exp $ */
-/* $KAME: uipc_mbuf2.c,v 1.15 2000/02/22 14:01:37 itojun Exp $ */
+/* $OpenBSD: uipc_mbuf2.c,v 1.5 2001/02/14 17:04:34 itojun Exp $ */
+/* $KAME: uipc_mbuf2.c,v 1.29 2001/02/14 13:42:10 itojun Exp $ */
/* $NetBSD: uipc_mbuf.c,v 1.40 1999/04/01 00:23:25 thorpej Exp $ */
/*
@@ -66,14 +66,19 @@
* @(#)uipc_mbuf.c 8.4 (Berkeley) 2/14/95
*/
-/*#define PULLDOWN_DEBUG*/
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
+#define M_SHAREDCLUSTER(m) \
+ (((m)->m_flags & M_EXT) != 0 && \
+ ((m)->m_ext.ext_free || mclrefcnt[mtocl((m)->m_ext.ext_buf)] > 1))
+
+/* can't call it m_dup(), as freebsd[34] uses m_dup() with different arg */
+static struct mbuf *m_dup1 __P((struct mbuf *, int, int, int));
+
/*
* ensure that [off, off + len) is contiguous on the mbuf chain "m".
* packet chain before "off" is kept untouched.
@@ -102,15 +107,6 @@ m_pulldown(m, off, len, offp)
return NULL; /* impossible */
}
-#ifdef PULLDOWN_DEBUG
- {
- struct mbuf *t;
- printf("before:");
- for (t = m; t; t = t->m_next)
- printf(" %d", t->m_len);
- printf("\n");
- }
-#endif
n = m;
while (n != NULL && off > 0) {
if (n->m_len > off)
@@ -126,21 +122,23 @@ m_pulldown(m, off, len, offp)
return NULL; /* mbuf chain too short */
}
+ sharedcluster = M_SHAREDCLUSTER(n);
+
/*
* the target data is on <n, off>.
* if we got enough data on the mbuf "n", we're done.
*/
- if ((off == 0 || offp) && len <= n->m_len - off)
+ if ((off == 0 || offp) && len <= n->m_len - off && !sharedcluster)
goto ok;
/*
- * when len < n->m_len - off and off != 0, it is a special case.
+ * when len <= n->m_len - off and off != 0, it is a special case.
* len bytes from <n, off> sits in single mbuf, but the caller does
* not like the starting position (off).
* chop the current mbuf into two pieces, set off to 0.
*/
- if (len < n->m_len - off) {
- o = m_copym(n, off, n->m_len - off, M_DONTWAIT);
+ if (len <= n->m_len - off) {
+ o = m_dup1(n, off, n->m_len - off, M_DONTWAIT);
if (o == NULL) {
m_freem(m);
return NULL; /* ENOBUFS */
@@ -177,25 +175,15 @@ m_pulldown(m, off, len, offp)
* easy cases first.
* we need to use m_copydata() to get data from <n->m_next, 0>.
*/
- if ((n->m_flags & M_EXT) == 0)
- sharedcluster = 0;
- else {
- if (n->m_ext.ext_free)
- sharedcluster = 1;
- else if (mclrefcnt[mtocl(n->m_ext.ext_buf)] > 1)
- sharedcluster = 1;
- else
- sharedcluster = 0;
- }
- if ((off == 0 || offp) && M_TRAILINGSPACE(n) >= tlen
- && !sharedcluster) {
+ if ((off == 0 || offp) && M_TRAILINGSPACE(n) >= tlen &&
+ !sharedcluster) {
m_copydata(n->m_next, 0, tlen, mtod(n, caddr_t) + n->m_len);
n->m_len += tlen;
m_adj(n->m_next, tlen);
goto ok;
}
- if ((off == 0 || offp) && M_LEADINGSPACE(n->m_next) >= hlen
- && !sharedcluster) {
+ if ((off == 0 || offp) && M_LEADINGSPACE(n->m_next) >= hlen &&
+ !sharedcluster) {
n->m_next->m_data -= hlen;
n->m_next->m_len += hlen;
bcopy(mtod(n, caddr_t) + off, mtod(n->m_next, caddr_t), hlen);
@@ -210,18 +198,17 @@ m_pulldown(m, off, len, offp)
* on both end.
*/
MGET(o, M_DONTWAIT, m->m_type);
- if (o == NULL) {
- m_freem(m);
- return NULL; /* ENOBUFS */
- }
- if (len > MHLEN) { /* use MHLEN just for safety */
+ if (o && len > MLEN) {
MCLGET(o, M_DONTWAIT);
if ((o->m_flags & M_EXT) == 0) {
- m_freem(m);
m_free(o);
- return NULL; /* ENOBUFS */
+ o = NULL;
}
}
+ if (!o) {
+ m_freem(m);
+ return NULL; /* ENOBUFS */
+ }
/* get hlen from <n, off> into <o, 0> */
o->m_len = hlen;
bcopy(mtod(n, caddr_t) + off, mtod(o, caddr_t), hlen);
@@ -236,16 +223,45 @@ m_pulldown(m, off, len, offp)
off = 0;
ok:
-#ifdef PULLDOWN_DEBUG
- {
- struct mbuf *t;
- printf("after:");
- for (t = m; t; t = t->m_next)
- printf("%c%d", t == n ? '*' : ' ', t->m_len);
- printf(" (off=%d)\n", off);
- }
-#endif
if (offp)
*offp = off;
return n;
}
+
+static struct mbuf *
+m_dup1(m, off, len, wait)
+ struct mbuf *m;
+ int off;
+ int len;
+ int wait;
+{
+ struct mbuf *n;
+ int l;
+ int copyhdr;
+
+ if (len > MCLBYTES)
+ return NULL;
+ if (off == 0 && (m->m_flags & M_PKTHDR) != 0) {
+ copyhdr = 1;
+ MGETHDR(n, wait, m->m_type);
+ l = MHLEN;
+ } else {
+ copyhdr = 0;
+ MGET(n, wait, m->m_type);
+ l = MLEN;
+ }
+ if (n && len > l) {
+ MCLGET(n, wait);
+ if ((n->m_flags & M_EXT) == 0) {
+ m_free(n);
+ n = NULL;
+ }
+ }
+ if (!n)
+ return NULL;
+
+ if (copyhdr)
+ M_COPY_PKTHDR(n, m);
+ m_copydata(m, off, len, mtod(n, caddr_t));
+ return n;
+}