diff options
author | Mike Belopuhov <mikeb@cvs.openbsd.org> | 2011-10-21 15:45:56 +0000 |
---|---|---|
committer | Mike Belopuhov <mikeb@cvs.openbsd.org> | 2011-10-21 15:45:56 +0000 |
commit | ab52f437470f82127e4526429af1c0289187b834 (patch) | |
tree | 8e17279ae32d6f5b3a452a19e6ebdddb69d1fd9e /sys/net | |
parent | 41aaaeaecbb5e1b5703dd28e705b539385627016 (diff) |
strengthen some checks to prevent m_copy* routines from operating
on mbuf chains of insufficient length; prevents crashes seen by
dhill. also bring in some chunks omitted in the nat64 commit and
are essential for correct packet interpretation.
tested by dhill and me, ok henning
Diffstat (limited to 'sys/net')
-rw-r--r-- | sys/net/if_pflog.c | 38 |
1 files changed, 29 insertions, 9 deletions
diff --git a/sys/net/if_pflog.c b/sys/net/if_pflog.c index f8ae8be545d..3ea408aa6d4 100644 --- a/sys/net/if_pflog.c +++ b/sys/net/if_pflog.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_pflog.c,v 1.44 2011/10/13 18:23:39 claudio Exp $ */ +/* $OpenBSD: if_pflog.c,v 1.45 2011/10/21 15:45:55 mikeb Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), * Angelos D. Keromytis (kermit@csd.uch.gr) and @@ -296,6 +296,7 @@ pflog_bpfcopy(const void *src_arg, void *dst_arg, size_t len) struct pf_pdesc pd; struct pf_addr osaddr, odaddr; u_int16_t osport = 0, odport = 0; + u_int8_t proto = 0; m = (struct mbuf *)src_arg; dst = dst_arg; @@ -340,33 +341,46 @@ pflog_bpfcopy(const void *src_arg, void *dst_arg, size_t len) case AF_INET: { struct ip *h; + if (m->m_pkthdr.len < sizeof(*h)) + return; m_copydata(m, 0, sizeof(*h), mdst); h = (struct ip *)mdst; hlen = h->ip_hl << 2; - if (hlen > sizeof(*h)) + if (hlen > sizeof(*h) && (m->m_pkthdr.len >= hlen)) m_copydata(m, sizeof(*h), hlen - sizeof(*h), mdst + sizeof(*h)); break; } case AF_INET6: { + struct ip6_hdr *h; + + if (m->m_pkthdr.len < sizeof(*h)) + return; hlen = sizeof(struct ip6_hdr); m_copydata(m, 0, hlen, mdst); + h = (struct ip6_hdr *)mdst; + proto = h->ip6_nxt; break; } default: /* shouldn't happen ever :-) */ - m_copydata(m, 0, len, dst); + m_copydata(m, 0, min(len, m->m_pkthdr.len), dst); return; } - /* copy 8 bytes of the protocol header */ - m_copydata(m, hlen, 8, mdst + hlen); + if (m->m_pkthdr.len < hlen + 8 && proto != IPPROTO_NONE) + return; + else if (proto != IPPROTO_NONE) { + /* copy 8 bytes of the protocol header */ + m_copydata(m, hlen, 8, mdst + hlen); + hlen += 8; + } - mhdr->m_len += hlen + 8; + mhdr->m_len += hlen; mhdr->m_pkthdr.len = mhdr->m_len; - /* create a chain mhdr -> mptr, mptr->m_data = (m->m_data+hlen+8) */ - mp = m_getptr(m, hlen + 8, &off); + /* create a chain mhdr -> mptr, mptr->m_data = (m->m_data+hlen) */ + mp = m_getptr(m, hlen, &off); if (mp != NULL) { bcopy(mp, mptr, sizeof(*mptr)); cp = mtod(mp, char *); @@ -374,7 +388,7 @@ pflog_bpfcopy(const void *src_arg, void *dst_arg, size_t len) mptr->m_len -= off; mptr->m_flags &= ~M_PKTHDR; mhdr->m_next = mptr; - mhdr->m_pkthdr.len += m->m_pkthdr.len - (hlen + 8); + mhdr->m_pkthdr.len += m->m_pkthdr.len - hlen; } /* rewrite addresses if needed */ @@ -405,9 +419,15 @@ pflog_bpfcopy(const void *src_arg, void *dst_arg, size_t len) pfloghdr->dport = odport; } + pd.tot_len = min(pd.tot_len, len); + pd.tot_len -= pd.m->m_data - pd.m->m_pktdat; + if (afto) pf_translate_af(&pd); mlen = min(pd.m->m_pkthdr.len, len); m_copydata(pd.m, 0, mlen, dst); + len -= mlen; + if (len > 0) + bzero(dst + mlen, len); } |