From: Jason Ish Date: Tue, 17 Sep 2019 10:08:15 +0000 (+0200) Subject: defrag: check minimum size of reassembled packet X-Git-Tag: suricata-5.0.0-rc1~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c8b49aee56b9ae10e0aa8a5bf2b4a49b386ad942;p=thirdparty%2Fsuricata.git defrag: check minimum size of reassembled packet Before re-assembling, check that the first fragment is large enough to contain the IPv4 or IPv6 header to prevent an out of bounds read (IPv4) or write (IPv6). Reported-by: Sirko Höer -- Code Intelligence for DCSO. Bug #3171. --- diff --git a/src/defrag.c b/src/defrag.c index 95c12422fe..d388438385 100644 --- a/src/defrag.c +++ b/src/defrag.c @@ -260,11 +260,23 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) return NULL; } + /* Check that we have the first fragment and its of a valid size. */ + Frag *first = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree); + if (first == NULL) { + goto done; + } else if (first->offset != 0) { + /* Still waiting for the first fragment. */ + goto done; + } else if (first->len < sizeof(IPV4Hdr)) { + /* First fragment isn't enough for an IPv6 header. */ + goto error_remove_tracker; + } + /* Check that we have all the data. Relies on the fact that * fragments are inserted if frag_offset order. */ Frag *frag = NULL; - int len = 0; - RB_FOREACH(frag, IP_FRAGMENTS, &tracker->fragment_tree) { + size_t len = 0; + RB_FOREACH_FROM(frag, IP_FRAGMENTS, first) { if (frag->offset > len) { /* This fragment starts after the end of the previous * fragment. We have a hole. */ @@ -374,10 +386,21 @@ Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) if (!tracker->seen_last) return NULL; + /* Check that we have the first fragment and its of a valid size. */ + Frag *first = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree); + if (first == NULL) { + goto done; + } else if (first->offset != 0) { + /* Still waiting for the first fragment. */ + goto done; + } else if (first->len < sizeof(IPV6Hdr)) { + /* First fragment isn't enough for an IPv6 header. */ + goto error_remove_tracker; + } + /* Check that we have all the data. Relies on the fact that * fragments are inserted if frag_offset order. */ - int len = 0; - Frag *first = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree); + size_t len = 0; Frag *frag = NULL; RB_FOREACH_FROM(frag, IP_FRAGMENTS, first) { if (frag->skip) {