diff options
Diffstat (limited to '')
31 files changed, 3132 insertions, 0 deletions
diff --git a/fluent-bit/tests/internal/fuzzers/CMakeLists.txt b/fluent-bit/tests/internal/fuzzers/CMakeLists.txt new file mode 100644 index 00000000..e76be548 --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/CMakeLists.txt @@ -0,0 +1,60 @@ +set(UNIT_TESTS_FILES + aws_util_fuzzer.c + aws_credentials_fuzzer.c + base64_fuzzer.c + engine_fuzzer.c + cmetrics_decode_fuzz.c + config_fuzzer.c + config_random_fuzzer.c + ctrace_fuzzer.c + input_fuzzer.c + signv4_fuzzer.c + flb_json_fuzzer.c + flb_mp_fuzzer.c + filter_stdout_fuzzer.c + fstore_fuzzer.c + parser_fuzzer.c + parse_json_fuzzer.c + parse_logfmt_fuzzer.c + parse_ltsv_fuzzer.c + msgpack_parse_fuzzer.c + msgpack_to_gelf_fuzzer.c + multiline_fuzzer.c + pack_json_state_fuzzer.c + http_fuzzer.c + strp_fuzzer.c + utils_fuzzer.c + config_map_fuzzer.c + record_ac_fuzzer.c + config_yaml_fuzzer.c + ) + +# Prepare list of unit tests +foreach(source_file ${UNIT_TESTS_FILES}) + get_filename_component(source_file_we ${source_file} NAME_WE) + set(source_file_we flb-it-fuzz-${source_file_we}) + + add_executable( + ${source_file_we} + ${source_file} local_test.c + ) + + if(FLB_JEMALLOC) + target_link_libraries(${source_file_we} libjemalloc ${CMAKE_THREAD_LIBS_INIT}) + else() + target_link_libraries(${source_file_we} ${CMAKE_THREAD_LIBS_INIT}) + endif() + + if(FLB_STREAM_PROCESSOR) + target_link_libraries(${source_file_we} flb-sp) + endif() + + target_link_libraries(${source_file_we} fluent-bit-static) + + if (FLB_TESTS_OSSFUZZ) + add_executable(${source_file_we}_OSSFUZZ ${source_file}) + target_link_libraries(${source_file_we}_OSSFUZZ ${CMAKE_THREAD_LIBS_INIT}) + set_target_properties(${source_file_we}_OSSFUZZ PROPERTIES LINK_FLAGS $ENV{LIB_FUZZING_ENGINE}) + target_link_libraries(${source_file_we}_OSSFUZZ fluent-bit-static) + endif() +endforeach() diff --git a/fluent-bit/tests/internal/fuzzers/aws_credentials_fuzzer.c b/fluent-bit/tests/internal/fuzzers/aws_credentials_fuzzer.c new file mode 100644 index 00000000..d6ccb22e --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/aws_credentials_fuzzer.c @@ -0,0 +1,132 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2023 The Fluent Bit Authors + * + * 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 <fluent-bit.h> +#include <fluent-bit/flb_sds.h> +#include <fluent-bit/flb_aws_credentials.h> +#include <fluent-bit/flb_mem.h> +#include "flb_fuzz_header.h" + +int initialization_crutch() +{ + struct flb_config *config; + config = flb_config_init(); + if (config == NULL) { + return -1; + } + flb_config_exit(config); + return 0; +} + + +void fuzz_sts(const uint8_t *data, size_t size) { + char *sks_response = get_null_terminated(150, &data, &size); + + struct flb_aws_credentials *creds; + time_t expiration; + + creds = flb_parse_sts_resp(sks_response, &expiration); + if (creds != NULL) { + flb_aws_credentials_destroy(creds); + } + + if (size > 300) { + char *action = get_null_terminated(50, &data, &size); + char *role_arn = get_null_terminated(50, &data, &size); + char *session_name = get_null_terminated(50, &data, &size); + char *external_id = get_null_terminated(50, &data, &size); + char *identity_token = get_null_terminated(50, &data, &size); + + flb_sds_t s1 = flb_sts_uri(action, role_arn, session_name, + external_id, identity_token); + if (s1 != NULL) { + flb_sds_destroy(s1); + } + + flb_free(action); + flb_free(role_arn); + flb_free(session_name); + flb_free(external_id); + flb_free(identity_token); + } + + if (sks_response != NULL) { + flb_free(sks_response); + } +} + + +void fuzz_http(const uint8_t *data, size_t size) { + time_t expiration; + struct flb_aws_credentials *creds = NULL; + + char *response = get_null_terminated(250, &data, &size); + creds = flb_parse_http_credentials(response, 250, &expiration); + if (creds != NULL) { + flb_aws_credentials_destroy(creds); + } + flb_free(response); +} + + +void fuzz_process(const uint8_t *data, size_t size) { + char** tokens = NULL; + char *input = get_null_terminated(250, &data, &size); + tokens = parse_credential_process(input); + if (tokens != NULL) { + flb_free(tokens); + } + flb_free(input); +} + + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + /* Set flb_malloc_mod to be fuzzer-data dependent */ + if (size < 304) { + return 0; + } + flb_malloc_p = 0; + flb_malloc_mod = *(int*)data; + data += 4; + size -= 4; + + /* Avoid division by zero for modulo operations */ + if (flb_malloc_mod == 0) { + flb_malloc_mod = 1; + } + if (initialization_crutch() == -1) { + return 0; + } + + const uint8_t *data_copy = data; + size_t size_copy = size; + fuzz_sts(data_copy, size_copy); + + data_copy = data; + size_copy = size; + fuzz_http(data_copy, size_copy); + + data_copy = data; + size_copy = size; + fuzz_process(data_copy, size_copy); + + return 0; +} diff --git a/fluent-bit/tests/internal/fuzzers/aws_util_fuzzer.c b/fluent-bit/tests/internal/fuzzers/aws_util_fuzzer.c new file mode 100644 index 00000000..dcaa2b9e --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/aws_util_fuzzer.c @@ -0,0 +1,107 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2023 The Fluent Bit Authors + * + * 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 <fluent-bit.h> +#include <fluent-bit/flb_sds.h> +#include <fluent-bit/flb_aws_util.h> +#include <fluent-bit/flb_mem.h> +#include "flb_fuzz_header.h" + +int initialization_crutch() +{ + struct flb_config *config; + config = flb_config_init(); + if (config == NULL) { + return -1; + } + flb_config_exit(config); + return 0; +} + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + char *format = NULL; + char *tag = NULL; + char *tag_delimiter = NULL; + + /* Set flb_malloc_mod to be fuzzer-data dependent */ + if (size < 4) { + return 0; + } + flb_malloc_p = 0; + flb_malloc_mod = *(int*)data; + data += 4; + size -= 4; + + /* Avoid division by zero for modulo operations */ + if (flb_malloc_mod == 0) { + flb_malloc_mod = 1; + } + + if (size < 300) { + return 0; + } + + format = get_null_terminated(50, &data, &size); + tag = get_null_terminated(100, &data, &size); + tag_delimiter = get_null_terminated(100, &data, &size); + + struct tm day = { 0, 0, 0, 15, 7, 120}; + time_t t; + memset(&t, 0, sizeof(time_t)); + + if (format && tag && tag_delimiter) { + if (!initialization_crutch()) { + flb_sds_t s3_key_format = NULL; + s3_key_format = flb_get_s3_key(format, t, tag, tag_delimiter, 0); + if (s3_key_format) { + flb_sds_destroy(s3_key_format); + } + if (size > 200) { + char *json_val = get_null_terminated(100, &data, &size); + if (json_val != NULL) { + flb_sds_t s1 = flb_aws_error(json_val, strlen(json_val)); + if (s1 != NULL) { + flb_sds_destroy(s1); + } + flb_free(json_val); + } + char *xml_val = get_null_terminated(100, &data, &size); + if (xml_val != NULL) { + flb_sds_t s2 = flb_aws_xml_error(xml_val, strlen(xml_val)); + if (s2 != NULL) { + flb_sds_destroy(s2); + } + flb_free(xml_val); + } + } + } + } + if (format) { + flb_free(format); + } + if (tag) { + flb_free(tag); + } + if (tag_delimiter) { + flb_free(tag_delimiter); + } + return 0; +} diff --git a/fluent-bit/tests/internal/fuzzers/base64_fuzzer.c b/fluent-bit/tests/internal/fuzzers/base64_fuzzer.c new file mode 100644 index 00000000..90c4c08f --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/base64_fuzzer.c @@ -0,0 +1,20 @@ +#include <unistd.h> +#include <stdint.h> +#include <fluent-bit/flb_base64.h> +#include <fluent-bit/flb_mem.h> + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + char out[100]; + size_t olen; + + /* Set fuzzer-malloc chance of failure */ + flb_malloc_p = 0; + flb_malloc_mod = 25000; + + flb_base64_encode((unsigned char *) out, 100, + &olen, (unsigned char *)data, size); + flb_base64_decode((unsigned char *) out, 100, + &olen, (unsigned char *)data, size); + return 0; +} diff --git a/fluent-bit/tests/internal/fuzzers/cmetrics_decode_fuzz.c b/fluent-bit/tests/internal/fuzzers/cmetrics_decode_fuzz.c new file mode 100644 index 00000000..1d1098c0 --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/cmetrics_decode_fuzz.c @@ -0,0 +1,69 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2023 The Fluent Bit Authors + * + * 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 <cmetrics/cmt_decode_opentelemetry.h> +#include <cmetrics/cmt_decode_prometheus.h> + + +int +LLVMFuzzerTestOneInput(const uint8_t * data, size_t size) +{ + struct cfl_list decoded_contexts; + struct cmt *cmt = NULL; + size_t off = 0; + uint8_t decider; + int result; + + /* At least one byte is needed for deciding which decoder to use */ + if (size < 1) { + return 0; + } + + decider = data[0] % 3; + + /* Adjust data pointer since the first byte is used */ + data += 1; + size -= 1; + + /* Fuzz a given decoder */ + if (decider == 0) { + result = cmt_decode_opentelemetry_create(&decoded_contexts, data, size, + &off); + if (result == CMT_DECODE_OPENTELEMETRY_SUCCESS) { + cmt_decode_opentelemetry_destroy (&decoded_contexts); + } + } + else if (decider == 1) { + result = cmt_decode_msgpack_create(&cmt, (char *) data, size, &off); + if (result == 0) { + cmt_destroy(cmt); + } + } + else if (decider == 2) { + if (size == 0) { + return 0; + } + struct cmt_decode_prometheus_parse_opts opts; + result = cmt_decode_prometheus_create(&cmt, data, size, &opts); + if (result == CMT_DECODE_PROMETHEUS_SUCCESS) { + cmt_decode_prometheus_destroy(cmt); + } + } + return 0; +} diff --git a/fluent-bit/tests/internal/fuzzers/config_fuzzer.c b/fluent-bit/tests/internal/fuzzers/config_fuzzer.c new file mode 100644 index 00000000..5512dac2 --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/config_fuzzer.c @@ -0,0 +1,417 @@ +#include <stdint.h> +#include <string.h> +#include <stdlib.h> +#include <fluent-bit/flb_parser.h> +#include <fluent-bit/flb_slist.h> +#include <fluent-bit/flb_kv.h> +#include "flb_fuzz_header.h" + +/* A sample of configurations */ +char conf_file[] = "# Parser: no_year\n" +"# ===============\n" +"# the given format don't contain the Year, this is a common\n" +"# case on old Syslog implementations.\n" +"#\n" +"[PARSER]\n" +" Name no_year\n" +" Format json\n" +" Time_Key time\n" +" Time_Format %b %d %H:%M:%S\n" +" Time_Keep On\n" +"\n" +"# Parser: no_year_N\n" +"# =================\n" +"# Just for compatibility, check a string with no year but including Nanoseconds.\n" +"#\n" +"[PARSER]\n" +" Name no_year_N\n" +" Format json\n" +" Time_Key time\n" +" Time_Format %b %d %H:%M:%S.%L\n" +" Time_Keep On\n" +"\n" +"# Parser: no_year_NC\n" +"# =================\n" +"# Just for compatibility, check a string with no year but including Nanoseconds with comma as fractional separator.\n" +"#\n" +"[PARSER]\n" +" Name no_year_NC\n" +" Format json\n" +" Time_Key time\n" +" Time_Format %b %d %H:%M:%S,%L\n" +" Time_Keep On\n" +"\n" +"# Parser: no_year_TZ\n" +"# =================\n" +"# Time string with no year and including timezone\n" +"#\n" +"[PARSER]\n" +" Name no_year_TZ\n" +" Format json\n" +" Time_Key time\n" +" Time_Format %b %d %H:%M:%S %z\n" +" Time_Keep On\n" +"\n" +"# Parser: no_year_N_TZ\n" +"# ====================\n" +"# Time string with no year, nanoseconds and timezone\n" +"#\n" +"[PARSER]\n" +" Name no_year_N_TZ\n" +" Format json\n" +" Time_Key time\n" +" Time_Format %b %d %H:%M:%S.%L %z\n" +" Time_Keep On\n" +"\n" +"\n" +"# Parser: no_year_NC_TZ\n" +"# ====================\n" +"# Time string with no year, nanoseconds and timezone with comma as fractional separator.\n" +"#\n" +"[PARSER]\n" +" Name no_year_NC_TZ\n" +" Format json\n" +" Time_Key time\n" +" Time_Format %b %d %H:%M:%S,%L %z\n" +" Time_Keep On\n" +"\n" +"\n" +"# Parser: default_UTC\n" +"# ===================\n" +"# Time string with timezone in UTC\n" +"#\n" +"[PARSER]\n" +" Name default_UTC\n" +" Format json\n" +" Time_Key time\n" +" Time_Format %m/%d/%Y %H:%M:%S\n" +" Time_Keep On\n" +"\n" +"# Parser: default_UTC_Z\n" +"# =====================\n" +"# Time string with timezone in UTC and ending Z\n" +"#\n" +"[PARSER]\n" +" Name default_UTC_Z\n" +" Format json\n" +" Time_Key time\n" +" Time_Format %m/%d/%Y %H:%M:%SZ\n" +" Time_Keep On\n" +"\n" +"# Parser: default_UTC_N_Z\n" +"# =======================\n" +"# Time string with timezone in UTC, nanoseconds and ending Z\n" +"#\n" +"[PARSER]\n" +" Name default_UTC_N_Z\n" +" Format json\n" +" Time_Key time\n" +" Time_Format %m/%d/%Y %H:%M:%S.%LZ\n" +" Time_Keep On\n" +"\n" +"# Parser: default_UTC_NC_Z\n" +"# =======================\n" +"# Time string with timezone in UTC, nanoseconds with comma as fractional separator and ending Z\n" +"#\n" +"[PARSER]\n" +" Name default_UTC_NC_Z\n" +" Format json\n" +" Time_Key time\n" +" Time_Format %m/%d/%Y %H:%M:%S,%LZ\n" +" Time_Keep On\n" +"\n" +"# Parser: generic_TZ\n" +"# ==================\n" +"# Generic date with timezone\n" +"#\n" +"[PARSER]\n" +" Name generic_TZ\n" +" Format json\n" +" Time_Key time\n" +" Time_Format %m/%d/%Y %H:%M:%S %z\n" +" Time_Keep On\n" +"\n" +"# Parser: generic\n" +"# ===============\n" +"# Generic date\n" +"#\n" +"[PARSER]\n" +" Name generic\n" +" Format json\n" +" Time_Key time\n" +" Time_Format %m/%d/%Y %H:%M:%S\n" +" Time_Keep On\n" +"\n" +"# Parser: generic_N\n" +"# ===============\n" +"# Generic date with nanoseconds\n" +"#\n" +"[PARSER]\n" +" Name generic_N\n" +" Format json\n" +" Time_Key time\n" +" Time_Format %m/%d/%Y %H:%M:%S.%L\n" +" Time_Keep On\n" +"\n" +"# Parser: generic_NC\n" +"# ===============\n" +"# Generic date with nanoseconds with comma as fractional separator\n" +"#\n" +"[PARSER]\n" +" Name generic_NC\n" +" Format json\n" +" Time_Key time\n" +" Time_Format %m/%d/%Y %H:%M:%S,%L\n" +" Time_Keep On\n" +"\n" +"# Parser: generic_N_TZ\n" +"# ====================\n" +"# Generic date with nanoseconds and timezone\n" +"#\n" +"[PARSER]\n" +" Name generic_N_TZ\n" +" Format json\n" +" Time_Key time\n" +" Time_Format %m/%d/%Y %H:%M:%S.%L %z\n" +" Time_Keep On\n" +"\n" +"# Parser: generic_NC_TZ\n" +"# ====================\n" +"# Generic date with nanoseconds with comma as fractional separator and timezone\n" +"#\n" +"[PARSER]\n" +" Name generic_NC_TZ\n" +" Format json\n" +" Time_Key time\n" +" Time_Format %m/%d/%Y %H:%M:%S,%L %z\n" +" Time_Keep On\n" +"\n" +"# Parser: apache_error\n" +"# ====================\n" +"# Apache error log time format\n" +"#\n" +"[PARSER]\n" +" Name apache_error\n" +" Format json\n" +" Time_Key time\n" +" Time_Format %a %b %d %H:%M:%S.%L %Y\n" +" Time_Keep On\n" +"# Parser: mysql_quoted_stuff\n" +"# ====================\n" +"# Apache error log time format\n" +"#\n" +"[PARSER]\n" +" Name mysql_quoted_stuff\n" +" Format regex\n" +" Regex ^(?<time>.*?),(?<key001>.*)$\n" +" Time_Key time\n" +" Time_Format %Y-%M-%S %H:%M:%S\n" +" Time_Keep On\n" +" Decode_Field_As mysql_quoted key001\n" +"# Parser: REGEX_generic_NC_TZ\n" +"# ====================\n" +"# Generic date with nanoseconds with comma as fractional separator and timezone\n" +"#\n" +"[PARSER]\n" +" Name REGEX_generic_NC_TZ\n" +" Format regex\n" +" Regex ^(?<key001>[^ ]*) (?<key002>[^ ]*) (?<time>.+)$\n" +" Time_Key time\n" +" Time_Format %m/%d/%Y %H:%M:%S,%L %z\n" +" Time_Keep On\n" +"\n" +"# Parser: REGEX_apache_error\n" +"# ====================\n" +"# Apache error log time format\n" +"#\n" +"[PARSER]\n" +" Name REGEX_apache_error\n" +" Format regex\n" +" Regex ^(?<key001>[^ ]*) (?<key002>[^ ]*) (?<time>.+)$\n" +" Time_Key time\n" +" Time_Format %a %b %d %H:%M:%S.%L %Y\n" +" Time_Keep On\n" +"\n" +"\n" +"\n" +"# Parser: REGEX_mysql_quoted_stuff\n" +"# ====================\n" +"# Apache error log time format\n" +"#\n" +"[PARSER]\n" +" Name REGEX_mysql_quoted_stuff\n" +" Format regex\n" +" Regex ^(?<time>.*?),(?<key001>.*)$\n" +" Time_Key time\n" +" Time_Format %Y-%M-%S %H:%M:%S\n" +" Time_Keep On\n" +" Decode_Field_As mysql_quoted key001\n" +"\n" +"\n" +"\n" +"# Parser: REGEX2_mysql_quoted_stuff\n" +"# ====================\n" +"# Apache error log time format\n" +"#\n" +"[PARSER]\n" +" Name REGEX2_mysql_quoted_stuff\n" +" Format logfmt\n" +" Regex ^(?<time>.*?),(?<key001>.*)$\n" +" Time_Key time\n" +" Time_Format %Y-%M-%S %H:%M:%S\n" +" Time_Keep On\n" +" Decode_Field_As mysql_quoted key001\n" +" Types A1:integer A2:string A3:bool A4:float A5:hex\n" +"\n" +"\n" +"\n" +"# Parser: REGEX3_mysql_quoted_stuff\n" +"# ====================\n" +"# Apache error log time format\n" +"#\n" +"[PARSER]\n" +" Name REGEX3_mysql_quoted_stuff\n" +" Format json\n" +" Regex ^(?<time>.*?),(?<key001>.*)$\n" +" Time_Key time\n" +" Time_Format %Y-%M-%S %H:%M:%S\n" +" Time_Keep On\n" +" Decode_Field_As escaped_utf8 key001\n" +" Types A1:integer A2:string A3:bool A4:float A5:hex\n" +"\n" +"\n" +"\n" +"# Parser: REGEX33_mysql_quoted_stuff\n" +"# ====================\n" +"# Apache error log time format\n" +"#\n" +"[PARSER]\n" +" Name REGEX33_mysql_quoted_stuff\n" +" Format json\n" +" Regex ^(?<time>.*?),(?<key001>.*)$\n" +" Time_Key time\n" +" Time_Format %Y-%M-%S %H:%M:%S\n" +" Time_Keep On\n" +" Decode_Field_As escaped key001\n" +" Types A1:integer A2:string A3:bool A4:float A5:hex\n" +"\n" +"\n" +"\n" +"# Parser: REGEX4_mysql_quoted_stuff\n" +"# ====================\n" +"# Apache error log time format\n" +"#\n" +"[PARSER]\n" +" Name REGEX4_mysql_quoted_stuff\n" +" Format json\n" +" Regex ^(?<time>.*?),(?<key001>.*)$\n" +" Time_Key time\n" +" Time_Format %Y-%M-%S %H:%M:%S\n" +" Time_Keep On\n" +" Decode_Field_As json key001\n" +" Types A1:integer A2:string A3:bool A4:float A5:hex\n" +"[MULTILINE_PARSER]\n" +" name exception_test\n" +" type regex\n" +" flush_timeout 1000\n" +" rule \"start_state\" \"/(Dec \\d+ \\d+\\:\\d+\\:\\d+)(.*)/\" \"cont\"\n" +" rule \"cont\" \"/^\\s+at.*/\" \"cont\"\n"; + + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + /* Set fuzzer-malloc chance of failure */ + flb_malloc_p = 0; + flb_malloc_mod = 25000; + + /* Limit the size of the config files to 32KB. */ + if (size > 32768) { + return 0; + } + + /* Write the config file to a location we know OSS-Fuzz has */ + char filename[256]; + sprintf(filename, "/tmp/libfuzzer.%d", getpid()); + FILE *fp = fopen(filename, "wb"); + if (!fp) { + return 0; + } + fwrite(conf_file, strlen(conf_file), 1, fp); + fclose(fp); + + + /* Now parse random data based on the config files */ + struct flb_config *config = NULL; + config = flb_config_init(); + int ret = flb_parser_conf_file(filename, config); + if (ret == 0) { + struct mk_list *head = NULL; + mk_list_foreach(head, &config->parsers) { + size_t out_size; + char *out_buf = NULL; + struct flb_parser *parser = NULL; + struct flb_time out_time; + parser = mk_list_entry(head, struct flb_parser, _head); + flb_parser_do(parser, (const char*)data, size, (void **)&out_buf, + &out_size, &out_time); + if (out_buf != NULL) { + free(out_buf); + } + } + } + flb_parser_exit(config); + flb_config_exit(config); + + if (size > 100) { + /* Now let's do a second run where we also call flb_config_set_property */ + config = flb_config_init(); + ret = flb_parser_conf_file(filename, config); + char *key_1 = get_null_terminated(15, &data, &size); + char *val_1 = get_null_terminated(15, &data, &size); + char *key_2 = get_null_terminated(15, &data, &size); + char *val_2 = get_null_terminated(15, &data, &size); + char *progname = get_null_terminated(15, &data, &size); + + flb_config_set_property(config, key_1, val_1); + flb_config_set_property(config, key_2, val_2); + flb_config_set_program_name(config, progname); + set_log_level_from_env(config); + + struct mk_list prop; + flb_kv_init(&prop); + flb_kv_item_create(&prop, key_1, val_1); + flb_config_prop_get(progname, &prop); + flb_slist_entry_get(&prop, (int)data[0]); + flb_slist_dump(&prop); + + if (ret == 0) { + struct mk_list *head = NULL; + mk_list_foreach(head, &config->parsers) { + size_t out_size; + char *out_buf = NULL; + struct flb_parser *parser = NULL; + struct flb_time out_time; + + parser = mk_list_entry(head, struct flb_parser, _head); + flb_parser_do(parser, (const char*)data, size, (void **)&out_buf, + &out_size, &out_time); + if (out_buf != NULL) { + free(out_buf); + } + } + } + flb_parser_exit(config); + flb_config_exit(config); + flb_free(key_1); + flb_free(val_1); + flb_free(key_2); + flb_free(val_2); + flb_free(progname); + flb_kv_release(&prop); + } + + /* clean up the file */ + unlink(filename); + + return 0; +} diff --git a/fluent-bit/tests/internal/fuzzers/config_map_fuzzer.c b/fluent-bit/tests/internal/fuzzers/config_map_fuzzer.c new file mode 100644 index 00000000..79697f65 --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/config_map_fuzzer.c @@ -0,0 +1,212 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +#include <fluent-bit/flb_info.h> +#include <fluent-bit/flb_kv.h> +#include <fluent-bit/flb_slist.h> +#include <fluent-bit/flb_mem.h> +#include <fluent-bit/flb_config.h> +#include <fluent-bit/flb_config_map.h> + +#include "flb_fuzz_header.h" + +struct context { + /* Single values */ + int num_int; + size_t size; + time_t time; + char boolean; + double num_double; + flb_sds_t string; + struct mk_list *list1; + struct mk_list *list2; + + /* Multiple entries */ + struct mk_list *mult_num_int; + struct mk_list *mult_boolean; + struct mk_list *mult_num_double; + struct mk_list *mult_string; + struct mk_list *mult_list1; + struct mk_list *mult_list2; +}; + +struct flb_config_map config_map[] = { + { + FLB_CONFIG_MAP_BOOL, + "boolean", + "true", + 0, FLB_TRUE, offsetof(struct context, boolean), + NULL + }, + { + FLB_CONFIG_MAP_INT, + "num_int", + "123", + 0, FLB_TRUE, offsetof(struct context, num_int), + NULL + }, + { + FLB_CONFIG_MAP_DOUBLE, + "num_double", "0.12345", + 0, FLB_TRUE, offsetof(struct context, num_double), + NULL + }, + { + FLB_CONFIG_MAP_STR, + "string", + "test", + 0, FLB_TRUE, offsetof(struct context, string), + NULL + }, + + /* SIZE */ + { + FLB_CONFIG_MAP_SIZE, + "test_size", + "2M", + 0, FLB_TRUE, offsetof(struct context, size), + NULL + }, + + /* TIME */ + { + FLB_CONFIG_MAP_TIME, + "test_time", + "2H", + 0, FLB_TRUE, offsetof(struct context, time), + NULL + }, + + /* CSLIST */ + { + FLB_CONFIG_MAP_CLIST, + "test_clist", + "a, b, c ,d,e , f, g,h,i,jk , lm , n o,pqr,, , ,stuv,xyz", + 0, FLB_TRUE, offsetof(struct context, list1), + NULL + }, + + /* SLIST */ + { + FLB_CONFIG_MAP_SLIST_4, + "test_slist", + "a b c de f ghi jk l m n o pqr stuv xyz", + 0, FLB_TRUE, offsetof(struct context, list2), + NULL + }, + + /* EOF */ + {0} +}; + +struct flb_config_map config_map_mult[] = { + { + FLB_CONFIG_MAP_BOOL, + "no_mult", + "true", + 0, FLB_TRUE, 1, + NULL + }, + { + FLB_CONFIG_MAP_BOOL, + "mult_boolean", + NULL, + FLB_CONFIG_MAP_MULT, FLB_TRUE, offsetof(struct context, mult_boolean), + NULL + }, + { + FLB_CONFIG_MAP_INT, + "mult_num_int", + "123", + FLB_CONFIG_MAP_MULT, FLB_TRUE, offsetof(struct context, mult_num_int), + NULL + }, + { + FLB_CONFIG_MAP_DOUBLE, + "mult_num_double", "0.12345", + FLB_CONFIG_MAP_MULT, FLB_TRUE, offsetof(struct context, mult_num_double), + NULL + }, + { + FLB_CONFIG_MAP_STR, + "mult_string", + "test", + FLB_CONFIG_MAP_MULT, FLB_TRUE, offsetof(struct context, mult_string), + NULL + }, + { + FLB_CONFIG_MAP_CLIST, + "mult_clist", + "a, b, c ,d,e , f, g,h,i,jk , lm , n o,pqr,, , ,stuv,xyz", + FLB_CONFIG_MAP_MULT, FLB_TRUE, offsetof(struct context, mult_list1), + NULL + }, + { + FLB_CONFIG_MAP_SLIST_4, + "mult_slist", + "a b c de f ghi jk l m n o pqr stuv xyz", + FLB_CONFIG_MAP_MULT, FLB_TRUE, offsetof(struct context, mult_list2), + NULL + }, + + /* EOF */ + {0} +}; + +struct flb_config_map *configs[] = {config_map_mult, config_map}; + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + /* Set flb_malloc_mod to be fuzzer-data dependent */ + if (size < 4) { + return 0; + } + flb_malloc_p = 0; + flb_malloc_mod = *(int*)data; + data += 4; + size -= 4; + + /* Avoid division by zero for modulo operations */ + if (flb_malloc_mod == 0) { + flb_malloc_mod = 1; + } + + if (size < 40) { + return 0; + } + + struct mk_list *map = NULL; + struct flb_config *config = NULL; + struct context ctx; + bzero(&ctx, sizeof(struct context)); + struct mk_list prop; + bzero(&prop, sizeof(struct mk_list)); + + char *fuzz_str1 = get_null_terminated(15, &data, &size); + char *fuzz_str2 = get_null_terminated(15, &data, &size); + char *fuzz_str3 = get_null_terminated(size, &data, &size); + + for (int i = 0; i < 2; i++) { + config = flb_config_init(); + if (config) { + memset(&ctx, '\0', sizeof(struct context)); + + flb_kv_init(&prop); + if (flb_kv_item_create(&prop, fuzz_str1, fuzz_str2) != NULL) { + /* Assign one of the config maps */ + map = flb_config_map_create(config, configs[i]); + if (map) { + if (flb_config_map_set(&prop, map, &ctx) != -1) { + flb_config_map_properties_check(fuzz_str3, &prop, map); + } + flb_config_map_destroy(map); + } + } + flb_kv_release(&prop); + flb_config_exit(config); + } + } + + flb_free(fuzz_str1); + flb_free(fuzz_str2); + flb_free(fuzz_str3); + return 0; +} diff --git a/fluent-bit/tests/internal/fuzzers/config_random_fuzzer.c b/fluent-bit/tests/internal/fuzzers/config_random_fuzzer.c new file mode 100644 index 00000000..ead06ad0 --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/config_random_fuzzer.c @@ -0,0 +1,57 @@ +/* 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_parser.h> +#include <fluent-bit/flb_slist.h> +#include "flb_fuzz_header.h" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + /* Set fuzzer-malloc chance of failure */ + flb_malloc_p = 0; + flb_malloc_mod = 25000; + + /* Limit the size of the config files to 32KB. */ + if (size > 32768) { + return 0; + } + + /* Write the config file to a location we know OSS-Fuzz has */ + char filename[256]; + sprintf(filename, "/tmp/libfuzzer.%d", getpid()); + FILE *fp = fopen(filename, "wb"); + if (!fp) { + return 0; + } + fwrite(data, size, 1, fp); + fclose(fp); + + /* Now parse a random config file */ + struct flb_config *config = NULL; + config = flb_config_init(); + flb_parser_conf_file(filename, config); + flb_parser_exit(config); + flb_config_exit(config); + + /* Cleanup written config file */ + unlink(filename); + + return 0; +} diff --git a/fluent-bit/tests/internal/fuzzers/config_yaml_fuzzer.c b/fluent-bit/tests/internal/fuzzers/config_yaml_fuzzer.c new file mode 100644 index 00000000..99e17ba6 --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/config_yaml_fuzzer.c @@ -0,0 +1,65 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2023 The Fluent Bit Authors + * + * 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 <fluent-bit/flb_info.h> +#include <fluent-bit/flb_mem.h> +#include <fluent-bit/flb_kv.h> +#include <fluent-bit/flb_config_format.h> + +#include <cfl/cfl.h> +#include <cfl/cfl_list.h> + +#include "flb_fuzz_header.h" + + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + /* Set fuzzer-malloc chance of failure */ + flb_malloc_p = 0; + flb_malloc_mod = 25000; + + /* Limit the size of the config files to 32KB. */ + if (size > 32768) { + return 0; + } + + /* Write the config file to a location we know OSS-Fuzz has */ + char filename[256]; + sprintf(filename, "/tmp/libfuzzer.%d.yaml", getpid()); + FILE *fp = fopen(filename, "wb"); + if (!fp) { + return 0; + } + fwrite(data, size, 1, fp); + fclose(fp); + + + struct flb_cf *cf; + struct flb_cf_section *s; + + cf = flb_cf_yaml_create(NULL, filename, NULL, 0); + if (cf != NULL) { + flb_cf_destroy(cf); + } + + /* clean up the file */ + unlink(filename); + + return 0; +} diff --git a/fluent-bit/tests/internal/fuzzers/ctrace_fuzzer.c b/fluent-bit/tests/internal/fuzzers/ctrace_fuzzer.c new file mode 100644 index 00000000..bcd2ca58 --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/ctrace_fuzzer.c @@ -0,0 +1,24 @@ +#include <stdint.h> +#include <fluent-bit/flb_mem.h> +#include <ctraces/ctraces.h> +#include <ctraces/ctr_decode_msgpack.h> + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size){ + size_t off = 0; + struct ctrace *ctr = NULL; + size_t msgpack_text_size; + char *msgpack_text_buffer = NULL; + + /* Set fuzzer-malloc chance of failure */ + flb_malloc_p = 0; + flb_malloc_mod = 25000; + + ctr_decode_msgpack_create(&ctr, data, size, &off); + if (ctr != NULL) { + ctr_encode_msgpack_create(ctr, &msgpack_text_buffer, &msgpack_text_size); + ctr_encode_msgpack_destroy(msgpack_text_buffer); + + ctr_destroy(ctr); + } + return 0; +} diff --git a/fluent-bit/tests/internal/fuzzers/engine_fuzzer.c b/fluent-bit/tests/internal/fuzzers/engine_fuzzer.c new file mode 100644 index 00000000..498b86a8 --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/engine_fuzzer.c @@ -0,0 +1,171 @@ +#include <fluent-bit.h> +#include <fluent-bit/flb_parser.h> +#include <fluent-bit/flb_parser.h> +#include <fluent-bit/flb_input_chunk.h> +#include <fluent-bit/flb_metrics.h> +#include "flb_fuzz_header.h" + +#include <stdio.h> +#include <monkey/mk_core.h> + +struct flb_parser *parser; + flb_ctx_t *ctx; + int in_ffd; + int out_ffd; +int filter_ffd; + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + if (size < 100) { + return 0; + } + /* Set fuzzer-malloc chance of failure */ + flb_malloc_p = 0; + flb_malloc_mod = 25000; + + uint8_t ud = data[0]; + MOVE_INPUT(1); + #define NM_SIZE 50 + char *null_terminated = get_null_terminated(NM_SIZE, &data, &size); + + char *nm3 = get_null_terminated(10, &data, &size); + char *nm4 = get_null_terminated(10, &data, &size); + int random_i1 = *(int *)data; + MOVE_INPUT(4); + int random_i2 = *(int *)data; + + #define FUNC_NUMS 10 + switch (ud % FUNC_NUMS) { + case 0: + flb_output(ctx, null_terminated, nm3); + break; + case 1: + flb_filter(ctx, null_terminated, nm3); + break; + case 2: + flb_input(ctx, null_terminated, nm3); + break; + case 3: + flb_output_check(ctx->config); + break; + case 4: { + struct mk_list *head; + struct flb_input_instance *entry; + mk_list_foreach(head, &ctx->config->inputs) { + entry = mk_list_entry(head, struct flb_input_instance, _head); + flb_input_name_exists(nm3, ctx->config); + flb_input_get_property(nm3, entry); + flb_input_name(entry); + flb_input_collector_running(0, entry); + flb_input_collector_pause(random_i1, entry); + flb_input_collector_resume(random_i2, entry); + flb_input_net_default_listener(nm4, random_i1, entry); + flb_input_collector_start(random_i2, entry); + } + } + break; + case 5: { + struct mk_list *head; + struct flb_input_instance *entry; + mk_list_foreach(head, &ctx->config->inputs) { + entry = mk_list_entry(head, struct flb_input_instance, _head); + if (entry->storage != NULL) { + char bufbuf[100]; + flb_input_chunk_append_raw(entry, FLB_INPUT_LOGS, 0, "A", + 1, "\0", 0); + + struct flb_input_chunk *ic = NULL; + ic = flb_input_chunk_create(entry, FLB_INPUT_LOGS, nm3, 10); + if (ic != NULL) { + flb_input_chunk_get_size(ic); + flb_input_chunk_set_up_down(ic); + flb_input_chunk_down(ic); + flb_input_chunk_set_up(ic); + flb_input_chunk_get_name(ic); + char *tag_buf; + int tag_len; + flb_input_chunk_get_tag(ic, &tag_buf, &tag_len); + size_t flushed; + flb_input_chunk_flush(ic, &flushed); + } + } + } + } + break; + case 6: + flb_input_check(ctx->config); + flb_input_pause_all(ctx->config); + break; + case 7: { + struct mk_list *head; + struct flb_output_instance *entry; + mk_list_foreach(head, &ctx->config->outputs) { + entry = mk_list_entry(head, struct flb_output_instance, _head); + flb_output_net_default(nm4, random_i1, entry); + flb_output_name(entry); + } + } + break; + default: + flb_lib_push(ctx, in_ffd, null_terminated, NM_SIZE); + break; + } + + flb_free(null_terminated); + flb_free(nm3); + flb_free(nm4); + return 0; +} + +int callback_test(void* data, size_t size, void* cb_data) +{ + return 0; +} + +struct flb_lib_out_cb cb; + + +int LLVMFuzzerInitialize(int *argc, char ***argv) { + /* Set fuzzer-malloc chance of failure */ + flb_malloc_p = 0; + flb_malloc_mod = 25000; + + ctx = flb_create(); + flb_service_set(ctx, "Flush", "0", "Grace", + "0", "Log_Level", "debug", NULL); + + in_ffd = flb_input(ctx, (char *) "lib", NULL); + flb_input_set(ctx, in_ffd, (char *) "test", NULL); + flb_input_set(ctx, in_ffd, (char *) "BBBB", NULL); + flb_input_set(ctx, in_ffd, (char *) "AAAA", NULL); + flb_input_set(ctx, in_ffd, (char *) "AAAAA", NULL); + flb_input_set(ctx, in_ffd, (char *) "CC", NULL); + flb_input_set(ctx, in_ffd, (char *) "A", NULL); + + parser = flb_parser_create("timestamp", "regex", "^(?<time>.*)$", FLB_TRUE, + "%s.%L", "time", NULL, MK_FALSE, 0, FLB_FALSE, + NULL, 0, NULL, ctx->config); + filter_ffd = flb_filter(ctx, (char *) "parser", NULL); + int ret; + ret = flb_filter_set(ctx, filter_ffd, "Match", "test", + "Key_Name", "@timestamp", + "Parser", "timestamp", + "Reserve_Data", "On", + NULL); + + cb.cb = callback_test; + cb.data = NULL; + out_ffd = flb_output(ctx, (char *) "lib", &cb); + flb_output_set(ctx, out_ffd, "Match", "*", + "format", "json", NULL); + + flb_output_set(ctx, out_ffd,"match", "test", NULL); + flb_output_set(ctx, out_ffd,"region", "us-west-2", NULL); + flb_output_set(ctx, out_ffd,"log_group_name", "fluent", NULL); + flb_output_set(ctx, out_ffd,"log_stream_prefix", "from-fluent-", NULL); + flb_output_set(ctx, out_ffd,"auto_create_group", "On", NULL); + flb_output_set(ctx, out_ffd,"net.keepalive", "Off", NULL); + flb_output_set(ctx, out_ffd,"Retry_Limit", "1", NULL); + + /* start the engine */ + flb_start(ctx); +} diff --git a/fluent-bit/tests/internal/fuzzers/filter_stdout_fuzzer.c b/fluent-bit/tests/internal/fuzzers/filter_stdout_fuzzer.c new file mode 100644 index 00000000..ed9a3f49 --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/filter_stdout_fuzzer.c @@ -0,0 +1,62 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2022 The Fluent Bit Authors + * + * 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 <fluent-bit.h> +#include "flb_fuzz_header.h" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + int ret; + flb_ctx_t *ctx; + int in_ffd; + int out_ffd; + + /* Set fuzzer-malloc chance of failure */ + flb_malloc_p = 0; + flb_malloc_mod = 25000; + + + ctx = flb_create(); + flb_service_set(ctx, "Flush", "1", "Grace", "1", "Log_Level", "error", NULL); + in_ffd = flb_input(ctx, (char *) "lib", NULL); + if (in_ffd >= 0) { + flb_input_set(ctx, in_ffd, "tag", "test", NULL); + + out_ffd = flb_output(ctx, (char *) "stdout", NULL); + if (out_ffd >= 0) { + flb_output_set(ctx, out_ffd, "match", "test", NULL); + + ret = flb_start(ctx); + if (ret == 0) { + char *p = get_null_terminated(size, &data, &size); + for (int i = 0; i < strlen(p); i++) { + flb_lib_push(ctx, in_ffd, p+i, 1); + } + free(p); + + sleep(1); /* waiting flush */ + } + } + } + flb_stop(ctx); + flb_destroy(ctx); + + return 0; +} diff --git a/fluent-bit/tests/internal/fuzzers/flb_fuzz_header.h b/fluent-bit/tests/internal/fuzzers/flb_fuzz_header.h new file mode 100644 index 00000000..cda08920 --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/flb_fuzz_header.h @@ -0,0 +1,42 @@ +/* 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> + +#define GET_MOD_EQ(max, idx) (data[0] % max) == idx +#define MOVE_INPUT(offset) data += offset; size -= offset; + +#define TIMEOUT_GUARD if (size > 32768) return 0; + +char *get_null_terminated(size_t size, const uint8_t **data, + size_t *total_data_size) +{ + char *tmp = flb_malloc(size+1); + if (tmp == NULL) { + tmp = malloc(size+1); + } + memcpy(tmp, *data, size); + tmp[size] = '\0'; + + /* Modify the fuzz variables */ + *total_data_size -= size; + *data += size; + + return tmp; +} diff --git a/fluent-bit/tests/internal/fuzzers/flb_json_fuzzer.c b/fluent-bit/tests/internal/fuzzers/flb_json_fuzzer.c new file mode 100644 index 00000000..916b1a51 --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/flb_json_fuzzer.c @@ -0,0 +1,82 @@ +/* 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 <stdlib.h> +#include <stdint.h> +#include <fluent-bit/flb_pack.h> +#include <fluent-bit/flb_str.h> +#include "flb_fuzz_header.h" + +int LLVMFuzzerTestOneInput(unsigned char *data, size_t size) +{ + TIMEOUT_GUARD + /* Set fuzzer-malloc chance of failure */ + flb_malloc_p = 0; + flb_malloc_mod = 25000; + + if (size < 1) { + return 0; + } + unsigned char decider = *data; + data++; + size--; + + /* json packer */ + char *out_buf = NULL; + size_t out_size; + int root_type; + int ret = flb_pack_json((char*)data, size, &out_buf, &out_size, &root_type, NULL); + + if (ret == 0) { + size_t off = 0; + msgpack_unpacked result; + msgpack_unpacked_init(&result); + int ret2 = msgpack_unpack_next(&result, out_buf, out_size, &off); + if (ret2 == MSGPACK_UNPACK_SUCCESS) { + msgpack_object root = result.data; + char *tmp = NULL; + tmp = flb_msgpack_to_json_str(0, &root); + if (tmp != NULL) { + flb_free(tmp); + } + } + msgpack_unpacked_destroy(&result); + flb_sds_t d; + d = flb_sds_create("date"); + if (decider < 0x30) { + flb_sds_t ret_s = flb_pack_msgpack_to_json_format(out_buf, out_size, + FLB_PACK_JSON_FORMAT_LINES, + (int)decider, d); + free(out_buf); + if (ret_s != NULL) { + flb_sds_destroy(ret_s); + } + } + else { + flb_sds_t ret_s = flb_pack_msgpack_to_json_format(out_buf, out_size, + FLB_PACK_JSON_FORMAT_LINES, + FLB_PACK_JSON_DATE_EPOCH, NULL); + free(out_buf); + if (ret_s != NULL) { + flb_sds_destroy(ret_s); + } + } + flb_sds_destroy(d); + } + + return 0; +} diff --git a/fluent-bit/tests/internal/fuzzers/flb_mp_fuzzer.c b/fluent-bit/tests/internal/fuzzers/flb_mp_fuzzer.c new file mode 100644 index 00000000..b33c9040 --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/flb_mp_fuzzer.c @@ -0,0 +1,55 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2023 The Fluent Bit Authors + * + * 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 <stdlib.h> +#include <stdint.h> +#include <fluent-bit/flb_mem.h> +#include <fluent-bit/flb_mp.h> + +#include "flb_fuzz_header.h" + +int LLVMFuzzerTestOneInput(unsigned char *data, size_t size) +{ + /* Set flb_malloc_mod to be fuzzer-data dependent */ + if (size < 5) { + return 0; + } + flb_malloc_p = 0; + flb_malloc_mod = *(int*)data; + data += 4; + size -= 4; + + /* Avoid division by zero for modulo operations */ + if (flb_malloc_mod == 0) { + flb_malloc_mod = 1; + } + + unsigned char decider = *data; + data++; + size--; + + int out_records; + size_t processed_bytes; + if (decider % 2 == 0) { + flb_mp_validate_log_chunk(data, size, &out_records, &processed_bytes); + } + else if (decider % 2 == 1) { + flb_mp_validate_metric_chunk(data, size, &out_records, &processed_bytes); + } + return 0; +} diff --git a/fluent-bit/tests/internal/fuzzers/fstore_fuzzer.c b/fluent-bit/tests/internal/fuzzers/fstore_fuzzer.c new file mode 100644 index 00000000..e2a95106 --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/fstore_fuzzer.c @@ -0,0 +1,86 @@ +/* Fluent Bit + * ========== + * Copyright (C) 2019-2022 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 <assert.h> + +#include <fluent-bit/flb_info.h> +#include <fluent-bit/flb_fstore.h> +#include <fluent-bit/flb_mem.h> +#include <fluent-bit/flb_compat.h> + +#include <chunkio/chunkio.h> +#include <chunkio/cio_utils.h> + +#include <sys/types.h> +#include <sys/stat.h> + + +#define FSF_STORE_PATH "/tmp/flb-fstore" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + int ret; + void *out_buf; + size_t out_size; + struct stat st_data; + struct flb_fstore *fs; + struct flb_fstore_stream *st; + struct flb_fstore_file *fsf; + + /* Set flb_malloc_mod to be fuzzer-data dependent */ + if (size < 4) { + return 0; + } + flb_malloc_p = 0; + flb_malloc_mod = *(int*)data; + data += 4; + size -= 4; + + /* Avoid division by zero for modulo operations */ + if (flb_malloc_mod == 0) { + flb_malloc_mod = 1; + } + + cio_utils_recursive_delete(FSF_STORE_PATH); + fs = flb_fstore_create(FSF_STORE_PATH, FLB_FSTORE_FS); + if (fs == NULL) { + return 0; + } + st = flb_fstore_stream_create(fs, "abc"); + if (st != NULL) { + fsf = flb_fstore_file_create(fs, st, "example.txt", size); + + if (fsf != NULL) { + ret = flb_fstore_file_append(fsf, data, size); + if (ret == 0) { + ret = flb_fstore_file_content_copy(fs, fsf, &out_buf, &out_size); + if (ret == 0) { + assert(memcmp(out_buf, data, size) == 0); + } + flb_free(out_buf); + } + } + } + + flb_fstore_dump(fs); + flb_fstore_destroy(fs); + return 0; +} diff --git a/fluent-bit/tests/internal/fuzzers/http_fuzzer.c b/fluent-bit/tests/internal/fuzzers/http_fuzzer.c new file mode 100644 index 00000000..28f0c8d2 --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/http_fuzzer.c @@ -0,0 +1,116 @@ +#include <stdlib.h> +#include <fluent-bit/flb_time.h> +#include <fluent-bit/flb_parser.h> +#include <fluent-bit/flb_info.h> +#include <fluent-bit/flb_mem.h> +#include <fluent-bit/flb_error.h> +#include <fluent-bit/flb_socket.h> +#include <fluent-bit/flb_stream.h> +#include <fluent-bit/flb_connection.h> +#include <fluent-bit/flb_http_client.h> + +#include "flb_fuzz_header.h" + +extern int fuzz_process_data(struct flb_http_client *c); +extern int fuzz_check_connection(struct flb_http_client *c); + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + /* Set fuzzer-malloc chance of failure */ + flb_malloc_p = 0; + flb_malloc_mod = 25000; + + struct flb_upstream *u; + struct flb_connection *u_conn = NULL; + struct flb_http_client *c; + struct flb_config *config; + char *uri = NULL; + + if (size < 160) { + return 0; + } + + config = flb_config_init(); + if (config == NULL) { + return 0; + } + + u = flb_upstream_create(config, "127.0.0.1", 8001, 0, NULL); + + u_conn = flb_connection_create(-1, + FLB_TRANSPORT_TCP, + (void *) u, + NULL, + NULL); + + if (u_conn == NULL) { + return 0; + } + + char *proxy = NULL; + if (GET_MOD_EQ(2,1)) { + proxy = get_null_terminated(50, &data, &size); + } + + uri = get_null_terminated(20, &data, &size); + + int method = (int)data[0]; + c = flb_http_client(u_conn, method, uri, NULL, 0, + "127.0.0.1", 8001, proxy, 0); + if (c != NULL) { + char *null_terminated = get_null_terminated(30, &data, &size); + + /* Perform a set of operations on the http_client */ + flb_http_basic_auth(c, null_terminated, null_terminated); + flb_http_set_content_encoding_gzip(c); + flb_http_set_keepalive(c); + flb_http_strip_port_from_host(c); + flb_http_allow_duplicated_headers(c, 0); + + flb_http_buffer_size(c, (*(size_t *)data) & 0xfff); + MOVE_INPUT(4) + flb_http_add_header(c, "User-Agent", 10, "Fluent-Bit", 10); + flb_http_add_header(c, (char*)data, size, "Fluent-Bit", 10); + flb_http_buffer_size(c, (int)data[0]); + MOVE_INPUT(1) + flb_http_buffer_available(c); + + size_t b_sent; + flb_http_do(c, &b_sent); + + size_t out_size = 0; + flb_http_buffer_increase(c, (*(size_t *)data) & 0xfff, &out_size); + MOVE_INPUT(4) + + /* Now we need to simulate the reading of data */ + c->resp.status = 200; + + if (c->resp.data != NULL) { + flb_free(c->resp.data); + } + + char *new_nulltm = get_null_terminated(30, &data, &size); + c->resp.data_len = 30; + c->resp.data = new_nulltm; + fuzz_process_data(c); + fuzz_check_connection(c); + + flb_http_client_destroy(c); + flb_free(null_terminated); + } + + /* Now try the http_client_proxy_connect function. */ + flb_http_client_proxy_connect(u_conn); + + flb_connection_destroy(u_conn); + flb_upstream_destroy(u); + flb_config_exit(config); + if (uri != NULL) { + flb_free(uri); + } + if (proxy != NULL) { + flb_free(proxy); + } + + return 0; +} diff --git a/fluent-bit/tests/internal/fuzzers/input_fuzzer.c b/fluent-bit/tests/internal/fuzzers/input_fuzzer.c new file mode 100644 index 00000000..57458d36 --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/input_fuzzer.c @@ -0,0 +1,164 @@ +#include <fluent-bit.h> +#include <pthread.h> +#include <stdlib.h> +#include <unistd.h> +#include <stdint.h> +#include <sys/stat.h> +#include <fluent-bit/flb_input_chunk.h> +#include <fluent-bit/flb_storage.h> +#include <fluent-bit/flb_router.h> +#include <fluent-bit/flb_time.h> + +#include "chunkio/chunkio.h" +#include "flb_fuzz_header.h" + + +const char *input_chunk_property_keywords[] = { + "log_suppress_interval", + "routable", + "alias", + "mem_buf_limit", + "listen", + "log_level", + "host", + "port", + "ipv6", + "net.", + "tls", + "tls.verify", + "tls.debug", + "tls.ca_path", + "tls.key_file", + "tls.vhost", + "tls.ca_file", + "tls.crt_file", + "tls.key_passwd", + "threaded", + "storage.type", +}; + +int LLVMFuzzerTestOneInput(const uint8_t *data3, size_t size3) +{ + int i; + int ret; + int in_ffd; + int out_ffd; + + flb_ctx_t *ctx; + size_t total_bytes; + struct flb_input_instance *i_ins; + struct mk_list *tmp; + struct mk_list *head; + struct flb_input_chunk *ic; + struct flb_task *task; + + if (size3 < 60) { + return 0; + } + /* Set fuzzer-malloc chance of failure */ + flb_malloc_p = 0; + flb_malloc_mod = 25000; + char *input_buffer1 = get_null_terminated(30, &data3, &size3); + if (input_buffer1 == NULL) { + return 0; + } + size_t input_buffer1_len = strlen(input_buffer1); + + char *input_buffer2 = get_null_terminated(10, &data3, &size3); + if (input_buffer2 == NULL) { + return 0; + } + size_t input_buffer_len2 = strlen(input_buffer2); + + char *input_buffer3 = get_null_terminated(10, &data3, &size3); + if (input_buffer3 == NULL) { + return 0; + } + size_t input_buffer_len3 = strlen(input_buffer3); + /* Create context, flush every second (some checks omitted here) */ + ctx = flb_create(); + + /* create chunks in /tmp folder */ + ret = flb_service_set(ctx, + "flush", "2", "grace", "1", + "storage.path", "/tmp/input-chunk-test/", + "Log_Level", "error", + NULL); + if (ret != 0) { + flb_free(input_buffer1); + flb_free(input_buffer2); + flb_free(input_buffer3); + return 0; + } + + /* Lib input mode */ + in_ffd = flb_input(ctx, (char *) "lib", NULL); + ret = flb_input_set(ctx, in_ffd, + "tag", "test", + "storage.type", "filesystem", + NULL); + if (ret != 0) { + flb_free(input_buffer1); + flb_free(input_buffer2); + flb_free(input_buffer3); + return 0; + } + + /* an invalid output destination */ + out_ffd = flb_output(ctx, (char *) "http", NULL); + flb_output_set(ctx, out_ffd, + "match", "test", + "Host", "127.0.0.1", + "Port", "1", + "storage.total_limit_size", "1K", + NULL); + + /* Start */ + ret = flb_start(ctx); + if (ret != 0) { + flb_free(input_buffer1); + flb_free(input_buffer2); + flb_free(input_buffer3); + return 0; + } + + i_ins = mk_list_entry_first(&ctx->config->inputs, + struct flb_input_instance, + _head); + + /* main fuzzing logic */ + flb_input_set_property(i_ins, input_buffer2, input_buffer3); + for (int i = 0; i < sizeof(input_chunk_property_keywords)/sizeof(char*); i++) { + flb_input_set_property(i_ins, + input_chunk_property_keywords[i], + input_buffer3); + } + + /* Ingest fuzz data sample */ + for (i = 0; i < 2; ++i) { + flb_lib_push(ctx, in_ffd, (char *) input_buffer1, input_buffer1_len); + sleep(1); + total_bytes = flb_input_chunk_total_size(i_ins); + ret = total_bytes > 1000 ? -1 : 0; + } + + /* FORCE clean up test tasks */ + mk_list_foreach_safe(head, tmp, &i_ins->tasks) { + task = mk_list_entry(head, struct flb_task, _head); + flb_info("[task] cleanup test task"); + flb_task_destroy(task, FLB_TRUE); + } + + /* clean up test chunks */ + mk_list_foreach_safe(head, tmp, &i_ins->chunks) { + ic = mk_list_entry(head, struct flb_input_chunk, _head); + flb_input_chunk_destroy(ic, FLB_TRUE); + } + flb_free(input_buffer1); + flb_free(input_buffer2); + flb_free(input_buffer3); + + flb_time_msleep(200); + flb_stop(ctx); + flb_destroy(ctx); +} diff --git a/fluent-bit/tests/internal/fuzzers/local_test.c b/fluent-bit/tests/internal/fuzzers/local_test.c new file mode 100644 index 00000000..309f66b7 --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/local_test.c @@ -0,0 +1,85 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2019-2020 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 <fluent-bit/flb_info.h> +#include <fluent-bit/flb_log.h> +#include <fluent-bit/flb_mem.h> +#include <monkey/mk_core.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + +/* declare external function test */ +int LLVMFuzzerTestOneInput(unsigned char *data, size_t size); + +int main(int argc, char **argv) +{ + int i; + int ret; + FILE *fp; + char *buffer; + long bytes; + struct stat st; + + if (argc < 2) { + flb_error("usage: %s TESTCASE_FILE", argv[0]); + exit(EXIT_FAILURE); + } + + /* Validate the file */ + ret = stat(argv[1], &st); + if (ret == -1) { + flb_errno(); + flb_error("cannot stat(2) testcase file '%s'", argv[1]); + exit(EXIT_FAILURE); + } + + if (!(fp = fopen(argv[1], "rb"))) { + flb_errno(); + flb_error("cannot fopen(2) testcase file '%s'", argv[1]); + return -1; + } + + buffer = flb_malloc(st.st_size); + if (!buffer) { + flb_errno(); + return -1; + } + + bytes = fread(buffer, st.st_size, 1, fp); + if (bytes < 1) { + fclose(fp); + flb_free(buffer); + return -1; + } + fclose(fp); + + /* Invoke the fuzzer entry-point function */ + for (i = 0; i < 100; i++) { + ret = LLVMFuzzerTestOneInput((unsigned char *) buffer, st.st_size); + } + flb_free(buffer); + return 0; +} diff --git a/fluent-bit/tests/internal/fuzzers/msgpack_parse_fuzzer.c b/fluent-bit/tests/internal/fuzzers/msgpack_parse_fuzzer.c new file mode 100644 index 00000000..cbf2ecf1 --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/msgpack_parse_fuzzer.c @@ -0,0 +1,30 @@ +#include <stdint.h> +#include <stdlib.h> +#include <msgpack.h> +#include <fluent-bit/flb_pack.h> + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size){ + /* Set flb_malloc_mod to be fuzzer-data dependent */ + if (size < 4) { + return 0; + } + flb_malloc_p = 0; + flb_malloc_mod = *(int*)data; + data += 4; + size -= 4; + + /* Avoid division by zero for modulo operations */ + if (flb_malloc_mod == 0) { + flb_malloc_mod = 1; + } + + if (size != 512) + return 0; + + /* target the conversion of raw msgpack to json */ + flb_sds_t record; + record = flb_msgpack_raw_to_json_sds(data, size); + flb_sds_destroy(record); + + return 0; +} diff --git a/fluent-bit/tests/internal/fuzzers/msgpack_to_gelf_fuzzer.c b/fluent-bit/tests/internal/fuzzers/msgpack_to_gelf_fuzzer.c new file mode 100644 index 00000000..cf57437b --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/msgpack_to_gelf_fuzzer.c @@ -0,0 +1,25 @@ +#include <stdint.h> +#include <string.h> +#include <msgpack.h> +#include <fluent-bit/flb_pack.h> + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size){ + /* Set fuzzer-malloc chance of failure */ + flb_malloc_mod = 25000; + flb_malloc_p = 0; + if (size != 512) + return 0; + + /* Target the conversion of raw msgpack to gelf */ + flb_sds_t record; + struct flb_time tm = {0}; + struct flb_gelf_fields fields = {0}; + fields.short_message_key = flb_sds_create("AAAAAAAAAA"); + record = flb_msgpack_raw_to_gelf((char*)data, size, &tm, &fields); + + /* cleanup */ + flb_sds_destroy(record); + flb_sds_destroy(fields.short_message_key); + + return 0; +} diff --git a/fluent-bit/tests/internal/fuzzers/multiline_fuzzer.c b/fluent-bit/tests/internal/fuzzers/multiline_fuzzer.c new file mode 100644 index 00000000..bc03e246 --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/multiline_fuzzer.c @@ -0,0 +1,180 @@ +/* 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 <stdlib.h> + +#include <fluent-bit/flb_info.h> +#include <fluent-bit/flb_mem.h> +#include <fluent-bit/flb_pack.h> +#include <fluent-bit/flb_parser.h> +#include <fluent-bit/multiline/flb_ml.h> +#include <fluent-bit/multiline/flb_ml_parser.h> +#include <fluent-bit/multiline/flb_ml_rule.h> + +#include "flb_fuzz_header.h" + +static int flush_callback(struct flb_ml_parser *parser, + struct flb_ml_stream *mst, void *data, char *buf_data, + size_t buf_size) { + return 0; +} + +struct record_check { + char *buf; +}; + +struct expected_result { + int current_record; + char *key; + struct record_check *out_records; +}; + +char *random_strings[4]; + +void test_multiline_parser(msgpack_object *root2, int rand_val) { + struct expected_result res = {0}; + struct flb_config *config = NULL; + + config = flb_config_init(); + + struct flb_ml *ml = NULL; + ml = flb_ml_create(config, "fuzz-test"); + + if (ml != NULL) { + uint64_t stream_ids[5]; + + flb_ml_parser_instance_create(ml, "docker"); + flb_ml_parser_instance_create(ml, "python"); + flb_ml_parser_instance_create(ml, "go"); + flb_ml_parser_instance_create(ml, "cri"); + struct flb_ml_parser_ins *mlp_i = + flb_ml_parser_instance_create(ml, "java"); + flb_ml_parser_instance_set(mlp_i, "key_content", "log"); + + if (rand_val & 0x01) { + flb_ml_stream_create(ml, "java", -1, flush_callback, (void *)&res, + &(stream_ids[0])); + } + if (rand_val >> 1 & 0x01) { + flb_ml_stream_create(ml, "python", -1, flush_callback, (void *)&res, + &(stream_ids[1])); + } + if (rand_val >> 2 & 0x01) { + flb_ml_stream_create(ml, "go", -1, flush_callback, (void *)&res, + &(stream_ids[2])); + } + if (rand_val >> 3 & 0x01) { + flb_ml_stream_create(ml, "docker", -1, flush_callback, (void *)&res, + &(stream_ids[3])); + } + if (rand_val >> 4 & 0x01) { + flb_ml_stream_create(ml, "cri", -1, flush_callback, (void *)&res, + &(stream_ids[4])); + } + + /* Target with msgpack object */ + if (root2 != NULL) { + struct flb_time tm; + flb_time_get(&tm); + for (int i = 0; i < 4; i++) { + flb_ml_append_object(ml, stream_ids[i], &tm, NULL, root2); + } + } + + /* Target with raw text */ + struct flb_time tm2; + flb_time_get(&tm2); + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 5; j++) { + if (random_strings[i] != NULL && stream_ids[j] != NULL) { + /* stream_ids index by j, random_strings index by i */ + flb_ml_append_text(ml, stream_ids[j], &tm2, + random_strings[i], strlen(random_strings[i])); + flb_ml_append_text(ml, stream_ids[j], &tm2, + random_strings[i], strlen(random_strings[i])); + flb_ml_append_text(ml, stream_ids[j], &tm2, + random_strings[i], strlen(random_strings[i])); + flb_ml_append_text(ml, stream_ids[j], &tm2, + random_strings[i],strlen(random_strings[i])); + flb_ml_append_text(ml, stream_ids[j], &tm2, + random_strings[i], strlen(random_strings[i])); + } + } + } + } + + flb_ml_flush_pending_now(ml); + + if (ml) { + flb_ml_destroy(ml); + } + + flb_config_exit(config); +} + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + TIMEOUT_GUARD + /* Set fuzzer-malloc chance of failure */ + flb_malloc_mod = 25000; + flb_malloc_p = 0; + /* Ensure there's enough data */ + if (size < 250) { + return 0; + } + + int rand_val = *(int *)data; + data += 4; + size -= 4; + for (int i = 0; i < 4; i++) { + random_strings[i] = NULL; + } + + random_strings[0] = get_null_terminated(40, &data, &size); + random_strings[1] = get_null_terminated(40, &data, &size); + random_strings[2] = get_null_terminated(40, &data, &size); + random_strings[3] = get_null_terminated(40, &data, &size); + + char *out_buf = NULL; + size_t out_size; + int root_type; + int ret = + flb_pack_json((char *)data, size, &out_buf, &out_size, &root_type, NULL); + if (ret == 0) { + size_t off = 0; + msgpack_unpacked result; + msgpack_unpacked_init(&result); + int ret2 = msgpack_unpack_next(&result, out_buf, out_size, &off); + if (ret2 == MSGPACK_UNPACK_SUCCESS) { + msgpack_object root = result.data; + + /* Pass fuzz data into the multiline parser code */ + test_multiline_parser(&root, rand_val); + } + msgpack_unpacked_destroy(&result); + free(out_buf); + } else { + test_multiline_parser(NULL, rand_val); + } + + for (int i = 0; i < 4; i++) { + if (random_strings[i] != NULL) { + free(random_strings[i]); + } + } + return 0; +} diff --git a/fluent-bit/tests/internal/fuzzers/pack_json_state_fuzzer.c b/fluent-bit/tests/internal/fuzzers/pack_json_state_fuzzer.c new file mode 100644 index 00000000..4549557a --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/pack_json_state_fuzzer.c @@ -0,0 +1,25 @@ +#include <stdint.h> +#include <stdlib.h> +#include <fluent-bit/flb_pack.h> + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size){ + int out_size= 0; + char *out_buf = NULL; + struct flb_pack_state state; + /* Set fuzzer-malloc chance of failure */ + flb_malloc_mod = 25000; + flb_malloc_p = 0; + + /* Exit early to avoid timeouts due to excessive size */ + if (size > 4096) + return 0; + + /* Target json packer */ + flb_pack_state_init(&state); + flb_pack_json_state(data, size, &out_buf, &out_size, &state); + flb_pack_state_reset(&state); + if (out_buf != NULL) + flb_free(out_buf); + + return 0; +} diff --git a/fluent-bit/tests/internal/fuzzers/parse_json_fuzzer.c b/fluent-bit/tests/internal/fuzzers/parse_json_fuzzer.c new file mode 100644 index 00000000..dab8880d --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/parse_json_fuzzer.c @@ -0,0 +1,69 @@ +/* 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_time.h> +#include <fluent-bit/flb_parser.h> +#include "flb_fuzz_header.h" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size){ + TIMEOUT_GUARD + void *out_buf = NULL; + size_t out_size = 0; + struct flb_time out_time; + struct flb_config *fuzz_config; + struct flb_parser *fuzz_parser; + + /* Set flb_malloc_mod to be fuzzer-data dependent */ + if (size < 4) { + return 0; + } + flb_malloc_p = 0; + flb_malloc_mod = *(int*)data; + data += 4; + size -= 4; + + /* Avoid division by zero for modulo operations */ + if (flb_malloc_mod == 0) { + flb_malloc_mod = 1; + } + + /* json parser */ + fuzz_config = flb_config_init(); + if (fuzz_config == NULL) { + return 0; + } + + fuzz_parser = flb_parser_create("fuzzer", "json", NULL, FLB_TRUE, NULL, + NULL, NULL, MK_FALSE, MK_TRUE, FLB_FALSE, + NULL, 0, NULL, fuzz_config); + if (fuzz_parser) { + 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); + } + flb_config_exit(fuzz_config); + + return 0; +} diff --git a/fluent-bit/tests/internal/fuzzers/parse_logfmt_fuzzer.c b/fluent-bit/tests/internal/fuzzers/parse_logfmt_fuzzer.c new file mode 100644 index 00000000..c65a2adb --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/parse_logfmt_fuzzer.c @@ -0,0 +1,50 @@ +#include <stdint.h> +#include <string.h> +#include <stdlib.h> +#include <fluent-bit/flb_time.h> +#include <fluent-bit/flb_parser.h> + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size){ + void *out_buf = NULL; + size_t out_size = 0; + struct flb_time out_time; + struct flb_config *fuzz_config; + struct flb_parser *fuzz_parser; + + /* Set flb_malloc_mod to be fuzzer-data dependent */ + if (size < 4) { + return 0; + } + flb_malloc_p = 0; + flb_malloc_mod = *(int*)data; + data += 4; + size -= 4; + + /* Avoid division by zero for modulo operations */ + if (flb_malloc_mod == 0) { + flb_malloc_mod = 1; + } + + /* logfmt parser */ + fuzz_config = flb_config_init(); + if (fuzz_config == NULL) { + return 0; + } + fuzz_parser = flb_parser_create("fuzzer", "logfmt", NULL, FLB_TRUE, + NULL, NULL, NULL, MK_FALSE, + MK_TRUE, FLB_FALSE, NULL, 0, NULL, + fuzz_config); + if (fuzz_parser) { + 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); + } + + flb_config_exit(fuzz_config); + + return 0; +} diff --git a/fluent-bit/tests/internal/fuzzers/parse_ltsv_fuzzer.c b/fluent-bit/tests/internal/fuzzers/parse_ltsv_fuzzer.c new file mode 100644 index 00000000..cb8bf95a --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/parse_ltsv_fuzzer.c @@ -0,0 +1,35 @@ +#include <stdint.h> +#include <string.h> +#include <stdlib.h> +#include <fluent-bit/flb_time.h> +#include <fluent-bit/flb_parser.h> + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size){ + void *out_buf = NULL; + size_t out_size = 0; + struct flb_time out_time; + struct flb_config *fuzz_config; + struct flb_parser *fuzz_parser; + + /* Set fuzzer-malloc chance of failure */ + flb_malloc_mod = 25000; + flb_malloc_p = 0; + + /* ltsvc parser */ + fuzz_config = flb_config_init(); + fuzz_parser = flb_parser_create("fuzzer", "ltsv", NULL, FLB_TRUE, + NULL, NULL, NULL, MK_FALSE, + MK_TRUE, FLB_FALSE, NULL, 0, NULL, + fuzz_config); + 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); + flb_config_exit(fuzz_config); + + return 0; +} 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; +} diff --git a/fluent-bit/tests/internal/fuzzers/record_ac_fuzzer.c b/fluent-bit/tests/internal/fuzzers/record_ac_fuzzer.c new file mode 100644 index 00000000..9f2ae580 --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/record_ac_fuzzer.c @@ -0,0 +1,101 @@ +#include <fluent-bit/flb_info.h> +#include <fluent-bit/flb_mem.h> +#include <fluent-bit/flb_error.h> +#include <fluent-bit/flb_sds.h> +#include <fluent-bit/flb_pack.h> +#include <fluent-bit/flb_record_accessor.h> +#include <fluent-bit/record_accessor/flb_ra_parser.h> +#include <msgpack.h> +#include "flb_fuzz_header.h" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + /* Limit size to 32KB */ + if (size > 32768 || size < 6) { + return 0; + } + + char *outbuf = NULL; + char *ra_str = NULL; + size_t outsize; + int type; + int len; + size_t off = 0; + msgpack_object map; + + /* Set flb_malloc_mod to be fuzzer-data dependent */ + flb_malloc_p = 0; + flb_malloc_mod = *(int*)data; + data += 4; + size -= 4; + + /* Avoid division by zero for modulo operations */ + if (flb_malloc_mod == 0) { + flb_malloc_mod = 1; + } + + if (size < 100) { + return 0; + } + + struct flb_record_accessor *ra = NULL; + + /* Sample JSON message */ + len = 60; + char *json_raw = get_null_terminated(len, &data, &size); + + /* Convert to msgpack */ + int ret = flb_pack_json(json_raw, len, &outbuf, &outsize, &type, NULL); + if (ret == -1) { + flb_free(json_raw); + return 0; + } + flb_free(json_raw); + + char *null_terminated = get_null_terminated(size, &data, &size); + + ra_str = flb_sds_create(null_terminated); + if (ra_str != NULL) { + ra = flb_ra_create(ra_str, FLB_FALSE); + if (!ra) { + flb_sds_destroy(ra_str); + flb_free(null_terminated); + flb_free(outbuf); + return 0; + } + + flb_ra_is_static(ra); + + msgpack_unpacked result; + msgpack_unpacked_init(&result); + msgpack_unpack_next(&result, outbuf, outsize, &off); + map = result.data; + + flb_sds_t str = flb_ra_translate(ra, NULL, -1, map, NULL); + if (!str) { + flb_ra_destroy(ra); + flb_sds_destroy(ra_str); + msgpack_unpacked_destroy(&result); + + /* General cleanup */ + flb_free(null_terminated); + flb_free(outbuf); + return 0; + } + flb_ra_dump(ra); + + + flb_sds_destroy(str); + flb_ra_destroy(ra); + flb_sds_destroy(ra_str); + msgpack_unpacked_destroy(&result); + } + + if (outbuf != NULL) { + flb_free(outbuf); + } + if (null_terminated != NULL) { + flb_free(null_terminated); + } + return 0; +} diff --git a/fluent-bit/tests/internal/fuzzers/signv4_fuzzer.c b/fluent-bit/tests/internal/fuzzers/signv4_fuzzer.c new file mode 100644 index 00000000..4393d159 --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/signv4_fuzzer.c @@ -0,0 +1,111 @@ +#include <fluent-bit/flb_info.h> +#include <fluent-bit/flb_mem.h> +#include <fluent-bit/flb_http_client.h> +#include <fluent-bit/flb_upstream.h> +#include <fluent-bit/flb_signv4.h> +#include <fluent-bit/flb_aws_credentials.h> +#include <monkey/mk_core.h> +#include <unistd.h> +#include <fluent-bit/flb_sds.h> +#include "flb_fuzz_header.h" + +#define AWS_ACCESS_KEY_ID "AWS_ACCESS_KEY_ID" +#define AWS_SECRET_ACCESS_KEY "AWS_SECRET_ACCESS_KEY" +#define AWS_SESSION_TOKEN "AWS_SESSION_TOKEN" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + if (size < 59) { + return 0; + } + + /* Set flb_malloc_mod to be fuzzer-data dependent */ + flb_malloc_p = 0; + flb_malloc_mod = *(int*)data; + data += 4; + size -= 4; + + /* Avoid division by zero for modulo operations */ + if (flb_malloc_mod == 0) { + flb_malloc_mod = 1; + } + + char s3_mode = data[0]; + MOVE_INPUT(1) + int method = (int)data[0]; + + /* Prepare a general null-terminated string */ + char *uri = get_null_terminated(50, &data, &size); + char *null_terminated = get_null_terminated(size, &data, &size); + + /* Now begin the core work of the fuzzer */ + struct flb_config *config; + struct mk_list *tests; + struct flb_aws_provider *provider; + config = flb_calloc(1, sizeof(struct flb_config)); + if (!config) { + flb_free(uri); + flb_free(null_terminated); + return 0; + } + mk_list_init(&config->upstreams); + provider = flb_aws_env_provider_create(); + + /* Create the necessary http context */ + struct flb_upstream *http_u; + struct flb_connection *http_u_conn = NULL; + struct flb_http_client *http_c; + struct flb_config *http_config; + + http_config = flb_config_init(); + if (http_config == NULL) { + flb_aws_provider_destroy(provider); + flb_free(uri); + flb_free(null_terminated); + flb_free(config); + return 0; + } + + http_u = flb_upstream_create(http_config, "127.0.0.1", 8001, 0, NULL); + if (http_u != NULL) { + http_u_conn = flb_calloc(1, sizeof(struct flb_connection)); + if (http_u_conn != NULL) { + http_u_conn->upstream = http_u; + + http_c = flb_http_client(http_u_conn, method, uri, + null_terminated, size, "127.0.0.1", 8001, NULL, 0); + if (http_c) { + /* Call into the main target flb_signv4_do*/ + time_t t = 1440938160; + char *region = "us-east-1"; + char *access_key = "AKIDEXAMPLE"; + char *service = "service"; + char *secret_key = "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY"; + int ret = setenv(AWS_ACCESS_KEY_ID, access_key, 1); + if (ret >= 0) { + ret = setenv(AWS_SECRET_ACCESS_KEY, secret_key, 1); + if (ret >= 0) { + flb_sds_t signature = flb_signv4_do(http_c, FLB_TRUE, FLB_FALSE, + t, region, service, s3_mode, NULL, provider); + if (signature) { + flb_sds_destroy(signature); + } + } + } + flb_http_client_destroy(http_c); + } + } + flb_upstream_destroy(http_u); + } + + /* Cleanup */ + flb_config_exit(http_config); + flb_aws_provider_destroy(provider); + flb_free(config); + + flb_free(null_terminated); + flb_free(http_u_conn); + flb_free(uri); + + return 0; +} diff --git a/fluent-bit/tests/internal/fuzzers/strp_fuzzer.c b/fluent-bit/tests/internal/fuzzers/strp_fuzzer.c new file mode 100644 index 00000000..3de21c7a --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/strp_fuzzer.c @@ -0,0 +1,35 @@ +#include <stdint.h> +#include <string.h> +#include <stdlib.h> +#include <fluent-bit/flb_time.h> +#include <fluent-bit/flb_parser.h> +#include <msgpack.h> +#include <fluent-bit/flb_info.h> +#include <fluent-bit/flb_mem.h> +#include <fluent-bit/flb_pack.h> +#include <fluent-bit/flb_utils.h> +#include <fluent-bit/flb_version.h> +#include <fluent-bit/flb_strptime.h> + +#include "flb_fuzz_header.h" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + if (size < 40) { + return 0; + } + + /* Set fuzzer-malloc chance of failure */ + flb_malloc_mod = 25000; + flb_malloc_p = 0; + + char *fmt = get_null_terminated(size - 30, &data, &size); + char *buf = get_null_terminated(size, &data, &size); + + struct tm tt; + flb_strptime(buf, fmt, &tt); + + flb_free(buf); + flb_free(fmt); + return 0; +} diff --git a/fluent-bit/tests/internal/fuzzers/utils_fuzzer.c b/fluent-bit/tests/internal/fuzzers/utils_fuzzer.c new file mode 100644 index 00000000..2352adf3 --- /dev/null +++ b/fluent-bit/tests/internal/fuzzers/utils_fuzzer.c @@ -0,0 +1,242 @@ +/* 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 <msgpack.h> +#include <fluent-bit/flb_mem.h> +#include <fluent-bit/flb_utils.h> +#include <fluent-bit/flb_slist.h> +#include <fluent-bit/flb_gzip.h> +#include <fluent-bit/flb_hash_table.h> +#include <fluent-bit/flb_uri.h> +#include <fluent-bit/flb_hash.h> +#include <fluent-bit/flb_regex.h> +#include "flb_fuzz_header.h" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + TIMEOUT_GUARD + + if (size < 750) { + return 0; + } + + /* Set fuzzer-malloc chance of failure */ + flb_malloc_mod = 25000; + flb_malloc_p = 0; + + uint64_t ran_hash = *(uint64_t *)data; + char *null_terminated1 = get_null_terminated(25, &data, &size); + char *null_terminated2 = get_null_terminated(25, &data, &size); + char *null_terminated3 = get_null_terminated(25, &data, &size); + + /* Prepare a general null-terminated string */ + char *null_terminated = (char*)malloc(size+1); + null_terminated[size] = '\0'; + memcpy(null_terminated, data, size); + + /* Fuzzing of flb_utils.c */ + int sec; + long nsec; + size_t new_size; + char *prot = NULL; + char *host = NULL; + char *port = NULL; + char *uri = NULL; + char *new_dst = NULL; + + if (flb_utils_write_str_buf(null_terminated, size, &new_dst, &new_size) == 0) { + flb_free(new_dst); + } + + struct mk_list *list = flb_utils_split(null_terminated, 'A', 3); + if (list != NULL) { + flb_utils_split_free(list); + } + struct mk_list *list2 = flb_utils_split_quoted(null_terminated, 'A', 3); + if (list2 != NULL) { + flb_utils_split_free(list2); + } + + if (flb_utils_url_split(null_terminated, &prot, &host, &port, &uri) == 0) { + flb_free(prot); + flb_free(port); + flb_free(host); + flb_free(uri); + } + + char *split_protocol = NULL; + char *split_username = NULL; + char *split_password = NULL; + char *split_host = NULL; + char *split_port = NULL; + if (flb_utils_proxy_url_split(null_terminated, &split_protocol, + &split_username, &split_password, &split_host, &split_port) == 0) { + if (split_protocol) { + flb_free(split_protocol); + } + if (split_username) { + flb_free(split_username); + } + if (split_password) { + flb_free(split_password); + } + if (split_host) { + flb_free(split_host); + } + if (split_port) { + flb_free(split_port); + } + } + + + flb_utils_size_to_bytes(null_terminated); + flb_utils_time_split(null_terminated, &sec, &nsec); + flb_utils_time_to_seconds(null_terminated); + flb_utils_bool(null_terminated); + flb_utils_hex2int(null_terminated, size); + + /* Fuzzong of flb_uri.c */ + struct flb_uri *uri2 = NULL; + uri2 = flb_uri_create(null_terminated); + if (uri2 != NULL) { + flb_uri_get(uri2, (int)data[0]); + flb_uri_dump(uri2); + flb_uri_destroy(uri2); + } + flb_sds_t encoded = flb_uri_encode((char*)data, size); + if (encoded != NULL) { + flb_sds_destroy(encoded); + } + + /* Fuzzing of flb_hash.c */ + struct flb_hash_table *ht = NULL; + ht = flb_hash_table_create((int)(data[2] % 0x04), + (size_t)data[0], + (int)data[1]); + if (ht != NULL) { + flb_hash_table_add(ht, null_terminated, size, null_terminated, size); + + char *out_buf = NULL; + size_t out_size; + flb_hash_table_get(ht, null_terminated, size, (void **)&out_buf, &out_size); + + /* now let's create some more instances */ + char *instances1[128] = { NULL }; + char *instances2[128] = { NULL }; + for (int i = 0; i < 128; i++) { + char *in1 = malloc(3); + char *in2 = malloc(3); + memcpy(in1, data+(i*4), 2); + memcpy(in2, data+(i*4)+2, 2); + in1[2] = '\0'; + in2[2] = '\0'; + flb_hash_table_add(ht, in1, 2, in2, 2); + instances1[i] = in1; + instances2[i] = in2; + } + + for(int i = 0; i < 20; i++) { + char *hash_out_buf; + size_t hash_out_size; + flb_hash_table_get_by_id(ht, (int)data[i], null_terminated, + (const char **)&hash_out_buf, &hash_out_size); + } + + flb_hash_table_del(ht, null_terminated1); + flb_hash_table_exists(ht, ran_hash); + flb_hash_table_del_ptr(ht, null_terminated2, strlen(null_terminated2), NULL); + flb_hash_table_get_ptr(ht, null_terminated3, strlen(null_terminated3)); + + flb_hash_table_destroy(ht); + for (int i =0; i<128; i++) { + flb_free(instances1[i]); + flb_free(instances2[i]); + } + } + + /* sds */ + flb_sds_t fs = flb_sds_create_len((const char*)data, size); + if (fs != NULL) { + fs = flb_sds_cat_esc(fs, "AAABBBCCC", 9, "ABC", 3); + if (fs != NULL) { + flb_sds_destroy(fs); + } + } + + /* Fuzzing of flb_gzip.c */ + void *str = NULL; + size_t len; + void *out_data = NULL; + size_t out_len; + if (flb_gzip_compress((char*)data, size, &str, &len) != -1) { + flb_gzip_uncompress(str, len, &out_data, &out_len); + } + if (str != NULL) { + free(str); + } + if (out_data != NULL) { + free(out_data); + } + void *out_data2 = NULL; + size_t out2_len; + int uncompress_ret = flb_gzip_uncompress((char*)data, size, &out_data2, &out2_len); + if (uncompress_ret != -1 && out_data2 != NULL) { + flb_free(out_data2); + } + + /* Fuzzing the sha routines */ + struct flb_hash sha512; + uint8_t buf[64]; + + flb_hash_init(&sha512, FLB_HASH_SHA512); + flb_hash_update(&sha512, (unsigned char *) null_terminated, 32); + flb_hash_update(&sha512, (unsigned char *) null_terminated+32, 32); + flb_hash_update(&sha512, (unsigned char *) null_terminated+64, 32); + flb_hash_finalize(&sha512, buf, sizeof(buf)); + flb_hash_cleanup(&sha512); + + /* regex */ + char *pregex = "^(?<INT>[^ ]+) (?<FLOAT>[^ ]+) (?<BOOL>[^ ]+) (?<STRING>.+)$"; + flb_regex_init(); + struct flb_regex *freg = flb_regex_create(pregex); + if (freg != NULL) { + flb_regex_match(freg, (unsigned char*)null_terminated, size); + flb_regex_destroy(freg); + } + flb_regex_exit(); + + /* slist */ + struct mk_list list3; + flb_slist_create(&list3); + flb_sds_t slist_str = flb_sds_create_len((const char*)data, size); + flb_slist_add_sds(&list3, slist_str); + flb_slist_entry_get(&list3, 100); + flb_slist_dump(&list3); + flb_slist_destroy(&list3); + + + /* General cleanup */ + flb_free(null_terminated); + flb_free(null_terminated1); + flb_free(null_terminated2); + flb_free(null_terminated3); + return 0; +} |