From 8b0e90d62e283d3aa7b00aa17a55a53bde362da4 Mon Sep 17 00:00:00 2001 From: Gerald Combs Date: Wed, 21 Feb 2024 15:01:00 -0800 Subject: [PATCH] AllJoyn: Add recursion checks --- epan/dissectors/packet-alljoyn.c | 39 +++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/epan/dissectors/packet-alljoyn.c b/epan/dissectors/packet-alljoyn.c index c9934417ba..a73c4c3c4a 100644 --- a/epan/dissectors/packet-alljoyn.c +++ b/epan/dissectors/packet-alljoyn.c @@ -11,6 +11,7 @@ #include "config.h" #include +#include #include #include #include @@ -29,6 +30,9 @@ static dissector_handle_t alljoyn_handle_ardp; /* DBus limits packet length to 2^27. AllJoyn limits it further to 2^17 + 4096 to allow for 2^17 payload */ #define MAX_PACKET_LEN (MAX_ARRAY_LEN + 4096) +/* Arbitrarily chosen. */ +#define MAX_RECURSION_DEPTH 10 + /* The following are protocols within a frame. The actual value of the handle is set when the various fields are registered in proto_register_AllJoyn() with a call to @@ -769,13 +773,17 @@ append_struct_signature(proto_item *item, * @param signature_length is a pointer to the length of the signature. */ static void -advance_to_end_of_signature(const guint8 **signature, - guint8 *signature_length) +// NOLINTNEXTLINE(misc-no-recursion) +advance_to_end_of_signature(packet_info *pinfo, const guint8 **signature, guint8 *signature_length) { gboolean done = FALSE; gint8 current_type; gint8 end_type = ARG_INVALID; + unsigned recursion_depth = p_get_proto_depth(pinfo, proto_AllJoyn_mess); + DISSECTOR_ASSERT(recursion_depth <= MAX_RECURSION_DEPTH); + p_set_proto_depth(pinfo, proto_AllJoyn_mess, recursion_depth + 1); + while (*signature_length > 0 && **signature && !done) { current_type = *(++(*signature)); --*signature_length; @@ -792,15 +800,15 @@ advance_to_end_of_signature(const guint8 **signature, switch(current_type) { case ARG_ARRAY: - advance_to_end_of_signature(signature, signature_length); + advance_to_end_of_signature(pinfo, signature, signature_length); break; case ARG_STRUCT: end_type = ')'; - advance_to_end_of_signature(signature, signature_length); + advance_to_end_of_signature(pinfo, signature, signature_length); break; case ARG_DICT_ENTRY: end_type = '}'; - advance_to_end_of_signature(signature, signature_length); + advance_to_end_of_signature(pinfo, signature, signature_length); break; case ARG_BYTE: @@ -825,6 +833,7 @@ advance_to_end_of_signature(const guint8 **signature, break; } } + p_set_proto_depth(pinfo, proto_AllJoyn_mess, recursion_depth); } /* This is called to add a padding item. There is not padding done for each call made. @@ -877,6 +886,7 @@ static void add_padding_item(gint padding_start, gint padding_end, tvbuff_t *tvb * parameters come in. */ static gint +// NOLINTNEXTLINE(misc-no-recursion) parse_arg(tvbuff_t *tvb, packet_info *pinfo, proto_item *header_item, @@ -941,10 +951,14 @@ parse_arg(tvbuff_t *tvb, add_padding_item(padding_start, offset, tvb, tree); if(0 == length) { - advance_to_end_of_signature(signature, signature_length); + advance_to_end_of_signature(pinfo, signature, signature_length); } else { guint8 sig_length_saved = *signature_length - 1; + unsigned recursion_depth = p_get_proto_depth(pinfo, proto_AllJoyn_mess); + DISSECTOR_ASSERT(recursion_depth <= MAX_RECURSION_DEPTH); + p_set_proto_depth(pinfo, proto_AllJoyn_mess, recursion_depth + 1); + while((offset - starting_offset) < length) { const guint8 *sig_pointer; guint8 remaining_sig_length; @@ -970,6 +984,7 @@ parse_arg(tvbuff_t *tvb, *signature = sig_pointer; *signature_length = remaining_sig_length; } + p_set_proto_depth(pinfo, proto_AllJoyn_mess, recursion_depth); } if(item) { @@ -1180,14 +1195,20 @@ parse_arg(tvbuff_t *tvb, offset += length; sig_pointer = sig_saved; + unsigned recursion_depth = p_get_proto_depth(pinfo, proto_AllJoyn_mess); + DISSECTOR_ASSERT(recursion_depth <= MAX_RECURSION_DEPTH); + p_set_proto_depth(pinfo, proto_AllJoyn_mess, recursion_depth + 1); + /* The signature of the variant has now been taken care of. So now take care of the variant data. */ while(((sig_pointer - sig_saved) < (length - 1)) && (tvb_reported_length_remaining(tvb, offset) > 0)) { proto_item_append_text(item, "%c", g_ascii_isprint(*sig_pointer) ? *sig_pointer : '?'); offset = parse_arg(tvb, pinfo, header_item, encoding, offset, tree, is_reply_to, *sig_pointer, field_code, &sig_pointer, &variant_sig_length, field_starting_offset); + } + p_set_proto_depth(pinfo, proto_AllJoyn_mess, recursion_depth); proto_item_append_text(item, "'"); proto_item_set_end(item, tvb, offset); } @@ -1241,6 +1262,10 @@ parse_arg(tvbuff_t *tvb, (*signature)++; /* Advance past the '(' or '{'. */ (*signature_length)--; + unsigned recursion_depth = p_get_proto_depth(pinfo, proto_AllJoyn_mess); + DISSECTOR_ASSERT(recursion_depth <= MAX_RECURSION_DEPTH); + p_set_proto_depth(pinfo, proto_AllJoyn_mess, recursion_depth + 1); + /* *signature should never be NULL but just make sure to avoid potential issues. */ while(*signature && **signature && **signature != type_stop && tvb_reported_length_remaining(tvb, offset) > 0) { @@ -1258,6 +1283,8 @@ parse_arg(tvbuff_t *tvb, field_starting_offset); } + p_set_proto_depth(pinfo, proto_AllJoyn_mess, recursion_depth); + proto_item_set_end(item, tvb, offset); } break;