From: Timo Sirainen Date: Wed, 6 May 2020 09:38:22 +0000 (+0300) Subject: lib: json-parser - Fail if strings contain NULs X-Git-Tag: 2.3.13~126 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a4057ea644636ad38f28f66c29ce91ea13ff5039;p=thirdparty%2Fdovecot%2Fcore.git lib: json-parser - Fail if strings contain NULs Previous behavior was to just truncate the string, which could be worse than failing entirely. --- diff --git a/src/lib/json-parser.c b/src/lib/json-parser.c index adcd6fc181..3c645868d3 100644 --- a/src/lib/json-parser.c +++ b/src/lib/json-parser.c @@ -269,6 +269,10 @@ static int json_parse_unicode_escape(struct json_parser *parser) t_strdup_printf("Invalid unicode character U+%04x", chr); return -1; } + if (chr == 0) { + parser->error = "\\u0000 not supported in strings"; + return -1; + } uni_ucs4_to_utf8_c(chr, parser->value); parser->data += 3; return 1; @@ -295,9 +299,8 @@ static int json_parse_string(struct json_parser *parser, bool allow_skip, *value_r = str_c(parser->value); return 1; } - if (*parser->data != '\\') - str_append_c(parser->value, *parser->data); - else { + switch (*parser->data) { + case '\\': if (++parser->data == parser->end) return 0; switch (*parser->data) { @@ -328,6 +331,13 @@ static int json_parse_string(struct json_parser *parser, bool allow_skip, default: return -1; } + break; + case '\0': + parser->error = "NULs not supported in strings"; + return -1; + default: + str_append_c(parser->value, *parser->data); + break; } } return 0; diff --git a/src/lib/test-json-parser.c b/src/lib/test-json-parser.c index 09e654d923..037802e832 100644 --- a/src/lib/test-json-parser.c +++ b/src/lib/test-json-parser.c @@ -309,7 +309,8 @@ static void test_json_parser_skip_object_fields(void) } static int -test_json_parse_input(const char *test_input, enum json_parser_flags flags) +test_json_parse_input(const void *test_input, size_t test_input_size, + enum json_parser_flags flags) { struct json_parser *parser; struct istream *input; @@ -317,7 +318,7 @@ test_json_parse_input(const char *test_input, enum json_parser_flags flags) const char *value, *error; int ret = 0; - input = test_istream_create_data(test_input, strlen(test_input)); + input = test_istream_create_data(test_input, test_input_size); parser = json_parser_init_flags(input, flags); while (json_parse_next(parser, &type, &value) > 0) ret++; @@ -346,7 +347,9 @@ static void test_json_parser_primitive_values(void) test_begin("json_parser (primitives)"); for (i = 0; i < N_ELEMENTS(test_inputs); i++) - test_assert_idx(test_json_parse_input(test_inputs[i].str, JSON_PARSER_NO_ROOT_OBJECT) == test_inputs[i].ret, i); + test_assert_idx(test_json_parse_input(test_inputs[i].str, + strlen(test_inputs[i].str), + JSON_PARSER_NO_ROOT_OBJECT) == test_inputs[i].ret, i); test_end(); } @@ -371,7 +374,25 @@ static void test_json_parser_errors(void) test_begin("json parser error handling"); for (i = 0; i < N_ELEMENTS(test_inputs); i++) - test_assert_idx(test_json_parse_input(test_inputs[i], 0) < 0, i); + test_assert_idx(test_json_parse_input(test_inputs[i], + strlen(test_inputs[i]), + 0) < 0, i); + test_end(); +} + +static void test_json_parser_nuls_in_string(void) +{ + static const unsigned char test_input[] = + { '{', '"', 'k', '"', ':', '"', '\0', '"', '}' }; + static const unsigned char test_input2[] = + { '{', '"', 'k', '"', ':', '"', '\\', '\0', '"', '}' }; + static const unsigned char test_input3[] = + { '{', '"', 'k', '"', ':', '"', '\\', 'u', '0', '0', '0', '0', '"', '}' }; + + test_begin("json parser nuls in string"); + test_assert(test_json_parse_input(test_input, sizeof(test_input), 0) < 0); + test_assert(test_json_parse_input(test_input2, sizeof(test_input2), 0) < 0); + test_assert(test_json_parse_input(test_input3, sizeof(test_input3), 0) < 0); test_end(); } @@ -405,6 +426,7 @@ void test_json_parser(void) test_json_parser_skip_object_fields(); test_json_parser_primitive_values(); test_json_parser_errors(); + test_json_parser_nuls_in_string(); test_json_append_escaped(); test_json_append_escaped_data(); }