On Mon, Jun 16, 2025 at 12:03:21AM +0300, Adrian Bunk wrote: > Package: release.debian.org > Severity: normal > Tags: bookworm moreinfo > User: release.debian....@packages.debian.org > Usertags: pu > X-Debbugs-Cc: secur...@debian.org,Maytham Alsudany <maytha8the...@gmail.com> > > * CVE-2023-26819: rejection of valid texts (Closes: #1103687) > * CVE-2023-53154: heap buffer overflow > > Tagged moreinfo, as question to the security team whether they want > this in pu or as DSA.
And here comes the debdiff I forgot. cu Adrian
diffstat for cjson-1.7.15 cjson-1.7.15 changelog | 8 patches/0001-allocate-memory-for-the-temporary-buffer.patch | 187 ++++++++++++ patches/0002-Fix-heap-buffer-overflow.patch | 29 + patches/series | 2 4 files changed, 226 insertions(+) diff -Nru cjson-1.7.15/debian/changelog cjson-1.7.15/debian/changelog --- cjson-1.7.15/debian/changelog 2024-06-23 09:27:41.000000000 +0300 +++ cjson-1.7.15/debian/changelog 2025-06-13 19:20:51.000000000 +0300 @@ -1,3 +1,11 @@ +cjson (1.7.15-1+deb12u3) bookworm; urgency=medium + + * Non-maintainer upload. + * CVE-2023-26819: rejection of valid texts (Closes: #1103687) + * CVE-2023-53154: heap buffer overflow + + -- Adrian Bunk <b...@debian.org> Fri, 13 Jun 2025 19:20:51 +0300 + cjson (1.7.15-1+deb12u2) bookworm; urgency=medium * Non-maintainer upload. diff -Nru cjson-1.7.15/debian/patches/0001-allocate-memory-for-the-temporary-buffer.patch cjson-1.7.15/debian/patches/0001-allocate-memory-for-the-temporary-buffer.patch --- cjson-1.7.15/debian/patches/0001-allocate-memory-for-the-temporary-buffer.patch 1970-01-01 02:00:00.000000000 +0200 +++ cjson-1.7.15/debian/patches/0001-allocate-memory-for-the-temporary-buffer.patch 2025-06-13 19:20:24.000000000 +0300 @@ -0,0 +1,187 @@ +From 16f21a59bb85c5cec8ac236bb42318319d456365 Mon Sep 17 00:00:00 2001 +From: PeterAlfredLee <peteralfred...@gmail.com> +Date: Mon, 21 Apr 2025 15:18:10 +0800 +Subject: allocate memory for the temporary buffer + +Allocate memory for the temporary buffer when paring numbers. +This fixes CVE-2023-26819 +--- + cJSON.c | 37 ++++++++++++++++++++++++++++++++----- + tests/misc_tests.c | 17 +++++++++++++++++ + tests/parse_number.c | 20 ++++++++++++++++++++ + 3 files changed, 69 insertions(+), 5 deletions(-) + +diff --git a/cJSON.c b/cJSON.c +index b6a328f..e5e62bc 100644 +--- a/cJSON.c ++++ b/cJSON.c +@@ -306,9 +306,11 @@ static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_bu + { + double number = 0; + unsigned char *after_end = NULL; +- unsigned char number_c_string[64]; ++ unsigned char *number_c_string; + unsigned char decimal_point = get_decimal_point(); + size_t i = 0; ++ size_t number_string_length = 0; ++ cJSON_bool has_decimal_point = false; + + if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { +@@ -318,7 +320,7 @@ static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_bu + /* copy the number into a temporary buffer and replace '.' with the decimal point + * of the current locale (for strtod) + * This also takes care of '\0' not necessarily being available for marking the end of the input */ +- for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) ++ for (i = 0; can_access_at_index(input_buffer, i); i++) + { + switch (buffer_at_offset(input_buffer)[i]) + { +@@ -336,11 +338,12 @@ static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_bu + case '-': + case 'e': + case 'E': +- number_c_string[i] = buffer_at_offset(input_buffer)[i]; ++ number_string_length++; + break; + + case '.': +- number_c_string[i] = decimal_point; ++ number_string_length++; ++ has_decimal_point = true; + break; + + default: +@@ -348,11 +351,33 @@ static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_bu + } + } + loop_end: +- number_c_string[i] = '\0'; ++ /* malloc for temporary buffer, add 1 for '\0' */ ++ number_c_string = (unsigned char *) input_buffer->hooks.allocate(number_string_length + 1); ++ if (number_c_string == NULL) ++ { ++ return false; /* allocation failure */ ++ } ++ ++ memcpy(number_c_string, buffer_at_offset(input_buffer), number_string_length); ++ number_c_string[number_string_length] = '\0'; ++ ++ if (has_decimal_point) ++ { ++ for (i = 0; i < number_string_length; i++) ++ { ++ if (number_c_string[i] == '.') ++ { ++ /* replace '.' with the decimal point of the current locale (for strtod) */ ++ number_c_string[i] = decimal_point; ++ } ++ } ++ } + + number = strtod((const char*)number_c_string, (char**)&after_end); + if (number_c_string == after_end) + { ++ /* free the temporary buffer */ ++ input_buffer->hooks.deallocate(number_c_string); + return false; /* parse_error */ + } + +@@ -375,6 +400,8 @@ loop_end: + item->type = cJSON_Number; + + input_buffer->offset += (size_t)(after_end - number_c_string); ++ /* free the temporary buffer */ ++ input_buffer->hooks.deallocate(number_c_string); + return true; + } + +diff --git a/tests/misc_tests.c b/tests/misc_tests.c +index 8031c0d..ae4681a 100644 +--- a/tests/misc_tests.c ++++ b/tests/misc_tests.c +@@ -671,6 +671,22 @@ static void cjson_set_valuestring_to_object_should_not_leak_memory(void) + cJSON_Delete(root); + } + ++static void cjson_parse_big_numbers_should_not_report_error(void) ++{ ++ cJSON *valid_big_number_json_object1 = cJSON_Parse("{\"a\": true, \"b\": [ null,9999999999999999999999999999999999999999999999912345678901234567]}"); ++ cJSON *valid_big_number_json_object2 = cJSON_Parse("{\"a\": true, \"b\": [ null,999999999999999999999999999999999999999999999991234567890.1234567E3]}"); ++ const char *invalid_big_number_json1 = "{\"a\": true, \"b\": [ null,99999999999999999999999999999999999999999999999.1234567890.1234567]}"; ++ const char *invalid_big_number_json2 = "{\"a\": true, \"b\": [ null,99999999999999999999999999999999999999999999999E1234567890e1234567]}"; ++ ++ TEST_ASSERT_NOT_NULL(valid_big_number_json_object1); ++ TEST_ASSERT_NOT_NULL(valid_big_number_json_object2); ++ TEST_ASSERT_NULL_MESSAGE(cJSON_Parse(invalid_big_number_json1), "Invalid big number JSONs should not be parsed."); ++ TEST_ASSERT_NULL_MESSAGE(cJSON_Parse(invalid_big_number_json2), "Invalid big number JSONs should not be parsed."); ++ ++ cJSON_Delete(valid_big_number_json_object1); ++ cJSON_Delete(valid_big_number_json_object2); ++} ++ + int CJSON_CDECL main(void) + { + UNITY_BEGIN(); +@@ -700,6 +716,7 @@ int CJSON_CDECL main(void) + RUN_TEST(cjson_add_item_to_object_should_not_use_after_free_when_string_is_aliased); + RUN_TEST(cjson_delete_item_from_array_should_not_broken_list_structure); + RUN_TEST(cjson_set_valuestring_to_object_should_not_leak_memory); ++ RUN_TEST(cjson_parse_big_numbers_should_not_report_error); + + return UNITY_END(); + } +diff --git a/tests/parse_number.c b/tests/parse_number.c +index 4cb72ec..defda4a 100644 +--- a/tests/parse_number.c ++++ b/tests/parse_number.c +@@ -48,6 +48,7 @@ static void assert_parse_number(const char *string, int integer, double real) + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + buffer.content = (const unsigned char*)string; + buffer.length = strlen(string) + sizeof(""); ++ buffer.hooks = global_hooks; + + TEST_ASSERT_TRUE(parse_number(item, &buffer)); + assert_is_number(item); +@@ -55,6 +56,17 @@ static void assert_parse_number(const char *string, int integer, double real) + TEST_ASSERT_EQUAL_DOUBLE(real, item->valuedouble); + } + ++static void assert_parse_big_number(const char *string) ++{ ++ parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; ++ buffer.content = (const unsigned char*)string; ++ buffer.length = strlen(string) + sizeof(""); ++ buffer.hooks = global_hooks; ++ ++ TEST_ASSERT_TRUE(parse_number(item, &buffer)); ++ assert_is_number(item); ++} ++ + static void parse_number_should_parse_zero(void) + { + assert_parse_number("0", 0, 0); +@@ -96,6 +108,13 @@ static void parse_number_should_parse_negative_reals(void) + assert_parse_number("-123e-128", 0, -123e-128); + } + ++static void parse_number_should_parse_big_numbers(void) ++{ ++ assert_parse_big_number("9999999999999999999999999999999999999999999999912345678901234567"); ++ assert_parse_big_number("9999999999999999999999999999999999999999999999912345678901234567E10"); ++ assert_parse_big_number("999999999999999999999999999999999999999999999991234567890.1234567"); ++} ++ + int CJSON_CDECL main(void) + { + /* initialize cJSON item */ +@@ -106,5 +125,6 @@ int CJSON_CDECL main(void) + RUN_TEST(parse_number_should_parse_positive_integers); + RUN_TEST(parse_number_should_parse_positive_reals); + RUN_TEST(parse_number_should_parse_negative_reals); ++ RUN_TEST(parse_number_should_parse_big_numbers); + return UNITY_END(); + } +-- +2.30.2 + diff -Nru cjson-1.7.15/debian/patches/0002-Fix-heap-buffer-overflow.patch cjson-1.7.15/debian/patches/0002-Fix-heap-buffer-overflow.patch --- cjson-1.7.15/debian/patches/0002-Fix-heap-buffer-overflow.patch 1970-01-01 02:00:00.000000000 +0200 +++ cjson-1.7.15/debian/patches/0002-Fix-heap-buffer-overflow.patch 2025-06-13 19:20:24.000000000 +0300 @@ -0,0 +1,29 @@ +From 77852dba3f539d057cae97f5f499ffba138b5084 Mon Sep 17 00:00:00 2001 +From: orri <o...@systemb.is> +Date: Tue, 30 Apr 2024 09:50:19 +0000 +Subject: Fix heap buffer overflow + +Fixes #800 +--- + cJSON.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/cJSON.c b/cJSON.c +index e5e62bc..6bc316b 100644 +--- a/cJSON.c ++++ b/cJSON.c +@@ -1682,6 +1682,11 @@ static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_bu + current_item = new_item; + } + ++ if (cannot_access_at_index(input_buffer, 1)) ++ { ++ goto fail; /* nothing comes after the comma */ ++ } ++ + /* parse the name of the child */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); +-- +2.30.2 + diff -Nru cjson-1.7.15/debian/patches/series cjson-1.7.15/debian/patches/series --- cjson-1.7.15/debian/patches/series 2024-06-23 09:27:41.000000000 +0300 +++ cjson-1.7.15/debian/patches/series 2025-06-13 19:20:51.000000000 +0300 @@ -1,2 +1,4 @@ 0001-add-null-checkings.patch 0002-add-null-check-to-cjson-setvaluestring.patch +0001-allocate-memory-for-the-temporary-buffer.patch +0002-Fix-heap-buffer-overflow.patch