From: Frantisek Sumsal Date: Fri, 10 Apr 2026 15:20:03 +0000 (+0200) Subject: sd-json: limit the stack depth during parsing as well X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1016dd315f94917cd0818a90bc09c99ef76ab556;p=thirdparty%2Fsystemd.git sd-json: limit the stack depth during parsing as well --- diff --git a/src/libsystemd/sd-json/sd-json.c b/src/libsystemd/sd-json/sd-json.c index 6245d471b7a..1fd006c7d95 100644 --- a/src/libsystemd/sd-json/sd-json.c +++ b/src/libsystemd/sd-json/sd-json.c @@ -3122,6 +3122,12 @@ static int json_parse_internal( goto finish; } + /* n_stack includes the top level entry, hence > instead of >= */ + if (n_stack > DEPTH_MAX) { + r = -ELNRNG; + goto finish; + } + if (!GREEDY_REALLOC(stack, n_stack+1)) { r = -ENOMEM; goto finish; @@ -3178,6 +3184,12 @@ static int json_parse_internal( goto finish; } + /* n_stack includes the top level entry, hence > instead of >= */ + if (n_stack > DEPTH_MAX) { + r = -ELNRNG; + goto finish; + } + if (!GREEDY_REALLOC(stack, n_stack+1)) { r = -ENOMEM; goto finish; diff --git a/src/test/test-json.c b/src/test/test-json.c index 016416dc4b7..8e2c8621c1f 100644 --- a/src/test/test-json.c +++ b/src/test/test-json.c @@ -556,6 +556,49 @@ TEST(depth) { fputs("\n", stdout); } +static char *prepare_nested_json(const char *open, unsigned depth) { + char *s, *p; + size_t olen; + + assert_se(open); + + olen = strlen(open); + s = p = new(char, olen * depth + 1); + if (!s) + return NULL; + + for (unsigned i = 0; i < depth; i++) + p = mempcpy(p, open, olen); + *p = '\0'; + + return s; +} + +TEST(parse_depth) { + _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; + _cleanup_free_ char *s = NULL; + + /* Refuse parsing > DEPTH_MAX (currently 2048) levels of nested arrays */ + s = prepare_nested_json("[", 2049); + ASSERT_ERROR(sd_json_parse(s, 0, &v, NULL, NULL), ELNRNG); + s = mfree(s); + + /* Same for nested objects */ + s = prepare_nested_json("{\"a\":", 2049); + ASSERT_ERROR(sd_json_parse(s, 0, &v, NULL, NULL), ELNRNG); + s = mfree(s); + + /* <= DEPTH_MAX levels of nested arrays should be refused by EINVAL + * later in the parsing process */ + s = prepare_nested_json("[", 2048); + ASSERT_ERROR(sd_json_parse(s, 0, &v, NULL, NULL), EINVAL); + s = mfree(s); + + /* And the same for nested objects */ + s = prepare_nested_json("{\"a\":", 2048); + ASSERT_ERROR(sd_json_parse(s, 0, &v, NULL, NULL), EINVAL); +} + TEST(normalize) { _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL, *w = NULL; _cleanup_free_ char *t = NULL;