mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-04 13:29:59 -05:00
json: Error out for objects and arrays that are nested too deep
Signed-off-by: Arun Raghavan <arun@arunraghavan.net>
This commit is contained in:
parent
5b1bd84902
commit
0c1dbf5c79
2 changed files with 19 additions and 10 deletions
|
|
@ -30,6 +30,8 @@
|
||||||
#include <pulsecore/refcnt.h>
|
#include <pulsecore/refcnt.h>
|
||||||
#include <pulsecore/strbuf.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 {
|
struct pa_json_object {
|
||||||
PA_REFCNT_DECLARE;
|
PA_REFCNT_DECLARE;
|
||||||
pa_json_type type;
|
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) {
|
static pa_json_object* json_object_new(void) {
|
||||||
pa_json_object *obj;
|
pa_json_object *obj;
|
||||||
|
|
@ -303,7 +305,7 @@ error:
|
||||||
return NULL;
|
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;
|
pa_json_object *name = NULL, *value = NULL;
|
||||||
|
|
||||||
obj->object_values = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func,
|
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 != '}') {
|
while (*str != '}') {
|
||||||
str++; /* Consume leading '{' or ',' */
|
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) {
|
if (!str || pa_json_object_get_type(name) != PA_JSON_TYPE_STRING) {
|
||||||
pa_log("Could not parse key for object");
|
pa_log("Could not parse key for object");
|
||||||
goto error;
|
goto error;
|
||||||
|
|
@ -321,7 +323,7 @@ static const char *parse_object(const char *str, pa_json_object *obj) {
|
||||||
/* Consume the ':' */
|
/* Consume the ':' */
|
||||||
str++;
|
str++;
|
||||||
|
|
||||||
str = parse_value(str, ",}", &value);
|
str = parse_value(str, ",}", &value, depth + 1);
|
||||||
if (!str) {
|
if (!str) {
|
||||||
pa_log("Could not parse value for object");
|
pa_log("Could not parse value for object");
|
||||||
goto error;
|
goto error;
|
||||||
|
|
@ -354,7 +356,7 @@ error:
|
||||||
return NULL;
|
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;
|
pa_json_object *value;
|
||||||
|
|
||||||
obj->array_values = pa_idxset_new(NULL, NULL);
|
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 == ']')
|
if (*str == ']')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
str = parse_value(str, ",]", &value);
|
str = parse_value(str, ",]", &value, depth + 1);
|
||||||
if (!str) {
|
if (!str) {
|
||||||
pa_log("Could not parse value for array");
|
pa_log("Could not parse value for array");
|
||||||
goto error;
|
goto error;
|
||||||
|
|
@ -398,7 +400,7 @@ typedef enum {
|
||||||
JSON_PARSER_STATE_FINISH,
|
JSON_PARSER_STATE_FINISH,
|
||||||
} json_parser_state;
|
} 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;
|
json_parser_state state = JSON_PARSER_STATE_INIT;
|
||||||
pa_json_object *o;
|
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();
|
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)) {
|
while (!is_end(*str, end)) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case JSON_PARSER_STATE_INIT:
|
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);
|
str = parse_number(str, o);
|
||||||
state = JSON_PARSER_STATE_FINISH;
|
state = JSON_PARSER_STATE_FINISH;
|
||||||
} else if (*str == '{') {
|
} else if (*str == '{') {
|
||||||
str = parse_object(str, o);
|
str = parse_object(str, o, depth);
|
||||||
state = JSON_PARSER_STATE_FINISH;
|
state = JSON_PARSER_STATE_FINISH;
|
||||||
} else if (*str == '[') {
|
} else if (*str == '[') {
|
||||||
str = parse_array(str, o);
|
str = parse_array(str, o, depth);
|
||||||
state = JSON_PARSER_STATE_FINISH;
|
state = JSON_PARSER_STATE_FINISH;
|
||||||
} else {
|
} else {
|
||||||
pa_log("Invalid JSON string: %s", str);
|
pa_log("Invalid JSON string: %s", str);
|
||||||
|
|
@ -468,7 +475,7 @@ error:
|
||||||
pa_json_object* pa_json_parse(const char *str) {
|
pa_json_object* pa_json_parse(const char *str) {
|
||||||
pa_json_object *obj;
|
pa_json_object *obj;
|
||||||
|
|
||||||
str = parse_value(str, NULL, &obj);
|
str = parse_value(str, NULL, &obj, 0);
|
||||||
|
|
||||||
if (!str) {
|
if (!str) {
|
||||||
pa_log("JSON parsing failed");
|
pa_log("JSON parsing failed");
|
||||||
|
|
|
||||||
|
|
@ -227,6 +227,8 @@ START_TEST(bad_test) {
|
||||||
"1." /* Bad number string */,
|
"1." /* Bad number string */,
|
||||||
"1.e3" /* Bad number string */,
|
"1.e3" /* Bad number string */,
|
||||||
"-" /* 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++) {
|
for (i = 0; i < PA_ELEMENTSOF(bad_parse); i++) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue