Control: tags 1103687 + patch
Control: tags 1103687 + pending

Dear maintainer,

I've prepared an NMU for cjson (versioned as 1.7.18-3.1) and uploaded
it to DELAYED/2. Please feel free to tell me if I should cancel it.

cu
Adrian
diffstat for cjson-1.7.18 cjson-1.7.18

 changelog                                                   |    7 
 patches/0001-allocate-memory-for-the-temporary-buffer.patch |  187 ++++++++++++
 patches/series                                              |    1 
 3 files changed, 195 insertions(+)

diff -Nru cjson-1.7.18/debian/changelog cjson-1.7.18/debian/changelog
--- cjson-1.7.18/debian/changelog	2024-06-23 13:12:46.000000000 +0300
+++ cjson-1.7.18/debian/changelog	2025-06-13 19:02:53.000000000 +0300
@@ -1,3 +1,10 @@
+cjson (1.7.18-3.1) unstable; urgency=medium
+
+  * Non-maintainer upload.
+  * CVE-2023-26819: rejection of valid texts (Closes: #1103687)
+
+ -- Adrian Bunk <b...@debian.org>  Fri, 13 Jun 2025 19:02:53 +0300
+
 cjson (1.7.18-3) unstable; urgency=medium
 
   * autopkgtest: Set CC=gcc so cmake can find the compiler
diff -Nru cjson-1.7.18/debian/patches/0001-allocate-memory-for-the-temporary-buffer.patch cjson-1.7.18/debian/patches/0001-allocate-memory-for-the-temporary-buffer.patch
--- cjson-1.7.18/debian/patches/0001-allocate-memory-for-the-temporary-buffer.patch	1970-01-01 02:00:00.000000000 +0200
+++ cjson-1.7.18/debian/patches/0001-allocate-memory-for-the-temporary-buffer.patch	2025-06-13 19:02:53.000000000 +0300
@@ -0,0 +1,187 @@
+From 6d373bf9259f76f3fc30375a0d2544a919dc49f0 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 61483d9..c7a605b 100644
+--- a/cJSON.c
++++ b/cJSON.c
+@@ -308,9 +308,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))
+     {
+@@ -320,7 +322,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])
+         {
+@@ -338,11 +340,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:
+@@ -350,11 +353,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 */
+     }
+ 
+@@ -377,6 +402,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 94dd91a..0b7ac1d 100644
+--- a/tests/misc_tests.c
++++ b/tests/misc_tests.c
+@@ -749,6 +749,22 @@ static void deallocated_pointers_should_be_set_to_null(void)
+ #endif
+ }
+ 
++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();
+@@ -780,6 +796,7 @@ int CJSON_CDECL main(void)
+     RUN_TEST(cjson_set_valuestring_to_object_should_not_leak_memory);
+     RUN_TEST(cjson_set_bool_value_must_not_break_objects);
+     RUN_TEST(deallocated_pointers_should_be_set_to_null);
++    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.18/debian/patches/series cjson-1.7.18/debian/patches/series
--- cjson-1.7.18/debian/patches/series	1970-01-01 02:00:00.000000000 +0200
+++ cjson-1.7.18/debian/patches/series	2025-06-13 19:02:53.000000000 +0300
@@ -0,0 +1 @@
+0001-allocate-memory-for-the-temporary-buffer.patch

Reply via email to