diff options
author | Guy Harris <guy@alum.mit.edu> | 2013-04-18 19:22:24 +0000 |
---|---|---|
committer | Guy Harris <guy@alum.mit.edu> | 2013-04-18 19:22:24 +0000 |
commit | c0c15029ed8d1234c95a71fdf7510a8bf0964fcb (patch) | |
tree | 585d3be4be77a93eb5fed23814d87ced468e9df9 /epan/tvbuff.c | |
parent | d89d6c8314b8a5c407f86fe0f6e029b4da582b43 (diff) |
Add to tvbuffs a "fragment length" field; if the tvbuff represents the
first fragment of a non-reassembled packet, and we know the length the
packet would have if it were reassembled, this field holds the length of
the fragment, and the "reported length" field shows the length the
packet would have if it were reassembled, so going past the end of the
fragment but staying within the length of the reassembled packet can be
reported as "dissection would have worked if the packet had been
reassembled" rather than "the packet is too short, so it was probably
malformed".
Add a FragmentBoundsError exception, thrown in the "dissection would
have worked if the packet had been reassembled" case.
Add a new tvb_new_subset_length_fragment() routine to create a new
subset tvb with specified fragment and reported lengths. Use it in the
CLNP dissector.
Add some more sanity checks in the CLNP dissector.
svn path=/trunk/; revision=48917
Diffstat (limited to 'epan/tvbuff.c')
-rw-r--r-- | epan/tvbuff.c | 115 |
1 files changed, 99 insertions, 16 deletions
diff --git a/epan/tvbuff.c b/epan/tvbuff.c index 2f292a6ed1..37c14bbc60 100644 --- a/epan/tvbuff.c +++ b/epan/tvbuff.c @@ -74,6 +74,7 @@ tvb_init(tvbuff_t *tvb, const tvbuff_type type) tvb->initialized = FALSE; tvb->length = 0; tvb->reported_length = 0; + tvb->fragment_length = 0; tvb->free_cb = NULL; tvb->real_data = NULL; tvb->raw_offset = -1; @@ -226,6 +227,7 @@ tvb_new_real_data(const guint8* data, const guint length, const gint reported_le tvb->real_data = data; tvb->length = length; tvb->reported_length = reported_length; + tvb->fragment_length = reported_length; tvb->initialized = TRUE; /* @@ -277,6 +279,12 @@ compute_offset_length(const tvbuff_t *tvb, } return FALSE; } + else if ((guint) offset > tvb->fragment_length) { + if (exception) { + *exception = FragmentBoundsError; + } + return FALSE; + } else if ((guint) offset > tvb->length) { if (exception) { *exception = BoundsError; @@ -295,6 +303,12 @@ compute_offset_length(const tvbuff_t *tvb, } return FALSE; } + else if ((guint) -offset > tvb->fragment_length) { + if (exception) { + *exception = FragmentBoundsError; + } + return FALSE; + } else if ((guint) -offset > tvb->length) { if (exception) { *exception = BoundsError; @@ -359,11 +373,17 @@ check_offset_length_no_exception(const tvbuff_t *tvb, if (end_offset <= tvb->length) { return TRUE; } - else if (end_offset <= tvb->reported_length) { + else if (end_offset <= tvb->fragment_length) { if (exception) { *exception = BoundsError; } } + else if (end_offset <= tvb->reported_length) { + if (exception) { + *exception = FragmentBoundsError; + } + return FALSE; + } else { if (exception) { *exception = ReportedBoundsError; @@ -391,8 +411,9 @@ check_offset_length(const tvbuff_t *tvb, } static tvbuff_t * -tvb_new_with_subset(tvbuff_t *backing, const gint reported_length, - const guint subset_tvb_offset, const guint subset_tvb_length) +tvb_new_with_subset(tvbuff_t *backing, const gint fragment_length, + const gint reported_length, const guint subset_tvb_offset, + const guint subset_tvb_length) { tvbuff_t *tvb = tvb_new(TVBUFF_SUBSET); @@ -403,11 +424,14 @@ tvb_new_with_subset(tvbuff_t *backing, const gint reported_length, tvb->length = tvb->tvbuffs.subset.length; if (reported_length == -1) { + tvb->fragment_length = backing->fragment_length - tvb->tvbuffs.subset.offset; tvb->reported_length = backing->reported_length - tvb->tvbuffs.subset.offset; } else { + tvb->fragment_length = fragment_length; tvb->reported_length = reported_length; } + tvb->initialized = TRUE; add_to_chain(backing, tvb); @@ -435,7 +459,7 @@ tvb_new_subset(tvbuff_t *backing, const gint backing_offset, const gint backing_ &subset_tvb_offset, &subset_tvb_length); - tvb = tvb_new_with_subset(backing, reported_length, + tvb = tvb_new_with_subset(backing, reported_length, reported_length, subset_tvb_offset, subset_tvb_length); /* @@ -471,7 +495,46 @@ tvb_new_subset_length(tvbuff_t *backing, const gint backing_offset, const gint b &subset_tvb_offset, &subset_tvb_length); - tvb = tvb_new_with_subset(backing, backing_length, + tvb = tvb_new_with_subset(backing, backing_length, backing_length, + subset_tvb_offset, subset_tvb_length); + + /* + * The top-level data source of this tvbuff is the top-level + * data source of its parent. + */ + tvb->ds_tvb = backing->ds_tvb; + + return tvb; +} + +tvbuff_t * +tvb_new_subset_length_fragment(tvbuff_t *backing, const gint backing_offset, + const gint fragment_length, const gint reported_length) +{ + gint captured_length; + tvbuff_t *tvb; + guint subset_tvb_offset; + guint subset_tvb_length; + + DISSECTOR_ASSERT(backing && backing->initialized); + + THROW_ON(fragment_length < 0, ReportedBoundsError); + THROW_ON(reported_length < 0, ReportedBoundsError); + THROW_ON(reported_length < fragment_length, ReportedBoundsError); + + /* + * Give the next dissector only captured_length bytes. + */ + captured_length = tvb_length_remaining(backing, backing_offset); + THROW_ON(captured_length < 0, BoundsError); + if (captured_length > fragment_length) + captured_length = fragment_length; + + check_offset_length(backing, backing_offset, captured_length, + &subset_tvb_offset, + &subset_tvb_length); + + tvb = tvb_new_with_subset(backing, fragment_length, reported_length, subset_tvb_offset, subset_tvb_length); /* @@ -494,8 +557,8 @@ tvb_new_subset_remaining(tvbuff_t *backing, const gint backing_offset) &subset_tvb_offset, &subset_tvb_length); - tvb = tvb_new_with_subset(backing, -1 /* reported_length */, - subset_tvb_offset, subset_tvb_length); + tvb = tvb_new_with_subset(backing, -1 /* fragment_length */, + -1 /* reported_length */, subset_tvb_offset, subset_tvb_length); /* * The top-level data source of this tvbuff is the top-level @@ -634,6 +697,7 @@ tvb_composite_finalize(tvbuff_t *tvb) DISSECTOR_ASSERT(tvb && !tvb->initialized); DISSECTOR_ASSERT(tvb->type == TVBUFF_COMPOSITE); DISSECTOR_ASSERT(tvb->length == 0); + DISSECTOR_ASSERT(tvb->fragment_length == 0); DISSECTOR_ASSERT(tvb->reported_length == 0); composite = &tvb->tvbuffs.composite; @@ -653,6 +717,7 @@ tvb_composite_finalize(tvbuff_t *tvb) member_tvb = (tvbuff_t *)slist->data; composite->start_offsets[i] = tvb->length; tvb->length += member_tvb->length; + tvb->fragment_length += member_tvb->fragment_length; tvb->reported_length += member_tvb->reported_length; composite->end_offsets[i] = tvb->length - 1; i++; @@ -705,6 +770,8 @@ tvb_ensure_length_remaining(const tvbuff_t *tvb, const gint offset) */ if (abs_offset >= tvb->reported_length) THROW(ReportedBoundsError); + else if (abs_offset >= tvb->fragment_length) + THROW(FragmentBoundsError); else THROW(BoundsError); } @@ -805,8 +872,10 @@ tvb_reported_length_remaining(const tvbuff_t *tvb, const gint offset) /* Set the reported length of a tvbuff to a given value; used for protocols * 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. */ + * this protocol, or where a packet may be a fragment of a larger packet + * and the length of the larger packet is known. + * + * Also adjusts the data length and fragment length. */ void tvb_set_reported_length(tvbuff_t *tvb, const guint reported_length) { @@ -818,6 +887,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->fragment_length) + tvb->fragment_length = reported_length; } @@ -984,6 +1055,9 @@ fast_ensure_contiguous(tvbuff_t *tvb, const gint offset, const guint length) if (end_offset > tvb->reported_length) { THROW(ReportedBoundsError); } + if (end_offset > tvb->fragment_length) { + THROW(FragmentBoundsError); + } THROW(BoundsError); /* not reached */ return NULL; @@ -2017,15 +2091,24 @@ 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. + * Did we hit the end of the captured data, the end of + * the fragment data, or the end of the actual data? + * + * If there's less captured data than fragment data, + * we presumably hit the end of the captured data. + * + * Otherwise, if there's less fragment data than actual + * data, we presumably hit the end of the fragment data. + * + * Otherwise we hit the end of the actual data. */ - if (tvb_length(tvb) < tvb_reported_length(tvb)) { + if (tvb->length < tvb->fragment_length) { THROW(BoundsError); - } else { + } + else if (tvb->fragment_length < tvb->reported_length) { + THROW(FragmentBoundsError); + } + else { THROW(ReportedBoundsError); } } |