Skip to content

Limit recursion to 1000 by default #106

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions json.h
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,10 @@ enum json_parse_error_e {
JSON value. */
json_parse_error_unexpected_trailing_characters,

/* the JSON has too many nested objects & arrays - to prevent a stack
overflow, the library only supports recursion up to JSON_MAX_RECURSION */
json_parse_error_recursion,

/* catch-all error for everything else that exploded (real bad chi!). */
json_parse_error_unknown
};
Expand Down Expand Up @@ -464,6 +468,11 @@ typedef struct json_parse_result_s {
#pragma warning(disable : 5045)
#endif

/* set recursion limit for recursing nested arrays & objects */
#ifndef JSON_MAX_RECURSION
#define JSON_MAX_RECURSION 1000
#endif

struct json_parse_state_s {
const char *src;
size_t size;
Expand All @@ -477,6 +486,7 @@ struct json_parse_state_s {
size_t line_offset; /* (offset-line_offset) is the character number (in
bytes). */
size_t error;
size_t recursion;
};

json_weak int json_hexadecimal_digit(const char c);
Expand Down Expand Up @@ -929,6 +939,12 @@ int json_get_object_size(struct json_parse_state_s *state,
int allow_comma = 0;
int found_closing_brace = 0;

if (++state->recursion > JSON_MAX_RECURSION) {
// recursion error
state->error = json_parse_error_recursion;
return 1;
}

if (is_global_object) {
/* if we found an opening '{' of an object, we actually have a normal JSON
* object at the root of the DOM... */
Expand All @@ -941,6 +957,7 @@ int json_get_object_size(struct json_parse_state_s *state,
if (!is_global_object) {
if ('{' != src[state->offset]) {
state->error = json_parse_error_unknown;
--state->recursion;
return 1;
}

Expand All @@ -952,13 +969,15 @@ int json_get_object_size(struct json_parse_state_s *state,

if ((state->offset == size) && !is_global_object) {
state->error = json_parse_error_premature_end_of_buffer;
--state->recursion;
return 1;
}

do {
if (!is_global_object) {
if (json_skip_all_skippables(state)) {
state->error = json_parse_error_premature_end_of_buffer;
--state->recursion;
return 1;
}

Expand Down Expand Up @@ -991,6 +1010,7 @@ int json_get_object_size(struct json_parse_state_s *state,
} else {
/* otherwise we are required to have a comma, and we found none. */
state->error = json_parse_error_expected_comma_or_closing_bracket;
--state->recursion;
return 1;
}

Expand All @@ -999,6 +1019,7 @@ int json_get_object_size(struct json_parse_state_s *state,
} else {
if (json_skip_all_skippables(state)) {
state->error = json_parse_error_premature_end_of_buffer;
--state->recursion;
return 1;
}
}
Expand All @@ -1007,23 +1028,27 @@ int json_get_object_size(struct json_parse_state_s *state,
if (json_get_key_size(state)) {
/* key parsing failed! */
state->error = json_parse_error_invalid_string;
--state->recursion;
return 1;
}

if (json_skip_all_skippables(state)) {
state->error = json_parse_error_premature_end_of_buffer;
--state->recursion;
return 1;
}

if (json_parse_flags_allow_equals_in_object & flags_bitset) {
const char current = src[state->offset];
if ((':' != current) && ('=' != current)) {
state->error = json_parse_error_expected_colon;
--state->recursion;
return 1;
}
} else {
if (':' != src[state->offset]) {
state->error = json_parse_error_expected_colon;
--state->recursion;
return 1;
}
}
Expand All @@ -1033,11 +1058,13 @@ int json_get_object_size(struct json_parse_state_s *state,

if (json_skip_all_skippables(state)) {
state->error = json_parse_error_premature_end_of_buffer;
--state->recursion;
return 1;
}

if (json_get_value_size(state, /* is_global_object = */ 0)) {
/* value parsing failed! */
--state->recursion;
return 1;
}

Expand All @@ -1048,10 +1075,12 @@ int json_get_object_size(struct json_parse_state_s *state,

if ((state->offset == size) && !is_global_object && !found_closing_brace) {
state->error = json_parse_error_premature_end_of_buffer;
--state->recursion;
return 1;
}

state->dom_size += sizeof(struct json_object_element_s) * elements;
--state->recursion;

return 0;
}
Expand All @@ -1064,9 +1093,16 @@ int json_get_array_size(struct json_parse_state_s *state) {
const char *const src = state->src;
const size_t size = state->size;

if (++state->recursion > JSON_MAX_RECURSION) {
// recursion error
state->error = json_parse_error_recursion;
return 1;
}

if ('[' != src[state->offset]) {
/* expected array to begin with leading '['. */
state->error = json_parse_error_unknown;
--state->recursion;
return 1;
}

Expand All @@ -1078,6 +1114,7 @@ int json_get_array_size(struct json_parse_state_s *state) {
while (state->offset < size) {
if (json_skip_all_skippables(state)) {
state->error = json_parse_error_premature_end_of_buffer;
--state->recursion;
return 1;
}

Expand All @@ -1088,6 +1125,7 @@ int json_get_array_size(struct json_parse_state_s *state) {
state->dom_size += sizeof(struct json_array_element_s) * elements;

/* finished the object! */
--state->recursion;
return 0;
}

Expand All @@ -1099,6 +1137,7 @@ int json_get_array_size(struct json_parse_state_s *state) {
allow_comma = 0;
} else if (!(json_parse_flags_allow_no_commas & flags_bitset)) {
state->error = json_parse_error_expected_comma_or_closing_bracket;
--state->recursion;
return 1;
}

Expand All @@ -1108,13 +1147,15 @@ int json_get_array_size(struct json_parse_state_s *state) {
} else {
if (json_skip_all_skippables(state)) {
state->error = json_parse_error_premature_end_of_buffer;
--state->recursion;
return 1;
}
}
}

if (json_get_value_size(state, /* is_global_object = */ 0)) {
/* value parsing failed! */
--state->recursion;
return 1;
}

Expand All @@ -1126,6 +1167,7 @@ int json_get_array_size(struct json_parse_state_s *state) {
/* we consumed the entire input before finding the closing ']' of the array!
*/
state->error = json_parse_error_premature_end_of_buffer;
--state->recursion;
return 1;
}

Expand Down Expand Up @@ -2089,6 +2131,7 @@ json_parse_ex(const void *src, size_t src_size, size_t flags_bitset,
state.dom_size = 0;
state.data_size = 0;
state.flags_bitset = flags_bitset;
state.recursion = 0;

input_error = json_get_value_size(
&state, (int)(json_parse_flags_allow_global_object & state.flags_bitset));
Expand Down