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 | |
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.
-rw-r--r-- | .github/workflows/cifuzz.yml | 2 | ||||
-rw-r--r-- | configure.ac | 5 | ||||
-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 | ||||
-rw-r--r-- | src/include/ndpi_api.h | 3 | ||||
-rw-r--r-- | src/include/ndpi_define.h.in | 6 | ||||
-rw-r--r-- | src/lib/ndpi_main.c | 84 | ||||
-rw-r--r-- | src/lib/ndpi_utils.c | 13 | ||||
-rw-r--r-- | src/lib/third_party/src/ahocorasick.c | 15 | ||||
-rw-r--r-- | src/lib/third_party/src/ndpi_patricia.c | 32 |
13 files changed, 310 insertions, 60 deletions
diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml index a4b7ddbe9..62f0d417c 100644 --- a/.github/workflows/cifuzz.yml +++ b/.github/workflows/cifuzz.yml @@ -18,7 +18,7 @@ jobs: uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master with: oss-fuzz-project-name: 'ndpi' - fuzz-seconds: 900 + fuzz-seconds: 1200 dry-run: false sanitizer: ${{ matrix.sanitizer }} - name: Check Crash (fails when a crash is detected) diff --git a/configure.ac b/configure.ac index 3b3e64d4c..b55abdf61 100644 --- a/configure.ac +++ b/configure.ac @@ -28,7 +28,10 @@ AC_ARG_ENABLE(npcap, AS_HELP_STRING([--disable-npcap], [msys2 only: Disable link AC_ARG_WITH(nbpf-path, AS_HELP_STRING([--with-nbpf-path], [nBPF library custom path; default: ${PWD}/../PF_RING/userland/nbpf]),[NBPF_HOME=$withval],[NBPF_HOME=${PWD}/../PF_RING/userland/nbpf]) AC_ARG_WITH(lto-and-gold-linker, AS_HELP_STRING([--with-lto-and-gold-linker], [Build with LTO and Gold linker])]) -AS_IF([test "x$enable_fuzztargets" = "xyes"], [BUILD_FUZZTARGETS=1], [BUILD_FUZZTARGETS=0]) +AS_IF([test "x$enable_fuzztargets" = "xyes"], [ + BUILD_FUZZTARGETS=1 + NDPI_CFLAGS="${NDPI_CFLAGS} -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION" +], [BUILD_FUZZTARGETS=0]) AM_CONDITIONAL([BUILD_FUZZTARGETS], [test "x$enable_fuzztargets" = "xyes"]) AS_IF([test "${with_sanitizer+set}" = set -a "${with_thread_sanitizer+set}" = set],[ 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; diff --git a/src/include/ndpi_api.h b/src/include/ndpi_api.h index bd754f1e1..5214c054f 100644 --- a/src/include/ndpi_api.h +++ b/src/include/ndpi_api.h @@ -264,9 +264,10 @@ extern "C" { * * @par ndpi_struct = the detection module * @par detection_bitmask = the protocol bitmask to set + * @return 0 if ok, -1 if error * */ - void ndpi_set_protocol_detection_bitmask2(struct ndpi_detection_module_struct *ndpi_struct, + int ndpi_set_protocol_detection_bitmask2(struct ndpi_detection_module_struct *ndpi_struct, const NDPI_PROTOCOL_BITMASK * detection_bitmask); /** diff --git a/src/include/ndpi_define.h.in b/src/include/ndpi_define.h.in index 31b7a1825..75f41dac2 100644 --- a/src/include/ndpi_define.h.in +++ b/src/include/ndpi_define.h.in @@ -218,7 +218,11 @@ # define NDPI_LOG_DBG2(...) {} # else # define NDPI_LOG(proto, mod, log_level, args...) { /* printf(args); */ } -# define NDPI_LOG_ERR(mod, args...) { printf(args); } +# ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION +# define NDPI_LOG_ERR(mod, args...) { printf(args); } +# else +# define NDPI_LOG_ERR(mod, args...) { /* printf(args); */ } +# endif # define NDPI_LOG_INFO(mod, args...) { /* printf(args); */ } # define NDPI_LOG_DBG(mod, args...) { /* printf(args); */ } # define NDPI_LOG_DBG2(mod, args...) { /* printf(args); */ } diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c index c67e7b2c8..95d880dcb 100644 --- a/src/lib/ndpi_main.c +++ b/src/lib/ndpi_main.c @@ -491,13 +491,16 @@ void ndpi_set_proto_subprotocols(struct ndpi_detection_module_struct *ndpi_str, ndpi_str->proto_defaults[protoId].subprotocols = ndpi_malloc(sizeof(protoId) * ndpi_str->proto_defaults[protoId].subprotocol_count); + if(!ndpi_str->proto_defaults[protoId].subprotocols) { + ndpi_str->proto_defaults[protoId].subprotocol_count = 0; + return; + } va_start(ap, protoId); current_arg = va_arg(ap, int); while (current_arg != NDPI_PROTOCOL_NO_MORE_SUBPROTOCOLS) { - if(is_proto_enabled(ndpi_str, current_arg) && - ndpi_str->proto_defaults[protoId].subprotocols != NULL) { + if(is_proto_enabled(ndpi_str, current_arg)) { ndpi_str->proto_defaults[protoId].subprotocols[i++] = current_arg; } current_arg = va_arg(ap, int); @@ -621,6 +624,11 @@ static void addDefaultPort(struct ndpi_detection_module_struct *ndpi_str, (void *) root, ndpi_default_ports_tree_node_t_cmp); /* Add it to the tree */ + if(ret == NULL) { + NDPI_LOG_DBG(ndpi_str, "[NDPI] %s:%d error searching for port %u\n", _func, _line, port); + ndpi_free(node); + break; + } if(ret != node) { NDPI_LOG_DBG(ndpi_str, "[NDPI] %s:%d found duplicate for port %u: overwriting it with new value\n", _func, _line, port); @@ -803,6 +811,8 @@ void ndpi_init_protocol_match(struct ndpi_detection_module_struct *ndpi_str, if(ndpi_str->proto_defaults[match->protocol_id].protoName == NULL) { ndpi_str->proto_defaults[match->protocol_id].protoName = ndpi_strdup(match->proto_name); + if(!ndpi_str->proto_defaults[match->protocol_id].protoName) + return; ndpi_str->proto_defaults[match->protocol_id].isAppProtocol = 1; ndpi_str->proto_defaults[match->protocol_id].protoId = match->protocol_id; ndpi_str->proto_defaults[match->protocol_id].protoCategory = match->protocol_category; @@ -925,6 +935,9 @@ static void init_string_based_protocols(struct ndpi_detection_module_struct *ndp int ndpi_set_detection_preferences(struct ndpi_detection_module_struct *ndpi_str, ndpi_detection_preference pref, int value) { + if(!ndpi_str) + return -1; + switch(pref) { case ndpi_pref_direction_detect_disable: ndpi_str->direction_detect_disable = (u_int8_t) value; @@ -2157,6 +2170,9 @@ void ndpi_patricia_get_stats(ndpi_patricia_tree_t *tree, struct ndpi_patricia_tr int ndpi_get_patricia_stats(struct ndpi_detection_module_struct *ndpi_struct, ptree_type ptree_type, struct ndpi_patricia_tree_stats *stats) { + if(!ndpi_struct || !stats) + return -1; + switch(ptree_type) { case NDPI_PTREE_RISK_MASK: ndpi_patricia_get_stats((ndpi_patricia_tree_t *)ndpi_struct->ip_risk_mask_ptree, stats); @@ -2296,6 +2312,9 @@ u_int16_t ndpi_network_port_ptree_match(struct ndpi_detection_module_struct *ndp ndpi_prefix_t prefix; ndpi_patricia_node_t *node; + if(!ndpi_str->protocols_ptree) + return(NDPI_PROTOCOL_UNKNOWN); + if(ndpi_str->ndpi_num_custom_protocols == 0) { /* In case we don't have defined any custom protocol we check the ptree @@ -2823,7 +2842,7 @@ struct ndpi_detection_module_struct *ndpi_init_detection_module(ndpi_init_prefs if((ndpi_str->custom_categories.ipAddresses == NULL) || (ndpi_str->custom_categories.ipAddresses_shadow == NULL)) { NDPI_LOG_ERR(ndpi_str, "[NDPI] Error allocating Patricia trees\n"); - ndpi_free(ndpi_str); + ndpi_exit_detection_module(ndpi_str); return(NULL); } @@ -2841,7 +2860,6 @@ struct ndpi_detection_module_struct *ndpi_init_detection_module(ndpi_init_prefs ndpi_str->opportunistic_tls_pop_enabled = 1; ndpi_str->opportunistic_tls_ftp_enabled = 1; - for(i = 0; i < NUM_CUSTOM_CATEGORIES; i++) ndpi_snprintf(ndpi_str->custom_category_labels[i], CUSTOM_CATEGORY_LABEL_LEN, "User custom category %u", (unsigned int) (i + 1)); @@ -2899,6 +2917,9 @@ static void ndpi_add_domain_risk_exceptions(struct ndpi_detection_module_struct void ndpi_finalize_initialization(struct ndpi_detection_module_struct *ndpi_str) { u_int i; + if(!ndpi_str) + return; + ndpi_add_domain_risk_exceptions(ndpi_str); if(ndpi_str->ookla_cache_num_entries > 0) { @@ -3035,6 +3056,9 @@ int ndpi_get_automa_stats(struct ndpi_detection_module_struct *ndpi_struct, automa_type automa_type, struct ndpi_automa_stats *stats) { + if(!ndpi_struct || !stats) + return -1; + switch(automa_type) { case NDPI_AUTOMA_HOST: ndpi_automa_get_stats(ndpi_struct->host_automa.ac_automa, stats); @@ -3537,7 +3561,7 @@ int ndpi_add_host_risk_mask(struct ndpi_detection_module_struct *ndpi_str, u_int len; char *host_dup = NULL; - if((ndpi_str->host_risk_mask_automa.ac_automa == NULL) || (host == NULL)) + if((ndpi_str == NULL) || (ndpi_str->host_risk_mask_automa.ac_automa == NULL) || (host == NULL)) return(-2); /* Zap heading/trailing quotes */ @@ -3928,6 +3952,8 @@ int ndpi_load_malicious_ja3_file(struct ndpi_detection_module_struct *ndpi_str, FILE *fd; int len, num = 0; + if(!ndpi_str) + return(-1); if(ndpi_str->malicious_ja3_hashmap == NULL && ndpi_hash_init(&ndpi_str->malicious_ja3_hashmap) != 0) return(-1); @@ -3990,6 +4016,8 @@ int ndpi_load_malicious_sha1_file(struct ndpi_detection_module_struct *ndpi_str, size_t i, len; int num = 0; + if(!ndpi_str) + return(-1); if(ndpi_str->malicious_sha1_hashmap == NULL && ndpi_hash_init(&ndpi_str->malicious_sha1_hashmap) != 0) return(-1); @@ -5119,16 +5147,19 @@ void ndpi_free_flow_data(struct ndpi_flow_struct* flow) { if(flow->l4.udp.quic_reasm_buf_bitmap) ndpi_free(flow->l4.udp.quic_reasm_buf_bitmap); } - } - if(flow->flow_payload != NULL) - ndpi_free(flow->flow_payload); + if(flow->flow_payload != NULL) + ndpi_free(flow->flow_payload); + } } /* ************************************************ */ -void ndpi_set_protocol_detection_bitmask2(struct ndpi_detection_module_struct *ndpi_str, +int ndpi_set_protocol_detection_bitmask2(struct ndpi_detection_module_struct *ndpi_str, const NDPI_PROTOCOL_BITMASK *dbm) { + if(!ndpi_str) + return -1; + NDPI_BITMASK_SET(ndpi_str->detection_bitmask, *dbm); ndpi_init_protocol_defaults(ndpi_str); @@ -5137,7 +5168,9 @@ void ndpi_set_protocol_detection_bitmask2(struct ndpi_detection_module_struct *n if(ndpi_callback_init(ndpi_str)) { NDPI_LOG_ERR(ndpi_str, "[NDPI] Error allocating callbacks\n"); + return -1; } + return 0; } /* ************************************************ */ @@ -5942,7 +5975,7 @@ ndpi_protocol ndpi_detection_giveup(struct ndpi_detection_module_struct *ndpi_st *protocol_was_guessed = 0; - if(flow == NULL) + if(!ndpi_str || !flow) return(ret); /* Init defaults */ @@ -6178,7 +6211,8 @@ int ndpi_enable_loaded_categories(struct ndpi_detection_module_struct *ndpi_str) 1 /* free patterns strings memory */); /* Finalize */ - ac_automata_finalize((AC_AUTOMATA_t *) ndpi_str->custom_categories.hostnames_shadow.ac_automa); + if(ndpi_str->custom_categories.hostnames_shadow.ac_automa) + ac_automata_finalize((AC_AUTOMATA_t *) ndpi_str->custom_categories.hostnames_shadow.ac_automa); /* Swap */ ndpi_str->custom_categories.hostnames.ac_automa = ndpi_str->custom_categories.hostnames_shadow.ac_automa; @@ -6410,18 +6444,23 @@ ndpi_protocol ndpi_detection_process_packet(struct ndpi_detection_module_struct struct ndpi_flow_struct *flow, const unsigned char *packet_data, const unsigned short packetlen, const u_int64_t current_time_ms, const struct ndpi_flow_input_info *input_info) { - struct ndpi_packet_struct *packet = &ndpi_str->packet; + struct ndpi_packet_struct *packet; NDPI_SELECTION_BITMASK_PROTOCOL_SIZE ndpi_selection_packet; u_int32_t num_calls = 0; - ndpi_protocol ret = { flow->detected_protocol_stack[1], flow->detected_protocol_stack[0], flow->guessed_protocol_id_by_ip, flow->category, NULL }; + ndpi_protocol ret = { 0 }; + + if(!flow || !ndpi_str) + return(ret); + + packet = &ndpi_str->packet; NDPI_LOG_DBG(ndpi_str, "[%d/%d] START packet processing\n", flow->detected_protocol_stack[0], flow->detected_protocol_stack[1]); - if(flow == NULL) - return(ret); - else - ret.category = flow->category; + ret.master_protocol = flow->detected_protocol_stack[1], + ret.app_protocol = flow->detected_protocol_stack[0]; + ret.protocol_by_ip = flow->guessed_protocol_id_by_ip; + ret.category = flow->category; if(flow->fail_with_unknown) { // printf("%s(): FAIL_WITH_UNKNOWN\n", __FUNCTION__); @@ -6437,8 +6476,6 @@ ndpi_protocol ndpi_detection_process_packet(struct ndpi_detection_module_struct flow->num_processed_pkts++; /* Init default */ - ret.master_protocol = flow->detected_protocol_stack[1], - ret.app_protocol = flow->detected_protocol_stack[0]; if(flow->extra_packets_func) { ndpi_process_extra_packet(ndpi_str, flow, packet_data, packetlen, current_time_ms, input_info); @@ -8442,6 +8479,9 @@ int ndpi_get_lru_cache_stats(struct ndpi_detection_module_struct *ndpi_struct, lru_cache_type cache_type, struct ndpi_lru_cache_stats *stats) { + if(!ndpi_struct || !stats) + return -1; + switch(cache_type) { case NDPI_LRUCACHE_OOKLA: ndpi_lru_get_stats(ndpi_struct->ookla_cache, stats); @@ -8476,6 +8516,9 @@ int ndpi_set_lru_cache_size(struct ndpi_detection_module_struct *ndpi_struct, lru_cache_type cache_type, u_int32_t num_entries) { + if(!ndpi_struct) + return -1; + switch(cache_type) { case NDPI_LRUCACHE_OOKLA: ndpi_struct->ookla_cache_num_entries = num_entries; @@ -8510,6 +8553,9 @@ int ndpi_get_lru_cache_size(struct ndpi_detection_module_struct *ndpi_struct, lru_cache_type cache_type, u_int32_t *num_entries) { + if(!ndpi_struct) + return -1; + switch(cache_type) { case NDPI_LRUCACHE_OOKLA: *num_entries = ndpi_struct->ookla_cache_num_entries; diff --git a/src/lib/ndpi_utils.c b/src/lib/ndpi_utils.c index c7b2ff45a..990aef9bd 100644 --- a/src/lib/ndpi_utils.c +++ b/src/lib/ndpi_utils.c @@ -2309,6 +2309,9 @@ static u_int64_t ndpi_host_ip_risk_ptree_match(struct ndpi_detection_module_stru ndpi_prefix_t prefix; ndpi_patricia_node_t *node; + if(!ndpi_str->protocols_ptree) + return((u_int64_t)-1); + /* Make sure all in network byte order otherwise compares wont work */ ndpi_fill_prefix_v4(&prefix, pin, 32, ((ndpi_patricia_tree_t *) ndpi_str->protocols_ptree)->maxbits); node = ndpi_patricia_search_best(ndpi_str->ip_risk_mask_ptree, &prefix); @@ -2642,10 +2645,16 @@ void load_common_alpns(struct ndpi_detection_module_struct *ndpi_str) { memset(&ac_pattern, 0, sizeof(ac_pattern)); ac_pattern.astring = ndpi_strdup((char*)common_alpns[i]); + if(!ac_pattern.astring) { + NDPI_LOG_ERR(ndpi_str, "Unable to add %s [mem alloc error]\n", common_alpns[i]); + continue; + } ac_pattern.length = strlen(common_alpns[i]); - if(ac_automata_add(ndpi_str->common_alpns_automa.ac_automa, &ac_pattern) != ACERR_SUCCESS) - printf("%s(): unable to add %s\n", __FUNCTION__, common_alpns[i]); + if(ac_automata_add(ndpi_str->common_alpns_automa.ac_automa, &ac_pattern) != ACERR_SUCCESS) { + ndpi_free(ac_pattern.astring); + NDPI_LOG_ERR(ndpi_str, "Unable to add %s\n", common_alpns[i]); + } } } diff --git a/src/lib/third_party/src/ahocorasick.c b/src/lib/third_party/src/ahocorasick.c index 71b414558..192735f9c 100644 --- a/src/lib/third_party/src/ahocorasick.c +++ b/src/lib/third_party/src/ahocorasick.c @@ -223,10 +223,15 @@ void ac_automata_enable_debug (int debug) { AC_ERROR_t ac_automata_add (AC_AUTOMATA_t * thiz, AC_PATTERN_t * patt) { unsigned int i; - AC_NODE_t * n = thiz->root; + AC_NODE_t * n; AC_NODE_t * next; AC_ALPHABET_t alpha; + if(!thiz || !patt || !patt->astring) + return ACERR_ERROR; + + n = thiz->root; + if(!thiz->automata_open) return ACERR_AUTOMATA_CLOSED; @@ -556,6 +561,9 @@ static AC_ERROR_t ac_automata_release_node(AC_AUTOMATA_t * thiz, } void ac_automata_release (AC_AUTOMATA_t * thiz, uint8_t free_pattern) { + if(!thiz) + return; + ac_automata_walk(thiz,ac_automata_release_node,NULL,free_pattern ? (void *)1:NULL); if(free_pattern <= 1) { @@ -1013,8 +1021,11 @@ static int node_register_matchstr (AC_NODE_t * thiz, AC_PATTERN_t * str,int is_e if (thiz->matched_patterns && node_has_matchstr(thiz, str)) return 0; - if(!thiz->matched_patterns) + if(!thiz->matched_patterns) { thiz->matched_patterns = node_resize_mp(thiz->matched_patterns); + if(!thiz->matched_patterns) + return 1; + } /* Manage memory */ if (thiz->matched_patterns->num >= thiz->matched_patterns->max) { diff --git a/src/lib/third_party/src/ndpi_patricia.c b/src/lib/third_party/src/ndpi_patricia.c index b4cc76964..5f2aefd89 100644 --- a/src/lib/third_party/src/ndpi_patricia.c +++ b/src/lib/third_party/src/ndpi_patricia.c @@ -218,6 +218,8 @@ static ndpi_prefix_t * ndpi_New_Prefix2 (int family, void *dest, int bitlen, ndp default_bitlen = sizeof(struct in6_addr) * 8; if(prefix == NULL) { prefix = (ndpi_prefix_t*)ndpi_calloc(1, sizeof (ndpi_prefix_t)); + if(!prefix) + return (NULL); dynamic_allocated++; } memcpy (&prefix->add.sin6, dest, sizeof(struct in6_addr)); @@ -232,7 +234,9 @@ static ndpi_prefix_t * ndpi_New_Prefix2 (int family, void *dest, int bitlen, ndp //prefix4_t size incorrect on NT prefix = ndpi_calloc(1, sizeof (ndpi_prefix_t)); #endif /* NT */ - + if(!prefix) + return (NULL); + dynamic_allocated++; } memcpy (&prefix->add.sin, dest, sizeof(struct in_addr)); @@ -298,6 +302,8 @@ ndpi_patricia_tree_t * ndpi_patricia_new (u_int16_t maxbits) { ndpi_patricia_tree_t *patricia = (ndpi_patricia_tree_t*)ndpi_calloc(1, sizeof *patricia); + if(!patricia) + return (NULL); patricia->maxbits = maxbits; patricia->head = NULL; @@ -536,7 +542,9 @@ ndpi_patricia_search_best2 (ndpi_patricia_tree_t *patricia, ndpi_prefix_t *prefi u_int16_t bitlen; int cnt = 0; - assert (patricia); + if(patricia == NULL) + return (NULL); + assert (prefix); assert (prefix->bitlen <= patricia->maxbits); @@ -653,8 +661,14 @@ ndpi_patricia_lookup (ndpi_patricia_tree_t *patricia, ndpi_prefix_t *prefix) if(patricia->head == NULL) { node = (ndpi_patricia_node_t*)ndpi_calloc(1, sizeof *node); + if(!node) + return NULL; node->bit = prefix->bitlen; node->prefix = ndpi_Ref_Prefix (prefix); + if(!node->prefix) { + ndpi_free(node); + return NULL; + } node->parent = NULL; node->l = node->r = NULL; node->data = NULL; @@ -757,6 +771,9 @@ ndpi_patricia_lookup (ndpi_patricia_tree_t *patricia, ndpi_prefix_t *prefix) return (node); } node->prefix = ndpi_Ref_Prefix (prefix); + if(!node->prefix) { + return NULL; + } #ifdef PATRICIA_DEBUG fprintf (stderr, "patricia_lookup: new node #1 %s/%d (glue mod)\n", ndpi_prefix_toa (prefix), prefix->bitlen); @@ -769,6 +786,10 @@ ndpi_patricia_lookup (ndpi_patricia_tree_t *patricia, ndpi_prefix_t *prefix) if(!new_node) return NULL; new_node->bit = prefix->bitlen; new_node->prefix = ndpi_Ref_Prefix (prefix); + if(!new_node->prefix) { + ndpi_free(new_node); + return NULL; + } new_node->parent = NULL; new_node->l = new_node->r = NULL; new_node->data = NULL; @@ -820,7 +841,12 @@ ndpi_patricia_lookup (ndpi_patricia_tree_t *patricia, ndpi_prefix_t *prefix) else { glue = (ndpi_patricia_node_t*)ndpi_calloc(1, sizeof *glue); - if(!glue) return(NULL); + if(!glue) { + ndpi_Deref_Prefix(new_node->prefix); + ndpi_DeleteEntry (new_node); + patricia->num_active_node--; + return(NULL); + } glue->bit = differ_bit; glue->prefix = NULL; glue->parent = node->parent; |