diff options
Diffstat (limited to 'fluent-bit/tests/internal/fuzzers/parser_fuzzer.c')
-rw-r--r-- | fluent-bit/tests/internal/fuzzers/parser_fuzzer.c | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/fluent-bit/tests/internal/fuzzers/parser_fuzzer.c b/fluent-bit/tests/internal/fuzzers/parser_fuzzer.c new file mode 100644 index 00000000..a0355551 --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/parser_fuzzer.c @@ -0,0 +1,203 @@ +/* Fluent Bit + * ========== + * Copyright (C) 2019-2021 The Fluent Bit Authors + * Copyright (C) 2015-2018 Treasure Data Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <stdint.h> +#include <string.h> +#include <stdlib.h> +#include <fluent-bit/flb_utils.h> +#include <fluent-bit/flb_time.h> +#include <fluent-bit/flb_parser.h> +#include <fluent-bit/flb_parser_decoder.h> + +#include "flb_fuzz_header.h" + +#define TYPES_LEN 5 + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + TIMEOUT_GUARD + + char *format = NULL; + char *time_fmt = NULL; + char *time_key = NULL; + char *time_offset = NULL; + char *pregex = NULL; + struct flb_parser_types *types = NULL; + struct flb_config *fuzz_config = NULL; + struct flb_parser *fuzz_parser = NULL; + int time_keep = 0; + int types_len = 0; + + /* Set fuzzer-malloc chance of failure */ + flb_malloc_mod = 25000; + flb_malloc_p = 0; + + if (size < 100) { + return 0; + } + + /* json parser */ + fuzz_config = flb_config_init(); + + /* format + pregex */ + if (GET_MOD_EQ(4,0)) { + format = "json"; + } + else if (GET_MOD_EQ(4,1)) { + format = "regex"; +#ifdef PREG_FUZZ + pregex = malloc(30); + pregex[29] = '\0'; + memcpy(pregex, data, 29); + data += 29; + size -= 29; +#else + pregex = "^(?<INT>[^ ]+) (?<FLOAT>[^ ]+) (?<BOOL>[^ ]+) (?<STRING>.+)$"; +#endif + } + else if (GET_MOD_EQ(4,2)) { + format = "ltsv"; + } + else { + format = "logfmt"; + } + MOVE_INPUT(1); + + /* time_fmt */ + if (GET_MOD_EQ(2,1)) { + time_fmt = get_null_terminated(15, &data, &size); + } + MOVE_INPUT(1); + + /* time_key */ + if (GET_MOD_EQ(2,1)) { + time_key = get_null_terminated(15, &data, &size); + } + MOVE_INPUT(1); + + /* time_offset */ + if (GET_MOD_EQ(2,1)) { + time_offset = get_null_terminated(15, &data, &size); + } + MOVE_INPUT(1); + + /* time_keep */ + time_keep = (GET_MOD_EQ(2,1)) ? MK_TRUE : MK_FALSE; + MOVE_INPUT(1); + + /* types_str */ + if (GET_MOD_EQ(2,1)) { + types = flb_malloc(sizeof(struct flb_parser_types) * TYPES_LEN); + char *parser_type_keys[5] = {"AAA", "BBB", "CCC", "DDD", "EEE" }; + int parser_types[5] = {FLB_PARSER_TYPE_INT, FLB_PARSER_TYPE_FLOAT, + FLB_PARSER_TYPE_BOOL, FLB_PARSER_TYPE_STRING, + FLB_PARSER_TYPE_HEX}; + for (int i = 0; i < TYPES_LEN; i++) { + types[i].key = strdup(parser_type_keys[i]); + types[i].key_len = strlen(parser_type_keys[i]); + types[i].type = parser_types[i]; + } + types_len = TYPES_LEN; + } + MOVE_INPUT(1); + + /* decoders */ + struct mk_list *list = NULL; + if (GET_MOD_EQ(2,1)) { + MOVE_INPUT(1); + list = flb_malloc(sizeof(struct mk_list)); + mk_list_init(list); + + struct flb_parser_dec *dec = malloc(sizeof(struct flb_parser_dec)); + dec->key = flb_sds_create_len("AAA", 3); + dec->buffer = flb_sds_create_size(FLB_PARSER_DEC_BUF_SIZE); + dec->add_extra_keys = FLB_TRUE; + mk_list_init(&dec->rules); + mk_list_add(&dec->_head, list); + + struct flb_parser_dec_rule *dec_rule = malloc(sizeof(struct flb_parser_dec_rule)); + dec_rule->type = (int)(data[0] % 0x02); + MOVE_INPUT(1); + dec_rule->backend = (int)(data[0] % 0x04); + MOVE_INPUT(1); + dec_rule->action = (int)data[0] % 0x03; + mk_list_add(&dec_rule->_head, &dec->rules); + + if (GET_MOD_EQ(2,1)) { + struct flb_parser_dec_rule *dec_rule2 = malloc(sizeof(struct flb_parser_dec_rule)); + dec_rule2->type = (int)(data[0] % 0x02); + MOVE_INPUT(1); + dec_rule2->backend = (int)(data[0] % 0x04); + MOVE_INPUT(1); + dec_rule->action = (int)data[0] % 0x03; + mk_list_add(&dec_rule2->_head, &dec->rules); + } + } + MOVE_INPUT(1); + /* print our config struct */ + flb_utils_print_setup(fuzz_config); + + /* now call into the parser */ + fuzz_parser = flb_parser_create("fuzzer", format, pregex, FLB_TRUE, + time_fmt, time_key, time_offset, time_keep, 0, FLB_FALSE, + types, types_len, list, fuzz_config); + + /* Second step is to use the random parser to parse random input */ + if (fuzz_parser != NULL) { + void *out_buf = NULL; + size_t out_size = 0; + struct flb_time out_time; + flb_parser_do(fuzz_parser, (char*)data, size, + &out_buf, &out_size, &out_time); + if (out_buf != NULL) { + free(out_buf); + } + flb_parser_destroy(fuzz_parser); + } + else { + /* Parser creation failed but we still need to clean + * up types and decoders */ + if (types != NULL) { + for (int i=0; i< TYPES_LEN; i++){ + flb_free(types[i].key); + } + flb_free(types); + } + if (list != NULL) { + flb_parser_decoder_list_destroy(list); + } + } + + /* Cleanup everything but the parser */ + flb_config_exit(fuzz_config); + if (time_fmt != NULL) { + flb_free(time_fmt); + } + if (time_key != NULL) { + flb_free(time_key); + } + if (time_offset != NULL) { + flb_free(time_offset); + } +#ifdef PREG_FUZZ + if (pregex != NULL) { + flb_free(pregex); + } +#endif + + return 0; +} |