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>
This commit is contained in:
Guy Harris 2018-04-19 20:18:10 -07:00
parent 9011a25afc
commit 0a130c5756
12 changed files with 273 additions and 146 deletions

View File

@ -659,7 +659,7 @@ static const value_string scsi_disc_info_disc_type_val[] = {
};
static void
dissect_mmc4_readdiscinformation (tvbuff_t *tvb_a, packet_info *pinfo, proto_tree *tree,
dissect_mmc4_readdiscinformation (tvbuff_t *tvb_a, packet_info *pinfo _U_, proto_tree *tree,
guint offset_a, gboolean isreq, gboolean iscdb,
guint payload_len _U_, scsi_task_data_t *cdata)
{
@ -946,7 +946,7 @@ static const value_string scsi_rti_address_type_val[] = {
};
static void
dissect_mmc4_readtrackinformation (tvbuff_t *tvb_a, packet_info *pinfo, proto_tree *tree,
dissect_mmc4_readtrackinformation (tvbuff_t *tvb_a, packet_info *pinfo _U_, proto_tree *tree,
guint offset_a, gboolean isreq, gboolean iscdb,
guint payload_len _U_, scsi_task_data_t *cdata)

View File

@ -238,8 +238,8 @@ extern value_string_ext scsi_asc_val_ext;
* This is semi-common in SCSI and it would be wrong to mark these packets
* as [malformed packets].
* These macros will reset the reported length to what the data pdu specified
* and if a ReportedBoundsError is generated we will instead throw
* ScsiBoundsError
* and if a ContainedBoundsError or ReportedBoundsError is generated we will
* instead throw ScsiBoundsError
*
* Please see dissect_spc_inquiry() for an example how to use these
* macros.
@ -250,13 +250,11 @@ extern value_string_ext scsi_asc_val_ext;
#define TRY_SCSI_CDB_ALLOC_LEN(length_arg) \
{ \
volatile gboolean try_short_packet; \
tvbuff_t *try_tvb; \
volatile guint try_offset; \
guint32 try_end_data_offset=0; \
\
try_short_packet=pinfo->fd->cap_len<pinfo->fd->pkt_len; \
try_tvb=tvb_new_subset_length_caplen(tvb_a, offset_a, tvb_captured_length_remaining(tvb_a, offset_a), length_arg); \
try_tvb=tvb_new_subset_length(tvb_a, offset_a, length_arg); \
try_offset=0; \
TRY {
@ -269,29 +267,23 @@ extern value_string_ext scsi_asc_val_ext;
} \
} /* TRY */ \
CATCH(BoundsError) { \
if(try_short_packet){ \
/* this was a short packet */ \
RETHROW; \
} else { \
/* We probably tried to dissect beyond the end \
* of the alloc len reported in the data \
* pdu. This is not an error so don't flag it \
* as one \
* it is the alloc_len in the CDB that is the \
* important one \
*/ \
} \
/* this was a short packet */ \
RETHROW; \
} \
CATCH(ContainedBoundsError) { \
/* We probably tried to dissect beyond the end \
* of the alloc len reported in the data \
* pdu. This is not an error so don't flag it \
* as one \
* it is the alloc_len in the CDB that is the \
* important one \
*/ \
} \
CATCH(ReportedBoundsError) { \
if(try_short_packet){ \
/* this was a short packet */ \
RETHROW; \
} else { \
/* this packet was not really short but limited \
* due to a short SCSI allocation length \
*/ \
THROW(ScsiBoundsError); \
} \
/* this packet was not really short but limited \
* due to a short SCSI allocation length \
*/ \
THROW(ScsiBoundsError); \
} \
ENDTRY; \
}

View File

@ -86,12 +86,12 @@ static gint ett_nt_ace_object = -1;
static gint ett_nt_ace_object_flags = -1;
static gint ett_nt_security_information = -1;
static expert_field ei_nt_owner_sid_beyond_data = EI_INIT;
static expert_field ei_nt_owner_sid_beyond_reassembled_data = EI_INIT;
static expert_field ei_nt_ace_extends_beyond_data = EI_INIT;
static expert_field ei_nt_ace_extends_beyond_reassembled_data = EI_INIT;
static expert_field ei_nt_ace_extends_beyond_capture = EI_INIT;
static expert_field ei_nt_group_sid_beyond_data = EI_INIT;
static expert_field ei_nt_group_sid_beyond_reassembled_data = EI_INIT;
static expert_field ei_nt_group_sid_beyond_captured_data = EI_INIT;
static expert_field ei_nt_owner_sid_beyond_captured_data = EI_INIT;
static expert_field ei_nt_item_offs_out_of_range = EI_INIT;
@ -2189,8 +2189,8 @@ dissect_nt_acl(tvbuff_t *tvb, int offset_a, packet_info *pinfo,
}
}
CATCH(BoundsError) {
proto_tree_add_expert(tree, pinfo, &ei_nt_ace_extends_beyond_capture, tvb, offset_v, 0);
CATCH(ContainedBoundsError) {
proto_tree_add_expert(tree, pinfo, &ei_nt_ace_extends_beyond_data, tvb, offset_v, 0);
missing_data = TRUE;
}
@ -2430,8 +2430,8 @@ dissect_nt_sec_desc(tvbuff_t *tvb, int offset_a, packet_info *pinfo,
end_offset = offset_v;
}
CATCH(BoundsError) {
proto_tree_add_expert(tree, pinfo, &ei_nt_owner_sid_beyond_captured_data, tvb, item_offset, 0);
CATCH(ContainedBoundsError) {
proto_tree_add_expert(tree, pinfo, &ei_nt_owner_sid_beyond_data, tvb, item_offset, 0);
}
CATCH(ReportedBoundsError) {
@ -2455,8 +2455,8 @@ dissect_nt_sec_desc(tvbuff_t *tvb, int offset_a, packet_info *pinfo,
end_offset = offset_v;
}
CATCH(BoundsError) {
proto_tree_add_expert(tree, pinfo, &ei_nt_group_sid_beyond_captured_data, tvb, item_offset, 0);
CATCH(ContainedBoundsError) {
proto_tree_add_expert(tree, pinfo, &ei_nt_group_sid_beyond_data, tvb, item_offset, 0);
}
CATCH(ReportedBoundsError) {
@ -2888,11 +2888,11 @@ proto_do_register_windows_common(int proto_smb)
};
static ei_register_info ei[] = {
{ &ei_nt_ace_extends_beyond_capture, { "nt.ace_extends_beyond_capture", PI_MALFORMED, PI_ERROR, "ACE Extends beyond end of captured data", EXPFILL }},
{ &ei_nt_ace_extends_beyond_data, { "nt.ace_extends_beyond_data", PI_MALFORMED, PI_ERROR, "ACE Extends beyond end of data", EXPFILL }},
{ &ei_nt_ace_extends_beyond_reassembled_data, { "nt.ace_extends_beyond_reassembled_data", PI_MALFORMED, PI_ERROR, "ACE Extends beyond end of reassembled data", EXPFILL }},
{ &ei_nt_owner_sid_beyond_captured_data, { "nt.owner_sid.beyond_captured_data", PI_MALFORMED, PI_ERROR, "Owner SID beyond end of captured data", EXPFILL }},
{ &ei_nt_owner_sid_beyond_data, { "nt.owner_sid.beyond_data", PI_MALFORMED, PI_ERROR, "Owner SID beyond end of data", EXPFILL }},
{ &ei_nt_owner_sid_beyond_reassembled_data, { "nt.owner_sid.beyond_reassembled_data", PI_MALFORMED, PI_ERROR, "Owner SID beyond end of reassembled data", EXPFILL }},
{ &ei_nt_group_sid_beyond_captured_data, { "nt.group_sid.beyond_captured_data", PI_MALFORMED, PI_ERROR, "Group SID beyond end of captured data", EXPFILL }},
{ &ei_nt_group_sid_beyond_data, { "nt.group_sid.beyond_data", PI_MALFORMED, PI_ERROR, "Group SID beyond end of data", EXPFILL }},
{ &ei_nt_group_sid_beyond_reassembled_data, { "nt.group_sid.beyond_reassembled_data", PI_MALFORMED, PI_ERROR, "Group SID beyond end of reassembled data", EXPFILL }},
{ &ei_nt_item_offs_out_of_range, { "nt.item_offset.out_of_range", PI_MALFORMED, PI_ERROR, "Item offset is out of range", EXPFILL }},
};

View File

@ -17,8 +17,7 @@
#define XCEPT_GROUP_WIRESHARK 1
/**
Index is out of range.
An attempt was made to read past the end of a buffer.
Index is beyond the captured length of the tvbuff.
This generally means that the capture was done with a "slice"
length or "snapshot" length less than the maximum packet size,
and a link-layer packet was cut short by that, so not all of the
@ -27,28 +26,37 @@
#define BoundsError 1
/**
Index is beyond reported length (not cap_len)
An attempt was made to read past the logical end of a buffer. This
differs from a BoundsError in that the parent protocol established a
limit past which this dissector should not process in the buffer and that
limit was exceeded.
Index is beyond the contained length of the tvbuff.
This generally means that the tvbuff was constructed as
a subset of a parent tvbuff, based on a length specified
by data in the packet, but the length in question runs
past the reported length of the data in the parent tvbuff.
That means that the packet is invalid, as the data indicating
the length says the length exceeds what's contained in the
packet. It is therefore currently reported as a "Malformed
packet".
**/
#define ContainedBoundsError 2
/**
Index is beyond the reported length of the tvbuff.
This generally means that the packet is invalid, i.e. whatever
code constructed the packet and put it on the wire didn't put enough
data into it. It is therefore currently reported as a "Malformed
packet".
**/
#define ReportedBoundsError 2
#define ReportedBoundsError 3
/**
Index is beyond fragment length but not reported length.
Index is beyond the fragment length but not the reported length.
This means that the packet wasn't reassembled.
**/
#define FragmentBoundsError 3
#define FragmentBoundsError 4
/**
During dfilter parsing
**/
#define TypeError 4
#define TypeError 5
/**
A bug was detected in a dissector.
@ -59,7 +67,7 @@
Instead, use the DISSECTOR_ASSERT(), etc. macros in epan/proto.h.
**/
#define DissectorError 5
#define DissectorError 6
/**
Index is out of range.
@ -70,13 +78,13 @@
to get the "size" of lun list back after which the initiator will
reissue the command with an allocation_length that is big enough.
**/
#define ScsiBoundsError 6
#define ScsiBoundsError 7
/**
Running out of memory.
A dissector tried to allocate memory but that failed.
**/
#define OutOfMemoryError 7
#define OutOfMemoryError 8
/**
The reassembly state machine was passed a bad fragment offset,
@ -85,7 +93,7 @@
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 8
#define ReassemblyError 9
/*
* Catch errors that, if you're calling a subdissector and catching
@ -111,14 +119,14 @@
* separately.
*/
#define CATCH_NONFATAL_ERRORS \
CATCH3(ReportedBoundsError, ScsiBoundsError, ReassemblyError)
CATCH4(ReportedBoundsError, ContainedBoundsError, ScsiBoundsError, ReassemblyError)
/*
* Catch all bounds-checking errors.
*/
#define CATCH_BOUNDS_ERRORS \
CATCH4(BoundsError, FragmentBoundsError, ReportedBoundsError, \
ScsiBoundsError)
CATCH5(BoundsError, FragmentBoundsError, ReportedBoundsError, \
ContainedBoundsError, ScsiBoundsError)
/*
* Catch all bounds-checking errors, and catch dissector bugs.
@ -126,8 +134,9 @@
* go all the way to the top level and get reported immediately.
*/
#define CATCH_BOUNDS_AND_DISSECTOR_ERRORS \
CATCH6(BoundsError, FragmentBoundsError, ReportedBoundsError, \
ScsiBoundsError, DissectorError, ReassemblyError)
CATCH7(BoundsError, FragmentBoundsError, ContainedBoundsError, \
ReportedBoundsError, ScsiBoundsError, DissectorError, \
ReassemblyError)
/* Usage:
*
@ -159,6 +168,10 @@
* code;
* }
*
* CATCH7(exception1, exception2, exception3, exception4, exception5, exception6, exception7) {
* code;
* }
*
* CATCH_NONFATAL_ERRORS {
* code;
* }
@ -335,6 +348,18 @@
(except_state|=EXCEPT_CAUGHT)) \
/* user's code goes here */
#define CATCH7(t, u,v,w,x,y,z) \
if (except_state == 0 && exc != 0 && \
(exc->except_id.except_code == (t) || \
exc->except_id.except_code == (u) || \
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)) \

View File

@ -637,7 +637,7 @@ dissect_file(epan_dissect_t *edt, wtap_rec *rec,
CATCH(BoundsError) {
g_assert_not_reached();
}
CATCH2(FragmentBoundsError, ReportedBoundsError) {
CATCH3(FragmentBoundsError, ContainedBoundsError, ReportedBoundsError) {
proto_tree_add_protocol_format(edt->tree, proto_malformed, edt->tvb, 0, 0,
"[Malformed Record: Packet Length]");
}
@ -874,7 +874,7 @@ call_dissector_work_error(dissector_handle_t handle, tvbuff_t *tvb,
*/
RETHROW;
}
CATCH2(FragmentBoundsError, ReportedBoundsError) {
CATCH3(FragmentBoundsError, ContainedBoundsError, ReportedBoundsError) {
/*
* "ret" wasn't set because an exception was thrown
* before "call_dissector_through_handle()" returned.

View File

@ -114,6 +114,14 @@ show_exception(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
* (any case where it's caused by something else is a bug). */
break;
case ContainedBoundsError:
col_append_fstr(pinfo->cinfo, COL_INFO, "[Malformed Packet: length of contained item exceeds length of containing item]");
item = proto_tree_add_protocol_format(tree, proto_malformed,
tvb, 0, 0, "[Malformed Packet: length of contained item exceeds length of containing item: %s]",
pinfo->current_proto);
expert_add_info(pinfo, item, &ei_malformed);
break;
case ReportedBoundsError:
show_reported_bounds_error(tvb, pinfo, tree);
break;

View File

@ -55,7 +55,9 @@ struct tvbuff {
* file. This is the length of virtual buffer (and/or
* real_data). It may be less than the reported
* length if this is from a packet that was cut short
* by the capture process. */
* by the capture process.
*
* This must never be > reported_length or contained_length. */
guint length;
/** Amount of data that was reported as being in
@ -64,6 +66,22 @@ struct tvbuff {
* amount of data that's available. */
guint reported_length;
/** If this was extracted from a parent tvbuff,
* this is the amount of extracted data that
* was reported as being in the parent tvbuff;
* if this represents a blob of data in that
* tvbuff that has a length specified by data
* in that tvbuff, it might be greater than
* the amount of data that was actually there
* to extract, so it could be greater than
* reported_length.
*
* If this wasn't extracted from a parent tvbuff,
* this is the same as reported_length.
*
* This must never be > reported_length. */
guint contained_length;
/* Offset from beginning of first "real" tvbuff. */
gint raw_offset;
};

View File

@ -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;

View File

@ -259,6 +259,7 @@ tvb_composite_finalize(tvbuff_t *tvb)
DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops);
DISSECTOR_ASSERT(tvb->length == 0);
DISSECTOR_ASSERT(tvb->reported_length == 0);
DISSECTOR_ASSERT(tvb->contained_length == 0);
composite = &composite_tvb->composite;
num_members = g_slist_length(composite->tvbs);
@ -278,6 +279,7 @@ tvb_composite_finalize(tvbuff_t *tvb)
composite->start_offsets[i] = tvb->length;
tvb->length += member_tvb->length;
tvb->reported_length += member_tvb->reported_length;
tvb->contained_length += member_tvb->contained_length;
composite->end_offsets[i] = tvb->length - 1;
i++;
}

View File

@ -64,10 +64,11 @@ tvb_new_real_data(const guint8* data, const guint length, const gint reported_le
tvb = tvb_new(&tvb_real_ops);
tvb->real_data = data;
tvb->length = length;
tvb->reported_length = reported_length;
tvb->initialized = TRUE;
tvb->real_data = data;
tvb->length = length;
tvb->reported_length = reported_length;
tvb->contained_length = reported_length;
tvb->initialized = TRUE;
/*
* This is the top-level real tvbuff for this data source,

View File

@ -95,7 +95,7 @@ static const struct tvb_ops tvb_subset_ops = {
};
static tvbuff_t *
tvb_new_with_subset(tvbuff_t *backing, const gint reported_length,
tvb_new_with_subset(tvbuff_t *backing, const guint reported_length,
const guint subset_tvb_offset, const guint subset_tvb_length)
{
tvbuff_t *tvb = tvb_new(&tvb_subset_ops);
@ -106,14 +106,14 @@ tvb_new_with_subset(tvbuff_t *backing, const gint reported_length,
subset_tvb->subset.tvb = backing;
tvb->length = subset_tvb_length;
/*
* The contained length must not exceed what remains in the
* backing tvbuff.
*/
tvb->contained_length = MIN(reported_length, backing->contained_length - subset_tvb_offset);
tvb->flags = backing->flags;
if (reported_length == -1) {
tvb->reported_length = backing->reported_length - subset_tvb_offset;
}
else {
tvb->reported_length = reported_length;
}
tvb->reported_length = reported_length;
tvb->initialized = TRUE;
/* Optimization. If the backing buffer has a pointer to contiguous, real data,
@ -137,6 +137,7 @@ tvb_new_subset_length_caplen(tvbuff_t *backing, const gint backing_offset, const
tvbuff_t *tvb;
guint subset_tvb_offset;
guint subset_tvb_length;
guint actual_reported_length;
DISSECTOR_ASSERT(backing && backing->initialized);
@ -146,7 +147,12 @@ tvb_new_subset_length_caplen(tvbuff_t *backing, const gint backing_offset, const
&subset_tvb_offset,
&subset_tvb_length);
tvb = tvb_new_with_subset(backing, reported_length,
if (reported_length == -1)
actual_reported_length = backing->reported_length - subset_tvb_offset;
else
actual_reported_length = (guint)reported_length;
tvb = tvb_new_with_subset(backing, actual_reported_length,
subset_tvb_offset, subset_tvb_length);
tvb_add_to_chain(backing, tvb);
@ -167,7 +173,8 @@ tvb_new_subset_length(tvbuff_t *backing, const gint backing_offset, const gint r
THROW_ON(reported_length < 0, ReportedBoundsError);
/*
* Give the next dissector only captured_length bytes.
* Cut the captured length short, so it doesn't go past the subset's
* reported length.
*/
captured_length = tvb_captured_length_remaining(backing, backing_offset);
THROW_ON(captured_length < 0, BoundsError);
@ -178,7 +185,7 @@ tvb_new_subset_length(tvbuff_t *backing, const gint backing_offset, const gint r
&subset_tvb_offset,
&subset_tvb_length);
tvb = tvb_new_with_subset(backing, reported_length,
tvb = tvb_new_with_subset(backing, (guint)reported_length,
subset_tvb_offset, subset_tvb_length);
tvb_add_to_chain(backing, tvb);
@ -192,12 +199,16 @@ tvb_new_subset_remaining(tvbuff_t *backing, const gint backing_offset)
tvbuff_t *tvb;
guint subset_tvb_offset;
guint subset_tvb_length;
guint reported_length;
tvb_check_offset_length(backing, backing_offset, -1 /* backing_length */,
&subset_tvb_offset,
&subset_tvb_length);
tvb = tvb_new_with_subset(backing, -1 /* reported_length */,
THROW_ON(backing->reported_length < subset_tvb_offset, ReportedBoundsError);
reported_length = backing->reported_length - subset_tvb_offset;
tvb = tvb_new_with_subset(backing, reported_length,
subset_tvb_offset, subset_tvb_length);
tvb_add_to_chain(backing, tvb);

View File

@ -190,10 +190,11 @@ frame_tvbuff_new(const struct packet_provider_data *prov, const frame_data *fd,
* tvb_new_real_data() now there's no one
*/
tvb->real_data = buf;
tvb->length = fd->cap_len;
tvb->reported_length = fd->pkt_len > G_MAXINT ? G_MAXINT : fd->pkt_len;
tvb->initialized = TRUE;
tvb->real_data = buf;
tvb->length = fd->cap_len;
tvb->reported_length = fd->pkt_len > G_MAXINT ? G_MAXINT : fd->pkt_len;
tvb->contained_length = tvb->reported_length;
tvb->initialized = TRUE;
/*
* This is the top-level real tvbuff for this data source,
@ -240,10 +241,11 @@ frame_clone(tvbuff_t *tvb, guint abs_offset, guint abs_length)
cloned_tvb = tvb_new(&tvb_frame_ops);
/* data will be read when needed */
cloned_tvb->real_data = NULL;
cloned_tvb->length = abs_length;
cloned_tvb->reported_length = abs_length; /* XXX? */
cloned_tvb->initialized = TRUE;
cloned_tvb->real_data = NULL;
cloned_tvb->length = abs_length;
cloned_tvb->reported_length = abs_length; /* XXX? */
cloned_tvb->contained_length = cloned_tvb->reported_length;
cloned_tvb->initialized = TRUE;
/*
* This is the top-level real tvbuff for this data source,
@ -293,10 +295,11 @@ file_tvbuff_new(const struct packet_provider_data *prov, const frame_data *fd,
* tvb_new_real_data() now there's no one
*/
tvb->real_data = buf;
tvb->length = fd->cap_len;
tvb->reported_length = fd->pkt_len > G_MAXINT ? G_MAXINT : fd->pkt_len;
tvb->initialized = TRUE;
tvb->real_data = buf;
tvb->length = fd->cap_len;
tvb->reported_length = fd->pkt_len > G_MAXINT ? G_MAXINT : fd->pkt_len;
tvb->contained_length = tvb->reported_length;
tvb->initialized = TRUE;
/*
* This is the top-level real tvbuff for this data source,