From 4a117859e7a512458ab78cfedfae0372805196b1 Mon Sep 17 00:00:00 2001 From: Andre Heinecke Date: Wed, 27 Feb 2019 14:27:47 +0100 Subject: 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 --- src/cJSON.c | 54 +++++++++++++++++++++++++++++++++++++++++------------- 1 file 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; } -- cgit v1.2.1