]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: json-parser - Fail if strings contain NULs
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Wed, 6 May 2020 09:38:22 +0000 (12:38 +0300)
committertimo.sirainen <timo.sirainen@open-xchange.com>
Wed, 7 Oct 2020 13:57:26 +0000 (13:57 +0000)
Previous behavior was to just truncate the string, which could be worse than
failing entirely.

src/lib/json-parser.c
src/lib/test-json-parser.c

index adcd6fc181a9f7ab857a7d2bafed062b961a9990..3c645868d39c4c2141de061b499dfbe7745d2753 100644 (file)
@@ -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;
index 09e654d92387e65404ce91f5fff48ef678c52b64..037802e8327abfab3589be10a8dd2c9bc74fb625 100644 (file)
@@ -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();
 }