diff options
author | Jun-ichiro itojun Hagino <itojun@cvs.openbsd.org> | 2001-02-14 17:04:35 +0000 |
---|---|---|
committer | Jun-ichiro itojun Hagino <itojun@cvs.openbsd.org> | 2001-02-14 17:04:35 +0000 |
commit | 146aaca1e9e7e36d07238d7ae71096ed0add2016 (patch) | |
tree | 0483402e77e5c500f51f1410ec912e513fbafadf /sys/kern | |
parent | 53195031cd73d83cb0a0183780f9151305fe18db (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.c | 110 |
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; +} |