diff options
Diffstat (limited to 'epan/reassemble.c')
-rw-r--r-- | epan/reassemble.c | 81 |
1 files changed, 47 insertions, 34 deletions
diff --git a/epan/reassemble.c b/epan/reassemble.c index 54e20b10db..3fb07a6d9d 100644 --- a/epan/reassemble.c +++ b/epan/reassemble.c @@ -544,7 +544,7 @@ fragment_set_tot_len(const packet_info *pinfo, const guint32 id, GHashTable *fra while (fd) { if (fd->offset > max_offset) { max_offset = fd->offset; - DISSECTOR_ASSERT(max_offset <= tot_len); + THROW_MESSAGE_ON(max_offset > tot_len, ReassemblyError, "Bad total reassembly block count"); } fd = fd->next; } @@ -553,14 +553,14 @@ fragment_set_tot_len(const packet_info *pinfo, const guint32 id, GHashTable *fra while (fd) { if (fd->offset + fd->len > max_offset) { max_offset = fd->offset + fd->len; - DISSECTOR_ASSERT(max_offset <= tot_len); + THROW_MESSAGE_ON(max_offset > tot_len, ReassemblyError, "Bad total reassembly length"); } fd = fd->next; } } if (fd_head->flags & FD_DEFRAGMENTED) { - DISSECTOR_ASSERT(max_offset == tot_len); + THROW_MESSAGE_ON(max_offset != tot_len, ReassemblyError, "Defragmented complete but total length not satisfied"); } /* We got this far so the value is sane. */ @@ -715,37 +715,52 @@ fragment_add_work(fragment_data *fd_head, tvbuff_t *tvb, const int offset, fragment_data *fd_i; guint32 max, dfpos; unsigned char *old_data; + const char *error = NULL; /* create new fd describing this fragment */ fd = g_slice_new(fragment_data); fd->next = NULL; fd->flags = 0; fd->frame = pinfo->fd->num; - if (fd->frame > fd_head->frame) - fd_head->frame = fd->frame; fd->offset = frag_offset; fd->len = frag_data_len; fd->data = NULL; - /* - * If it was already defragmented and this new fragment goes beyond - * data limits, set flag in already empty fds & point old fds to malloc'ed data. - */ - if(fd_head->flags & FD_DEFRAGMENTED && (frag_offset+frag_data_len) >= fd_head->datalen && - fd_head->flags & FD_PARTIAL_REASSEMBLY){ - for(fd_i=fd_head->next; fd_i; fd_i=fd_i->next){ - if( !fd_i->data ) { - fd_i->data = fd_head->data + fd_i->offset; - fd_i->flags |= FD_NOT_MALLOCED; + /* If it was already defragmented and this new fragment goes beyond the + * old data limits... */ + if(fd_head->flags & FD_DEFRAGMENTED && (frag_offset+frag_data_len) >= fd_head->datalen) { + /* If we've been requested to continue reassembly, set flag in + * already empty fds & point old fds to malloc'ed data. */ + if (fd_head->flags & FD_PARTIAL_REASSEMBLY) { + for(fd_i=fd_head->next; fd_i; fd_i=fd_i->next){ + if( !fd_i->data ) { + fd_i->data = fd_head->data + fd_i->offset; + fd_i->flags |= FD_NOT_MALLOCED; + } + fd_i->flags &= (~FD_TOOLONGFRAGMENT) & (~FD_MULTIPLETAILS); } - fd_i->flags &= (~FD_TOOLONGFRAGMENT) & (~FD_MULTIPLETAILS); + fd_head->flags &= ~(FD_DEFRAGMENTED|FD_PARTIAL_REASSEMBLY|FD_DATALEN_SET); + fd_head->flags &= (~FD_TOOLONGFRAGMENT) & (~FD_MULTIPLETAILS); + fd_head->datalen=0; + fd_head->reassembled_in=0; + } + else { + /* Otherwise, bail out since we have no idea what to do + * with this fragment (and if we keep going we'll run + * past the end of a buffer sooner or later). + * + * XXX: Is ReportedBoundsError the right thing to throw? + */ + g_slice_free(fragment_data, fd); + THROW(ReportedBoundsError); } - fd_head->flags &= ~(FD_DEFRAGMENTED|FD_PARTIAL_REASSEMBLY|FD_DATALEN_SET); - fd_head->flags &= (~FD_TOOLONGFRAGMENT) & (~FD_MULTIPLETAILS); - fd_head->datalen=0; - fd_head->reassembled_in=0; } + /* Do this after we may have bailed out (above) so that we don't leave + * fd_head->frame in a bad state if we do */ + if (fd->frame > fd_head->frame) + fd_head->frame = fd->frame; + if (!more_frags) { /* * This is the tail fragment in the sequence. @@ -878,19 +893,13 @@ fragment_add_work(fragment_data *fd_head, tvbuff_t *tvb, const int offset, if ( fd_i->offset+fd_i->len > dfpos ) { if (fd_i->offset+fd_i->len > max) - g_warning("Reassemble error in frame %u: offset %u + len %u > max %u", - pinfo->fd->num, fd_i->offset, - fd_i->len, max); + error = "offset + len > max"; else if (dfpos < fd_i->offset) - g_warning("Reassemble error in frame %u: dfpos %u < offset %u", - pinfo->fd->num, dfpos, fd_i->offset); + error = "dfpos < offset"; else if (dfpos-fd_i->offset > fd_i->len) - g_warning("Reassemble error in frame %u: dfpos %u - offset %u > len %u", - pinfo->fd->num, dfpos, fd_i->offset, - fd_i->len); + error = "dfpos - offset > len"; else if (!fd_head->data) - g_warning("Reassemble error in frame %u: no data", - pinfo->fd->num); + error = "no data"; else { if (fd_i->offset < dfpos) { fd_i->flags |= FD_OVERLAP; @@ -908,10 +917,9 @@ fragment_add_work(fragment_data *fd_head, tvbuff_t *tvb, const int offset, fd_i->len-(dfpos-fd_i->offset)); } } else { - if (fd_i->offset + fd_i->len < fd_i->offset) /* Integer overflow? */ - g_warning("Reassemble error in frame %u: offset %u + len %u < offset", - pinfo->fd->num, fd_i->offset, - fd_i->len); + if (fd_i->offset + fd_i->len < fd_i->offset) { /* Integer overflow? */ + error = "offset + len < offset"; + } } if( fd_i->flags & FD_NOT_MALLOCED ) fd_i->flags &= ~FD_NOT_MALLOCED; @@ -929,6 +937,11 @@ fragment_add_work(fragment_data *fd_head, tvbuff_t *tvb, const int offset, fd_head->flags |= FD_DEFRAGMENTED; fd_head->reassembled_in=pinfo->fd->num; + /* we don't throw until here to avoid leaking old_data and others */ + if (error) { + THROW_MESSAGE(ReassemblyError, error); + } + return TRUE; } |