aboutsummaryrefslogtreecommitdiff
path: root/fuzz
diff options
context:
space:
mode:
authorIvan Nardi <12729895+IvanNardi@users.noreply.github.com>2022-12-23 19:07:13 +0100
committerGitHub <noreply@github.com>2022-12-23 19:07:13 +0100
commit560280e6f082d22e6a9de8e537b7876bacf8d072 (patch)
treea8ed2ea6c43614606cc977fc27050dd41e0c3133 /fuzz
parent3de76812d978060c433864c2f72de113746d70e8 (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.am20
-rw-r--r--fuzz/fuzz_common_code.c30
-rw-r--r--fuzz/fuzz_common_code.h15
-rw-r--r--fuzz/fuzz_config.cpp113
-rw-r--r--fuzz/fuzz_ndpi_reader.c32
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;