From: Oleksandr Stepanov -X (ostepano - SOFTSERVE INC at Cisco) Date: Thu, 7 Aug 2025 12:05:22 +0000 (+0000) Subject: Pull request #4848: appid: out-of-range readings fix X-Git-Tag: 3.9.3.0~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2bc63127bf3a6b8316fe613c04b4f48ec9e021a4;p=thirdparty%2Fsnort3.git Pull request #4848: appid: out-of-range readings fix Merge in SNORT/snort3 from ~OSTEPANO/snort3:misc_out_of_range to master Squashed commit of the following: commit 3a72fb5d4060e7c0d5aa4b2a7f326cf70d7ea567 Author: Oleksandr Stepanov Date: Wed Jul 30 08:26:34 2025 -0400 appid: out-of-range readings fix --- diff --git a/src/network_inspectors/appid/detector_plugins/detector_dns.cc b/src/network_inspectors/appid/detector_plugins/detector_dns.cc index db1d19b39..851997b23 100644 --- a/src/network_inspectors/appid/detector_plugins/detector_dns.cc +++ b/src/network_inspectors/appid/detector_plugins/detector_dns.cc @@ -361,50 +361,50 @@ int DnsValidator::dns_validate_query(const uint8_t* data, uint16_t* offset, uint uint16_t id, bool host_reporting, AppIdSession& asd, AppidChangeBits& change_bits) { int ret; - const uint8_t* host; - uint8_t host_len; - bool host_len_valid; - uint16_t host_offset; + const uint8_t* host = data + *offset; + uint8_t host_len = 0; + bool host_len_valid = false; + uint16_t host_offset = *offset; - host = data + *offset; - host_offset = *offset; ret = dns_validate_label(data, *offset, size, host_len, host_len_valid); - if (ret == APPID_SUCCESS) + if ((ret == APPID_SUCCESS) and (host_reporting)) { + if ((*offset > size) || ((size - *offset) < (uint16_t)sizeof(DNSQueryFixed))) + return APPID_NOMATCH; + const DNSQueryFixed* query = (const DNSQueryFixed*)(data + *offset); + *offset += sizeof(DNSQueryFixed); - if (host_reporting) - { - uint16_t record_type = ntohs(query->QType); + uint16_t record_type = ntohs(query->QType); - if ((host_len == 0) || (!host_len_valid)) - { - host = nullptr; - host_len = 0; - host_offset = 0; - } - switch (record_type) - { - case PATTERN_A_REC: - case PATTERN_AAAA_REC: - case PATTERN_CNAME_REC: - case PATTERN_SRV_REC: - case PATTERN_TXT_REC: - case PATTERN_MX_REC: - case PATTERN_SOA_REC: - case PATTERN_NS_REC: - case PATTERN_ANY_REC: - ret = add_dns_query_info(asd, id, host, host_len, host_offset, record_type, *offset, change_bits); - break; - case PATTERN_PTR_REC: - ret = add_dns_query_info(asd, id, nullptr, 0, 0, record_type, *offset, change_bits); - break; - default: - break; - } + if ((host_len == 0) || (!host_len_valid)) + { + host = nullptr; + host_len = 0; + host_offset = 0; + } + switch (record_type) + { + case PATTERN_A_REC: + case PATTERN_AAAA_REC: + case PATTERN_CNAME_REC: + case PATTERN_SRV_REC: + case PATTERN_TXT_REC: + case PATTERN_MX_REC: + case PATTERN_SOA_REC: + case PATTERN_NS_REC: + case PATTERN_ANY_REC: + ret = add_dns_query_info(asd, id, host, host_len, host_offset, record_type, *offset, change_bits); + break; + case PATTERN_PTR_REC: + ret = add_dns_query_info(asd, id, nullptr, 0, 0, record_type, *offset, change_bits); + break; + default: + break; } + } return ret; } diff --git a/src/network_inspectors/appid/detector_plugins/detector_pop3.cc b/src/network_inspectors/appid/detector_plugins/detector_pop3.cc index d598c1b94..44f24855c 100644 --- a/src/network_inspectors/appid/detector_plugins/detector_pop3.cc +++ b/src/network_inspectors/appid/detector_plugins/detector_pop3.cc @@ -290,7 +290,7 @@ static int pop3_check_line(const uint8_t** data, const uint8_t* end) int Pop3ServiceDetector::pop3_server_validate(POP3DetectorData* dd, const uint8_t* data, uint16_t size, AppIdSession& asd, int server, AppidChangeBits& change_bits) -{ +{ ServicePOP3Data* pd = &dd->server; const uint8_t* begin = nullptr; @@ -305,7 +305,7 @@ int Pop3ServiceDetector::pop3_server_validate(POP3DetectorData* dd, const uint8_ // fallthrough case POP3_STATE_RESPONSE: - if (!begin && data[0] == '+' && data[1] == ' ') + if (!begin && size >= 2 && data[0] == '+' && data[1] == ' ') { data += 2; if (pop3_check_line(&data, end)) diff --git a/src/network_inspectors/appid/detector_plugins/detector_smtp.cc b/src/network_inspectors/appid/detector_plugins/detector_smtp.cc index 6f8c3c76c..e554eeebf 100644 --- a/src/network_inspectors/appid/detector_plugins/detector_smtp.cc +++ b/src/network_inspectors/appid/detector_plugins/detector_smtp.cc @@ -525,8 +525,8 @@ int SmtpClientDetector::validate(AppIdDiscoveryArgs& args) if (*args.data == '.') { if (len == 0 || - args.data[1] == '\n' || - (len >= 2 && args.data[1] == '\r' && args.data[2] == '\n')) + (len >= 2 && args.data[1] == '\n') || + (len >= 3 && args.data[1] == '\r' && args.data[2] == '\n')) { add_app(args.asd, APP_ID_SMTP, APP_ID_SMTP, nullptr, args.change_bits); goto done; diff --git a/src/network_inspectors/appid/detector_plugins/http_url_patterns.cc b/src/network_inspectors/appid/detector_plugins/http_url_patterns.cc index 333a21d3b..af769d9b3 100644 --- a/src/network_inspectors/appid/detector_plugins/http_url_patterns.cc +++ b/src/network_inspectors/appid/detector_plugins/http_url_patterns.cc @@ -1614,7 +1614,7 @@ void HttpPatternMatchers::get_server_vendor_version(const char* data, int len, c vendor_len = ver - data; ver++; - for (p = ver; *p && p < end; p++) + for (p = ver; p < end && *p; p++) { if ( *p == '(' ) { diff --git a/src/network_inspectors/appid/detector_plugins/test/CMakeLists.txt b/src/network_inspectors/appid/detector_plugins/test/CMakeLists.txt index 5b63a4ff5..4852e9173 100644 --- a/src/network_inspectors/appid/detector_plugins/test/CMakeLists.txt +++ b/src/network_inspectors/appid/detector_plugins/test/CMakeLists.txt @@ -1,8 +1,19 @@ include_directories ( appid PRIVATE ${APPID_INCLUDE_DIR} ) -add_cpputest( detector_smtp_test ) +add_cpputest( detector_smtp_test + SOURCES + ../../../../utils/util_cstring.cc ) -add_cpputest( http_url_patterns_test ) +add_cpputest( http_url_patterns_test + SOURCES + ../../../../utils/util_cstring.cc ) -add_cpputest( detector_sip_test ) +add_cpputest( detector_sip_test + SOURCES + ../../../../utils/util_cstring.cc + ../../appid_utils/sf_mlmp.cc ) + +add_cpputest( detector_pop3_test + SOURCES + ../../../../utils/util_cstring.cc ) diff --git a/src/network_inspectors/appid/detector_plugins/test/detector_plugins_mock.h b/src/network_inspectors/appid/detector_plugins/test/detector_plugins_mock.h index 6b0442b6c..ced4f9622 100644 --- a/src/network_inspectors/appid/detector_plugins/test/detector_plugins_mock.h +++ b/src/network_inspectors/appid/detector_plugins/test/detector_plugins_mock.h @@ -24,6 +24,12 @@ #include "config.h" #endif +#include +#include +#include +#include +#include + #include "log/messages.h" #include "utils/stats.h" @@ -93,18 +99,6 @@ void show_stats(PegCount*, const PegInfo*, unsigned, const char*) { } void show_stats(PegCount*, const PegInfo*, const std::vector&, const char*, FILE*) { } // LCOV_EXCL_STOP -#ifndef SIP_UNIT_TEST -class AppIdInspector : public snort::Inspector -{ -public: - AppIdInspector(AppIdModule&) { } - ~AppIdInspector() override = default; - bool configure(snort::SnortConfig*) override; -private: - AppIdContext* ctxt = nullptr; -}; -#endif - // Stubs for modules, config AppIdConfig::~AppIdConfig() = default; AppIdModule::AppIdModule() @@ -127,7 +121,7 @@ bool AppIdModule::end(const char*, int, snort::SnortConfig*) return false; } -const Command* AppIdModule::get_commands() const +const snort::Command* AppIdModule::get_commands() const { return nullptr; } @@ -148,8 +142,8 @@ snort::ProfileStats* AppIdModule::get_profile( return nullptr; } -void AppIdModule::set_trace(const Trace*) const { } -const TraceOption* AppIdModule::get_trace_options() const { return nullptr; } +void AppIdModule::set_trace(const snort::Trace*) const { } +const snort::TraceOption* AppIdModule::get_trace_options() const { return nullptr; } // LCOV_EXCL_STOP // Stubs for inspectors @@ -157,15 +151,15 @@ unsigned AppIdSession::inspector_id = 0; AppIdConfig stub_config; AppIdContext stub_ctxt(stub_config); OdpContext stub_odp_ctxt(stub_config, nullptr); -AppIdSession::AppIdSession(IpProtocol, const SfIp* ip, uint16_t, AppIdInspector& inspector, +AppIdSession::AppIdSession(IpProtocol, const snort::SfIp* ip, uint16_t, AppIdInspector& inspector, OdpContext& odpctxt, uint32_t #ifndef DISABLE_TENANT_ID ,uint32_t #endif ) : snort::FlowData(inspector_id, (snort::Inspector*)&inspector), - config(stub_config), api(*(new AppIdSessionApi(this, *ip))), odp_ctxt(odpctxt) + config(stub_config), api(*(new snort::AppIdSessionApi(this, *ip))), odp_ctxt(odpctxt) { - this->set_session_flags(APPID_SESSION_DISCOVER_APP); + } AppIdSession::~AppIdSession() { delete &api; } AppIdHttpSession::AppIdHttpSession(AppIdSession& asd, int64_t http2_stream_id) @@ -235,4 +229,76 @@ OdpContext::OdpContext(const AppIdConfig&, snort::SnortConfig*) { } THREAD_LOCAL OdpContext* pkt_thread_odp_ctxt = nullptr; + +// Stubs for module +snort::Module::Module(char const*, char const*) {} +void snort::Module::sum_stats(bool) {} +void snort::Module::show_interval_stats(std::vector&, FILE*) {} +void snort::Module::show_stats() {} +void snort::Module::init_stats(bool) {} +void snort::Module::reset_stats() {} +void snort::Module::main_accumulate_stats() {} +PegCount snort::Module::get_global_count(char const*) const { return 0; } + + +void ApplicationDescriptor::set_id(const snort::Packet&, AppIdSession&, AppidSessionDirection, AppId, AppidChangeBits&) { } +AppIdDiscovery::~AppIdDiscovery() = default; +void ClientDiscovery::initialize(AppIdInspector&) { } +void ClientDiscovery::reload() { } +void AppIdDiscovery::register_detector(const string&, AppIdDetector*, IpProtocol) { } +void AppIdDiscovery::add_pattern_data(AppIdDetector*, snort::SearchTool&, int, unsigned char const*, unsigned int, unsigned int) { } +void AppIdDiscovery::register_tcp_pattern(AppIdDetector*, unsigned char const*, unsigned int, int, unsigned int) { } +void AppIdDiscovery::register_udp_pattern(AppIdDetector*, unsigned char const*, unsigned int, int, unsigned int) { } +int AppIdDiscovery::add_service_port(AppIdDetector*, ServiceDetectorPort const&) { return 0; } +DnsPatternMatchers::~DnsPatternMatchers() = default; +EveCaPatternMatchers::~EveCaPatternMatchers() = default; +#ifndef SIP_UNIT_TEST +SipPatternMatchers::~SipPatternMatchers() = default; +#endif +HostPatternMatchers::~HostPatternMatchers() = default; +AlpnPatternMatchers::~AlpnPatternMatchers() = default; +#ifndef HTTP_PATTERNS_UNIT_TEST +HttpPatternMatchers::~HttpPatternMatchers() = default; +#endif +UserDataMap::~UserDataMap() = default; +CipPatternMatchers::~CipPatternMatchers() = default; +bool HostPatternMatchers::scan_url(const uint8_t*, size_t, AppId&, AppId&, bool*){ return true; } +void AppIdModule::reset_stats() {} +bool AppIdInspector::configure(snort::SnortConfig*) { return true; } +void appid_log(const snort::Packet*, unsigned char, char const*, ...) { } +void HostPatternMatchers::add_host_pattern(unsigned char const*, unsigned long, unsigned char, int, int, HostPatternType, bool, bool) {} + +#ifndef SIP_UNIT_TEST +snort::SearchTool::SearchTool(bool, const char*) { } +#endif + +ServiceDetector::ServiceDetector() {} +void ServiceDetector::register_appid(AppId appId, unsigned extractsInfo, OdpContext& odp_ctxt) {} +int ServiceDetector::add_service_consume_subtype(AppIdSession& asd, const snort::Packet* pkt, + AppidSessionDirection dir, AppId appId, const char* vendor, const char* version, + AppIdServiceSubtype* subtype, AppidChangeBits& change_bits) + { return 0; } +int ServiceDetector::add_service(AppidChangeBits& change_bits, AppIdSession& asd, + const snort::Packet* pkt, AppidSessionDirection dir, AppId appId, const char* vendor, + const char* version, AppIdServiceSubtype* subtype) + { return 0; } +int ServiceDetector::service_inprocess(AppIdSession& asd, const snort::Packet* pkt, AppidSessionDirection dir) { return 0; } + +snort::AppIdSessionApi::AppIdSessionApi(const AppIdSession*, const SfIp&) +{ } + +AppIdInspector::~AppIdInspector() = default; + +void ClientDetector::register_appid(int, unsigned int, OdpContext&) { } + +void AppIdInspector::eval(snort::Packet*) { } +void AppIdInspector::show(const snort::SnortConfig*) const { } +void AppIdInspector::tinit() { } +void AppIdInspector::tterm() { } +void AppIdInspector::tear_down(snort::SnortConfig*) { } + +ClientDetector::ClientDetector() { } + +void AppIdSession::set_client_appid_data(AppId, AppidChangeBits&, char*) { } +int AppIdSession::add_flow_data_id(uint16_t, ServiceDetector*) { return 0; } #endif diff --git a/src/network_inspectors/appid/detector_plugins/test/detector_pop3_test.cc b/src/network_inspectors/appid/detector_plugins/test/detector_pop3_test.cc new file mode 100644 index 000000000..5045dee61 --- /dev/null +++ b/src/network_inspectors/appid/detector_plugins/test/detector_pop3_test.cc @@ -0,0 +1,96 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2016-2025 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// detector_pop3_test.cc author Oleksandr Stepanov + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "appid_inspector.h" +#include "appid_session.h" +#include "detector_plugins_mock.h" + +#include "../detector_pop3.h" +#include "../detector_pop3.cc" + +#include +#include +#include + +using namespace snort; + +static ServiceDiscovery test_discovery; + +// Stubs for AppIdInspector +AppIdConfig test_app_config; +AppIdInspector::AppIdInspector(AppIdModule&) : config(&test_app_config), ctxt(test_app_config) { } + +void snort::SearchTool::reload() { } +int snort::SearchTool::find_all(const char*, unsigned, MpseMatch, bool, void* mp_arg, const snort::SnortConfig*) +{ + return 0; +} + +void AppIdDetector::add_user(AppIdSession&, const char*, AppId, bool, AppidChangeBits&){} +int AppIdDetector::data_add(AppIdSession&, AppIdFlowData*) { return 1; } +AppIdFlowData* AppIdDetector::data_get(const AppIdSession&) +{ + return nullptr; +} + +int ServiceDetector::fail_service(AppIdSession& asd, const Packet* pkt, AppidSessionDirection dir) { return 1; } + + +TEST_GROUP(detector_pop_tests) +{ + Pop3ServiceDetector* test_detector = nullptr; + void setup() override + { + test_detector = new Pop3ServiceDetector(&test_discovery); + } + + void teardown() override + { + delete test_detector; + test_detector = nullptr; + } +}; + +TEST(detector_pop_tests, pop_validate_incorrect_packet_len) +{ + OdpContext test_odp_ctxt(test_app_config, nullptr); + AppIdModule test_module; + AppIdInspector test_inspector(test_module); + AppIdSession test_asd(IpProtocol::TCP, nullptr, (uint16_t)0, test_inspector, test_odp_ctxt, (uint32_t)0, 0); + const uint8_t* test_data = (const uint8_t*)"."; + uint16_t test_data_size = 1; + AppidChangeBits cb; + + POP3DetectorData dd; + dd.server.state = POP3_STATE_CONNECT; + + auto result = test_detector->pop3_server_validate(&dd, test_data, test_data_size, test_asd, 1, cb); + CHECK_EQUAL(-1, result); +} + +int main(int argc, char** argv) +{ + int return_value = CommandLineTestRunner::RunAllTests(argc, argv); + return return_value; +} diff --git a/src/network_inspectors/appid/detector_plugins/test/detector_sip_test.cc b/src/network_inspectors/appid/detector_plugins/test/detector_sip_test.cc index ba5ddf337..6230ba001 100644 --- a/src/network_inspectors/appid/detector_plugins/test/detector_sip_test.cc +++ b/src/network_inspectors/appid/detector_plugins/test/detector_sip_test.cc @@ -27,14 +27,8 @@ #include "detector_plugins/detector_sip.cc" #include "detector_plugins/sip_patterns.cc" -#include "framework/data_bus.h" -#include "framework/module.cc" #include "framework/mpse_batch.h" -#include "main/thread_config.h" -#include "network_inspectors/appid/appid_utils/sf_mlmp.cc" -#include "protocols/protocol_ids.h" #include "service_inspectors/sip/sip_parser.h" -#include "utils/util_cstring.cc" #include "appid_inspector.h" #include "detector_plugins_mock.h" @@ -58,11 +52,13 @@ ClientSIPData* sip_data = nullptr; MpseGroup mpse_group; static bool prep_patterns = true; +// Stubs for AppIdInspector +AppIdConfig test_app_config; +AppIdInspector::AppIdInspector(AppIdModule&) : config(&test_app_config), ctxt(test_app_config) { } + namespace snort { AppIdApi appid_api; -AppIdSessionApi::AppIdSessionApi(const AppIdSession*, const SfIp&) -{ } Flow::~Flow() = default; AppIdSession* AppIdApi::get_appid_session(snort::Flow const&) { return nullptr; } @@ -83,23 +79,6 @@ unsigned get_instance_id() unsigned ThreadConfig::get_instance_max() { return 1; } } -AppIdInspector::AppIdInspector(AppIdModule&) : config(&s_config), ctxt(s_config) -{ } - -bool AppIdInspector::configure(snort::SnortConfig*) -{ - return true; -} - -// LCOV_EXCL_START -void AppIdInspector::eval(Packet*) { } -void AppIdInspector::show(const SnortConfig*) const { } -void AppIdInspector::tinit() { } -void AppIdInspector::tterm() { } -void AppIdInspector::tear_down(SnortConfig*) { } -// LCOV_EXCL_STOP - -AppIdInspector::~AppIdInspector() = default; void AppIdContext::create_odp_ctxt() { @@ -139,40 +118,8 @@ AppIdSession* AppIdSession::allocate_session(snort::Packet const*, IpProtocol, } void AppIdSession::publish_appid_event(AppidChangeBits&, const Packet&, bool, uint32_t) { } -AppIdDiscovery::~AppIdDiscovery() = default; - -// LCOV_EXCL_START -void ApplicationDescriptor::set_id(const Packet&, AppIdSession&, AppidSessionDirection, - AppId, AppidChangeBits&) { } -void ClientDiscovery::initialize(AppIdInspector&) { } -void ClientDiscovery::reload() { } -// LCOV_EXCL_STOP - -void AppIdDiscovery::register_detector(const string&, AppIdDetector*, IpProtocol) { } - -// LCOV_EXCL_START -void AppIdDiscovery::add_pattern_data(AppIdDetector*, snort::SearchTool&, int, - unsigned char const*, unsigned int, unsigned int) { } -void AppIdDiscovery::register_tcp_pattern(AppIdDetector*, unsigned char const*, unsigned int, - int, unsigned int) { } -void AppIdDiscovery::register_udp_pattern(AppIdDetector*, unsigned char const*, unsigned int, - int, unsigned int) { } -int AppIdDiscovery::add_service_port(AppIdDetector*, ServiceDetectorPort const&) { return 0; } -void AppIdModule::reset_stats() { } -// LCOV_EXCL_STOP - -DnsPatternMatchers::~DnsPatternMatchers() = default; -EveCaPatternMatchers::~EveCaPatternMatchers() = default; -HostPatternMatchers::~HostPatternMatchers() = default; -HttpPatternMatchers::~HttpPatternMatchers() = default; -AlpnPatternMatchers::~AlpnPatternMatchers() = default; -CipPatternMatchers::~CipPatternMatchers() = default; -UserDataMap::~UserDataMap() = default; - -ClientDetector::ClientDetector() { } // LCOV_EXCL_START -void ClientDetector::register_appid(int, unsigned int, OdpContext&) { } int AppIdDetector::initialize(AppIdInspector&) { return 1; } int AppIdDetector::data_add(AppIdSession&, AppIdFlowData*) { return 1; } void AppIdDetector::add_user(AppIdSession&, char const*, int, bool, AppidChangeBits&) { } diff --git a/src/network_inspectors/appid/detector_plugins/test/detector_smtp_test.cc b/src/network_inspectors/appid/detector_plugins/test/detector_smtp_test.cc index 6c123c0f5..179850c1f 100644 --- a/src/network_inspectors/appid/detector_plugins/test/detector_smtp_test.cc +++ b/src/network_inspectors/appid/detector_plugins/test/detector_smtp_test.cc @@ -23,15 +23,22 @@ #include "config.h" #endif -#if 0 -#include "network_inspectors/appid/detector_plugins/detector_smtp.cc" +#include "appid_inspector.h" +#include "appid_session.h" +#include "detector_plugins_mock.h" + + +#include "../detector_smtp.h" +#include "../detector_smtp.cc" + #include #include #include -#include +using namespace snort; +#if 0 struct AddAppData { AppId client_id = 0; @@ -239,15 +246,87 @@ TEST(client_app_smtp, identify_client_version_mozilla_thunderbird) check_client_version(client_str, APP_ID_THUNDERBIRD, "5.0", &appid_stats.smtp_thunderbird_clients); } - #endif -// FIXIT-M Add additional tests for other client types (Outlook, etc). -int main(int, char**) + +static ClientDiscovery test_discovery; + +// Stubs for AppIdInspector +AppIdConfig test_app_config; +AppIdInspector::AppIdInspector(AppIdModule&) : config(&test_app_config), ctxt(test_app_config) { } + +int AppIdDetector::data_add(AppIdSession&, AppIdFlowData*) { return 1; } + +SMTPDetectorData* test_data_get = nullptr; + +AppIdFlowData* AppIdDetector::data_get(const AppIdSession&) +{ + return test_data_get; +} + +int ServiceDetector::fail_service(AppIdSession& asd, const Packet* pkt, AppidSessionDirection dir) { return 1; } + +TEST_GROUP(detector_smtp_tests) +{ + SmtpClientDetector *test_detector = nullptr; + void setup() override + { + test_detector = new SmtpClientDetector(&test_discovery); + } + + void teardown() override + { + delete test_detector; + test_detector = nullptr; + } +}; + +TEST(detector_smtp_tests, client_message_wrong_len_1) +{ + OdpContext test_odp_ctxt(test_app_config, nullptr); + AppIdModule test_module; + AppIdInspector test_inspector(test_module); + AppIdSession test_asd(IpProtocol::TCP, nullptr, (uint16_t)0, test_inspector, test_odp_ctxt, (uint32_t)0, 0); + const uint8_t* test_data = (const uint8_t*)"."; + uint16_t test_data_size = 1; + AppidChangeBits cb; + + test_data_get = new SMTPDetectorData; + test_data_get->client.state = SMTP_CLIENT_STATE_MESSAGE; + + AppIdDiscoveryArgs test_args(test_data, test_data_size, AppidSessionDirection::APP_ID_FROM_INITIATOR, test_asd, nullptr, cb); + + auto result = test_detector->validate(test_args); + CHECK_EQUAL(result, APPID_INPROCESS); + CHECK_EQUAL(test_asd.is_client_detected(), false); + + delete test_data_get; +} + +TEST(detector_smtp_tests, client_message_wrong_len_2) +{ + OdpContext test_odp_ctxt(test_app_config, nullptr); + AppIdModule test_module; + AppIdInspector test_inspector(test_module); + AppIdSession test_asd(IpProtocol::TCP, nullptr, (uint16_t)0, test_inspector, test_odp_ctxt, (uint32_t)0, 0); + const uint8_t* test_data = (const uint8_t*)".\t"; + uint16_t test_data_size = 2; + AppidChangeBits cb; + + test_data_get = new SMTPDetectorData; + test_data_get->client.state = SMTP_CLIENT_STATE_MESSAGE; + + AppIdDiscoveryArgs test_args(test_data, test_data_size, AppidSessionDirection::APP_ID_FROM_INITIATOR, test_asd, nullptr, cb); + + auto result = test_detector->validate(test_args); + CHECK_EQUAL(result, APPID_INPROCESS); + CHECK_EQUAL(test_asd.is_client_detected(), false); + + delete test_data_get; +} + +int main(int argc, char** argv) { -#if 0 int return_value = CommandLineTestRunner::RunAllTests(argc, argv); return return_value; -#endif } - diff --git a/src/network_inspectors/appid/detector_plugins/test/http_url_patterns_test.cc b/src/network_inspectors/appid/detector_plugins/test/http_url_patterns_test.cc index 8f454effb..005be98e0 100644 --- a/src/network_inspectors/appid/detector_plugins/test/http_url_patterns_test.cc +++ b/src/network_inspectors/appid/detector_plugins/test/http_url_patterns_test.cc @@ -21,13 +21,13 @@ #include "config.h" #endif -#include "network_inspectors/appid/detector_plugins/http_url_patterns.cc" +#define HTTP_PATTERNS_UNIT_TEST + +#include "../http_url_patterns.h" +#include "../http_url_patterns.cc" -#include "main/thread_config.h" -#include "protocols/protocol_ids.h" -#include "framework/module.cc" #include "network_inspectors/appid/appid_utils/sf_mlmp.cc" -#include "utils/util_cstring.cc" + #include "detector_plugins_mock.h" #include @@ -61,15 +61,16 @@ static AppId service_id = APP_ID_NONE; static AppId client_id = APP_ID_NONE; static DetectorHTTPPattern mpattern; +// Stubs for AppIdInspector +AppIdConfig test_app_config; +AppIdInspector::AppIdInspector(AppIdModule&) : config(&test_app_config), ctxt(test_app_config) { } + namespace snort { -AppIdSessionApi::AppIdSessionApi(const AppIdSession*, const SfIp&) -{ } -SearchTool::SearchTool(bool, const char*) { } -void SearchTool::reload() { } static bool test_find_all_done = false; static bool test_find_all_enabled = false; static MatchedPatterns* mock_mp = nullptr; +void SearchTool::reload() { } int SearchTool::find_all(const char*, unsigned, MpseMatch, bool, void* mp_arg, const SnortConfig*) { test_find_all_done = true; @@ -77,33 +78,8 @@ int SearchTool::find_all(const char*, unsigned, MpseMatch, bool, void* mp_arg, c memcpy(mp_arg, &mock_mp, sizeof(MatchedPatterns*)); return 0; } -unsigned get_instance_id() -{ return 0; } -unsigned ThreadConfig::get_instance_max() { return 1; } } -void ApplicationDescriptor::set_id(const Packet&, AppIdSession&, AppidSessionDirection, AppId, AppidChangeBits&) { } -AppIdDiscovery::~AppIdDiscovery() = default; -void ClientDiscovery::initialize(AppIdInspector&) { } -void ClientDiscovery::reload() { } -void AppIdDiscovery::register_detector(const string&, AppIdDetector*, IpProtocol) { } -void AppIdDiscovery::add_pattern_data(AppIdDetector*, snort::SearchTool&, int, unsigned char const*, unsigned int, unsigned int) { } -void AppIdDiscovery::register_tcp_pattern(AppIdDetector*, unsigned char const*, unsigned int, int, unsigned int) { } -void AppIdDiscovery::register_udp_pattern(AppIdDetector*, unsigned char const*, unsigned int, int, unsigned int) { } -int AppIdDiscovery::add_service_port(AppIdDetector*, ServiceDetectorPort const&) { return 0; } -DnsPatternMatchers::~DnsPatternMatchers() = default; -EveCaPatternMatchers::~EveCaPatternMatchers() = default; -SipPatternMatchers::~SipPatternMatchers() = default; -HostPatternMatchers::~HostPatternMatchers() = default; -AlpnPatternMatchers::~AlpnPatternMatchers() = default; -UserDataMap::~UserDataMap() = default; -CipPatternMatchers::~CipPatternMatchers() = default; -bool HostPatternMatchers::scan_url(const uint8_t*, size_t, AppId&, AppId&, bool*){ return true; } -void AppIdModule::reset_stats() {} -bool AppIdInspector::configure(snort::SnortConfig*) { return true; } -void appid_log(const snort::Packet*, unsigned char, char const*, ...) { } -void HostPatternMatchers::add_host_pattern(unsigned char const*, unsigned long, unsigned char, int, int, HostPatternType, bool, bool) {} - TEST_GROUP(http_url_patterns_tests) { void setup() override @@ -558,6 +534,23 @@ TEST(http_url_patterns_tests, identify_user_agent_skypedirect) test_find_all_enabled = false; } +TEST(http_url_patterns_tests, empty_server_vendor_version) +{ + char* version = nullptr; + char* vendor = nullptr; + AppIdServiceSubtype* subtype = nullptr; + hm->get_server_vendor_version("test/", 5, &version, &vendor, &subtype); + + CHECK(version); + CHECK(version[0] == '\0'); + + CHECK(vendor); + CHECK_EQUAL(strcmp(vendor, "test"), 0); + + snort_free(version); + snort_free(vendor); +} + int main(int argc, char** argv) { int return_value = CommandLineTestRunner::RunAllTests(argc, argv); diff --git a/src/network_inspectors/appid/service_plugins/service_netbios.cc b/src/network_inspectors/appid/service_plugins/service_netbios.cc index 16c47310e..ab89509e8 100644 --- a/src/network_inspectors/appid/service_plugins/service_netbios.cc +++ b/src/network_inspectors/appid/service_plugins/service_netbios.cc @@ -230,6 +230,8 @@ static int netbios_validate_name_and_decode(const uint8_t** data, *data += sizeof(NBNSLabelData); break; case 0xC0: + if (end - *data < (int)sizeof(NBNSLabelPtr)) + return -1; lbl_ptr = (const NBNSLabelPtr*)(*data); *data += sizeof(NBNSLabelPtr); if (begin + lbl_ptr->position + sizeof(NBNSLabelData) > end) @@ -286,6 +288,8 @@ static int netbios_validate_name(const uint8_t** data, *data += sizeof(NBNSLabelData); break; case 0xC0: + if (end - *data < (int)sizeof(NBNSLabelPtr)) + return -1; lbl_ptr = (const NBNSLabelPtr*)(*data); *data += sizeof(NBNSLabelPtr); if (begin + lbl_ptr->position + sizeof(NBNSLabelData) > end) diff --git a/src/network_inspectors/appid/service_plugins/service_rtmp.cc b/src/network_inspectors/appid/service_plugins/service_rtmp.cc index 0df64cf1a..3646002a8 100644 --- a/src/network_inspectors/appid/service_plugins/service_rtmp.cc +++ b/src/network_inspectors/appid/service_plugins/service_rtmp.cc @@ -125,9 +125,9 @@ static int parse_rtmp_chunk_basic_header(const uint8_t** data_inout, uint16_t* s } else if (*chunk_stream_id == 1) { - *chunk_stream_id = data[2] * 256 + data[1] + 64; if (size < 3) return 0; + *chunk_stream_id = data[2] * 256 + data[1] + 64; data += 3; size -= 3; } diff --git a/src/network_inspectors/appid/service_plugins/service_snmp.cc b/src/network_inspectors/appid/service_plugins/service_snmp.cc index 5064040da..87e406435 100644 --- a/src/network_inspectors/appid/service_plugins/service_snmp.cc +++ b/src/network_inspectors/appid/service_plugins/service_snmp.cc @@ -166,7 +166,7 @@ static int snmp_verify_packet(const uint8_t** const data, return -1; if (snmp_ans1_length(data, end, &overall_length)) return -1; - if (overall_length < 3 || (int)overall_length > end-(*data)) + if (overall_length < 3 || (*data >= end) || overall_length > static_cast(end - *data)) return -1; if (**data != 0x02) return -1; diff --git a/src/network_inspectors/appid/service_plugins/test/CMakeLists.txt b/src/network_inspectors/appid/service_plugins/test/CMakeLists.txt index de668cdb2..a80b83fb8 100644 --- a/src/network_inspectors/appid/service_plugins/test/CMakeLists.txt +++ b/src/network_inspectors/appid/service_plugins/test/CMakeLists.txt @@ -3,4 +3,6 @@ include_directories ( appid PRIVATE ${APPID_INCLUDE_DIR} ) add_cpputest( service_rsync_test ) add_cpputest( alpn_patterns_tests ) - +add_cpputest( service_snmp_test ) +add_cpputest( service_rtmp_test ) +add_cpputest( service_netbios_test ) diff --git a/src/network_inspectors/appid/service_plugins/test/service_netbios_test.cc b/src/network_inspectors/appid/service_plugins/test/service_netbios_test.cc new file mode 100644 index 000000000..00d062082 --- /dev/null +++ b/src/network_inspectors/appid/service_plugins/test/service_netbios_test.cc @@ -0,0 +1,99 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2022-2025 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- +// +// service_netbios_test.cc author Oleksandr Stepanov + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "../service_netbios.h" +#include "../service_netbios.cc" +#include "service_plugin_mock.h" + +#include +#include +#include + +void AppIdSessionApi::set_netbios_name(AppidChangeBits& change_bits, const char* name) { } + +TEST_GROUP(netbios_parsing_tests) +{ + void setup() override + { + + } + void teardown() override + { + + } +}; + +TEST(netbios_parsing_tests, netbios_parse_invalid_len_missing_position) +{ + const uint8_t* data = (const uint8_t*)"\xC0"; // Invalid length + const uint8_t* original_data = data; + const uint8_t* end = data + 1; + char name[NBNS_NAME_LEN / 2 + 1] = {0}; + + int ret = netbios_validate_name_and_decode(&data, data, end, name); + CHECK_EQUAL(-1, ret); + CHECK_EQUAL(data, original_data); // Ensure data pointer is unchanged +} + +TEST(netbios_parsing_tests, netbios_parse_invalid_len_wrong_position) +{ + const uint8_t* data = (const uint8_t*)"\xC0\xFF"; // Invalid length + const uint8_t* original_data = data; + const uint8_t* end = data + 2; + char name[NBNS_NAME_LEN / 2 + 1] = {0}; + + int ret = netbios_validate_name_and_decode(&data, data, end, name); + CHECK_EQUAL(-1, ret); + CHECK_EQUAL(original_data + sizeof(NBNSLabelPtr), data); // Check that length and flags are parsed +} + +TEST(netbios_parsing_tests, netbios_parse_invalid_len_missing_position_without_decode) +{ + const uint8_t* data = (const uint8_t*)"\xC0"; // Invalid length + const uint8_t* original_data = data; + const uint8_t* end = data + 1; + char name[NBNS_NAME_LEN / 2 + 1] = {0}; + + int ret = netbios_validate_name(&data, data, end); + CHECK_EQUAL(-1, ret); + CHECK_EQUAL(data, original_data); // Ensure data pointer is unchanged +} + +TEST(netbios_parsing_tests, netbios_parse_invalid_len_wrong_position_without_decode) +{ + const uint8_t* data = (const uint8_t*)"\xC0\xFF"; // Invalid length + const uint8_t* original_data = data; + const uint8_t* end = data + 2; + char name[NBNS_NAME_LEN / 2 + 1] = {0}; + + int ret = netbios_validate_name(&data, data, end); + CHECK_EQUAL(-1, ret); + CHECK_EQUAL(original_data + sizeof(NBNSLabelPtr), data); // Check that length and flags are parsed +} + +int main(int argc, char** argv) +{ + int return_value = CommandLineTestRunner::RunAllTests(argc, argv); + return return_value; +} diff --git a/src/network_inspectors/appid/service_plugins/test/service_plugin_mock.h b/src/network_inspectors/appid/service_plugins/test/service_plugin_mock.h index d4e83c2d2..5fae71be9 100644 --- a/src/network_inspectors/appid/service_plugins/test/service_plugin_mock.h +++ b/src/network_inspectors/appid/service_plugins/test/service_plugin_mock.h @@ -19,14 +19,20 @@ #ifndef SERVICE_PLUGIN_MOCK_H #define SERVICE_PLUGIN_MOCK_H -#include "appid_detector.h" -#include "appid_module.h" -#include "appid_peg_counts.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif +#include +#include +#include +#include + +#include "appid_detector.h" +#include "appid_module.h" +#include "appid_peg_counts.h" + #define APPID_UT_ID 1492 namespace snort @@ -68,15 +74,12 @@ char* snort_strdup(const char* str) memcpy(p, str, n); return p; } -Module::Module(const char*, const char*) {} -Module::Module(const char*, const char*, const Parameter*, bool) -{} -PegCount Module::get_global_count(char const*) const { return 0; } -void Module::show_interval_stats(std::vector >&, FILE*) {} -void Module::show_stats(){} -void Module::sum_stats(bool){} -void Module::main_accumulate_stats(){} -void Module::reset_stats() {} +void snort::Module::sum_stats(bool) {} +void snort::Module::show_interval_stats(std::vector&, FILE*) {} +void snort::Module::show_stats() {} +void snort::Module::init_stats(bool) {} +void snort::Module::reset_stats() {} +void snort::Module::main_accumulate_stats() {} AppIdSessionApi::AppIdSessionApi(const AppIdSession*, const SfIp&) { } @@ -92,7 +95,6 @@ UserDataMap::~UserDataMap() { } CipPatternMatchers::~CipPatternMatchers() { } void ClientDiscovery::initialize(AppIdInspector&) {} void ClientDiscovery::reload() {} -FpSMBData* smb_data = nullptr; int AppIdDetector::initialize(AppIdInspector&){return 0;} int AppIdDetector::data_add(AppIdSession&, AppIdFlowData*){return 0;} @@ -112,18 +114,32 @@ void AppIdDiscovery::register_udp_pattern(AppIdDetector*, const uint8_t* const, int, unsigned){} int AppIdDiscovery::add_service_port(AppIdDetector*, const ServiceDetectorPort&){return 0;} void ApplicationDescriptor::set_id(const snort::Packet&, AppIdSession&, AppidSessionDirection, AppId, AppidChangeBits&){} -int AppIdSession::add_flow_data(void*, unsigned) { return 0; } int dcerpc_validate(const uint8_t*, int){return 0; } AppIdDiscovery::~AppIdDiscovery() { } void show_stats(PegCount*, const PegInfo*, unsigned, const char*) { } -void show_stats(PegCount*, const PegInfo*, const vector&, const char*, FILE*) { } AppIdConfig config; AppIdContext ctxt(config); -class AppIdInspector : public snort::Inspector -{ -public: - bool configure(snort::SnortConfig*) override { return true; } -}; +ServiceDetector::ServiceDetector() {} +int ServiceDetector::incompatible_data(AppIdSession& asd, const snort::Packet* pkt, AppidSessionDirection dir) { return 0; } +int ServiceDetector::fail_service(AppIdSession& asd, const snort::Packet* pkt, AppidSessionDirection dir) { return 0; } +int ServiceDetector::service_inprocess(AppIdSession& asd, const snort::Packet* pkt, AppidSessionDirection dir) { return 0; } +int ServiceDetector::add_service_consume_subtype(AppIdSession& asd, const snort::Packet* pkt, + AppidSessionDirection dir, AppId appId, const char* vendor, const char* version, + AppIdServiceSubtype* subtype, AppidChangeBits& change_bits) + { return 0; } +int ServiceDetector::add_service(AppidChangeBits& change_bits, AppIdSession& asd, + const snort::Packet* pkt, AppidSessionDirection dir, AppId appId, const char* vendor, + const char* version, AppIdServiceSubtype* subtype) + { return 0; } +void ServiceDetector::register_appid(AppId appId, unsigned extractsInfo, OdpContext& odp_ctxt) {} + +void AppIdDebug::activate(const snort::Flow*, const AppIdSession*, bool) { active = false; } + +AppIdSession* AppIdSession::create_future_session(const snort::Packet* ctrlPkt, const snort::SfIp* cliIp, + uint16_t cliPort, const snort::SfIp* srvIp, uint16_t srvPort, IpProtocol proto, + SnortProtocolId snort_protocol_id, OdpContext& odp_ctxt, bool swap_app_direction, + bool bidirectional, bool expect_persist) { return nullptr; } +void AppIdSession::initialize_future_session(AppIdSession& expected, uint64_t flags) {} // Stubs for modules, config AppIdConfig::~AppIdConfig() = default; @@ -142,7 +158,7 @@ bool AppIdModule::end(const char*, int, snort::SnortConfig*) return false; } -const Command* AppIdModule::get_commands() const +const snort::Command* AppIdModule::get_commands() const { return nullptr; } @@ -157,8 +173,8 @@ PegCount* AppIdModule::get_counts() const return nullptr; } -void AppIdModule::set_trace(const Trace*) const { } -const TraceOption* AppIdModule::get_trace_options() const { return nullptr; } +void AppIdModule::set_trace(const snort::Trace*) const { } +const snort::TraceOption* AppIdModule::get_trace_options() const { return nullptr; } // Stubs for inspectors unsigned AppIdSession::inspector_id = 0; @@ -166,25 +182,29 @@ AppIdConfig stub_config; AppIdContext stub_ctxt(stub_config); static OdpContext stub_odp_ctxt(stub_config, nullptr); OdpContext* AppIdContext::odp_ctxt = &stub_odp_ctxt; -AppIdSession::AppIdSession(IpProtocol, const SfIp* ip, uint16_t, AppIdInspector& inspector, - OdpContext& +AppIdSession::AppIdSession(IpProtocol, const snort::SfIp* ip, uint16_t, AppIdInspector& inspector, + OdpContext& odpctxt, uint32_t #ifndef DISABLE_TENANT_ID - ,uint16_t + ,uint32_t #endif ) : snort::FlowData(inspector_id, (snort::Inspector*)&inspector), - config(stub_config), api(*(new AppIdSessionApi(this, *ip))), odp_ctxt(stub_odp_ctxt) { } + config(stub_config), api(*(new snort::AppIdSessionApi(this, *ip))), odp_ctxt(odpctxt) +{ } AppIdSession::~AppIdSession() = default; DiscoveryFilter::~DiscoveryFilter(){} void AppIdSession::free_flow_data() { - snort_free(smb_data); + +} +AppIdFlowData* AppIdSession::get_flow_data(unsigned) const +{ + return nullptr; } -void* AppIdSession::get_flow_data(unsigned) const { return smb_data;} // Stubs for AppIdPegCounts -void AppIdPegCounts::inc_service_count(AppId, bool) { } -void AppIdPegCounts::inc_client_count(AppId, bool) { } -void AppIdPegCounts::inc_payload_count(AppId, bool) { } +//void AppIdPegCounts::inc_service_count(AppId, bool) { } +//void AppIdPegCounts::inc_client_count(AppId, bool) { } +//void AppIdPegCounts::inc_payload_count(AppId, bool) { } THREAD_LOCAL AppIdStats appid_stats; void AppIdModule::show_dynamic_stats() { } @@ -199,15 +219,26 @@ bool AppInfoManager::configured() { return true; } -ServiceDiscoveryState* AppIdServiceState::add(SfIp const*, IpProtocol, - unsigned short, int16_t, uint16_t, bool, bool) -{ - return nullptr; -} -void ServiceDiscoveryState::set_service_id_valid(ServiceDetector*) { } + +void ServiceDiscovery::initialize(AppIdInspector&) {} +void ServiceDiscovery::reload() {} +int ServiceDiscovery::add_service_port(AppIdDetector*, const ServiceDetectorPort&) { return 0; } OdpContext::OdpContext(const AppIdConfig&, snort::SnortConfig*) { } +void appid_log(const snort::Packet*, unsigned char, char const*, ...) { } +int AppIdSession::add_flow_data_id(uint16_t, ServiceDetector*) { return 0; } +AppIdHttpSession* AppIdSession::get_http_session(uint32_t) const { return nullptr; } +AppIdHttpSession* AppIdSession::create_http_session(int64_t stream_id) { return nullptr; } +void AppIdHttpSession::set_field(HttpFieldIds id, const std::string* str, AppidChangeBits&) { } + +void snort::DataBus::publish(unsigned, unsigned, snort::DataEvent&, snort::Flow*) { } +void snort::DataBus::publish(unsigned, unsigned, const uint8_t*, unsigned, snort::Flow*) { } +void snort::DataBus::publish(unsigned, unsigned, snort::Packet*, snort::Flow*) { } + +snort::Packet* snort::DetectionEngine::get_current_packet() { return nullptr; } + +unsigned AppIdInspector::get_pub_id() { return 0; } #endif diff --git a/src/network_inspectors/appid/service_plugins/test/service_rtmp_test.cc b/src/network_inspectors/appid/service_plugins/test/service_rtmp_test.cc new file mode 100644 index 000000000..a34cd1be4 --- /dev/null +++ b/src/network_inspectors/appid/service_plugins/test/service_rtmp_test.cc @@ -0,0 +1,62 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2022-2025 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- +// +// service_rtmp_test.cc author Oleksandr Stepanov + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "../service_rtmp.h" +#include "../service_rtmp.cc" +#include "service_plugin_mock.h" + +#include +#include +#include + +TEST_GROUP(rtmp_parsing_tests) +{ + void setup() override + { + + } + void teardown() override + { + + } +}; + +TEST(rtmp_parsing_tests, rtmp_parse_invalid_len) +{ + const uint8_t* data = (const uint8_t*)"\x41\x00"; + uint16_t size = 2; + uint8_t format = 0; + uint32_t chunk_stream_id = 0; + + int ret = parse_rtmp_chunk_basic_header(&data, &size, &format, &chunk_stream_id); + CHECK_EQUAL(0, ret); + CHECK_EQUAL(2, size); + CHECK_EQUAL(1, chunk_stream_id); +} + +int main(int argc, char** argv) +{ + int return_value = CommandLineTestRunner::RunAllTests(argc, argv); + return return_value; +} diff --git a/src/network_inspectors/appid/service_plugins/test/service_snmp_test.cc b/src/network_inspectors/appid/service_plugins/test/service_snmp_test.cc new file mode 100644 index 000000000..350fcfc24 --- /dev/null +++ b/src/network_inspectors/appid/service_plugins/test/service_snmp_test.cc @@ -0,0 +1,173 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2022-2025 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- +// +// service_snmp_test.cc author Oleksandr Stepanov + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "../service_detector.h" + +#include "../service_snmp.h" +#include "../service_snmp.cc" + +#include "service_plugin_mock.h" + +#include +#include +#include + +THREAD_LOCAL AppIdDebug* appidDebug = nullptr; +THREAD_LOCAL bool appid_trace_enabled = false; + + +TEST_GROUP(snmp_parsing_tests) +{ + void setup() override + { + + } + void teardown() override + { + + } +}; + +TEST(snmp_parsing_tests, fail_on_invalid_sequence_tag) +{ + const uint8_t* data = (const uint8_t*)"\x31\x02\x01\x00"; /* Invalid tag - should be 0x30 */ + const uint8_t* end = data + 4; + uint8_t pdu = 0; + uint8_t version = 0; + + int ret = snmp_verify_packet(&data, end, &pdu, &version); + CHECK_EQUAL(ret, -1); +} + +TEST(snmp_parsing_tests, fail_on_insufficient_data) +{ + const uint8_t* data = (const uint8_t*)"\x30"; /* Only sequence tag, no length */ + const uint8_t* end = data + 1; + uint8_t pdu = 0; + uint8_t version = 0; + + int ret = snmp_verify_packet(&data, end, &pdu, &version); + CHECK_EQUAL(ret, -1); +} + +TEST(snmp_parsing_tests, fail_on_invalid_version_tag) +{ + const uint8_t* data = (const uint8_t*)"\x30\x05\x03\x01\x00\x04\x01"; /* Wrong version tag (0x03 instead of 0x02) */ + const uint8_t* end = data + 7; + uint8_t pdu = 0; + uint8_t version = 0; + + int ret = snmp_verify_packet(&data, end, &pdu, &version); + CHECK_EQUAL(ret, -1); +} + +TEST(snmp_parsing_tests, fail_on_invalid_version_length) +{ + const uint8_t* data = (const uint8_t*)"\x30\x05\x02\x02\x00\x04\x01"; /* Version length should be 1, not 2 */ + const uint8_t* end = data + 7; + uint8_t pdu = 0; + uint8_t version = 0; + + int ret = snmp_verify_packet(&data, end, &pdu, &version); + CHECK_EQUAL(ret, -1); +} + +TEST(snmp_parsing_tests, success_snmp_v1_packet) +{ + const uint8_t snmp_v1[] = "\x30\x1c\x02\x01\x00\x04\x06public\xa0\x0f\x02\x01\x01\x02\x01\x00\x02\x01\x00\x30\x04\x30\x02\x06\x00"; + const uint8_t* data = snmp_v1; + const uint8_t* end = data + sizeof(snmp_v1) - 1; + uint8_t pdu = 0; + uint8_t version = 0; + + int ret = snmp_verify_packet(&data, end, &pdu, &version); + CHECK_EQUAL(ret, 0); + CHECK_EQUAL(version, 0); /* SNMP v1 */ + CHECK_EQUAL(pdu, 0); /* GET request */ +} + +TEST(snmp_parsing_tests, success_snmp_v2c_packet) +{ + const uint8_t snmp_v2c[] = "\x30\x1d\x02\x01\x01\x04\x06public\xa0\x10\x02\x01\x01\x02\x01\x00\x02\x01\x00\x30\x05\x30\x03\x06\x01\x00"; + const uint8_t* data = snmp_v2c; + const uint8_t* end = data + sizeof(snmp_v2c) - 1; + uint8_t pdu = 0; + uint8_t version = 0; + + int ret = snmp_verify_packet(&data, end, &pdu, &version); + CHECK_EQUAL(ret, 0); + CHECK_EQUAL(version, 1); /* SNMP v2c */ + CHECK_EQUAL(pdu, 0); /* GET request */ +} + +TEST(snmp_parsing_tests, fail_on_invalid_community_string) +{ + const uint8_t* data = (const uint8_t*)"\x30\x0b\x02\x01\x00\x04\x04\xff\xfe\xfd\xfc\xa0\x00"; /* Non-printable community */ + const uint8_t* end = data + 13; + uint8_t pdu = 0; + uint8_t version = 0; + + int ret = snmp_verify_packet(&data, end, &pdu, &version); + CHECK_EQUAL(ret, -1); +} + +TEST(snmp_parsing_tests, fail_on_unsupported_version) +{ + const uint8_t* data = (const uint8_t*)"\x30\x05\x02\x01\x05\x04\x00"; /* Version 5 (unsupported) */ + const uint8_t* end = data + 7; + uint8_t pdu = 0; + uint8_t version = 0; + + int ret = snmp_verify_packet(&data, end, &pdu, &version); + CHECK_EQUAL(ret, -1); +} + +TEST(snmp_parsing_tests, fail_on_length_overflow) +{ + const uint8_t* data = (const uint8_t*)"\x30\x82\xff\xff"; /* Length field indicates more data than available */ + const uint8_t* end = data + 4; + uint8_t pdu = 0; + uint8_t version = 0; + + int ret = snmp_verify_packet(&data, end, &pdu, &version); + CHECK_EQUAL(ret, -1); +} + +TEST(snmp_parsing_tests, fail_on_wrong_packet_length) +{ + const uint8_t* data = (const uint8_t*)"\x30\x7F"; /* SNMP packet with packet length = 127 */ + const uint8_t* end = data + 2; + uint8_t pdu = 0; + uint8_t version = 0; + + int ret = snmp_verify_packet(&data, end, &pdu, &version); + CHECK_EQUAL(ret, -1); +} + +int main(int argc, char** argv) +{ + int return_value = CommandLineTestRunner::RunAllTests(argc, argv); + return return_value; +} \ No newline at end of file diff --git a/src/protocols/ssl.cc b/src/protocols/ssl.cc index 23f902dd9..eae87c9ee 100644 --- a/src/protocols/ssl.cc +++ b/src/protocols/ssl.cc @@ -711,7 +711,7 @@ bool parse_server_certificates(SSLV3ServerCertData* server_cert_data) int common_name_len = 0; int org_unit_len = 0; - while (len > 0 and !(common_name and org_unit)) + while (len > 2 and !(common_name and org_unit)) { X509* cert = nullptr; X509_NAME* cert_name = nullptr; diff --git a/src/protocols/test/CMakeLists.txt b/src/protocols/test/CMakeLists.txt index b0e338f65..ef998c2f1 100644 --- a/src/protocols/test/CMakeLists.txt +++ b/src/protocols/test/CMakeLists.txt @@ -8,3 +8,5 @@ add_cpputest( decode_err_len_test ../packet.cc ../packet_manager.cc ) + +add_cpputest( ssl_protocol_test ) \ No newline at end of file diff --git a/src/protocols/test/ssl_protocol_test.cc b/src/protocols/test/ssl_protocol_test.cc new file mode 100644 index 000000000..bbf07202c --- /dev/null +++ b/src/protocols/test/ssl_protocol_test.cc @@ -0,0 +1,85 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2023-2025 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- +// ssl_protocol_test.cc author Oleksandr Stepanov + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include + +#include "../ssl.h" +#include "../ssl.cc" + +#include +#include +#include + +using namespace snort; + +typedef struct X509_name_entry_st X509_NAME_ENTRY; +X509_NAME *X509_get_subject_name(const X509 *a) { return nullptr; } +void X509_free(X509* a) { } +int X509_NAME_get_index_by_NID(X509_NAME *name, int nid, int lastpos) { return -1; } +X509_NAME_ENTRY *X509_NAME_get_entry(const X509_NAME *name, int loc) { return nullptr; } +ASN1_STRING *X509_NAME_ENTRY_get_data(const X509_NAME_ENTRY *ne) { return nullptr; } +const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *x) { return nullptr; } +X509* d2i_X509(X509 **a, const unsigned char **in, long len) +{ + return nullptr; +} + +namespace snort +{ +char* snort_strdup(const char* str) +{ + return str ? strdup(str) : nullptr; +} + +char* snort_strndup(const char* src, size_t) +{ + return snort_strdup(src); +} +} + +TEST_GROUP(ssl_protocol_tests) +{ + void setup() override + { + } + + void teardown() override + { + } +}; + +TEST(ssl_protocol_tests, cert_data_incomplete_len_2) +{ + SSLV3ServerCertData test_data; + test_data.certs_data = new uint8_t[2] { 0x01, 0x02 }; // Incomplete length, should be at least 3 bytes + test_data.certs_len = 2; + auto result = parse_server_certificates(&test_data); + CHECK_EQUAL(true, result); + CHECK_EQUAL(nullptr, test_data.certs_data); + CHECK_EQUAL(0, test_data.certs_len); +} + +int main(int argc, char** argv) +{ + return CommandLineTestRunner::RunAllTests(argc, argv); +} \ No newline at end of file