diff options
author | Yatian XU <yatian.xu@nokia-sbell.com> | 2019-09-04 22:43:34 +0800 |
---|---|---|
committer | Yatian XU <yatian.xu@nokia-sbell.com> | 2019-09-05 06:51:02 +0800 |
commit | 998c19266ef5f74fffd79e9c0c0a65f77ff19a43 (patch) | |
tree | 8e011aa227cc5b7a798c13bac6d193c54dff49b9 | |
parent | ad8ef0f0485a8e7490d84511159c274db123c5a3 (diff) |
Fix buffer overflow bug in evel_json_encode_event/evel_json_encode_batch_event.
Issue-ID: VNFSDK-463
Signed-off-by: Yatian XU <yatian.xu@nokia-sbell.com>
Change-Id: I6263ace34d9dab5e058490d9d011e1535902e41d
4 files changed, 230 insertions, 92 deletions
diff --git a/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel.h b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel.h index 9de3868..8cbbeb6 100644 --- a/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel.h +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel.h @@ -3063,7 +3063,11 @@ void evel_free_event(void * event); * @param mode Event mode or Batch mode * @param max_size Size of storage available in json_body. * @param event Pointer to the ::EVENT_HEADER to encode. - * @returns Number of bytes actually written. + * @returns The number of characters that would have been written if max_size + had been sufficiently large, not counting the terminating null + character. Notice that only when this returned value is less than + max_size, the string has been completely written(similar to snprintf). + Otherwise, need to enlarge the buffer size to returned value +1. *****************************************************************************/ int evel_json_encode_event(char * json, int max_size, diff --git a/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_event.c b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_event.c index 7200e06..62d38d4 100644 --- a/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_event.c +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_event.c @@ -784,10 +784,8 @@ int evel_json_encode_event(char * json, /* Sanity check. */ /***************************************************************************/ assert(jbuf->depth == 0); - if( jbuf->offset >= max_size ){ - EVEL_ERROR("Event exceeded size limit %d", max_size); - assert(0); - } + + evel_json_buffer_cleanup(jbuf); EVEL_EXIT(); @@ -852,6 +850,8 @@ int evel_json_encode_batch_event(char * json, evel_json_close_object(jbuf); } + evel_json_buffer_cleanup(jbuf); + } /***************************************************************************/ /* Sanity check. */ diff --git a/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_internal.h b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_internal.h index 29ba6cd..fc6456c 100644 --- a/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_internal.h +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_internal.h @@ -164,6 +164,11 @@ typedef struct evel_throttle_spec { /*****************************************************************************/ #define EVEL_THROTTLE_FIELD_DEPTH 3 +/*****************************************************************************/ +/* EVEL_JSON_BUFFER json buffer grow bytes. +/*****************************************************************************/ +#define EVEL_JSON_BUFFER_GROW_BYTES 512 + /**************************************************************************//** * Initialize the event handler. * @@ -274,6 +279,7 @@ typedef struct evel_json_buffer char * json; int offset; int max_size; + bool extend; /***************************************************************************/ /* The working throttle specification, which can be NULL. */ @@ -463,6 +469,39 @@ void evel_json_buffer_init(EVEL_JSON_BUFFER * jbuf, EVEL_THROTTLE_SPEC * throttle_spec); /**************************************************************************//** + * Cleanup a ::EVEL_JSON_BUFFER. + * + * @param jbuf Pointer to the ::EVEL_JSON_BUFFER to initialise. + *****************************************************************************/ +void evel_json_buffer_cleanup(EVEL_JSON_BUFFER * jbuf); + +/**************************************************************************//** + * Encode a list item with format and param list to a ::EVEL_JSON_BUFFER. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param format Format string in standard printf format. + * @param ... Variable parameters for format string. + *****************************************************************************/ +void evel_json_printf(EVEL_JSON_BUFFER * jbuf, const char* const format, ...); + +/**************************************************************************//** + * Encode a list item with format and param list to a ::EVEL_JSON_BUFFER. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param format Format string in standard printf format. + * @param largs Variable parameters for format string. + *****************************************************************************/ +void evel_json_vprintf(EVEL_JSON_BUFFER * jbuf, const char* const format, va_list largs); + +/**************************************************************************//** + * Extend the json buffer to size of max_size. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param max_size The max json buffer size. + *****************************************************************************/ +void evel_json_extend(EVEL_JSON_BUFFER * jbuf, int max_size); + +/**************************************************************************//** * Encode a string key and string value to a ::EVEL_JSON_BUFFER. * * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. diff --git a/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_json_buffer.c b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_json_buffer.c index a7ad019..7218953 100644 --- a/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_json_buffer.c +++ b/veslibrary/ves_clibrary/evel/evel-library/code/evel_library/evel_json_buffer.c @@ -52,6 +52,7 @@ void evel_json_buffer_init(EVEL_JSON_BUFFER * jbuf, jbuf->json = json; jbuf->max_size = max_size; jbuf->offset = 0; + jbuf->extend = false; jbuf->throttle_spec = throttle_spec; jbuf->depth = 0; jbuf->checkpoint = -1; @@ -60,6 +61,118 @@ void evel_json_buffer_init(EVEL_JSON_BUFFER * jbuf, } /**************************************************************************//** + * Cleanup a ::EVEL_JSON_BUFFER. + * + * @param jbuf Pointer to the ::EVEL_JSON_BUFFER to initialise. + *****************************************************************************/ +void evel_json_buffer_cleanup(EVEL_JSON_BUFFER * jbuf) +{ + EVEL_ENTER(); + + assert(jbuf != NULL); + if (jbuf->extend && jbuf->json) + { + free(jbuf->json); + jbuf->extend = false; + } + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Encode a list item with format and param list to a ::EVEL_JSON_BUFFER. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param format Format string in standard printf format. + * @param ... Variable parameters for format string. + *****************************************************************************/ +void evel_json_printf(EVEL_JSON_BUFFER * jbuf, const char* const format, ...) +{ + EVEL_ENTER(); + + assert(jbuf != NULL); + assert(format != NULL); + + va_list largs; + va_start(largs, format); + evel_json_vprintf(jbuf, format, largs); + va_end(largs); + + EVEL_EXIT(); +} + +/**************************************************************************//** + * Encode a list item with format and param list to a ::EVEL_JSON_BUFFER. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param format Format string in standard printf format. + * @param largs Variable parameters for format string. + *****************************************************************************/ +void evel_json_vprintf(EVEL_JSON_BUFFER * jbuf, const char* const format, va_list largs) +{ + EVEL_ENTER(); + + assert(jbuf != NULL); + assert(format != NULL); + + va_list largs_dup; + va_copy(largs_dup, largs); + + int left = jbuf->max_size - jbuf->offset; + int len = vsnprintf(jbuf->json + jbuf->offset, left, format, largs); + + if (len < left) + { + jbuf->offset += len; + } + else //buffer is not enough + { + evel_json_extend(jbuf, jbuf->offset + len + 1 + EVEL_JSON_BUFFER_GROW_BYTES); + jbuf->offset += vsnprintf(jbuf->json + jbuf->offset, jbuf->max_size - jbuf->offset, format, largs_dup); + } + + va_end(largs_dup); + + EVEL_EXIT(); +} + + +/**************************************************************************//** + * Extend the json buffer to size of max_size. + * + * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. + * @param max_size The max json buffer size. + *****************************************************************************/ +void evel_json_extend(EVEL_JSON_BUFFER * jbuf, int max_size) +{ + EVEL_ENTER(); + + assert(jbuf != NULL); + + if (jbuf->max_size < max_size) + { + if (jbuf->extend) //already extent the buffer + { + jbuf->json = (char*)realloc(jbuf->json, max_size); + assert(jbuf->json != NULL); + } + else // extent for the first time + { + char* json = (char*)malloc(max_size); + assert(json != NULL); + strncpy(json, jbuf->json, jbuf->offset); + jbuf->json = json; + jbuf->extend = true; + } + + jbuf->max_size = max_size; + } + + EVEL_EXIT(); +} + + +/**************************************************************************//** * Encode an integer value to a JSON buffer. * * @param jbuf Pointer to working ::EVEL_JSON_BUFFER. @@ -75,9 +188,7 @@ void evel_enc_int(EVEL_JSON_BUFFER * jbuf, /***************************************************************************/ assert(jbuf != NULL); - jbuf->offset += snprintf(jbuf->json + jbuf->offset, - jbuf->max_size - jbuf->offset, - "%d", value); + evel_json_printf(jbuf, "%d", value); EVEL_EXIT(); } @@ -146,11 +257,10 @@ void evel_enc_kv_string(EVEL_JSON_BUFFER * jbuf, assert(jbuf != NULL); assert(key != NULL); - jbuf->offset += snprintf(jbuf->json + jbuf->offset, - jbuf->max_size - jbuf->offset, - "%s\"%s\": \"", - evel_json_kv_comma(jbuf), - key); + evel_json_printf(jbuf, + "%s\"%s\": \"", + evel_json_kv_comma(jbuf), + key); /***************************************************************************/ /* We need to escape quotation marks and backslashes in the value. */ @@ -159,13 +269,8 @@ void evel_enc_kv_string(EVEL_JSON_BUFFER * jbuf, for (index = 0; index < length; index++) { - /*************************************************************************/ - /* Drop out if no more space. */ - /*************************************************************************/ - if (jbuf->max_size - jbuf->offset < 2) - { - break; - } + //make sure there are 3 bytes available(2 for json, 1 for null) + evel_json_extend(jbuf, jbuf->offset + 3); /*************************************************************************/ /* Add an escape character if necessary, then write the character */ @@ -181,9 +286,7 @@ void evel_enc_kv_string(EVEL_JSON_BUFFER * jbuf, jbuf->offset++; } - jbuf->offset += snprintf(jbuf->json + jbuf->offset, - jbuf->max_size - jbuf->offset, - "\""); + evel_json_printf(jbuf, "\""); EVEL_EXIT(); } @@ -250,12 +353,11 @@ void evel_enc_kv_int(EVEL_JSON_BUFFER * jbuf, assert(jbuf != NULL); assert(key != NULL); - jbuf->offset += snprintf(jbuf->json + jbuf->offset, - jbuf->max_size - jbuf->offset, - "%s\"%s\": %d", - evel_json_kv_comma(jbuf), - key, - value); + evel_json_printf(jbuf, + "%s\"%s\": %d", + evel_json_kv_comma(jbuf), + key, + value); EVEL_EXIT(); } @@ -279,12 +381,11 @@ void evel_enc_kv_object(EVEL_JSON_BUFFER * jbuf, assert(jbuf != NULL); assert(key != NULL); - jbuf->offset += snprintf(jbuf->json + jbuf->offset, - jbuf->max_size - jbuf->offset, - "%s\"%s\": %s", - evel_json_kv_comma(jbuf), - key, - value); + evel_json_printf(jbuf, + "%s\"%s\": %s", + evel_json_kv_comma(jbuf), + key, + value); EVEL_EXIT(); } @@ -350,12 +451,11 @@ void evel_enc_kv_double(EVEL_JSON_BUFFER * jbuf, assert(jbuf != NULL); assert(key != NULL); - jbuf->offset += snprintf(jbuf->json + jbuf->offset, - jbuf->max_size - jbuf->offset, - "%s\"%s\": %1f", - evel_json_kv_comma(jbuf), - key, - value); + evel_json_printf(jbuf, + "%s\"%s\": %1f", + evel_json_kv_comma(jbuf), + key, + value); EVEL_EXIT(); } @@ -421,12 +521,11 @@ void evel_enc_kv_ull(EVEL_JSON_BUFFER * jbuf, assert(jbuf != NULL); assert(key != NULL); - jbuf->offset += snprintf(jbuf->json + jbuf->offset, - jbuf->max_size - jbuf->offset, - "%s\"%s\": %llu", - evel_json_kv_comma(jbuf), - key, - value); + evel_json_printf(jbuf, + "%s\"%s\": %llu", + evel_json_kv_comma(jbuf), + key, + value); EVEL_EXIT(); } @@ -493,18 +592,20 @@ void evel_enc_kv_time(EVEL_JSON_BUFFER * jbuf, assert(key != NULL); assert(time != NULL); - jbuf->offset += snprintf(jbuf->json + jbuf->offset, - jbuf->max_size - jbuf->offset, - "%s\"%s\": \"", - evel_json_kv_comma(jbuf), - key); - jbuf->offset += strftime(jbuf->json + jbuf->offset, - jbuf->max_size - jbuf->offset, - EVEL_RFC2822_STRFTIME_FORMAT, - localtime(time)); - jbuf->offset += snprintf(jbuf->json + jbuf->offset, - jbuf->max_size - jbuf->offset, - "\""); + evel_json_printf(jbuf, + "%s\"%s\": \"", + evel_json_kv_comma(jbuf), + key); + + char time_buf[128] = { 0 }; + strftime(time_buf, + sizeof(time_buf), + EVEL_RFC2822_STRFTIME_FORMAT, + localtime(time)); + evel_json_printf(jbuf, time_buf); + + evel_json_printf(jbuf, "\""); + EVEL_EXIT(); } @@ -532,12 +633,11 @@ void evel_enc_version(EVEL_JSON_BUFFER * jbuf, ver = (float)major_version + (float)minor_version/10.0; - jbuf->offset += snprintf(jbuf->json + jbuf->offset, - jbuf->max_size - jbuf->offset, - "%s\"%s\": \"%.1f\"", - evel_json_kv_comma(jbuf), - key, - ver); + evel_json_printf(jbuf, + "%s\"%s\": \"%.1f\"", + evel_json_kv_comma(jbuf), + key, + ver); EVEL_EXIT(); } @@ -597,11 +697,11 @@ void evel_json_open_named_list(EVEL_JSON_BUFFER * jbuf, assert(jbuf != NULL); assert(key != NULL); - jbuf->offset += snprintf(jbuf->json + jbuf->offset, - jbuf->max_size - jbuf->offset, - "%s\"%s\": [", - evel_json_kv_comma(jbuf), - key); + evel_json_printf(jbuf, + "%s\"%s\": [", + evel_json_kv_comma(jbuf), + key); + jbuf->depth++; EVEL_EXIT(); @@ -621,9 +721,8 @@ void evel_json_close_list(EVEL_JSON_BUFFER * jbuf) /***************************************************************************/ assert(jbuf != NULL); - jbuf->offset += snprintf(jbuf->json + jbuf->offset, - jbuf->max_size - jbuf->offset, - "]"); + evel_json_printf(jbuf, "]"); + jbuf->depth--; EVEL_EXIT(); @@ -655,16 +754,13 @@ void evel_enc_list_item(EVEL_JSON_BUFFER * jbuf, /***************************************************************************/ if (jbuf->json[jbuf->offset - 1] != '[') { - jbuf->offset += snprintf(jbuf->json + jbuf->offset, - jbuf->max_size - jbuf->offset, - ", "); + evel_json_printf(jbuf, ", "); } va_start(largs, format); - jbuf->offset += vsnprintf(jbuf->json + jbuf->offset, - jbuf->max_size - jbuf->offset, - format, - largs); + + evel_json_vprintf(jbuf, format, largs); + va_end(largs); EVEL_EXIT(); @@ -725,11 +821,11 @@ void evel_json_open_named_object(EVEL_JSON_BUFFER * jbuf, assert(jbuf != NULL); assert(key != NULL); - jbuf->offset += snprintf(jbuf->json + jbuf->offset, - jbuf->max_size - jbuf->offset, - "%s\"%s\": {", - evel_json_kv_comma(jbuf), - key); + evel_json_printf(jbuf, + "%s\"%s\": {", + evel_json_kv_comma(jbuf), + key); + jbuf->depth++; EVEL_EXIT(); @@ -760,10 +856,10 @@ void evel_json_open_object(EVEL_JSON_BUFFER * jbuf) comma = ""; } - jbuf->offset += snprintf(jbuf->json + jbuf->offset, - jbuf->max_size - jbuf->offset, - "%s{", - comma); + evel_json_printf(jbuf, + "%s{", + comma); + jbuf->depth++; EVEL_EXIT(); @@ -783,9 +879,8 @@ void evel_json_close_object(EVEL_JSON_BUFFER * jbuf) /***************************************************************************/ assert(jbuf != NULL); - jbuf->offset += snprintf(jbuf->json + jbuf->offset, - jbuf->max_size - jbuf->offset, - "}"); + evel_json_printf(jbuf, "}"); + jbuf->depth--; EVEL_EXIT(); |