From 86b0e3f7c7fc2c689db88972221b5d4da1c7214f Mon Sep 17 00:00:00 2001 From: HoundThe Date: Tue, 12 Jul 2022 10:23:07 +0200 Subject: [PATCH] Fix unaligned read and missing length check in read_blob_*. (#1742) Add depth limit in namespace recursion due to the possible loops. --- libyara/include/yara/dotnet.h | 3 ++- libyara/modules/dotnet/dotnet.c | 28 +++++++++++++++++++--------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/libyara/include/yara/dotnet.h b/libyara/include/yara/dotnet.h index 8d66d33e..8462deac 100644 --- a/libyara/include/yara/dotnet.h +++ b/libyara/include/yara/dotnet.h @@ -212,7 +212,8 @@ typedef struct _TILDE_HEADER #define MAX_METHOD_COUNT 20000 #define MAX_STRING_LENGTH 10000 // Sanity check for loops in type parser -#define MAX_TYPE_DEPTH 0x10 +#define MAX_TYPE_DEPTH 0x10 +#define MAX_NAMESPACE_DEPTH 0x0a // // Module table diff --git a/libyara/modules/dotnet/dotnet.c b/libyara/modules/dotnet/dotnet.c index facd24fb..58c3779f 100644 --- a/libyara/modules/dotnet/dotnet.c +++ b/libyara/modules/dotnet/dotnet.c @@ -521,7 +521,7 @@ static uint32_t read_blob_unsigned(const uint8_t** data, uint32_t* len) // bits 13 through 0) if ((first_byte & 0xC0) == 0x80) { - uint32_t result = yr_be16toh(*(uint16_t*) *data); + uint32_t result = yr_be16toh(yr_unaligned_u16(*data)); *data += sizeof(uint16_t); *len -= sizeof(uint16_t); // value is in lower 14 bits @@ -535,7 +535,7 @@ static uint32_t read_blob_unsigned(const uint8_t** data, uint32_t* len) // bit 29 clear (value held in bits 28 through 0) if ((first_byte & 0xE0) == 0xC0) { - uint32_t result = yr_be32toh(*(uint32_t*) *data); + uint32_t result = yr_be32toh(yr_unaligned_u32(*data)); *data += sizeof(uint32_t); *len -= sizeof(uint32_t); // Uses last 29 bits for the result @@ -579,7 +579,7 @@ static int32_t read_blob_signed(const uint8_t** data, uint32_t* len) // in bits 13 through 0, giving 0x8001 (-2^13) to 0xBFFE (2^13-1). if ((first_byte & 0xC0) == 0x80) { - uint16_t tmp1 = yr_be16toh(*(uint16_t*) *data); + uint16_t tmp1 = yr_be16toh(yr_unaligned_u16(*data)); // shift and leave top 2 bits clear uint16_t tmp2 = (tmp1 >> 1) & 0x3FFF; // sign extension in case of negative number @@ -592,12 +592,15 @@ static int32_t read_blob_signed(const uint8_t** data, uint32_t* len) return (int32_t) tmp2; } + if (*len < 4) + return 0; + // Encode as a four-byte integer: bit 31 set, 30 set, bit 29 clear, // rotated value in bits 28 through 0, giving 0xC0000001 (-2^28) to // 0xDFFFFFFE (2^28-1). if ((first_byte & 0xE0) == 0xC0) { - uint32_t tmp1 = yr_be32toh(*(uint32_t*) *data); + uint32_t tmp1 = yr_be32toh(yr_unaligned_u32(*data)); // shift and leave top 3 bits clear uint32_t tmp2 = (tmp1 >> 1) & 0x1FFFFFFF; // sign extension in case of negative number @@ -622,7 +625,10 @@ static char* parse_signature_type( GENERIC_PARAMETERS* method_gen_params, uint32_t depth); -static char* parse_enclosing_types(const CLASS_CONTEXT* ctx, uint32_t type_idx); +static char* parse_enclosing_types( + const CLASS_CONTEXT* ctx, + uint32_t nested_idx, + uint32_t depth); static char* get_type_def_or_ref_fullname( const CLASS_CONTEXT* ctx, @@ -658,7 +664,7 @@ static char* get_type_def_or_ref_fullname( // Type might be nested, try to find correct namespace if (is_nested(def_row.Flags)) { - char* nested_namespace = parse_enclosing_types(ctx, index); + char* nested_namespace = parse_enclosing_types(ctx, index, 1); char* tmp = create_full_name(namespace, nested_namespace); result = create_full_name(name, tmp); yr_free(nested_namespace); @@ -1463,8 +1469,12 @@ static void parse_methods( // Walks NestedClass table, returns enclosing type fullname or NULL static char* parse_enclosing_types( const CLASS_CONTEXT* ctx, - uint32_t nested_idx) + uint32_t nested_idx, + uint32_t depth) { + if (depth > MAX_NAMESPACE_DEPTH) + return NULL; + const uint8_t* str_heap = ctx->str_heap; uint32_t str_size = ctx->str_size; @@ -1505,7 +1515,7 @@ static char* parse_enclosing_types( nested_row.EnclosingClass != nested_row.NestedClass) { char* nested_namespace = parse_enclosing_types( - ctx, nested_row.EnclosingClass); + ctx, nested_row.EnclosingClass, depth + 1); char* tmp = create_full_name(namespace, nested_namespace); char* fullname = create_full_name(name, tmp); @@ -1569,7 +1579,7 @@ static void parse_user_types(const CLASS_CONTEXT* ctx) // Type might be nested, if so -> find correct namespace if (is_nested(row.Flags)) { - char* nested_namespace = parse_enclosing_types(ctx, idx + 1); + char* nested_namespace = parse_enclosing_types(ctx, idx + 1, 1); namespace = create_full_name(namespace, nested_namespace); set_string(namespace, out_obj, "classes[%i].namespace", out_idx); fullname = create_full_name(name, namespace);