diff options
author | Nicolas Badoux <n.badoux@hotmail.com> | 2024-08-30 13:36:22 +0200 |
---|---|---|
committer | Alan Wang <wp_scut@163.com> | 2024-09-23 19:08:58 +0800 |
commit | 9d1b229086a7b069fb5f4e3be0226a22480a6707 (patch) | |
tree | 812676bd307cdad10eda47e224d25b47318062a7 | |
parent | 078c4e6c53f13dff15f0eaac1611abb6379e0206 (diff) | |
download | cjson-9d1b229086a7b069fb5f4e3be0226a22480a6707.tar.gz cjson-9d1b229086a7b069fb5f4e3be0226a22480a6707.zip |
Added max recusrion depth for cJSONDuplicate to prevent stack exhaustion in case of circular reference
-rw-r--r-- | cJSON.c | 12 | ||||
-rw-r--r-- | cJSON.h | 6 | ||||
-rw-r--r-- | tests/misc_tests.c | 18 |
3 files changed, 35 insertions, 1 deletions
@@ -2737,8 +2737,15 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int co } /* Duplication */ +cJSON * cJSON_Duplicate_rec(const cJSON *item, size_t depth, cJSON_bool recurse); + CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) { + return cJSON_Duplicate_rec(item, 0, recurse ); +} + +cJSON * cJSON_Duplicate_rec(const cJSON *item, size_t depth, cJSON_bool recurse) +{ cJSON *newitem = NULL; cJSON *child = NULL; cJSON *next = NULL; @@ -2784,7 +2791,10 @@ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) child = item->child; while (child != NULL) { - newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ + if(depth >= CJSON_CIRCULAR_LIMIT) { + goto fail; + } + newchild = cJSON_Duplicate_rec(child, ++depth, true); /* Duplicate (with recurse) each item in the ->next chain */ if (!newchild) { goto fail; @@ -137,6 +137,12 @@ typedef int cJSON_bool; #define CJSON_NESTING_LIMIT 1000 #endif +/* Limits the length of circular references can be before cJSON rejects to parse them. + * This is to prevent stack overflows. */ +#ifndef CJSON_CIRCULAR_LIMIT +#define CJSON_CIRCULAR_LIMIT 10000 +#endif + /* returns the version of cJSON as a string */ CJSON_PUBLIC(const char*) cJSON_Version(void); diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 606b460..a96c2fd 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -219,6 +219,23 @@ static void cjson_should_not_parse_to_deeply_nested_jsons(void) TEST_ASSERT_NULL_MESSAGE(cJSON_Parse(deep_json), "To deep JSONs should not be parsed."); } +static void cjson_should_not_follow_too_deep_circular_references(void) +{ + cJSON *o = cJSON_CreateArray(); + cJSON *a = cJSON_CreateArray(); + cJSON *b = cJSON_CreateArray(); + cJSON *x; + + cJSON_AddItemToArray(o, a); + cJSON_AddItemToArray(a, b); + cJSON_AddItemToArray(b, o); + + x = cJSON_Duplicate(o, 1); + TEST_ASSERT_NULL(x); + cJSON_DetachItemFromArray(b, 0); + cJSON_Delete(o); +} + static void cjson_set_number_value_should_set_numbers(void) { cJSON number[1] = {{NULL, NULL, NULL, cJSON_Number, NULL, 0, 0, NULL}}; @@ -777,6 +794,7 @@ int CJSON_CDECL main(void) RUN_TEST(cjson_get_object_item_case_sensitive_should_not_crash_with_array); RUN_TEST(typecheck_functions_should_check_type); RUN_TEST(cjson_should_not_parse_to_deeply_nested_jsons); + RUN_TEST(cjson_should_not_follow_too_deep_circular_references); RUN_TEST(cjson_set_number_value_should_set_numbers); RUN_TEST(cjson_detach_item_via_pointer_should_detach_items); RUN_TEST(cjson_detach_item_via_pointer_should_return_null_if_item_prev_is_null); |