diff options
author | Ivan Nardi <12729895+IvanNardi@users.noreply.github.com> | 2022-12-23 19:07:13 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-12-23 19:07:13 +0100 |
commit | 560280e6f082d22e6a9de8e537b7876bacf8d072 (patch) | |
tree | a8ed2ea6c43614606cc977fc27050dd41e0c3133 /fuzz | |
parent | 3de76812d978060c433864c2f72de113746d70e8 (diff) |
fuzz: add fuzzer testing nDPI (initial) configurations (#1830)
The goal of this fuzzer is to test init and deinit of the library, with
different configurations. In details:
* random memory allocation failures, even during init phase
* random `ndpi_init_prefs` parameter of `ndpi_init_detection_module()`
* random LRU caches sizes
* random bitmask of enabled protocols
* random parameters of `ndpi_set_detection_preferences()`
* random initialization of opportunistic TLS
* random load/don't load of configuration files
This new fuzzer is a C++ file, because it uses `FuzzedDataProvider`
class (see
https://github.com/google/fuzzing/blob/master/docs/split-inputs.md).
Note that the (existing) fuzzers need to be linked with C++ compiler
anyway, so this new fuzzer doesn't add any new requirements.
Diffstat (limited to 'fuzz')
-rw-r--r-- | fuzz/Makefile.am | 20 | ||||
-rw-r--r-- | fuzz/fuzz_common_code.c | 30 | ||||
-rw-r--r-- | fuzz/fuzz_common_code.h | 15 | ||||
-rw-r--r-- | fuzz/fuzz_config.cpp | 113 | ||||
-rw-r--r-- | fuzz/fuzz_ndpi_reader.c | 32 |
5 files changed, 180 insertions, 30 deletions
diff --git a/fuzz/Makefile.am b/fuzz/Makefile.am index 0d4f583e6..9ee8571c8 100644 --- a/fuzz/Makefile.am +++ b/fuzz/Makefile.am @@ -1,4 +1,4 @@ -bin_PROGRAMS = fuzz_process_packet fuzz_ndpi_reader fuzz_ndpi_reader_alloc_fail fuzz_quic_get_crypto_data +bin_PROGRAMS = fuzz_process_packet fuzz_ndpi_reader fuzz_ndpi_reader_alloc_fail fuzz_quic_get_crypto_data fuzz_config fuzz_process_packet_SOURCES = fuzz_process_packet.c fuzz_common_code.c fuzz_process_packet_CFLAGS = @NDPI_CFLAGS@ $(CXXFLAGS) @@ -26,7 +26,7 @@ fuzz_ndpi_reader_LINK=$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXX) @NDPI_CFLAGS@ $(AM_CXXFLAGS) $(CXXFLAGS) \ $(fuzz_ndpi_reader_LDFLAGS) @NDPI_LDFLAGS@ $(LDFLAGS) -o $@ -fuzz_ndpi_reader_alloc_fail_SOURCES = fuzz_ndpi_reader.c ../example/reader_util.c +fuzz_ndpi_reader_alloc_fail_SOURCES = fuzz_ndpi_reader.c fuzz_common_code.c ../example/reader_util.c fuzz_ndpi_reader_alloc_fail_CFLAGS = -I../example/ @NDPI_CFLAGS@ $(CXXFLAGS) -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -DENABLE_MEM_ALLOC_FAILURES fuzz_ndpi_reader_alloc_fail_LDADD = ../src/lib/libndpi.a fuzz_ndpi_reader_alloc_fail_LDFLAGS = $(PCAP_LIB) $(ADDITIONAL_LIBS) $(LIBS) @@ -52,6 +52,21 @@ fuzz_quic_get_crypto_data_LINK=$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXX) @NDPI_CFLAGS@ $(AM_CXXFLAGS) $(CXXFLAGS) \ $(fuzz_quic_get_crypto_data_LDFLAGS) @NDPI_LDFLAGS@ $(LDFLAGS) -o $@ +fuzz_config_SOURCES = fuzz_config.cpp fuzz_common_code.c +fuzz_config_CXXFLAGS = @NDPI_CFLAGS@ $(CXXFLAGS) -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -DENABLE_MEM_ALLOC_FAILURES +fuzz_config_CFLAGS = @NDPI_CFLAGS@ $(CXXFLAGS) -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -DENABLE_MEM_ALLOC_FAILURES +fuzz_config_LDADD = ../src/lib/libndpi.a +fuzz_config_LDFLAGS = $(ADDITIONAL_LIBS) $(LIBS) +if HAS_FUZZLDFLAGS +fuzz_config_CXXFLAGS += $(LIB_FUZZING_ENGINE) +fuzz_config_CFLAGS += $(LIB_FUZZING_ENGINE) +fuzz_config_LDFLAGS += $(LIB_FUZZING_ENGINE) +endif +# force usage of CXX for linker +fuzz_config_LINK=$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXX) @NDPI_CFLAGS@ $(AM_CXXFLAGS) $(CXXFLAGS) \ + $(fuzz_config_LDFLAGS) @NDPI_LDFLAGS@ $(LDFLAGS) -o $@ + # required for Google oss-fuzz # see https://github.com/google/oss-fuzz/tree/master/projects/ndpi testpcaps := $(wildcard ../tests/pcap/*.pcap*) @@ -74,6 +89,7 @@ distdir: find . -type f -name '*.c' \ -o -name '*.am' \ -o -name '*.h' \ + -o -name '*.cpp' \ -o -name '*.bin' | xargs -I'{}' cp '{}' '$(distdir)/{}' all: corpus diff --git a/fuzz/fuzz_common_code.c b/fuzz/fuzz_common_code.c index 5ad2a5899..bd5ef20a4 100644 --- a/fuzz/fuzz_common_code.c +++ b/fuzz/fuzz_common_code.c @@ -1,6 +1,32 @@ #include "fuzz_common_code.h" + +#ifdef ENABLE_MEM_ALLOC_FAILURES + +static int mem_alloc_state = 0; + +__attribute__((no_sanitize("integer"))) +static int fastrand () +{ + if(!mem_alloc_state) return 1; /* No failures */ + mem_alloc_state = (214013 * mem_alloc_state + 2531011); + return (mem_alloc_state >> 16) & 0x7FFF; +} + +void *malloc_wrapper(size_t size) { + return (fastrand () % 16) ? malloc (size) : NULL; +} +void free_wrapper(void *freeable) { + free(freeable); +} + +void set_mem_alloc_state(int value) { + mem_alloc_state = value; +} + +#endif + void fuzz_init_detection_module(struct ndpi_detection_module_struct **ndpi_info_mod, int enable_log) { @@ -8,6 +34,10 @@ void fuzz_init_detection_module(struct ndpi_detection_module_struct **ndpi_info_ NDPI_PROTOCOL_BITMASK all, debug_bitmask; if(*ndpi_info_mod == NULL) { +#ifdef ENABLE_MEM_ALLOC_FAILURES + set_ndpi_malloc(malloc_wrapper); + set_ndpi_free(free_wrapper); +#endif *ndpi_info_mod = ndpi_init_detection_module(prefs); NDPI_BITMASK_SET_ALL(all); ndpi_set_protocol_detection_bitmask2(*ndpi_info_mod, &all); diff --git a/fuzz/fuzz_common_code.h b/fuzz/fuzz_common_code.h index 5225446ad..9f26ea060 100644 --- a/fuzz/fuzz_common_code.h +++ b/fuzz/fuzz_common_code.h @@ -3,7 +3,22 @@ #include "ndpi_api.h" +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifdef ENABLE_MEM_ALLOC_FAILURES +void *malloc_wrapper(size_t size); +void free_wrapper(void *freeable); +void set_mem_alloc_state(int value); +#endif + void fuzz_init_detection_module(struct ndpi_detection_module_struct **ndpi_info_mod, int enable_log); +#ifdef __cplusplus +} +#endif + #endif diff --git a/fuzz/fuzz_config.cpp b/fuzz/fuzz_config.cpp new file mode 100644 index 000000000..884e3720e --- /dev/null +++ b/fuzz/fuzz_config.cpp @@ -0,0 +1,113 @@ +#include "ndpi_api.h" +#include "fuzz_common_code.h" + +#include <stdint.h> +#include <stdio.h> +#include <assert.h> +#include "fuzzer/FuzzedDataProvider.h" + + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + FuzzedDataProvider fuzzed_data(data, size); + struct ndpi_detection_module_struct *ndpi_info_mod; + struct ndpi_flow_struct flow; + u_int8_t protocol_was_guessed; + u_int32_t i, num; + u_int16_t random_proto; + int random_value; + NDPI_PROTOCOL_BITMASK enabled_bitmask; + struct ndpi_lru_cache_stats lru_stats; + struct ndpi_patricia_tree_stats patricia_stats; + struct ndpi_automa_stats automa_stats; + + if(fuzzed_data.remaining_bytes() < 4 + /* ndpi_init_detection_module() */ + NDPI_MAX_SUPPORTED_PROTOCOLS + NDPI_MAX_NUM_CUSTOM_PROTOCOLS + + 5 + /* files */ + (NDPI_LRUCACHE_MAX * 3) + /* LRU caches */ + 2 + 1 + 4 + /* ndpi_set_detection_preferences() */ + 7 + /* Opportunistic tls */ + 29 /* Min real data: ip length + udp length + 1 byte */) + return -1; + +#ifdef ENABLE_MEM_ALLOC_FAILURES + set_ndpi_malloc(malloc_wrapper); + set_ndpi_free(free_wrapper); + set_mem_alloc_state(size); +#endif + + ndpi_info_mod = ndpi_init_detection_module(fuzzed_data.ConsumeIntegral<u_int32_t>()); + + NDPI_BITMASK_RESET(enabled_bitmask); + for(i = 0; i < NDPI_MAX_SUPPORTED_PROTOCOLS + NDPI_MAX_NUM_CUSTOM_PROTOCOLS ; i++) { + if(fuzzed_data.ConsumeBool()) + NDPI_BITMASK_ADD(enabled_bitmask, i); + } + if(ndpi_set_protocol_detection_bitmask2(ndpi_info_mod, &enabled_bitmask) == -1) { + ndpi_exit_detection_module(ndpi_info_mod); + ndpi_info_mod = NULL; + } + + if(fuzzed_data.ConsumeBool()) + ndpi_load_protocols_file(ndpi_info_mod, "protos.txt"); + if(fuzzed_data.ConsumeBool()) + ndpi_load_categories_file(ndpi_info_mod, "categories.txt", NULL); + if(fuzzed_data.ConsumeBool()) + ndpi_load_risk_domain_file(ndpi_info_mod, "risky_domains.txt"); + if(fuzzed_data.ConsumeBool()) + ndpi_load_malicious_ja3_file(ndpi_info_mod, "ja3_fingerprints.csv"); + if(fuzzed_data.ConsumeBool()) + ndpi_load_malicious_sha1_file(ndpi_info_mod, "sha1_fingerprints.csv"); + + for(i = 0; i < NDPI_LRUCACHE_MAX; i++) { + ndpi_set_lru_cache_size(ndpi_info_mod, static_cast<lru_cache_type>(i), + fuzzed_data.ConsumeIntegralInRange(0, (1 << 24) - 1)); + ndpi_get_lru_cache_size(ndpi_info_mod, static_cast<lru_cache_type>(i), &num); + } + + if(fuzzed_data.ConsumeBool()) + ndpi_set_detection_preferences(ndpi_info_mod, ndpi_pref_direction_detect_disable, + fuzzed_data.ConsumeBool()); + if(fuzzed_data.ConsumeBool()) + ndpi_set_detection_preferences(ndpi_info_mod, ndpi_pref_enable_tls_block_dissection, + 0 /* unused */); + if(fuzzed_data.ConsumeBool()) + ndpi_set_detection_preferences(ndpi_info_mod, ndpi_pref_max_packets_to_process, + fuzzed_data.ConsumeIntegralInRange(0, (1 << 16))); + + ndpi_set_opportunistic_tls(ndpi_info_mod, NDPI_PROTOCOL_MAIL_SMTP, fuzzed_data.ConsumeBool()); + ndpi_get_opportunistic_tls(ndpi_info_mod, NDPI_PROTOCOL_MAIL_SMTP); + ndpi_set_opportunistic_tls(ndpi_info_mod, NDPI_PROTOCOL_MAIL_IMAP, fuzzed_data.ConsumeBool()); + ndpi_get_opportunistic_tls(ndpi_info_mod, NDPI_PROTOCOL_MAIL_IMAP); + ndpi_set_opportunistic_tls(ndpi_info_mod, NDPI_PROTOCOL_MAIL_POP, fuzzed_data.ConsumeBool()); + ndpi_get_opportunistic_tls(ndpi_info_mod, NDPI_PROTOCOL_MAIL_POP); + ndpi_set_opportunistic_tls(ndpi_info_mod, NDPI_PROTOCOL_FTP_CONTROL, fuzzed_data.ConsumeBool()); + ndpi_get_opportunistic_tls(ndpi_info_mod, NDPI_PROTOCOL_FTP_CONTROL); + + random_proto = fuzzed_data.ConsumeIntegralInRange(0, (1 << 16) - 1); + random_value = fuzzed_data.ConsumeIntegralInRange(0,2); /* Only 0-1 are valid values */ + ndpi_set_opportunistic_tls(ndpi_info_mod, random_proto, random_value); + ndpi_get_opportunistic_tls(ndpi_info_mod, random_proto); + + ndpi_finalize_initialization(ndpi_info_mod); + + + /* Basic code to try testing this "config" */ + memset(&flow, 0, sizeof(flow)); + std::vector<uint8_t>pkt = fuzzed_data.ConsumeRemainingBytes<uint8_t>(); + assert(pkt.size() >= 29); /* To be sure check on fuzzed_data.remaining_bytes() at the beginning is right */ + ndpi_detection_process_packet(ndpi_info_mod, &flow, pkt.data(), pkt.size(), 0, NULL); + ndpi_detection_giveup(ndpi_info_mod, &flow, 1, &protocol_was_guessed); + ndpi_free_flow_data(&flow); + + /* Get some final stats */ + for(i = 0; i < NDPI_LRUCACHE_MAX; i++) + ndpi_get_lru_cache_stats(ndpi_info_mod, static_cast<lru_cache_type>(i), &lru_stats); + for(i = 0; i < NDPI_PTREE_MAX; i++) + ndpi_get_patricia_stats(ndpi_info_mod, static_cast<ptree_type>(i), &patricia_stats); + for(i = 0; i < NDPI_AUTOMA_MAX; i++) + ndpi_get_automa_stats(ndpi_info_mod, static_cast<automa_type>(i), &automa_stats); + + ndpi_exit_detection_module(ndpi_info_mod); + + return 0; +} diff --git a/fuzz/fuzz_ndpi_reader.c b/fuzz/fuzz_ndpi_reader.c index dc63c7f07..ead9ce87b 100644 --- a/fuzz/fuzz_ndpi_reader.c +++ b/fuzz/fuzz_ndpi_reader.c @@ -1,5 +1,6 @@ #include "reader_util.h" #include "ndpi_api.h" +#include "fuzz_common_code.h" #include <pcap/pcap.h> @@ -23,27 +24,6 @@ int malloc_size_stats = 0; int max_malloc_bins = 0; struct ndpi_bin malloc_bins; /* unused */ -#ifdef ENABLE_MEM_ALLOC_FAILURES - -static int mem_alloc_state = 0; - -__attribute__((no_sanitize("integer"))) -static int fastrand () -{ - if(!mem_alloc_state) return 1; /* No failures */ - mem_alloc_state = (214013 * mem_alloc_state + 2531011); - return (mem_alloc_state >> 16) & 0x7FFF; -} - -static void *malloc_wrapper(size_t size) { - return (fastrand () % 16) ? malloc (size) : NULL; -} -static void free_wrapper(void *freeable) { - free(freeable); -} - -#endif - FILE *bufferToFile(const uint8_t *Data, size_t Size) { FILE *fd; fd = tmpfile(); @@ -99,17 +79,13 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { memset(workflow->stats.protocol_flows, 0, sizeof(workflow->stats.protocol_flows)); ndpi_finalize_initialization(workflow->ndpi_struct); -#ifdef ENABLE_MEM_ALLOC_FAILURES - set_ndpi_malloc(malloc_wrapper); - set_ndpi_free(free_wrapper); - /* Don't fail memory allocations until init phase is done */ -#endif } - #ifdef ENABLE_MEM_ALLOC_FAILURES - mem_alloc_state = Size; + /* Don't fail memory allocations until init phase is done */ + set_mem_alloc_state(Size); #endif + fd = bufferToFile(Data, Size); if (fd == NULL) return 0; |