aboutsummaryrefslogtreecommitdiffstats
path: root/epan/reassemble.c
diff options
context:
space:
mode:
Diffstat (limited to 'epan/reassemble.c')
-rw-r--r--epan/reassemble.c81
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;
}