DF-0741 / fix.diff
diff --git a/sys/netinet/ip_gre.c b/sys/netinet/ip_gre.c --- a/sys/netinet/ip_gre.c +++ b/sys/netinet/ip_gre.c @@ -234,6 +234,22 @@ return(IPPROTO_DONE); } + /* + * The mobile header is variable-length and is overlaid on the + * head mbuf right after the outer IP header. The bcopy below + * slides the (post-mobile-header) payload over the mobile header, + * so the head mbuf must hold at least ip_hl*4 + msiz bytes. + * Without this check, m->m_len - msiz - (ip->ip_hl << 2) under- + * flows (signed int) and is widened to size_t for bcopy(), causing + * a near-2^64 over-read/over-write and an immediate kernel panic + * (DF-0741). Drop short / chained-mbuf packets that don't carry + * the full mobile header in the head mbuf. + */ + if (m->m_len < (ip->ip_hl << 2) + msiz) { + m_freem(m); + return(IPPROTO_DONE); + } + bcopy((caddr_t)(ip) + (ip->ip_hl << 2) + msiz, (caddr_t)(ip) + (ip->ip_hl << 2), m->m_len - msiz - (ip->ip_hl << 2)); m->m_len -= msiz; |