aboutsummaryrefslogtreecommitdiffstats
path: root/epan/tvbuff.c
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2018-04-19 20:18:10 -0700
committerGuy Harris <guy@alum.mit.edu>2018-04-20 03:18:47 +0000
commit0a130c5756eda79cbb55f1d38824fbaf9d1abc68 (patch)
treefb3188f1965219c227e82fb5fcb7cc5307a5e1fc /epan/tvbuff.c
parent9011a25afc598bfb5d46be92b2ef112cd1b17594 (diff)
Handle subset tvbuffs where the length goes past the end of the parent.
Add a "contained length" to tvbuffs. For non-subset tvbuffs, that's the same as the reported length. For a subset tvbuff, that's the amount of the reported data that was actually present in the "contained data" of the parent tvbuff. This is unaffected by the *captured* length of any tvbuff; that differs from the contained length only if the capture was cut short by a snapshot length. If a reference is within the reported data, but not within the contained data, a ContainedBoundsError exception is thrown. This exception represents a protocol error, rather than a reference past the captured data in the packet; we treat it as such. Change-Id: Ide87f81238eaeb89b3093f54a87bf7f715485af5 Reviewed-on: https://code.wireshark.org/review/27039 Reviewed-by: Guy Harris <guy@alum.mit.edu>
Diffstat (limited to 'epan/tvbuff.c')
-rw-r--r--epan/tvbuff.c179
1 files changed, 123 insertions, 56 deletions
diff --git a/epan/tvbuff.c b/epan/tvbuff.c
index 68e550d383..d890f34aac 100644
--- a/epan/tvbuff.c
+++ b/epan/tvbuff.c
@@ -74,15 +74,16 @@ tvb_new(const struct tvb_ops *ops)
tvb = (tvbuff_t *) g_slice_alloc(size);
- tvb->next = NULL;
- tvb->ops = ops;
- tvb->initialized = FALSE;
- tvb->flags = 0;
- tvb->length = 0;
- tvb->reported_length = 0;
- tvb->real_data = NULL;
- tvb->raw_offset = -1;
- tvb->ds_tvb = NULL;
+ tvb->next = NULL;
+ tvb->ops = ops;
+ tvb->initialized = FALSE;
+ tvb->flags = 0;
+ tvb->length = 0;
+ tvb->reported_length = 0;
+ tvb->contained_length = 0;
+ tvb->real_data = NULL;
+ tvb->raw_offset = -1;
+ tvb->ds_tvb = NULL;
return tvb;
}
@@ -160,14 +161,72 @@ tvb_add_to_chain(tvbuff_t *parent, tvbuff_t *child)
static inline int
validate_offset(const tvbuff_t *tvb, const guint abs_offset)
{
- if (G_LIKELY(abs_offset <= tvb->length))
+ if (G_LIKELY(abs_offset <= tvb->length)) {
+ /* It's OK. */
return 0;
- else if (abs_offset <= tvb->reported_length)
+ }
+
+ /*
+ * It's not OK, but why? Which boundaries is it
+ * past?
+ */
+ if (abs_offset <= tvb->contained_length) {
+ /*
+ * It's past the captured length, but not past
+ * the reported end of any parent tvbuffs from
+ * which this is constructed, or the reported
+ * end of this tvbuff, so it's out of bounds
+ * solely because we're past the end of the
+ * captured data.
+ */
return BoundsError;
- else if (tvb->flags & TVBUFF_FRAGMENT)
+ }
+
+ /*
+ * There's some actual packet boundary, not just the
+ * artificial boundary imposed by packet slicing, that
+ * we're past.
+ */
+ if (abs_offset <= tvb->reported_length) {
+ /*
+ * We're within the bounds of what this tvbuff
+ * purportedly contains, based on some length
+ * value, but we're not within the bounds of
+ * something from which this tvbuff was
+ * extracted, so that length value ran past
+ * the end of some parent tvbuff.
+ */
+ return ContainedBoundsError;
+ }
+
+ /*
+ * OK, we're past the bounds of what this tvbuff
+ * purportedly contains.
+ */
+ if (tvb->flags & TVBUFF_FRAGMENT) {
+ /*
+ * This tvbuff is the first fragment of a larger
+ * packet that hasn't been reassembled, so we
+ * assume that's the source of the prblem - if
+ * we'd reassembled the packet, we wouldn't
+ * have gone past the end.
+ *
+ * That might not be true, but for at least
+ * some forms of reassembly, such as IP
+ * reassembly, you don't know how big the
+ * reassembled packet is unless you reassemble
+ * it, so, in those cases, we can't determine
+ * whether we would have gone past the end
+ * had we reassembled the packet.
+ */
return FragmentBoundsError;
- else
- return ReportedBoundsError;
+ }
+
+ /*
+ * OK, it looks as if we ran past the claimed length
+ * of data.
+ */
+ return ReportedBoundsError;
}
static inline int
@@ -175,10 +234,12 @@ compute_offset(const tvbuff_t *tvb, const gint offset, guint *offset_ptr)
{
if (offset >= 0) {
/* Positive offset - relative to the beginning of the packet. */
- if ((guint) offset <= tvb->length) {
+ if (G_LIKELY((guint) offset <= tvb->length)) {
*offset_ptr = offset;
- } else if ((guint) offset <= tvb->reported_length) {
+ } else if ((guint) offset <= tvb->contained_length) {
return BoundsError;
+ } else if ((guint) offset <= tvb->reported_length) {
+ return ContainedBoundsError;
} else if (tvb->flags & TVBUFF_FRAGMENT) {
return FragmentBoundsError;
} else {
@@ -187,10 +248,12 @@ compute_offset(const tvbuff_t *tvb, const gint offset, guint *offset_ptr)
}
else {
/* Negative offset - relative to the end of the packet. */
- if ((guint) -offset <= tvb->length) {
+ if (G_LIKELY((guint) -offset <= tvb->length)) {
*offset_ptr = tvb->length + offset;
- } else if ((guint) -offset <= tvb->reported_length) {
+ } else if ((guint) -offset <= tvb->contained_length) {
return BoundsError;
+ } else if ((guint) -offset <= tvb->reported_length) {
+ return ContainedBoundsError;
} else if (tvb->flags & TVBUFF_FRAGMENT) {
return FragmentBoundsError;
} else {
@@ -216,8 +279,11 @@ compute_offset_and_remaining(const tvbuff_t *tvb, const gint offset, guint *offs
/* Computes the absolute offset and length based on a possibly-negative offset
* and a length that is possible -1 (which means "to the end of the data").
* Returns integer indicating whether the offset is in bounds (0) or
- * not (exception number). The integer ptrs are modified with the new offset and length.
- * No exception is thrown.
+ * not (exception number). The integer ptrs are modified with the new offset,
+ * captured (available) length, and contained length (amount that's present
+ * in the parent tvbuff based on its reported length).
+ * No exception is thrown; on success, we return 0, otherwise we return an
+ * exception for the caller to throw if appropriate.
*
* XXX - we return success (0), if the offset is positive and right
* after the end of the tvbuff (i.e., equal to the length). We do this
@@ -460,14 +526,15 @@ tvb_ensure_captured_length_remaining(const tvbuff_t *tvb, const gint offset)
* There aren't any bytes available, so throw the appropriate
* exception.
*/
- if (abs_offset >= tvb->reported_length) {
- if (tvb->flags & TVBUFF_FRAGMENT) {
- THROW(FragmentBoundsError);
- } else {
- THROW(ReportedBoundsError);
- }
- } else
+ if (abs_offset < tvb->contained_length) {
THROW(BoundsError);
+ } else if (abs_offset < tvb->reported_length) {
+ THROW(ContainedBoundsError);
+ } else if (tvb->flags & TVBUFF_FRAGMENT) {
+ THROW(FragmentBoundsError);
+ } else {
+ THROW(ReportedBoundsError);
+ }
}
return rem_length;
}
@@ -540,10 +607,12 @@ tvb_ensure_bytes_exist(const tvbuff_t *tvb, const gint offset, const gint length
if (offset >= 0) {
/* Positive offset - relative to the beginning of the packet. */
- if ((guint) offset <= tvb->length) {
+ if (G_LIKELY((guint) offset <= tvb->length)) {
real_offset = offset;
- } else if ((guint) offset <= tvb->reported_length) {
+ } else if ((guint) offset <= tvb->contained_length) {
THROW(BoundsError);
+ } else if ((guint) offset <= tvb->reported_length) {
+ THROW(ContainedBoundsError);
} else if (tvb->flags & TVBUFF_FRAGMENT) {
THROW(FragmentBoundsError);
} else {
@@ -552,10 +621,12 @@ tvb_ensure_bytes_exist(const tvbuff_t *tvb, const gint offset, const gint length
}
else {
/* Negative offset - relative to the end of the packet. */
- if ((guint) -offset <= tvb->length) {
+ if (G_LIKELY((guint) -offset <= tvb->length)) {
real_offset = tvb->length + offset;
- } else if ((guint) -offset <= tvb->reported_length) {
+ } else if ((guint) -offset <= tvb->contained_length) {
THROW(BoundsError);
+ } else if ((guint) -offset <= tvb->reported_length) {
+ THROW(ContainedBoundsError);
} else if (tvb->flags & TVBUFF_FRAGMENT) {
THROW(FragmentBoundsError);
} else {
@@ -576,8 +647,10 @@ tvb_ensure_bytes_exist(const tvbuff_t *tvb, const gint offset, const gint length
if (G_LIKELY(end_offset <= tvb->length))
return;
- else if (end_offset <= tvb->reported_length)
+ else if (end_offset <= tvb->contained_length)
THROW(BoundsError);
+ else if (end_offset <= tvb->reported_length)
+ THROW(ContainedBoundsError);
else if (tvb->flags & TVBUFF_FRAGMENT)
THROW(FragmentBoundsError);
else
@@ -637,7 +710,7 @@ tvb_reported_length_remaining(const tvbuff_t *tvb, const gint offset)
* whose headers contain an explicit length and where the calling
* dissector's payload may include padding as well as the packet for
* this protocol.
- * Also adjusts the data length. */
+ * Also adjusts the available and contained length. */
void
tvb_set_reported_length(tvbuff_t *tvb, const guint reported_length)
{
@@ -649,6 +722,8 @@ tvb_set_reported_length(tvbuff_t *tvb, const guint reported_length)
tvb->reported_length = reported_length;
if (reported_length < tvb->length)
tvb->length = reported_length;
+ if (reported_length < tvb->contained_length)
+ tvb->contained_length = reported_length;
}
guint
@@ -725,19 +800,17 @@ fast_ensure_contiguous(tvbuff_t *tvb, const gint offset, const guint length)
u_offset = offset;
end_offset = u_offset + length;
- if (end_offset <= tvb->length) {
+ if (G_LIKELY(end_offset <= tvb->length)) {
return tvb->real_data + u_offset;
+ } else if (end_offset <= tvb->contained_length) {
+ THROW(BoundsError);
+ } else if (end_offset <= tvb->reported_length) {
+ THROW(ContainedBoundsError);
+ } else if (tvb->flags & TVBUFF_FRAGMENT) {
+ THROW(FragmentBoundsError);
+ } else {
+ THROW(ReportedBoundsError);
}
-
- if (end_offset > tvb->reported_length) {
- if (tvb->flags & TVBUFF_FRAGMENT) {
- THROW(FragmentBoundsError);
- } else {
- THROW(ReportedBoundsError);
- }
- /* not reached */
- }
- THROW(BoundsError);
/* not reached */
return NULL;
}
@@ -2130,21 +2203,15 @@ tvb_strsize(tvbuff_t *tvb, const gint offset)
/*
* OK, we hit the end of the tvbuff, so we should throw
* an exception.
- *
- * Did we hit the end of the captured data, or the end
- * of the actual data? If there's less captured data
- * than actual data, we presumably hit the end of the
- * captured data, otherwise we hit the end of the actual
- * data.
*/
- if (tvb->length < tvb->reported_length) {
+ if (tvb->length < tvb->contained_length) {
THROW(BoundsError);
+ } else if (tvb->length < tvb->reported_length) {
+ THROW(ContainedBoundsError);
+ } else if (tvb->flags & TVBUFF_FRAGMENT) {
+ THROW(FragmentBoundsError);
} else {
- if (tvb->flags & TVBUFF_FRAGMENT) {
- THROW(FragmentBoundsError);
- } else {
- THROW(ReportedBoundsError);
- }
+ THROW(ReportedBoundsError);
}
}
return (nul_offset - abs_offset) + 1;