allocate memory for the temporary buffer

Allocate memory for the temporary buffer when paring numbers.
This fixes CVE-2023-26819
This commit is contained in:
PeterAlfredLee
2025-04-21 15:18:10 +08:00
committed by Alan Wang
parent 12c4bf1986
commit a328d65ad4
3 changed files with 69 additions and 5 deletions

37
cJSON.c
View File

@ -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;
}