summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArun Raghavan <arun@arunraghavan.net>2016-06-01 17:18:36 +0530
committerArun Raghavan <arun@arunraghavan.net>2016-06-22 21:04:47 +0530
commit0c1dbf5c799272892da6f6a6f268b2207945f1f9 (patch)
tree7eb73dd27b3ad6ef6d7a4d7d94cfac672e5a5edf
parent5b1bd849023bcbf495cdb91eef9552734efb9ca2 (diff)
json: Error out for objects and arrays that are nested too deep
Signed-off-by: Arun Raghavan <arun@arunraghavan.net>
-rw-r--r--src/pulse/json.c27
-rw-r--r--src/tests/json-test.c2
2 files changed, 19 insertions, 10 deletions
diff --git a/src/pulse/json.c b/src/pulse/json.c
index 3c89a85e5..04501b72f 100644
--- a/src/pulse/json.c
+++ b/src/pulse/json.c
@@ -30,6 +30,8 @@
#include <pulsecore/refcnt.h>
#include <pulsecore/strbuf.h>
+#define MAX_NESTING_DEPTH 20 /* Arbitrary number to make sure we don't have a stack overflow */
+
struct pa_json_object {
PA_REFCNT_DECLARE;
pa_json_type type;
@@ -44,7 +46,7 @@ struct pa_json_object {
};
};
-static const char* parse_value(const char *str, const char *end, pa_json_object **obj);
+static const char* parse_value(const char *str, const char *end, pa_json_object **obj, unsigned int depth);
static pa_json_object* json_object_new(void) {
pa_json_object *obj;
@@ -303,7 +305,7 @@ error:
return NULL;
}
-static const char *parse_object(const char *str, pa_json_object *obj) {
+static const char *parse_object(const char *str, pa_json_object *obj, unsigned int depth) {
pa_json_object *name = NULL, *value = NULL;
obj->object_values = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func,
@@ -312,7 +314,7 @@ static const char *parse_object(const char *str, pa_json_object *obj) {
while (*str != '}') {
str++; /* Consume leading '{' or ',' */
- str = parse_value(str, ":", &name);
+ str = parse_value(str, ":", &name, depth + 1);
if (!str || pa_json_object_get_type(name) != PA_JSON_TYPE_STRING) {
pa_log("Could not parse key for object");
goto error;
@@ -321,7 +323,7 @@ static const char *parse_object(const char *str, pa_json_object *obj) {
/* Consume the ':' */
str++;
- str = parse_value(str, ",}", &value);
+ str = parse_value(str, ",}", &value, depth + 1);
if (!str) {
pa_log("Could not parse value for object");
goto error;
@@ -354,7 +356,7 @@ error:
return NULL;
}
-static const char *parse_array(const char *str, pa_json_object *obj) {
+static const char *parse_array(const char *str, pa_json_object *obj, unsigned int depth) {
pa_json_object *value;
obj->array_values = pa_idxset_new(NULL, NULL);
@@ -370,7 +372,7 @@ static const char *parse_array(const char *str, pa_json_object *obj) {
if (*str == ']')
break;
- str = parse_value(str, ",]", &value);
+ str = parse_value(str, ",]", &value, depth + 1);
if (!str) {
pa_log("Could not parse value for array");
goto error;
@@ -398,7 +400,7 @@ typedef enum {
JSON_PARSER_STATE_FINISH,
} json_parser_state;
-static const char* parse_value(const char *str, const char *end, pa_json_object **obj) {
+static const char* parse_value(const char *str, const char *end, pa_json_object **obj, unsigned int depth) {
json_parser_state state = JSON_PARSER_STATE_INIT;
pa_json_object *o;
@@ -406,6 +408,11 @@ static const char* parse_value(const char *str, const char *end, pa_json_object
o = json_object_new();
+ if (depth > MAX_NESTING_DEPTH) {
+ pa_log("Exceeded maximum permitted nesting depth of objects (%u)", MAX_NESTING_DEPTH);
+ goto error;
+ }
+
while (!is_end(*str, end)) {
switch (state) {
case JSON_PARSER_STATE_INIT:
@@ -424,10 +431,10 @@ static const char* parse_value(const char *str, const char *end, pa_json_object
str = parse_number(str, o);
state = JSON_PARSER_STATE_FINISH;
} else if (*str == '{') {
- str = parse_object(str, o);
+ str = parse_object(str, o, depth);
state = JSON_PARSER_STATE_FINISH;
} else if (*str == '[') {
- str = parse_array(str, o);
+ str = parse_array(str, o, depth);
state = JSON_PARSER_STATE_FINISH;
} else {
pa_log("Invalid JSON string: %s", str);
@@ -468,7 +475,7 @@ error:
pa_json_object* pa_json_parse(const char *str) {
pa_json_object *obj;
- str = parse_value(str, NULL, &obj);
+ str = parse_value(str, NULL, &obj, 0);
if (!str) {
pa_log("JSON parsing failed");
diff --git a/src/tests/json-test.c b/src/tests/json-test.c
index ca92877c0..3f8ed92d5 100644
--- a/src/tests/json-test.c
+++ b/src/tests/json-test.c
@@ -227,6 +227,8 @@ START_TEST(bad_test) {
"1." /* Bad number string */,
"1.e3" /* Bad number string */,
"-" /* Bad number string */,
+ "{ \"a\": { \"a\": { \"a\": { \"a\": { \"a\": { \"a\": { \"a\": { \"a\": { \"a\": { \"a\": { \"a\": { \"a\": { \"a\": { \"a\": { \"a\": { \"a\": { \"a\": { \"a\": { \"a\": { \"a\": { \"a\": { } } } } } } } } } } } } } } } } } } } } } }" /* Nested too deep */,
+ "[ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ { \"a\": \"b\" } ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ]" /* Nested too deep */,
};
for (i = 0; i < PA_ELEMENTSOF(bad_parse); i++) {