summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndre Heinecke <aheinecke@gnupg.org>2019-02-27 14:27:47 +0100
committerAndre Heinecke <aheinecke@gnupg.org>2019-02-27 14:27:47 +0100
commit4a117859e7a512458ab78cfedfae0372805196b1 (patch)
treef69655c791adef71c28afec054399d1f1e5a8db4
parent73b2f40ae5e6881991dea609b0781373b28d7d30 (diff)
downloadgpgme-4a117859e7a512458ab78cfedfae0372805196b1.tar.gz
json: Limit recursion depth
* src/cJSON.c (MAX_DEPTH): New. Maximum recursion depth. (parse_value, parse_array, parse_object): Carry and check depth argument. (cJSON_ParseWithOpts): Initialize depth. -- This fixes a stack overflow if we get weird recursive json data. GnuPG-Bug-Id: T4331
-rw-r--r--src/cJSON.c54
1 files changed, 41 insertions, 13 deletions
diff --git a/src/cJSON.c b/src/cJSON.c
index 64a54c72..101d5568 100644
--- a/src/cJSON.c
+++ b/src/cJSON.c
@@ -52,6 +52,9 @@
/* Only use calloc. */
#define CALLOC_ONLY 1
+/* Maximum recursion depth */
+#define MAX_DEPTH 512
+
/* To avoid that a compiler optimizes certain memset calls away, these
macros may be used instead. */
#define wipememory2(_ptr,_set,_len) do { \
@@ -462,13 +465,13 @@ print_string (cJSON * item)
/* Predeclare these prototypes. */
static const char *parse_value (cJSON * item, const char *value,
- const char **ep);
+ const char **ep, size_t depth);
static char *print_value (cJSON * item, int depth, int fmt);
static const char *parse_array (cJSON * item, const char *value,
- const char **ep);
+ const char **ep, size_t depth);
static char *print_array (cJSON * item, int depth, int fmt);
static const char *parse_object (cJSON * item, const char *value,
- const char **ep);
+ const char **ep, size_t depth);
static char *print_object (cJSON * item, int depth, int fmt);
/* Utility to jump whitespace and cr/lf */
@@ -496,7 +499,7 @@ cJSON_ParseWithOpts (const char *value, const char **return_parse_end,
if (!c)
return NULL; /* memory fail */
- end = parse_value (c, skip (value), &ep);
+ end = parse_value (c, skip (value), &ep, 0);
if (!end)
{
cJSON_Delete (c);
@@ -548,8 +551,15 @@ cJSON_PrintUnformatted (cJSON * item)
/* Parser core - when encountering text, process appropriately. */
static const char *
-parse_value (cJSON * item, const char *value, const char **ep)
+parse_value (cJSON * item, const char *value, const char **ep,
+ size_t depth)
{
+ if (depth > MAX_DEPTH)
+ {
+ *ep = value;
+ return 0;
+ }
+
if (!value)
return 0; /* Fail on null. */
if (!strncmp (value, "null", 4))
@@ -578,11 +588,11 @@ parse_value (cJSON * item, const char *value, const char **ep)
}
if (*value == '[')
{
- return parse_array (item, value, ep);
+ return parse_array (item, value, ep, depth + 1);
}
if (*value == '{')
{
- return parse_object (item, value, ep);
+ return parse_object (item, value, ep, depth + 1);
}
*ep = value;
@@ -625,9 +635,17 @@ print_value (cJSON * item, int depth, int fmt)
/* Build an array from input text. */
static const char *
-parse_array (cJSON * item, const char *value, const char **ep)
+parse_array (cJSON * item, const char *value, const char **ep,
+ size_t depth)
{
cJSON *child;
+
+ if (depth > MAX_DEPTH)
+ {
+ *ep = value;
+ return 0;
+ }
+
if (*value != '[')
{
*ep = value;
@@ -643,7 +661,8 @@ parse_array (cJSON * item, const char *value, const char **ep)
if (!item->child)
return 0; /* memory fail */
/* skip any spacing, get the value. */
- value = skip (parse_value (child, skip (value), ep));
+ value = skip (parse_value (child, skip (value), ep,
+ depth + 1));
if (!value)
return 0;
@@ -655,7 +674,8 @@ parse_array (cJSON * item, const char *value, const char **ep)
child->next = new_item;
new_item->prev = child;
child = new_item;
- value = skip (parse_value (child, skip (value + 1), ep));
+ value = skip (parse_value (child, skip (value + 1), ep,
+ depth + 1));
if (!value)
return 0; /* memory fail */
}
@@ -747,9 +767,16 @@ print_array (cJSON * item, int depth, int fmt)
/* Build an object from the text. */
static const char *
-parse_object (cJSON * item, const char *value, const char **ep)
+parse_object (cJSON * item, const char *value, const char **ep,
+ size_t depth)
{
cJSON *child;
+ if (depth > MAX_DEPTH)
+ {
+ *ep = value;
+ return 0;
+ }
+
if (*value != '{')
{
*ep = value;
@@ -775,7 +802,8 @@ parse_object (cJSON * item, const char *value, const char **ep)
return 0;
} /* fail! */
/* skip any spacing, get the value. */
- value = skip (parse_value (child, skip (value + 1), ep));
+ value = skip (parse_value (child, skip (value + 1), ep,
+ depth + 1));
if (!value)
return 0;
@@ -798,7 +826,7 @@ parse_object (cJSON * item, const char *value, const char **ep)
return 0;
} /* fail! */
/* skip any spacing, get the value. */
- value = skip (parse_value (child, skip (value + 1), ep));
+ value = skip (parse_value (child, skip (value + 1), ep, depth + 1));
if (!value)
return 0;
}