Thrift: Fix recursion check

Previous recursion check only worked with generic dissector.
The introduced changes cover the sub-dissectors as well.

Remove the existing check as it counted basic types as well.
Add a check at every place where a sub-tree is created:
- containers (list, set, map)
- structures
This commit is contained in:
Triton Circonflexe 2024-02-24 21:39:31 +01:00 committed by AndersBroman
parent 8989c732fc
commit 4eaf10bc4e
1 changed files with 91 additions and 16 deletions

View File

@ -605,6 +605,12 @@ dissect_thrift_field_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
/* Create the field header sub-tree if requested only. */
if (tree != NULL) {
guint nested_count = p_get_proto_depth(pinfo, proto_thrift);
if (nested_count >= thrift_opt->nested_type_depth) {
expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_thrift_too_many_subtypes);
return THRIFT_REQUEST_REASSEMBLY;
}
header->fh_tree = proto_tree_add_subtree_format(tree, tvb, header->type_offset, *offset - header->type_offset, ett_thrift_field, NULL,
"Field Header #%" PRId64, header->field_id);
if (thrift_opt->tprotocol & PROTO_THRIFT_COMPACT) {
@ -1476,6 +1482,7 @@ dissect_thrift_t_raw_data(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, i
/* Simple dispatch function for lists, sets, maps, and structs internal elements to avoid code duplication. */
static int
// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_t_member(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, const thrift_member_t *elt)
{
switch (elt->type) {
@ -1532,6 +1539,7 @@ dissect_thrift_t_member(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int
* so it's easy to use the same code and handle the additional elements only when necessary.
*/
static int
// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_b_linear(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id, gint ett_id, const thrift_member_t *key, const thrift_member_t *val, thrift_type_enum_t expected)
{
proto_item *container_pi = NULL;
@ -1539,6 +1547,7 @@ dissect_thrift_b_linear(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int
proto_tree *sub_tree;
gint32 key_type, val_type;
gint32 length;
guint nested_count = p_get_proto_depth(pinfo, proto_thrift);
/* Get the current state of dissection. */
DISSECTOR_ASSERT(thrift_opt);
@ -1551,6 +1560,11 @@ dissect_thrift_b_linear(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int
}
/* Create the sub-tree. */
if (nested_count >= thrift_opt->nested_type_depth) {
expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_thrift_too_many_subtypes);
return THRIFT_REQUEST_REASSEMBLY;
}
p_set_proto_depth(pinfo, proto_thrift, nested_count + 1);
container_pi = proto_tree_add_item(tree, hf_id, tvb, offset, -1, ENC_BIG_ENDIAN);
sub_tree = proto_item_add_subtree(container_pi, ett_id);
ABORT_SUBDISSECTION_ON_ISSUE(offset);
@ -1625,6 +1639,7 @@ dissect_thrift_b_linear(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int
if (container_pi && offset > 0) {
proto_item_set_end(container_pi, tvb, offset);
}
p_set_proto_depth(pinfo, proto_thrift, nested_count);
return offset;
}
@ -1633,6 +1648,7 @@ dissect_thrift_b_linear(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int
* this prevents code duplication.
*/
static int
// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_c_list_set(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id, gint ett_id, const thrift_member_t *elt, gboolean is_list)
{
proto_item *container_pi;
@ -1647,6 +1663,7 @@ dissect_thrift_c_list_set(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, i
int hf_num_item = hf_thrift_num_set_item;
int hf_pos_item = hf_thrift_num_set_pos;
thrift_type_enum_t expected = DE_THRIFT_T_SET;
guint nested_count = p_get_proto_depth(pinfo, proto_thrift);
if (is_list) {
hf_num_item = hf_thrift_num_list_item;
@ -1669,6 +1686,11 @@ dissect_thrift_c_list_set(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, i
}
/* Create the sub-tree. */
if (nested_count >= thrift_opt->nested_type_depth) {
expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_thrift_too_many_subtypes);
return THRIFT_REQUEST_REASSEMBLY;
}
p_set_proto_depth(pinfo, proto_thrift, nested_count + 1);
container_pi = proto_tree_add_item(tree, hf_id, tvb, offset, -1, ENC_BIG_ENDIAN);
sub_tree = proto_item_add_subtree(container_pi, ett_id);
@ -1729,10 +1751,12 @@ dissect_thrift_c_list_set(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, i
if (container_pi && offset > 0) {
proto_item_set_end(container_pi, tvb, offset);
}
p_set_proto_depth(pinfo, proto_thrift, nested_count);
return offset;
}
int
// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_t_list(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id, gint ett_id, const thrift_member_t *elt)
{
int result;
@ -1749,6 +1773,7 @@ dissect_thrift_t_list(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int o
}
int
// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_t_set(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id, gint ett_id, const thrift_member_t *elt)
{
int result;
@ -1765,6 +1790,7 @@ dissect_thrift_t_set(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int of
}
int
// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_t_map(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id, gint ett_id, const thrift_member_t *key, const thrift_member_t *value)
{
int result;
@ -1783,6 +1809,7 @@ dissect_thrift_t_map(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int of
gint32 len_offset = offset;
thrift_compact_type_enum_t ktype, vtype;
guint64 varint;
guint nested_count = p_get_proto_depth(pinfo, proto_thrift);
/* Dissect field header if necessary. */
if (is_field) {
@ -1815,12 +1842,18 @@ dissect_thrift_t_map(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int of
}
/* Create the sub-tree. */
if (nested_count >= thrift_opt->nested_type_depth) {
expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_thrift_too_many_subtypes);
return THRIFT_REQUEST_REASSEMBLY;
}
p_set_proto_depth(pinfo, proto_thrift, nested_count + 1);
container_pi = proto_tree_add_item(tree, hf_id, tvb, len_offset, -1, ENC_BIG_ENDIAN);
sub_tree = proto_item_add_subtree(container_pi, ett_id);
if (container_len == 0) {
proto_item_set_end(container_pi, tvb, offset);
proto_item_append_text(container_pi, " (Empty)");
p_set_proto_depth(pinfo, proto_thrift, nested_count);
return offset;
}
@ -1867,6 +1900,7 @@ dissect_thrift_t_map(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int of
proto_item_set_end(container_pi, tvb, offset);
}
result = offset;
p_set_proto_depth(pinfo, proto_thrift, nested_count);
}
if (is_field) {
@ -1882,6 +1916,7 @@ dissect_thrift_t_struct(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int
}
static int
// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_t_struct_expert(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, thrift_option_data_t *thrift_opt, gboolean is_field, int field_id, gint hf_id, gint ett_id, const thrift_member_t *seq, expert_field* ei)
{
thrift_field_header_t field_header;
@ -1889,6 +1924,7 @@ dissect_thrift_t_struct_expert(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tr
proto_item *type_pi = NULL;
gboolean enable_subtree = (ett_id != DISABLE_SUBTREE) || (hf_id != DISABLE_SUBTREE);
guint nested_count = p_get_proto_depth(pinfo, proto_thrift);
/* Get the current state of dissection. */
DISSECTOR_ASSERT(thrift_opt);
@ -1909,6 +1945,11 @@ dissect_thrift_t_struct_expert(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tr
/* Create the sub-tree, if not explicitly refused. */
if (enable_subtree) {
/* Add the struct to the tree. */
if (nested_count >= thrift_opt->nested_type_depth) {
expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_thrift_too_many_subtypes);
return THRIFT_REQUEST_REASSEMBLY;
}
p_set_proto_depth(pinfo, proto_thrift, nested_count--);
type_pi = proto_tree_add_item(tree, hf_id, tvb, offset, -1, ENC_BIG_ENDIAN);
sub_tree = proto_item_add_subtree(type_pi, ett_id);
} else {
@ -2002,6 +2043,7 @@ dissect_thrift_t_struct_expert(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tr
if (is_field) {
thrift_opt->previous_field_id = field_id;
}
p_set_proto_depth(pinfo, proto_thrift, nested_count);
return offset;
}
/*=====END SUB-DISSECTION=====*/
@ -2080,6 +2122,7 @@ dissect_thrift_binary_binary(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
}
static int
// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_binary_linear(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt, thrift_type_enum_t expected)
{
/* Binary protocol list and set (5 bytes + elements):
@ -2107,6 +2150,7 @@ dissect_thrift_binary_linear(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
int hf_num_item = -1;
int hf_vtype = hf_thrift_type;
int min_len = TBP_THRIFT_LINEAR_LEN;
guint nested_count = p_get_proto_depth(pinfo, proto_thrift);
/* Set the different hf_id & ett depending on effective type. */
switch (expected) {
@ -2134,6 +2178,11 @@ dissect_thrift_binary_linear(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
ABORT_ON_INCOMPLETE_PDU(min_len);
/* Create the sub-tree. */
if (nested_count >= thrift_opt->nested_type_depth) {
expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_thrift_too_many_subtypes);
return THRIFT_REQUEST_REASSEMBLY;
}
p_set_proto_depth(pinfo, proto_thrift, nested_count + 1);
container_pi = proto_tree_add_item(tree, hf_container, tvb, *offset, -1, ENC_NA);
sub_tree = proto_item_add_subtree(container_pi, ett);
@ -2164,28 +2213,33 @@ dissect_thrift_binary_linear(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
}
proto_item_set_end(container_pi, tvb, *offset);
p_set_proto_depth(pinfo, proto_thrift, nested_count);
return *offset;
}
static int
// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_binary_list(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt)
{
return dissect_thrift_binary_linear(tvb, pinfo, tree, offset, thrift_opt, DE_THRIFT_T_LIST);
}
static int
// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_binary_set(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt)
{
return dissect_thrift_binary_linear(tvb, pinfo, tree, offset, thrift_opt, DE_THRIFT_T_SET);
}
static int
// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_binary_map(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt)
{
return dissect_thrift_binary_linear(tvb, pinfo, tree, offset, thrift_opt, DE_THRIFT_T_MAP);
}
static int
// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_binary_fields(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt)
{
/*
@ -2231,6 +2285,7 @@ dissect_thrift_binary_fields(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
}
static int
// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_binary_struct(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt)
{
/* This function only creates the "Struct" sub-tree
@ -2238,8 +2293,14 @@ dissect_thrift_binary_struct(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
*/
proto_tree *sub_tree;
proto_item *pi;
guint nested_count = p_get_proto_depth(pinfo, proto_thrift);
ABORT_ON_INCOMPLETE_PDU(TBP_THRIFT_STRUCT_LEN);
if (nested_count >= thrift_opt->nested_type_depth) {
expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_thrift_too_many_subtypes);
return THRIFT_REQUEST_REASSEMBLY;
}
p_set_proto_depth(pinfo, proto_thrift, nested_count + 1);
pi = proto_tree_add_item(tree, hf_thrift_struct, tvb, *offset, -1, ENC_NA);
sub_tree = proto_item_add_subtree(pi, ett_thrift_struct);
@ -2248,19 +2309,14 @@ dissect_thrift_binary_struct(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
} else {
proto_item_set_end(pi, tvb, *offset);
}
p_set_proto_depth(pinfo, proto_thrift, nested_count);
return *offset;
}
static int
// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_binary_type(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt, proto_tree *header_tree, int type, proto_item *type_pi)
{
guint nested_count = p_get_proto_depth(pinfo, proto_thrift);
if (++nested_count > thrift_opt->nested_type_depth) {
expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_thrift_too_many_subtypes);
return THRIFT_REQUEST_REASSEMBLY;
}
p_set_proto_depth(pinfo, proto_thrift, nested_count);
switch (type) {
case DE_THRIFT_T_BOOL:
ABORT_ON_INCOMPLETE_PDU(TBP_THRIFT_BOOL_LEN);
@ -2328,7 +2384,6 @@ dissect_thrift_binary_type(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
return THRIFT_REQUEST_REASSEMBLY;
}
p_set_proto_depth(pinfo, proto_thrift, --nested_count);
return *offset;
}
/*=====END BINARY GENERIC DISSECTION=====*/
@ -2395,6 +2450,7 @@ dissect_thrift_compact_binary(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre
}
static int
// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_compact_list_set(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt, gboolean is_list)
{
/* Compact protocol list/set (short form, 1 byte):
@ -2422,6 +2478,7 @@ dissect_thrift_compact_list_set(tvbuff_t *tvb, packet_info *pinfo, proto_tree *t
int hf_container = hf_thrift_set;
int hf_num_item = hf_thrift_num_set_item;
int hf_pos_item = hf_thrift_num_set_pos;
guint nested_count = p_get_proto_depth(pinfo, proto_thrift);
ABORT_ON_INCOMPLETE_PDU(TBP_THRIFT_TYPE_LEN);
/* Set the different hf_id & ett depending on effective type. */
@ -2433,6 +2490,11 @@ dissect_thrift_compact_list_set(tvbuff_t *tvb, packet_info *pinfo, proto_tree *t
}
/* Create the sub-tree. */
if (nested_count >= thrift_opt->nested_type_depth) {
expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_thrift_too_many_subtypes);
return THRIFT_REQUEST_REASSEMBLY;
}
p_set_proto_depth(pinfo, proto_thrift, nested_count + 1);
container_pi = proto_tree_add_item(tree, hf_container, tvb, *offset, -1, ENC_NA);
sub_tree = proto_item_add_subtree(container_pi, ett);
@ -2483,22 +2545,26 @@ dissect_thrift_compact_list_set(tvbuff_t *tvb, packet_info *pinfo, proto_tree *t
}
proto_item_set_end(container_pi, tvb, *offset);
p_set_proto_depth(pinfo, proto_thrift, nested_count);
return *offset;
}
static int
// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_compact_list(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt)
{
return dissect_thrift_compact_list_set(tvb, pinfo, tree, offset, thrift_opt, TRUE);
}
static int
// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_compact_set(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt)
{
return dissect_thrift_compact_list_set(tvb, pinfo, tree, offset, thrift_opt, FALSE);
}
static int
// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_compact_map(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt)
{
/* Compact protocol map header (1 byte, empty map):
@ -2523,9 +2589,15 @@ dissect_thrift_compact_map(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
guint32 types, ktype, vtype;
gint32 container_len, len_len, i;
guint64 varint;
guint nested_count = p_get_proto_depth(pinfo, proto_thrift);
ABORT_ON_INCOMPLETE_PDU(TCP_THRIFT_MIN_VARINT_LEN);
/* Create the sub-tree. */
if (nested_count >= thrift_opt->nested_type_depth) {
expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_thrift_too_many_subtypes);
return THRIFT_REQUEST_REASSEMBLY;
}
p_set_proto_depth(pinfo, proto_thrift, nested_count + 1);
container_pi = proto_tree_add_item(tree, hf_thrift_map, tvb, *offset, -1, ENC_NA);
sub_tree = proto_item_add_subtree(container_pi, ett_thrift_map);
@ -2577,10 +2649,12 @@ dissect_thrift_compact_map(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
}
proto_item_set_end(container_pi, tvb, *offset);
p_set_proto_depth(pinfo, proto_thrift, nested_count);
return *offset;
}
static int
// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_compact_fields(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt)
{
/*
@ -2634,6 +2708,7 @@ dissect_thrift_compact_fields(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre
}
static int
// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_compact_struct(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt)
{
/* This function only creates the "Struct" sub-tree
@ -2641,8 +2716,14 @@ dissect_thrift_compact_struct(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre
*/
proto_tree *sub_tree;
proto_item *pi;
guint nested_count = p_get_proto_depth(pinfo, proto_thrift);
ABORT_ON_INCOMPLETE_PDU(TCP_THRIFT_STRUCT_LEN);
if (nested_count >= thrift_opt->nested_type_depth) {
expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_thrift_too_many_subtypes);
return THRIFT_REQUEST_REASSEMBLY;
}
p_set_proto_depth(pinfo, proto_thrift, nested_count + 1);
pi = proto_tree_add_item(tree, hf_thrift_struct, tvb, *offset, -1, ENC_NA);
sub_tree = proto_item_add_subtree(pi, ett_thrift_struct);
@ -2651,6 +2732,7 @@ dissect_thrift_compact_struct(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre
} else {
proto_item_set_end(pi, tvb, *offset);
}
p_set_proto_depth(pinfo, proto_thrift, nested_count);
return *offset;
}
@ -2661,15 +2743,9 @@ dissect_thrift_compact_struct(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre
* the bool type which is encoded in the same way as BOOL_FALSE (2).
*/
static int
// NOLINTNEXTLINE(misc-no-recursion)
dissect_thrift_compact_type(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, thrift_option_data_t *thrift_opt, proto_tree *header_tree, int type, proto_item *type_pi)
{
guint nested_count = p_get_proto_depth(pinfo, proto_thrift);
if (++nested_count > thrift_opt->nested_type_depth) {
expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_thrift_too_many_subtypes);
return THRIFT_REQUEST_REASSEMBLY;
}
p_set_proto_depth(pinfo, proto_thrift, nested_count);
switch (type) {
case DE_THRIFT_C_BOOL_FALSE:
ABORT_ON_INCOMPLETE_PDU(TBP_THRIFT_BOOL_LEN);
@ -2743,7 +2819,6 @@ dissect_thrift_compact_type(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
return THRIFT_REQUEST_REASSEMBLY;
}
p_set_proto_depth(pinfo, proto_thrift, --nested_count);
return *offset;
}
/*=====END COMPACT GENERIC DISSECTION=====*/