forked from osmocom/wireshark
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:
parent
9011a25afc
commit
0a130c5756
|
@ -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)
|
||||
|
||||
|
|
|
@ -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; \
|
||||
}
|
||||
|
|
|
@ -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 }},
|
||||
};
|
||||
|
|
|
@ -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)) \
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
179
epan/tvbuff.c
179
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;
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue