From f0d76677a94522e3f6a89987792ab8355d342242 Mon Sep 17 00:00:00 2001
From: Gerald Combs <gerald@wireshark.org>
Date: Tue, 5 Mar 2013 23:17:26 +0000
Subject: [PATCH 6/7] Copy over revisions from the trunk:

  ------------------------------------------------------------------------
  r48010 | eapache | 2013-03-02 08:23:21 -0800 (Sat, 02 Mar 2013) | 4 lines
  Changed paths:
     M /trunk/epan/dissectors/packet-dtls.c

  Pass the same offset to tvb_ensure_bytes_exist and fragment_add.

  One minor part of https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=8380
  ------------------------------------------------------------------------

Copy over with manual intervention:

  ------------------------------------------------------------------------
  r48011 | eapache | 2013-03-02 08:39:56 -0800 (Sat, 02 Mar 2013) | 23 lines
  Changed paths:
     M /trunk/epan/exceptions.h
     M /trunk/epan/reassemble.c
     M /trunk/epan/show_exception.c

  Define a new exception for reassembly errors, and throw it in several cases
  instead of using DISSECTOR_ASSERT. When a dissector passes bad data to the
  reassembly machine, that isn't necessarily the dissector's fault - the data may
  come straight from the packet, and the dissector may not have enough information
  to know it's bad without telling the reassembly machine in the first place.

  Also fix a bug in the reassembly machine. If it were given a fragment and all of
  the following conditions were met:
  - the other associated fragments were already marked as done (reassembled)
  - the fragment went beyond the end of the conceptual reassembled buffer
  - the dissector had not set the PARTIAL_REASSEMBLY flag
  then the reassembly machine would incorrectly think there was an overlap and
  run past the end of the already-reassembled buffer.

  Should fix the rest of
  https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=8380

  #BACKPORT
  This is probably too big and intrusive to backport directly, and parts of it
  will need adapting anyways since reassemble.c has changed. But the bug exists
  and crashes in 1.6 and 1.8, so we'll have to do something.
  ------------------------------------------------------------------------

Update the release notes.

svn path=/trunk-1.6/; revision=48113

Copy over from trunk

------------------------------------------------------------------------
r48123 | eapache | 2013-03-05 19:39:35 -0500 (Tue, 05 Mar 2013) | 5 lines

Followup to r48011, answering my own XXX comment:

No, ReportedBoundsError is not the right thing to throw, ReassemblyError is.
That's why I added it in the first place!

------------------------------------------------------------------------

svn path=/trunk-1.8/; revision=48124
---
 epan/dissectors/packet-dtls.c |    4 +++
 epan/exceptions.h             |   24 ++++++++++++++++
 epan/reassemble.c             |   62 ++++++++++++++++++++++++++---------------
 3 files changed, 67 insertions(+), 23 deletions(-)

diff --git a/epan/dissectors/packet-dtls.c b/epan/dissectors/packet-dtls.c
index 599fc02..063cfc7 100644
--- a/epan/dissectors/packet-dtls.c
+++ b/epan/dissectors/packet-dtls.c
@@ -1041,6 +1041,10 @@ dissect_dtls_handshake(tvbuff_t *tvb, packet_info *pinfo,
 	  if (frag_hand) {
 	    /* Fragmented handshake message */
 	    pinfo->fragmented = TRUE;
+
+	    /* Don't pass the reassembly code data that doesn't exist */
+        tvb_ensure_bytes_exist(tvb, offset+12, fragment_length);
+
 	    frag_msg = fragment_add(tvb, offset+12, pinfo, message_seq,
 				    dtls_fragment_table,
 				    fragment_offset, fragment_length, TRUE);
diff --git a/epan/exceptions.h b/epan/exceptions.h
index 4e36559..d80eb75 100644
--- a/epan/exceptions.h
+++ b/epan/exceptions.h
@@ -75,6 +75,15 @@
 **/
 #define OutOfMemoryError	6
 
+/**
+    The reassembly state machine was passed a bad fragment offset,
+    or other similar issues. We used to use DissectorError in these
+    cases, but they're not necessarily the dissector's fault - if the packet
+    contains a bad fragment offset, the dissector shouldn't have to figure
+    that out by itself since that's what the reassembly machine is for.
+**/
+#define ReassemblyError         7
+
 
 /* Usage:
  *
@@ -210,6 +219,16 @@
 	    (except_state|=EXCEPT_CAUGHT))                                             \
 		/* user's code goes here */
 
+#define CATCH5(v,w,x,y,z) \
+	if (except_state == 0 && exc != 0 && \
+	    (exc->except_id.except_code == (v) || \
+	     exc->except_id.except_code == (w) || \
+	     exc->except_id.except_code == (x) || \
+	     exc->except_id.except_code == (y) || \
+	     exc->except_id.except_code == (z)) && \
+	    (except_state|=EXCEPT_CAUGHT)) \
+		/* user's code goes here */
+
 #define CATCH_ALL \
 	if (except_state == 0 && exc != 0 && \
 	    (except_state|=EXCEPT_CAUGHT))                                             \
@@ -231,6 +250,11 @@
 #define THROW_MESSAGE(x, y) \
 	except_throw(XCEPT_GROUP_WIRESHARK, (x), (y))
 
+#define THROW_MESSAGE_ON(cond, x, y) G_STMT_START { \
+	if ((cond)) \
+		except_throw(XCEPT_GROUP_WIRESHARK, (x), (y)); \
+} G_STMT_END
+
 #define GET_MESSAGE			except_message(exc)
 
 #define RETHROW                                     \
diff --git a/epan/reassemble.c b/epan/reassemble.c
index 113fa66..ac50955 100644
--- a/epan/reassemble.c
+++ b/epan/reassemble.c
@@ -521,7 +521,7 @@ fragment_set_tot_len(packet_info *pinfo, guint32 id, GHashTable *fragment_table,
 		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;
 		}
@@ -530,14 +530,14 @@ fragment_set_tot_len(packet_info *pinfo, guint32 id, GHashTable *fragment_table,
 		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. */
@@ -700,6 +700,7 @@ fragment_add_work(fragment_data *fd_head, tvbuff_t *tvb, int offset,
 	fragment_data *fd_i;
 	guint32 max, dfpos;
 	unsigned char *old_data;
+	const char *error = NULL;
 
 	/* create new fd describing this fragment */
 #if GLIB_CHECK_VERSION(2,10,0)
@@ -710,18 +711,16 @@ fragment_add_work(fragment_data *fd_head, tvbuff_t *tvb, int offset,
 	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){
+	/* 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;
@@ -734,6 +733,22 @@ fragment_add_work(fragment_data *fd_head, tvbuff_t *tvb, int offset,
 		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);
+		}
+	}
+
+	/* 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) {
 		/*
@@ -867,16 +882,13 @@ fragment_add_work(fragment_data *fd_head, tvbuff_t *tvb, 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)
+					error = "no data";
 				else {
 					if (fd_i->offset < dfpos) {
 						fd_i->flags    |= FD_OVERLAP;
@@ -894,10 +906,9 @@ fragment_add_work(fragment_data *fd_head, tvbuff_t *tvb, int offset,
 						fd_i->len-(dfpos-fd_i->offset));
 				}
 			} else {
-				if (fd_i->offset+fd_i->len < fd_i->offset)
-					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;
@@ -915,6 +926,11 @@ fragment_add_work(fragment_data *fd_head, tvbuff_t *tvb, 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;
 }
 
-- 
1.7.10.4

