From: Bhargava Jandhyala (bjandhya) Date: Mon, 28 Nov 2022 17:21:09 +0000 (+0000) Subject: Pull request #3682: smb: handling smb duplicate sessions X-Git-Tag: 3.1.48.0~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2f7f5fd084f545215cceed4b07c0fc37d742e2f4;p=thirdparty%2Fsnort3.git Pull request #3682: smb: handling smb duplicate sessions Merge in SNORT/snort3 from ~BJANDHYA/snort3:pcap_test to master Squashed commit of the following: commit 6009316bdbe079c62494b1bcf8a8b9f72e3df393 Author: Bhargava Jandhyala Date: Thu Sep 1 02:24:57 2022 -0400 smb: handling smb duplicate sessions --- diff --git a/src/file_api/file_flows.cc b/src/file_api/file_flows.cc index 068b50f03..42fce79b7 100644 --- a/src/file_api/file_flows.cc +++ b/src/file_api/file_flows.cc @@ -43,6 +43,7 @@ #include "file_module.h" #include "file_service.h" #include "file_stats.h" +#include using namespace snort; @@ -199,6 +200,7 @@ uint64_t FileFlows::get_new_file_instance() FileFlows::~FileFlows() { + std::lock_guard guard(file_flow_context_mutex); FileCache* file_cache = FileService::get_file_cache(); assert(file_cache); uint64_t file_id = 0; diff --git a/src/file_api/file_flows.h b/src/file_api/file_flows.h index 6a3387620..abecb887b 100644 --- a/src/file_api/file_flows.h +++ b/src/file_api/file_flows.h @@ -56,6 +56,7 @@ public: FileFlows(Flow* f, FileInspect* inspect) : FlowData(file_flow_data_id, inspect), flow(f) { } ~FileFlows() override; + std::mutex file_flow_context_mutex; static void init() { file_flow_data_id = FlowData::create_flow_data_id(); } diff --git a/src/service_inspectors/dce_rpc/dce_smb2.cc b/src/service_inspectors/dce_rpc/dce_smb2.cc index cabb7a531..47181adb8 100644 --- a/src/service_inspectors/dce_rpc/dce_smb2.cc +++ b/src/service_inspectors/dce_rpc/dce_smb2.cc @@ -38,7 +38,8 @@ using namespace snort; Dce2Smb2SessionCache smb2_session_cache(SMB_DEFAULT_MEMCAP); -const char* smb2_command_string[SMB2_COM_MAX] = { +const char* smb2_command_string[SMB2_COM_MAX] = +{ "SMB2_COM_NEGOTIATE", "SMB2_COM_SESSION_SETUP", "SMB2_COM_LOGOFF", @@ -105,13 +106,14 @@ Dce2Smb2SessionData::Dce2Smb2SessionData(const Packet* p, { tcp_file_tracker = nullptr; flow_key = get_smb2_flow_key(tcp_flow->key); - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, p, "smb2 session created\n"); + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, p, + "smb2 session created\n"); dce2_smb_stats.total_smb2_sessions++; + vlan_id = p->get_flow_vlan_id(); } Dce2Smb2SessionData::~Dce2Smb2SessionData(void) { - session_data_mutex.lock(); for (auto it_session : connected_sessions) { it_session.second->detach_flow(flow_key); @@ -121,9 +123,10 @@ Dce2Smb2SessionData::~Dce2Smb2SessionData(void) if (get_tcp_file_tracker() && !(get_tcp_file_tracker()->get_flow_state_map().empty())) { get_tcp_file_tracker()->get_flow_state_map().erase(flow_key); - tcp_file_tracker = nullptr; } - session_data_mutex.unlock(); + if (tcp_file_tracker and tcp_file_tracker->get_flow_key() == flow_key ) + tcp_file_tracker->set_flow_key(0); + tcp_file_tracker = nullptr; } void Dce2Smb2SessionData::reset_matching_tcp_file_tracker( @@ -157,23 +160,31 @@ Smb2SessionKey Dce2Smb2SessionData::get_session_key(uint64_t session_id) Dce2Smb2SessionTrackerPtr Dce2Smb2SessionData::find_session(uint64_t session_id) { - std::lock_guard guard(session_data_mutex); + std::lock_guard guard(session_data_mutex); auto it_session = connected_sessions.find(session_id); if (it_session != connected_sessions.end()) { Dce2Smb2SessionTrackerPtr session = it_session->second; //we already have the session, but call find to update the LRU - smb2_session_cache.find_session(session->get_key(), this); + smb2_session_cache.find_session(session->get_key()); + if (session->vlan_id != 0 and session->vlan_id != + (DetectionEngine::get_current_packet()->get_flow_vlan_id())) + return nullptr; return session; } else { Dce2Smb2SessionTrackerPtr session = smb2_session_cache.find_session( - get_session_key(session_id), this); - if (session) + get_session_key(session_id)); + if (session and session->vlan_id != 0 and + session->vlan_id != (DetectionEngine::get_current_packet()->get_flow_vlan_id())) + { connected_sessions.insert(std::make_pair(session_id,session)); - return session; + return session; + } + else + return nullptr; } } @@ -181,17 +192,21 @@ Dce2Smb2SessionTrackerPtr Dce2Smb2SessionData::find_session(uint64_t session_id) Dce2Smb2SessionTrackerPtr Dce2Smb2SessionData::create_session(uint64_t session_id) { Smb2SessionKey session_key = get_session_key(session_id); - std::lock_guard guard(session_data_mutex); - Dce2Smb2SessionTrackerPtr session = smb2_session_cache.find_else_create_session(session_key, this); - connected_sessions.insert(std::make_pair(session_id, session)); + Dce2Smb2SessionTrackerPtr session = smb2_session_cache.find_else_create_session(session_key, + this); + if (session) + { + connected_sessions.insert(std::make_pair(session_id, session)); + session->vlan_id = DetectionEngine::get_current_packet()->get_flow_vlan_id(); + } return session; } -void Dce2Smb2SessionData::remove_session(uint64_t session_id, bool sync) +void Dce2Smb2SessionData::remove_session(uint64_t session_id) { - if (sync) session_data_mutex.lock(); + session_data_mutex.lock(); connected_sessions.erase(session_id); - if (sync) session_data_mutex.unlock(); + session_data_mutex.unlock(); } void Dce2Smb2SessionData::process_command(const Smb2Hdr* smb_hdr, @@ -219,7 +234,8 @@ void Dce2Smb2SessionData::process_command(const Smb2Hdr* smb_hdr, if (smb_data + SMB2_ ## cmd ## _ ## type ## _STRUC_SIZE - 1 > end) \ { \ dce2_smb_stats.v2_ ## counter ## _hdr_err++; \ - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, GET_CURRENT_PACKET, \ + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, \ + GET_CURRENT_PACKET, \ "%s : smb data beyond end detected\n", \ smb2_command_string[command]); \ if (session) \ @@ -236,7 +252,8 @@ void Dce2Smb2SessionData::process_command(const Smb2Hdr* smb_hdr, if (SMB2_COMMAND_TYPE(ERROR, RESPONSE) and Smb2Error(smb_hdr)) \ { \ dce2_smb_stats.v2_ ## counter ## _err_resp++; \ - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, GET_CURRENT_PACKET, "%s_RESP: error\n", \ + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, GET_CURRENT_PACKET, \ + "%s_RESP: error\n", \ smb2_command_string[command]); \ if (session) \ { \ @@ -251,9 +268,9 @@ void Dce2Smb2SessionData::process_command(const Smb2Hdr* smb_hdr, { \ dce2_smb_stats.v2_ ## counter ## _inv_str_sz++; \ SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL \ - , GET_CURRENT_PACKET, "%s: invalid struct size\n", \ + , GET_CURRENT_PACKET, "%s: invalid struct size\n", \ smb2_command_string[command]); \ - if (session) \ + if (session) \ { \ session->set_do_not_delete(false); \ session->set_prev_comand(SMB2_COM_MAX); \ @@ -267,9 +284,11 @@ void Dce2Smb2SessionData::process_command(const Smb2Hdr* smb_hdr, flow_key, Smb2Mid(smb_hdr), session_id, Smb2Tid(smb_hdr)); // Handling case of two threads trying to do close same session at a time - session = find_session(session_id); + session = smb2_session_cache.find(get_session_key(session_id)); + if (session and connected_sessions.size() < 9) + connected_sessions.insert(std::make_pair(session_id, session)); if ((command == SMB2_COM_CLOSE or command == - SMB2_COM_TREE_DISCONNECT) and (session and session->get_prev_command() != SMB2_COM_MAX)) + SMB2_COM_TREE_DISCONNECT)and (session and session->get_prev_command() != SMB2_COM_MAX)) { return; } @@ -288,7 +307,8 @@ void Dce2Smb2SessionData::process_command(const Smb2Hdr* smb_hdr, case SMB2_COM_NEGOTIATE: if (SMB2_COMMAND_TYPE(NEGOTIATE, RESPONSE)) { - const Smb2NegotiateResponseHdr* neg_resp_hdr = (const Smb2NegotiateResponseHdr*)smb_data; + const Smb2NegotiateResponseHdr* neg_resp_hdr = (const + Smb2NegotiateResponseHdr*)smb_data; if (neg_resp_hdr->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL) { //total multichannel sessions @@ -297,22 +317,25 @@ void Dce2Smb2SessionData::process_command(const Smb2Hdr* smb_hdr, Dce2SmbFlowData* fd = create_expected_smb_flow_data(p); if (fd) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_CRITICAL_LEVEL, GET_CURRENT_PACKET, + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_CRITICAL_LEVEL, + GET_CURRENT_PACKET, "Requesting for expected smb flow\n"); int result = Stream::set_snort_protocol_id_expected(p, PktType::TCP, - IpProtocol::TCP, p->ptrs.ip_api.get_dst() , 0 ,p->ptrs.ip_api.get_src(), - p->flow->server_port , snort_protocol_id_smb, fd, false, true); + IpProtocol::TCP, p->ptrs.ip_api.get_dst(), 0,p->ptrs.ip_api.get_src(), + p->flow->server_port, snort_protocol_id_smb, fd, false, true); if (result < 0) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_CRITICAL_LEVEL, GET_CURRENT_PACKET, + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_CRITICAL_LEVEL, + GET_CURRENT_PACKET, "Failed to create expected smb flow\n"); delete fd; } } else { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_CRITICAL_LEVEL, GET_CURRENT_PACKET, + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_CRITICAL_LEVEL, + GET_CURRENT_PACKET, "fd is null in negotiate , failed to create pinhole\n"); } } @@ -329,19 +352,15 @@ void Dce2Smb2SessionData::process_command(const Smb2Hdr* smb_hdr, } else if (!SMB2_COMMAND_TYPE(SETUP, REQUEST)) SMB2_HANDLE_INVALID_STRUC_SIZE(setup) - break; + break; case SMB2_COM_LOGOFF: dce2_smb_stats.v2_logoff++; if (SMB2_COMMAND_TYPE(LOGOFF, REQUEST)) - { - session_data_mutex.lock(); smb2_session_cache.remove(get_session_key(session_id)); - session_data_mutex.unlock(); - } else SMB2_HANDLE_INVALID_STRUC_SIZE(logoff) - break; + break; //commands processed by session case SMB2_COM_TREE_CONNECT: dce2_smb_stats.v2_tree_cnct++; @@ -351,11 +370,13 @@ void Dce2Smb2SessionData::process_command(const Smb2Hdr* smb_hdr, SMB2_HANDLE_HEADER_ERROR(TREE_CONNECT, RESPONSE, tree_cnct_resp) if (!session) session = create_session(session_id); + if (!session) + return; session->process(command, SMB2_CMD_TYPE_RESPONSE, smb_hdr, end, flow_key); } else if (!SMB2_COMMAND_TYPE(TREE_CONNECT,REQUEST)) SMB2_HANDLE_INVALID_STRUC_SIZE(tree_cnct) - break; + break; case SMB2_COM_TREE_DISCONNECT: dce2_smb_stats.v2_tree_discn++; @@ -382,16 +403,18 @@ void Dce2Smb2SessionData::process_command(const Smb2Hdr* smb_hdr, uint8_t command_type = SMB2_GET_COMMAND_TYPE(CREATE); if (SMB2_CMD_TYPE_INVALID == command_type) SMB2_HANDLE_INVALID_STRUC_SIZE(crt) - else if (SMB2_COMMAND_TYPE(CREATE, REQUEST)) - SMB2_HANDLE_HEADER_ERROR(CREATE, REQUEST, crt_req) - else if (SMB2_COMMAND_TYPE(CREATE, RESPONSE)) - SMB2_HANDLE_HEADER_ERROR(CREATE, RESPONSE, crt_resp) + else if (SMB2_COMMAND_TYPE(CREATE, REQUEST)) + SMB2_HANDLE_HEADER_ERROR(CREATE, REQUEST, crt_req) + else if (SMB2_COMMAND_TYPE(CREATE, RESPONSE)) + SMB2_HANDLE_HEADER_ERROR(CREATE, RESPONSE, crt_resp) + if (!session) + session = create_session(session_id); if (!session) - session = create_session(session_id); + return; session->process(command, command_type, smb_hdr, end, flow_key); } - break; + break; case SMB2_COM_CLOSE: dce2_smb_stats.v2_cls++; @@ -450,7 +473,7 @@ void Dce2Smb2SessionData::process_command(const Smb2Hdr* smb_hdr, } else SMB2_HANDLE_INVALID_STRUC_SIZE(read) - session->process(command, command_type, smb_hdr, end, flow_key); + session->process(command, command_type, smb_hdr, end, flow_key); } else dce2_smb_stats.v2_session_ignored++; @@ -475,7 +498,7 @@ void Dce2Smb2SessionData::process_command(const Smb2Hdr* smb_hdr, } else SMB2_HANDLE_INVALID_STRUC_SIZE(wrt) - session->process(command, command_type, smb_hdr, end, flow_key); + session->process(command, command_type, smb_hdr, end, flow_key); } else dce2_smb_stats.v2_session_ignored++; @@ -530,7 +553,8 @@ void Dce2Smb2SessionData::process() return; } const Smb2Hdr* smb_hdr = (const Smb2Hdr*)(data_ptr + sizeof(NbssHdr)); - const Smb2TransformHdr* smb_trans_hdr = (const Smb2TransformHdr*)(data_ptr + sizeof(NbssHdr)); + const Smb2TransformHdr* smb_trans_hdr = (const Smb2TransformHdr*)(data_ptr + + sizeof(NbssHdr)); uint32_t smb_proto_id = SmbTransformId(smb_trans_hdr); uint64_t sid = smb_trans_hdr->session_id; if (smb_proto_id == DCE2_SMB2_TRANS_ID) @@ -540,9 +564,9 @@ void Dce2Smb2SessionData::process() session = find_session(sid); if (session) { - bool flag = session->get_encryption_flag(); - if (!flag) - session->set_encryption_flag(true); + bool flag = session->get_encryption_flag(); + if (!flag) + session->set_encryption_flag(true); } } uint32_t next_command_offset; @@ -564,8 +588,8 @@ void Dce2Smb2SessionData::process() { dce_alert(GID_DCE2, DCE2_SMB_BAD_NEXT_COMMAND_OFFSET, (dce2CommonStats*)&dce2_smb_stats, sd); - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, - TRACE_ERROR_LEVEL, p, "bad next command offset\n"); + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, + TRACE_ERROR_LEVEL, p, "bad next command offset\n"); dce2_smb_stats.v2_bad_next_cmd_offset++; if (session) session->set_do_not_delete(false); @@ -580,8 +604,8 @@ void Dce2Smb2SessionData::process() if (compound_request_index > get_smb_max_compound()) { dce2_smb_stats.v2_cmpnd_req_lt_crossed++; - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, - TRACE_INFO_LEVEL, p, "compound request limit" + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, + TRACE_INFO_LEVEL, p, "compound request limit" " reached %" PRIu8 "\n",compound_request_index); if (session) session->set_do_not_delete(false); @@ -594,9 +618,11 @@ void Dce2Smb2SessionData::process() { if ( tcp_file_tracker ) { - session = find_session (tcp_file_tracker->get_session_id()); + session = smb2_session_cache.find(get_session_key(tcp_file_tracker->get_session_id())); if (session) session->set_do_not_delete(true); + else + return; } else return; @@ -604,7 +630,8 @@ void Dce2Smb2SessionData::process() if ( tcp_file_tracker and tcp_file_tracker.use_count() > 1 and tcp_file_tracker->accepting_raw_data_from(flow_key)) { - SMB_DEBUG(dce_smb_trace,DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, p, "processing raw data for file id %" PRIu64 "\n", + SMB_DEBUG(dce_smb_trace,DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, p, + "processing raw data for file id %" PRIu64 "\n", tcp_file_tracker->get_file_id()); tcp_file_tracker->process_data(flow_key, data_ptr, data_len, session); tcp_file_tracker->stop_accepting_raw_data_from(flow_key); @@ -619,7 +646,8 @@ void Dce2Smb2SessionData::process() } else { - SMB_DEBUG(dce_smb_trace,DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, p, "not processing raw data\n"); + SMB_DEBUG(dce_smb_trace,DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, p, + "not processing raw data\n"); } tcp_file_tracker_mutex.unlock(); } @@ -674,3 +702,4 @@ void Dce2Smb2SessionData::set_reassembled_data(uint8_t* nb_ptr, uint16_t co_len) read->length = alignedNtohs(&co_len); } } + diff --git a/src/service_inspectors/dce_rpc/dce_smb2.h b/src/service_inspectors/dce_rpc/dce_smb2.h index 4c78cc141..231aba48a 100644 --- a/src/service_inspectors/dce_rpc/dce_smb2.h +++ b/src/service_inspectors/dce_rpc/dce_smb2.h @@ -333,11 +333,11 @@ class Dce2Smb2SessionTracker; using Dce2Smb2SessionTrackerPtr = std::shared_ptr; using Dce2Smb2SessionTrackerMap = - std::unordered_map >; + std::unordered_map >; using Dce2Smb2FileTrackerPtr = std::shared_ptr; using Dce2Smb2FileTrackerMap = - std::unordered_map >; + std::unordered_map >; PADDING_GUARD_BEGIN struct Smb2SessionKey @@ -485,14 +485,13 @@ public: Dce2Smb2SessionData(const snort::Packet*, const dce2SmbProtoConf* proto); ~Dce2Smb2SessionData() override; void process() override; - void remove_session(uint64_t, bool = false); + void remove_session(uint64_t); void handle_retransmit(FilePosition, FileVerdict) override { } void reset_matching_tcp_file_tracker(Dce2Smb2FileTrackerPtr); void set_reassembled_data(uint8_t*, uint16_t) override; uint32_t get_flow_key() { return flow_key; } void set_tcp_file_tracker(Dce2Smb2FileTrackerPtr file_tracker) { - std::lock_guard guard(session_data_mutex); tcp_file_tracker = file_tracker; } @@ -502,21 +501,21 @@ public: } Dce2Smb2SessionTrackerPtr find_session(uint64_t); + std::recursive_mutex session_data_mutex; + uint16_t vlan_id; private: void process_command(const Smb2Hdr*, const uint8_t*); Smb2SessionKey get_session_key(uint64_t); Dce2Smb2SessionTrackerPtr create_session(uint64_t); - Dce2Smb2FileTrackerPtr tcp_file_tracker; uint32_t flow_key; Dce2Smb2SessionTrackerMap connected_sessions; - std::mutex session_data_mutex; std::mutex tcp_file_tracker_mutex; }; using Dce2Smb2SessionDataMap = - std::unordered_map >; + std::unordered_map >; #endif /* _DCE_SMB2_H_ */ diff --git a/src/service_inspectors/dce_rpc/dce_smb2_file.cc b/src/service_inspectors/dce_rpc/dce_smb2_file.cc index 9727a24d4..2d04e36cd 100644 --- a/src/service_inspectors/dce_rpc/dce_smb2_file.cc +++ b/src/service_inspectors/dce_rpc/dce_smb2_file.cc @@ -31,21 +31,27 @@ #include "dce_smb2.h" #include "dce_smb2_session.h" #include "dce_smb2_tree.h" +#include "dce_smb2_session_cache.h" +#include "flow/flow.h" +#include +#include "time/packet_time.h" #include using namespace snort; #define UNKNOWN_FILE_SIZE (~0) -void Dce2Smb2FileTracker::accept_raw_data_from(Dce2Smb2SessionData* flow, uint64_t offset, Dce2Smb2FileTrackerPtr file_tracker) +void Dce2Smb2FileTracker::accept_raw_data_from(Dce2Smb2SessionData* flow, uint64_t offset, + Dce2Smb2FileTrackerPtr file_tracker) { if (flow) { + std::lock_guard guard(flow->session_data_mutex); uint32_t current_flow_key = flow->get_flow_key(); - std::lock_guard guard(flow_state_mutex); + std::lock_guard guard1(flow_state_mutex); tcp_flow_state& current_flow_state = flow_state[current_flow_key]; - if ( (current_flow_state.pdu_state == DCE2_SMB_PDU_STATE__RAW_DATA) and - (current_flow_state.file_offset == current_flow_state.max_offset)) + if ( (current_flow_state.pdu_state == DCE2_SMB_PDU_STATE__RAW_DATA)and + (current_flow_state.file_offset == current_flow_state.max_offset)) { current_flow_state.file_offset = offset; } @@ -54,11 +60,12 @@ void Dce2Smb2FileTracker::accept_raw_data_from(Dce2Smb2SessionData* flow, uint64 flow->set_tcp_file_tracker(file_tracker); } } + void Dce2Smb2FileTracker::stop_accepting_raw_data_from(uint32_t current_flow_key) { std::lock_guard guard(flow_state_mutex); tcp_flow_state& current_flow_state = flow_state[current_flow_key]; - if(current_flow_state.file_offset == current_flow_state.max_offset) + if (current_flow_state.file_offset == current_flow_state.max_offset) current_flow_state.pdu_state = DCE2_SMB_PDU_STATE__COMMAND; } @@ -71,14 +78,28 @@ inline void Dce2Smb2FileTracker::file_detect() std::pair Dce2Smb2FileTracker::update_processing_flow( Dce2Smb2SessionData* current_flow,Dce2Smb2SessionTrackerPtr session_tracker) { - std::lock_guard guard(process_file_mutex); bool switched = false; - Dce2Smb2SessionData* processing_flow; - if (session_tracker) - processing_flow = session_tracker->get_flow(file_flow_key); - else - processing_flow = parent_tree->get_parent()->get_flow(file_flow_key); - + Dce2Smb2SessionData* processing_flow = nullptr; + std::lock_guard guard1(session_tracker->attached_flows_mutex); + auto it_flow = session_tracker->attached_flows.find(file_flow_key); + if (it_flow != session_tracker->attached_flows.end()) + processing_flow = (it_flow != session_tracker->attached_flows.end()) ? it_flow->second : + nullptr; + if (processing_flow) + { + if (session_tracker->vlan_id != processing_flow->vlan_id) + processing_flow = nullptr; + else + { + processing_flow->session_data_mutex.lock(); + if (processing_flow->get_tcp_flow()->session_state & STREAM_STATE_CLOSED or + processing_flow->get_tcp_flow()->session_state & STREAM_STATE_RELEASING) + { + processing_flow->session_data_mutex.unlock(); + return std::make_pair(switched, nullptr); + } + } + } if (!processing_flow) { switched = true; @@ -87,13 +108,27 @@ std::pair Dce2Smb2FileTracker::update_processing_flo else { Flow* flow = DetectionEngine::get_current_packet()->flow; - Dce2SmbFlowData* current_flow_data = (Dce2SmbFlowData*)(flow->get_flow_data(Dce2SmbFlowData::inspector_id)); - processing_flow = (Dce2Smb2SessionData*)current_flow_data->get_smb_session_data(); + Dce2SmbFlowData* current_flow_data = (Dce2SmbFlowData*)(flow->get_flow_data( + Dce2SmbFlowData::inspector_id)); + if (current_flow_data) + processing_flow = (Dce2Smb2SessionData*)current_flow_data->get_smb_session_data(); + } + if (processing_flow) + { + file_flow_key = processing_flow->get_flow_key(); + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, GET_CURRENT_PACKET, + "updating the processing flow key to %u\n", file_flow_key); } - file_flow_key = processing_flow->get_flow_key(); - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, GET_CURRENT_PACKET, - "updating the processing flow key to %u\n", file_flow_key); } + if (processing_flow and processing_flow->get_tcp_flow()) + processing_flow->get_tcp_flow()->last_data_seen = packet_time(); + + if (processing_flow and processing_flow->get_tcp_flow()) + { + processing_flow->get_tcp_flow()->last_data_seen = packet_time(); + } + if (processing_flow) + processing_flow->session_data_mutex.unlock(); return std::make_pair(switched, processing_flow); } @@ -107,8 +142,8 @@ void Dce2Smb2FileTracker::set_info(char* file_name_v, uint16_t name_len_v, uint6 file_name_hash = str_to_hash((uint8_t*)file_name, file_name_len); } file_size = size_v; - auto updated_flow = update_processing_flow(); - Flow* flow = updated_flow.second->get_tcp_flow(); + Packet* p = DetectionEngine::get_current_packet(); + Flow* flow = p->flow; { std::lock_guard guard(process_file_mutex); FileContext* file = get_smb_file_context(flow, file_name_hash, file_id, true); @@ -121,7 +156,7 @@ void Dce2Smb2FileTracker::set_info(char* file_name_v, uint16_t name_len_v, uint6 ignore = false; if (file->verdict == FILE_VERDICT_UNKNOWN) { - if ((file_name_v and name_len_v) or updated_flow.first) + if ((file_name_v and name_len_v)) file->set_file_name(file_name, file_name_len); file->set_file_size(size_v ? size_v : UNKNOWN_FILE_SIZE); } @@ -137,16 +172,30 @@ bool Dce2Smb2FileTracker::close(const uint32_t current_flow_key) if (!ignore and !file_size and file_offset) { file_size = file_offset; - Dce2Smb2SessionData* processing_flow = update_processing_flow().second; - Flow* flow = processing_flow->get_tcp_flow(); + std::lock_guard guard1( + get_parent()->get_parent()->attached_flows_mutex); + Dce2Smb2SessionData* current_flow; + Packet* p = DetectionEngine::get_current_packet(); + Flow* flow = p->flow; + Dce2SmbFlowData* current_flow_data = (Dce2SmbFlowData*)(flow->get_flow_data( + Dce2SmbFlowData::inspector_id)); + if (!current_flow_data) + return false; + current_flow = (Dce2Smb2SessionData*)current_flow_data->get_smb_session_data(); + Dce2Smb2SessionTracker* sess = parent_tree->get_parent(); + Dce2Smb2SessionTrackerPtr ses_ptr = smb2_session_cache.find_id(sess->get_key()); + Dce2Smb2SessionData* processing_flow = update_processing_flow(current_flow, + ses_ptr).second; + if (!processing_flow) + return false; + flow = processing_flow->get_tcp_flow(); { std::lock_guard guard(process_file_mutex); FileContext* file = get_smb_file_context(flow, file_name_hash, file_id, false); if (file) file->set_file_size(file_size); } - Dce2Smb2SessionTrackerPtr ses_ptr = processing_flow->find_session(session_id); - return (!process_data(current_flow_key, nullptr, 0,ses_ptr)); + return (!process_data(current_flow_key, nullptr, 0, ses_ptr)); } return true; } @@ -159,65 +208,65 @@ bool Dce2Smb2FileTracker::process_data(const uint32_t current_flow_key, const ui current_flow_state.file_offset = offset; current_flow_state.max_offset = offset + max_offset; flow_state_mutex.unlock(); + Dce2Smb2SessionTrackerPtr ses_ptr = nullptr; Dce2Smb2SessionTracker* sess = parent_tree->get_parent(); + if (!sess) + return false; + ses_ptr = smb2_session_cache.find_id(sess->get_key()); + if (ses_ptr.use_count() < 2) + return false; if (parent_tree->get_share_type() != SMB2_SHARE_TYPE_DISK) { Dce2Smb2SessionData* current_flow = nullptr; - if (sess) - { - parent_tree->get_parent()->set_do_not_delete(true); - current_flow = parent_tree->get_parent()->get_flow(current_flow_key); - if (!current_flow) - { - parent_tree->get_parent()->set_do_not_delete(false); - return false; - } - } - else - { + if (ses_ptr.use_count() < 2) + return false; + Packet* p = DetectionEngine::get_current_packet(); + Flow* flow = p->flow; + Dce2SmbFlowData* current_flow_data = (Dce2SmbFlowData*)(flow->get_flow_data( + Dce2SmbFlowData::inspector_id)); + if (!current_flow_data) + return false; + current_flow = (Dce2Smb2SessionData*)current_flow_data->get_smb_session_data(); + if (!current_flow) return false; - } - if (data_size > UINT16_MAX) { data_size = UINT16_MAX; } - if (parent_tree->get_cotracker()) - { + current_flow->session_data_mutex.lock(); + if (current_flow->get_tcp_flow()) + current_flow->get_tcp_flow()->last_data_seen = packet_time(); + + if (parent_tree->get_cotracker()) + { sess->co_tracker_mutex.lock(); DCE2_CoProcess(current_flow->get_dce2_session_data(), parent_tree->get_cotracker(), file_data, data_size); - sess->co_tracker_mutex.unlock(); - } - parent_tree->get_parent()->set_do_not_delete(false); + sess->co_tracker_mutex.unlock(); + } + current_flow->session_data_mutex.unlock(); return true; } - Dce2Smb2SessionData *current_flow = sess->get_flow(current_flow_key); - Dce2Smb2SessionTrackerPtr ses_ptr = current_flow->find_session(session_id); - return process_data(current_flow_key, file_data, data_size,ses_ptr); + return process_data(current_flow_key, file_data, data_size, ses_ptr); } bool Dce2Smb2FileTracker::process_data(const uint32_t current_flow_key, const uint8_t* file_data, uint32_t data_size,Dce2Smb2SessionTrackerPtr session_tracker) { - Dce2Smb2SessionData *current_flow; - if (session_tracker) - { - session_tracker->set_do_not_delete(true); - current_flow = session_tracker->get_flow(current_flow_key); - } - else - return false; - - if (!current_flow) - { - session_tracker->set_do_not_delete(false); - return true; - } - + if (!session_tracker or session_tracker.use_count() < 2) + return false; + std::lock_guard guard1(session_tracker->attached_flows_mutex); + Dce2Smb2SessionData* current_flow; + Packet* p = DetectionEngine::get_current_packet(); + Flow* flow = p->flow; + Dce2SmbFlowData* current_flow_data = (Dce2SmbFlowData*)(flow->get_flow_data( + Dce2SmbFlowData::inspector_id)); + if (!current_flow_data) + return false; + current_flow = (Dce2Smb2SessionData*)current_flow_data->get_smb_session_data(); int64_t file_detection_depth = current_flow->get_smb_file_depth(); int64_t detection_size = 0; - Packet* p = DetectionEngine::get_current_packet(); + flow_state_mutex.lock(); uint64_t file_offset = flow_state[current_flow_key].file_offset; flow_state_mutex.unlock(); @@ -235,7 +284,7 @@ bool Dce2Smb2FileTracker::process_data(const uint32_t current_flow_key, const ui if (detection_size) { set_file_data(file_data, (detection_size > UINT16_MAX) ? - UINT16_MAX : (uint16_t)detection_size, file_id); + UINT16_MAX : (uint16_t)detection_size); file_detect(); } @@ -243,49 +292,68 @@ bool Dce2Smb2FileTracker::process_data(const uint32_t current_flow_key, const ui { SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, p, "file name not set , ignored\n"); - session_tracker->set_do_not_delete(false); return true; } if (file_size and file_offset > file_size) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, p, "file_process: bad offset\n"); + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, p, + "file_process: bad offset\n"); dce_alert(GID_DCE2, DCE2_SMB_INVALID_FILE_OFFSET, (dce2CommonStats*) &dce2_smb_stats, *(current_flow->get_dce2_session_data())); } + if (session_tracker.use_count() < 2) + return false; auto updated_flow = update_processing_flow(current_flow, session_tracker); Dce2Smb2SessionData* processing_flow = updated_flow.second; - - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, p,"file_process fid %" PRIu64 " data_size %" - PRIu32 " offset %" PRIu64 "\n", file_id, data_size, file_offset); + if (!processing_flow) + return false; + if ( !processing_flow->get_tcp_flow()) + return false; + processing_flow->session_data_mutex.lock(); + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, p, + "file_process fid %" PRIu64 " data_size %" PRIu32 " offset %" PRIu64 "\n", file_id, + data_size, file_offset); { - std::lock_guard guard(process_file_mutex); + if (processing_flow->get_tcp_flow()->session_state & STREAM_STATE_CLOSED or + processing_flow->get_tcp_flow()->session_state & STREAM_STATE_RELEASING) + { + processing_flow->session_data_mutex.unlock(); + return true; + } FileFlows* file_flows = FileFlows::get_file_flows(processing_flow->get_tcp_flow()); if (!file_flows) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_CRITICAL_LEVEL, p, "file_flows not found\n"); - session_tracker->set_do_not_delete(false); + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_CRITICAL_LEVEL, p, + "file_flows not found\n"); + processing_flow->session_data_mutex.unlock(); return true; } - if (updated_flow.first) { - // update the new file context in case of flow switch - FileContext* file = file_flows->get_file_context(file_name_hash, true, file_id); - file->set_file_name(file_name, file_name_len); - file->set_file_size(file_size.load() ? file_size.load() : UNKNOWN_FILE_SIZE); - } - FileFlows::get_file_flows(p->flow); - bool continue_processing = file_flows->file_process(p, file_name_hash, file_data, data_size, - file_offset, direction, file_id); - - if (!continue_processing) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, p, "file_process completed\n"); - session_tracker->set_do_not_delete(false); - return false; + std::lock_guard guard(file_flows->file_flow_context_mutex); + + if (updated_flow.first) + { + // update the new file context in case of flow switch + FileContext* file = file_flows->get_file_context(file_name_hash, true, file_id); + file->set_file_name(file_name, file_name_len); + file->set_file_size(file_size.load() ? file_size.load() : UNKNOWN_FILE_SIZE); + } + FileFlows::get_file_flows(p->flow); + bool continue_processing = file_flows->file_process(p, file_name_hash, file_data, + data_size, + file_offset, direction, file_id); + + if (!continue_processing) + { + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, p, + "file_process completed\n"); + processing_flow->session_data_mutex.unlock(); + return false; + } } } @@ -293,7 +361,7 @@ bool Dce2Smb2FileTracker::process_data(const uint32_t current_flow_key, const ui flow_state_mutex.lock(); flow_state[current_flow_key].file_offset = file_offset; flow_state_mutex.unlock(); - session_tracker->set_do_not_delete(false); + processing_flow->session_data_mutex.unlock(); return true; } diff --git a/src/service_inspectors/dce_rpc/dce_smb2_file.h b/src/service_inspectors/dce_rpc/dce_smb2_file.h index efb26aff8..7665ad52b 100644 --- a/src/service_inspectors/dce_rpc/dce_smb2_file.h +++ b/src/service_inspectors/dce_rpc/dce_smb2_file.h @@ -50,7 +50,7 @@ public: file_id(file_idv), file_size(0), file_name_hash(0), file_name(nullptr), direction(FILE_DOWNLOAD), parent_tree(p_tree), session_id(sid) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, GET_CURRENT_PACKET, + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, GET_CURRENT_PACKET, "file tracker %" PRIu64 " created\n", file_id); } @@ -65,6 +65,7 @@ public: std::lock_guard guard(flow_state_mutex); return (flow_state[current_flow_key].pdu_state == DCE2_SMB_PDU_STATE__RAW_DATA); } + void stop_accepting_raw_data_from(uint32_t); void set_direction(FileDirection dir) { direction = dir; } @@ -78,6 +79,16 @@ public: return flow_state; } + uint32_t get_flow_key() + { + return file_flow_key; + } + + void set_flow_key(uint32_t key) + { + file_flow_key = key; + } + private: void file_detect(); std::pair update_processing_flow(Dce2Smb2SessionData* = nullptr, @@ -99,7 +110,7 @@ private: using Dce2Smb2FileTrackerPtr = std::shared_ptr; using Dce2Smb2FileTrackerMap = - std::unordered_map >; + std::unordered_map >; #endif diff --git a/src/service_inspectors/dce_rpc/dce_smb2_request.h b/src/service_inspectors/dce_rpc/dce_smb2_request.h index 1ea75309f..e9e6f96e1 100644 --- a/src/service_inspectors/dce_rpc/dce_smb2_request.h +++ b/src/service_inspectors/dce_rpc/dce_smb2_request.h @@ -37,13 +37,15 @@ public: Dce2Smb2RequestTracker(uint64_t file_id_v, uint64_t offset_v = 0) : fname(nullptr), fname_len(0), file_id(file_id_v), offset(offset_v) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, GET_CURRENT_PACKET, "request tracker created\n"); + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, GET_CURRENT_PACKET, + "request tracker created\n"); } Dce2Smb2RequestTracker(char* fname_v, uint16_t fname_len_v) : fname(fname_v), fname_len(fname_len_v), file_id(0), offset(0) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, GET_CURRENT_PACKET, "request tracker created\n"); + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, GET_CURRENT_PACKET, + "request tracker created\n"); } ~Dce2Smb2RequestTracker() @@ -64,8 +66,9 @@ private: uint64_t offset; }; +using Dce2Smb2RequestTrackerPtr = std::shared_ptr; using Dce2Smb2RequestTrackerMap = - std::unordered_map; + std::unordered_map; #endif diff --git a/src/service_inspectors/dce_rpc/dce_smb2_session.cc b/src/service_inspectors/dce_rpc/dce_smb2_session.cc index d2d2c6786..4284a0587 100644 --- a/src/service_inspectors/dce_rpc/dce_smb2_session.cc +++ b/src/service_inspectors/dce_rpc/dce_smb2_session.cc @@ -28,6 +28,8 @@ #include "file_api/file_flows.h" +#include + uint32_t Smb2Tid(const Smb2Hdr* hdr) { return snort::alignedNtohl(&(((const Smb2SyncHdr*)hdr)->tree_id)); @@ -35,7 +37,7 @@ uint32_t Smb2Tid(const Smb2Hdr* hdr) Dce2Smb2SessionData* Dce2Smb2SessionTracker::get_flow(uint32_t flow_key) { - std::lock_guard guard(attached_flows_mutex); + std::lock_guard guard(attached_flows_mutex); auto it_flow = attached_flows.find(flow_key); return (it_flow != attached_flows.end()) ? it_flow->second : nullptr; } @@ -46,7 +48,7 @@ Dce2Smb2TreeTrackerPtr Dce2Smb2SessionTracker::find_tree_for_message( std::lock_guard guard(connected_trees_mutex); for (auto it_tree : connected_trees) { - Dce2Smb2RequestTracker* request = it_tree.second->find_request(message_id, flow_key); + Dce2Smb2RequestTrackerPtr request = it_tree.second->find_request(message_id, flow_key); if (request) return it_tree.second; } @@ -63,6 +65,67 @@ Dce2Smb2TreeTrackerPtr Dce2Smb2SessionTracker::find_tree_for_tree_id( return nullptr; } +uint32_t Dce2Smb2SessionTracker::fill_map(const uint64_t msg_id, const uint8_t command_type, const + uint32_t current_flow_key) +{ + std::lock_guard guard(mid_mutex); + auto it = mid_map.find(current_flow_key); + msgid_state* mid_ptr; + if (it == mid_map.end()) + { + mid_ptr = new msgid_state { 0, 0, { 0 }, { 0 } + }; + mid_map.insert(std::make_pair(current_flow_key, mid_ptr)); + } + else + mid_ptr = it->second; + if (command_type == SMB2_CMD_TYPE_REQUEST) + { + if (msg_id > mid_ptr->max_req_msg_id) + { + const int size = msg_id-(mid_ptr->max_req_msg_id)-1; + std::vector v(size); + std::iota(v.begin(), v.end(), mid_ptr->max_req_msg_id+1); + mid_ptr->missing_req_msg_ids.insert(v.begin (), v.end ()); + mid_ptr->max_req_msg_id = msg_id; + } + else + { + if (mid_ptr->missing_req_msg_ids.find(msg_id) == mid_ptr->missing_req_msg_ids.end()) + { + return 1; + } + else + { + mid_ptr->missing_req_msg_ids.erase(msg_id); + } + } + } + if (command_type == SMB2_CMD_TYPE_RESPONSE) + { + if (msg_id > mid_ptr->max_resp_msg_id) + { + const int size = msg_id-(mid_ptr->max_resp_msg_id)-1; + std::vector v(size); + std::iota(v.begin(), v.end(), mid_ptr->max_resp_msg_id+1); + mid_ptr->missing_resp_msg_ids.insert(v.begin (), v.end ()); + mid_ptr->max_resp_msg_id = msg_id; + } + else + { + if (mid_ptr->missing_resp_msg_ids.find(msg_id) == mid_ptr->missing_resp_msg_ids.end()) + { + return 1; + } + else + { + mid_ptr->missing_resp_msg_ids.erase(msg_id); + } + } + } + return 0; +} + void Dce2Smb2SessionTracker::process(const uint16_t command, uint8_t command_type, const Smb2Hdr* smb_header, const uint8_t* end, const uint32_t current_flow_key) { @@ -83,19 +146,25 @@ void Dce2Smb2SessionTracker::process(const uint16_t command, uint8_t command_typ tree = find_tree_for_message(Smb2Mid(smb_header), current_flow_key); } + if (fill_map(Smb2Mid(smb_header), command_type, current_flow_key)) + { + dce2_smb_stats.ignore_dup_sessions++; + return; + } + switch (command) { case SMB2_COM_TREE_CONNECT: { uint8_t share_type = ((const Smb2TreeConnectResponseHdr*) ((const uint8_t*)smb_header + SMB2_HEADER_LENGTH))->share_type; - connect_tree(tree_id, current_flow_key, share_type); + connect_tree(tree_id, share_type); } break; case SMB2_COM_TREE_DISCONNECT: { - if (!tree) - dce2_smb_stats.v2_tree_discn_ignored++; + if (!tree) + dce2_smb_stats.v2_tree_discn_ignored++; } break; @@ -103,11 +172,11 @@ void Dce2Smb2SessionTracker::process(const uint16_t command, uint8_t command_typ case SMB2_COM_CREATE: if (!tree and SMB2_CMD_TYPE_REQUEST == command_type) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, - TRACE_INFO_LEVEL, GET_CURRENT_PACKET, + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, + TRACE_INFO_LEVEL, GET_CURRENT_PACKET, "%s_REQ: mid-stream session detected\n", smb2_command_string[command]); - tree = connect_tree(tree_id, current_flow_key); + tree = connect_tree(tree_id); if (!tree) { SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, @@ -122,7 +191,7 @@ void Dce2Smb2SessionTracker::process(const uint16_t command, uint8_t command_typ tree->process(command, command_type, smb_header, end, current_flow_key); else { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, GET_CURRENT_PACKET, "%s: tree tracker missing\n", smb2_command_string[command]); dce2_smb_stats.v2_tree_ignored++; @@ -132,19 +201,8 @@ void Dce2Smb2SessionTracker::process(const uint16_t command, uint8_t command_typ } Dce2Smb2TreeTrackerPtr Dce2Smb2SessionTracker::connect_tree(const uint32_t tree_id, - const uint32_t current_flow_key, const uint8_t share_type) + const uint8_t share_type) { - Dce2Smb2SessionData* current_flow = get_flow(current_flow_key); - if ((SMB2_SHARE_TYPE_DISK == share_type) and current_flow and - (-1 == current_flow->get_max_file_depth()) and - (-1 == current_flow->get_smb_file_depth())) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, - TRACE_INFO_LEVEL, GET_CURRENT_PACKET, "Not inserting TID (%u) " - "because it's not IPC and not inspecting normal file data.\n", tree_id); - dce2_smb_stats.v2_tree_cnct_ignored++; - return nullptr; - } Dce2Smb2TreeTrackerPtr tree; connected_trees_mutex.lock(); auto it_tree = connected_trees.find(tree_id); @@ -162,28 +220,6 @@ Dce2Smb2TreeTrackerPtr Dce2Smb2SessionTracker::connect_tree(const uint32_t tree_ return tree; } -void Dce2Smb2SessionTracker::clean_file_context_from_flow(uint64_t file_id, uint64_t - file_name_hash) -{ - set_do_not_delete(true); - attached_flows_mutex.lock(); - for (auto it_flow : attached_flows) - { - if (get_file_context_cleaned()) - { - attached_flows_mutex.unlock(); - set_do_not_delete(false); - return; - } - snort::FileFlows* file_flows = snort::FileFlows::get_file_flows( - it_flow.second->get_tcp_flow(), false); - if (file_flows) - file_flows->remove_processed_file_context(file_name_hash, file_id); - } - attached_flows_mutex.unlock(); - set_do_not_delete(false); -} - void Dce2Smb2SessionTracker::increase_size(const size_t size) { smb2_session_cache.increase_size(size); @@ -194,14 +230,6 @@ void Dce2Smb2SessionTracker::decrease_size(const size_t size) smb2_session_cache.decrease_size(size); } -void Dce2Smb2SessionTracker::unlink() -{ - attached_flows_mutex.lock(); - for (auto it_flow : attached_flows) - it_flow.second->remove_session(session_id, reload_prune.load()); - attached_flows_mutex.unlock(); -} - // Session Tracker is created and destroyed only from session cache Dce2Smb2SessionTracker::~Dce2Smb2SessionTracker(void) { @@ -215,19 +243,12 @@ Dce2Smb2SessionTracker::~Dce2Smb2SessionTracker(void) fcfs_mutex.unlock(); return; } - - connected_trees_mutex.lock(); - auto it_tree = connected_trees.begin(); - while (it_tree != connected_trees.end()) - { - auto next_it_tree = std::next(it_tree); - it_tree->second->close_all_files(); - disconnect_tree(it_tree->second->get_tree_id()); - it_tree = next_it_tree; - } - connected_trees_mutex.unlock(); + disconnect_tree(); + free_map(); do_not_delete = false; fcfs_mutex.unlock(); + std::lock_guard guard(attached_flows_mutex); + attached_flows.clear(); } diff --git a/src/service_inspectors/dce_rpc/dce_smb2_session.h b/src/service_inspectors/dce_rpc/dce_smb2_session.h index aa7c4ae44..e99fc4322 100644 --- a/src/service_inspectors/dce_rpc/dce_smb2_session.h +++ b/src/service_inspectors/dce_rpc/dce_smb2_session.h @@ -28,6 +28,14 @@ uint32_t Smb2Tid(const Smb2Hdr* hdr); +typedef struct _msgid_state +{ + uint64_t max_req_msg_id; + uint64_t max_resp_msg_id; + std::unordered_set missing_req_msg_ids; + std::unordered_set missing_resp_msg_ids; +} msgid_state; + class Dce2Smb2SessionTracker { public: @@ -40,35 +48,79 @@ public: file_context_cleaned = false; command_prev = SMB2_COM_MAX; encryption_flag = false; - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, GET_CURRENT_PACKET, + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, GET_CURRENT_PACKET, "session tracker %" PRIu64 "created\n", session_id); } ~Dce2Smb2SessionTracker(); - Dce2Smb2TreeTrackerPtr connect_tree(const uint32_t, const uint32_t, + Dce2Smb2TreeTrackerPtr connect_tree(const uint32_t, uint8_t=SMB2_SHARE_TYPE_DISK); - void disconnect_tree(uint32_t tree_id) + + void disconnect_tree() { - connected_trees.erase(tree_id); - decrease_size(sizeof(Dce2Smb2TreeTracker)); + std::lock_guard guard(connected_trees_mutex); + auto it_tree = connected_trees.begin(); + while (it_tree != connected_trees.end()) + { + auto next_it_tree = std::next(it_tree); + it_tree->second->close_all_files(); + connected_trees.erase(it_tree->second->get_tree_id()); + decrease_size(sizeof(Dce2Smb2TreeTracker)); + it_tree = next_it_tree; + } } void attach_flow(uint32_t flow_key, Dce2Smb2SessionData* ssd) { - std::lock_guard guard(attached_flows_mutex); - attached_flows.insert(std::make_pair(flow_key,ssd)); + std::lock_guard guard(attached_flows_mutex); + if (attached_flows.find(flow_key) == attached_flows.end()) + { + attached_flows.insert(std::make_pair(flow_key, ssd)); + } } bool detach_flow(uint32_t flow_key) { - std::lock_guard guard(attached_flows_mutex); - attached_flows.erase(flow_key); + std::lock_guard guard(attached_flows_mutex); + if (attached_flows.size()<2) + attached_flows.clear(); + else + { + attached_flows.erase(flow_key); + attached_flows[flow_key] = nullptr; + } + free_one_flow_map(flow_key); return (0 == attached_flows.size()); } + void free_one_flow_map(uint32_t flow_key) + { + std::lock_guard guard(mid_mutex); + auto it = mid_map.find(flow_key); + if (it != mid_map.end()) + { + delete it->second; + mid_map.erase(it); + } + } + + void free_map() + { + std::lock_guard guard(mid_mutex); + std::vector mid_ptrs; + auto it_map = mid_map.begin(); + while (it_map != mid_map.end()) + { + mid_ptrs.push_back(it_map->second); + it_map = mid_map.erase(it_map); + } + for (msgid_state* it_msg_id : mid_ptrs) + { + delete it_msg_id; + } + } + Smb2SessionKey get_key() { return session_key; } - void clean_file_context_from_flow(uint64_t, uint64_t); - void unlink(); Dce2Smb2SessionData* get_flow(uint32_t); void process(const uint16_t, uint8_t, const Smb2Hdr*, const uint8_t*, const uint32_t); void increase_size(const size_t size); @@ -82,14 +134,21 @@ public: void set_prev_comand(uint16_t cmd) { command_prev = cmd; } uint16_t get_prev_command() { return command_prev; } std::mutex co_tracker_mutex; - void set_encryption_flag(bool flag) - { - encryption_flag = flag; - if (flag) - dce2_smb_stats.total_encrypted_sessions++; + void set_encryption_flag(bool flag) + { + encryption_flag = flag; + if (flag) + dce2_smb_stats.total_encrypted_sessions++; } + bool get_encryption_flag() { return encryption_flag; } Dce2Smb2TreeTrackerPtr find_tree_for_tree_id(const uint32_t); + uint32_t fill_map(const uint64_t msg_id, const uint8_t command_type, const uint32_t + current_flow_key); + std::recursive_mutex attached_flows_mutex; + uint16_t vlan_id = 0; + Dce2Smb2SessionDataMap attached_flows; + private: // do_not_delete is to make sure when we are in processing we should not delete the context // which is being processed @@ -100,15 +159,16 @@ private: //to keep the tab of previous command uint16_t command_prev; Smb2SessionKey session_key; - Dce2Smb2SessionDataMap attached_flows; Dce2Smb2TreeTrackerMap connected_trees; std::atomic reload_prune; std::atomic encryption_flag; std::mutex connected_trees_mutex; - std::mutex attached_flows_mutex; - // fcfs_mutex is to make sure the mutex is taken at first come first basis if code + + // fcfs_mutex is to make sure the mutex is taken at first come first basis if code // is being hit by two different paths std::mutex fcfs_mutex; + std::mutex mid_mutex; + std::unordered_map > mid_map; }; #endif diff --git a/src/service_inspectors/dce_rpc/dce_smb2_session_cache.h b/src/service_inspectors/dce_rpc/dce_smb2_session_cache.h index fca5d3159..61267cf56 100644 --- a/src/service_inspectors/dce_rpc/dce_smb2_session_cache.h +++ b/src/service_inspectors/dce_rpc/dce_smb2_session_cache.h @@ -26,11 +26,10 @@ #include "hash/lru_cache_shared.h" #include "dce_smb2_session.h" - #define SMB_AVG_FILES_PER_SESSION 5 template, - typename Purgatory = std::vector > > +typename Purgatory = std::vector > > class Dce2Smb2SharedCache : public LruCacheShared { public: @@ -48,20 +47,22 @@ public: return session; } - Data find_session(Key key, Dce2Smb2SessionData* ssd) + Data find_session(Key key) { Data session = this->find(key); - if (session) - session->attach_flow(ssd->get_flow_key(), ssd); return session; } Data find_else_create_session(Key& key, Dce2Smb2SessionData* ssd) { Data new_session = Data(new Value(key)); - Data session = this->find_else_insert(key, new_session, nullptr); - session->attach_flow(ssd->get_flow_key(), ssd); - return session; + Data session = this->find_else_insert(key, new_session, nullptr,false); + if (new_session == session) + { + session->attach_flow(ssd->get_flow_key(), ssd); + return session; + } + return nullptr; } size_t mem_size() override @@ -131,14 +132,12 @@ private: { assert(current_size >= sizeof(*value_ptr) ); current_size -= sizeof(*value_ptr); - //This is going down, remove references from flow here - value_ptr->unlink(); } } }; using Dce2Smb2SessionCache = - Dce2Smb2SharedCache; + Dce2Smb2SharedCache; extern Dce2Smb2SessionCache smb2_session_cache; diff --git a/src/service_inspectors/dce_rpc/dce_smb2_tree.cc b/src/service_inspectors/dce_rpc/dce_smb2_tree.cc index 4d5c45160..ee8465025 100644 --- a/src/service_inspectors/dce_rpc/dce_smb2_tree.cc +++ b/src/service_inspectors/dce_rpc/dce_smb2_tree.cc @@ -85,14 +85,12 @@ void Dce2Smb2TreeTracker::close_all_files() auto it_file = opened_files.begin(); while (it_file != opened_files.end()) { - get_parent()->clean_file_context_from_flow(it_file->second->get_file_id(), - it_file->second->get_file_name_hash()); it_file = opened_files.erase(it_file); } tree_tracker_mutex.unlock(); } -Dce2Smb2RequestTracker* Dce2Smb2TreeTracker::find_request(const uint64_t message_id, +Dce2Smb2RequestTrackerPtr Dce2Smb2TreeTracker::find_request(const uint64_t message_id, const uint32_t current_flow_key) { Smb2MessageKey message_key = { message_id, current_flow_key, 0 }; @@ -109,7 +107,6 @@ bool Dce2Smb2TreeTracker::remove_request(const uint64_t message_id, auto request_it = active_requests.find(message_key); if (request_it != active_requests.end()) { - delete request_it->second; return active_requests.erase(message_key); } return false; @@ -133,7 +130,7 @@ void Dce2Smb2TreeTracker::process_set_info_request(const Smb2Hdr* smb_header) else { dce2_smb_stats.v2_stinf_req_ftrkr_misng++; - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, GET_CURRENT_PACKET, "%s_REQ: ftracker missing\n", smb2_command_string[SMB2_COM_SET_INFO]); } @@ -141,7 +138,7 @@ void Dce2Smb2TreeTracker::process_set_info_request(const Smb2Hdr* smb_header) } else { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, GET_CURRENT_PACKET, "%s_REQ: header error\n", smb2_command_string[SMB2_COM_SET_INFO]); dce2_smb_stats.v2_stinf_req_hdr_err++; @@ -153,15 +150,16 @@ void Dce2Smb2TreeTracker::process_close_request(const Smb2Hdr* smb_header, { const uint8_t* smb_data = (const uint8_t*)smb_header + SMB2_HEADER_LENGTH; uint64_t file_id = alignedNtohq(&(((const Smb2CloseRequestHdr*) - smb_data)->fileId_persistent)); + smb_data) + ->fileId_persistent)); do_not_delete_tree = true; Dce2Smb2FileTrackerPtr file_tracker = find_file(file_id); if (!file_tracker) { dce2_smb_stats.v2_cls_req_ftrkr_misng++; - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, - GET_CURRENT_PACKET, "%s_REQ: ftracker missing %" PRIu64 "\n", + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + GET_CURRENT_PACKET, "%s_REQ: ftracker missing %" PRIu64 "\n", smb2_command_string[SMB2_COM_CLOSE], file_id); do_not_delete_tree = false; return; @@ -194,18 +192,18 @@ uint64_t Dce2Smb2TreeTracker::get_durable_file_id( uint32_t data_length = alignedNtohl(&context->data_length); /* Check for general error condition */ - if (((next & 0x7) != 0) or (next > remaining) or (name_offset != 16) or - (name_length != 4) or (name_offset + name_length > remaining) or - ((data_offset & 0x7) != 0) or - (data_offset and (data_offset < name_offset + name_length)) or - (data_offset > remaining) or (data_offset + data_length > remaining)) + if (((next & 0x7) != 0)or (next > remaining) or (name_offset != 16) or + (name_length != 4) or (name_offset + name_length > remaining) or + ((data_offset & 0x7) != 0) or + (data_offset and (data_offset < name_offset + name_length)) or + (data_offset > remaining) or (data_offset + data_length > remaining)) { return 0; } if ((strncmp((const char*)context+name_offset, - SMB2_CREATE_DURABLE_RECONNECT_V2, name_length) == 0) or - (strncmp((const char*)context+name_offset, + SMB2_CREATE_DURABLE_RECONNECT_V2, name_length) == 0)or + (strncmp((const char*)context+name_offset, SMB2_CREATE_DURABLE_RECONNECT, name_length) == 0)) { return alignedNtohq((const uint64_t*)(((const uint8_t*)context) + @@ -232,15 +230,15 @@ void Dce2Smb2TreeTracker::process_create_response(const uint64_t message_id, file_size = alignedNtohq((const uint64_t*)(&(create_res_hdr->end_of_file))); if (create_res_hdr->file_attributes & SMB2_CREATE_RESPONSE_DIRECTORY) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, GET_CURRENT_PACKET, "%s_RESP: not processing for directory\n", - smb2_command_string[SMB2_COM_CREATE]); + smb2_command_string[SMB2_COM_CREATE]); close_file(file_id, true); } else { do_not_delete_tree = true; - Dce2Smb2RequestTracker* create_request = find_request(message_id, current_flow_key); + Dce2Smb2RequestTrackerPtr create_request = find_request(message_id, current_flow_key); if (create_request) { Dce2Smb2FileTrackerPtr file_tracker = find_file(file_id); @@ -255,7 +253,8 @@ void Dce2Smb2TreeTracker::process_create_response(const uint64_t message_id, } else { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, GET_CURRENT_PACKET, "%s_RESP: req tracker missing\n", + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + GET_CURRENT_PACKET, "%s_RESP: req tracker missing\n", smb2_command_string[SMB2_COM_CREATE]); dce2_smb_stats.v2_crt_rtrkr_misng++; } @@ -270,9 +269,9 @@ void Dce2Smb2TreeTracker::process_create_request(const uint64_t message_id, const Smb2CreateRequestHdr* create_req_hdr = (const Smb2CreateRequestHdr*)smb_data; if (alignedNtohs(&(create_req_hdr->name_offset)) <= SMB2_HEADER_LENGTH) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, GET_CURRENT_PACKET, "%s_REQ: name_offset %" PRIu16 "\n", - smb2_command_string[SMB2_COM_CREATE], create_req_hdr->name_offset); + smb2_command_string[SMB2_COM_CREATE], create_req_hdr->name_offset); dce2_smb_stats.v2_crt_req_hdr_err++; return; } @@ -280,7 +279,7 @@ void Dce2Smb2TreeTracker::process_create_request(const uint64_t message_id, create_req_hdr->name_offset; uint16_t file_name_size = alignedNtohs(&(create_req_hdr->name_length)); if (!file_name_size or (file_name_offset >= end) or - (file_name_offset + file_name_size > end)) + (file_name_offset + file_name_size > end)) { SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, GET_CURRENT_PACKET, "%s_REQ: invalid file name data seen with size %" PRIu16 "\n", @@ -292,12 +291,12 @@ void Dce2Smb2TreeTracker::process_create_request(const uint64_t message_id, uint16_t name_len = 0; char* file_name = get_smb_file_name(file_name_offset, file_name_size, true, &name_len); //keep a request tracker with the available info - Dce2Smb2RequestTracker* create_request = new Dce2Smb2RequestTracker(file_name, name_len); + Dce2Smb2RequestTrackerPtr create_request = std::make_shared(file_name, + name_len); if (!store_request(message_id, current_flow_key, create_request)) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_CRITICAL_LEVEL, + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_CRITICAL_LEVEL, GET_CURRENT_PACKET, "SMB2_COM_CREATE_REQ: store failed\n"); - delete create_request; } //check if file_id is available form a durable reconnect request. //if present we can create a file tracker right now. @@ -328,22 +327,28 @@ void Dce2Smb2TreeTracker::process_read_response(const uint64_t message_id, const Smb2ReadResponseHdr* read_resp_hdr = (const Smb2ReadResponseHdr*)smb_data; uint16_t data_offset = alignedNtohs((const uint16_t*)(&(read_resp_hdr->data_offset))); - Dce2Smb2SessionData* current_flow = parent_session->get_flow(current_flow_key); + Packet* p = DetectionEngine::get_current_packet(); + Flow* flow = p->flow; + Dce2SmbFlowData* current_flow_data = (Dce2SmbFlowData*)(flow->get_flow_data( + Dce2SmbFlowData::inspector_id)); + if (!current_flow_data) + return; + Dce2Smb2SessionData* current_flow = + (Dce2Smb2SessionData*)current_flow_data->get_smb_session_data(); if (data_offset + (const uint8_t*)smb_header > end) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, GET_CURRENT_PACKET, "SMB2_COM_READ_RESP: bad offset\n"); - if (current_flow) - dce_alert(GID_DCE2, DCE2_SMB_BAD_OFF, (dce2CommonStats*)&dce2_smb_stats, - *current_flow->get_dce2_session_data()); + dce_alert(GID_DCE2, DCE2_SMB_BAD_OFF, (dce2CommonStats*)&dce2_smb_stats, + *current_flow->get_dce2_session_data()); } do_not_delete_tree = true; - Dce2Smb2RequestTracker* read_request = find_request(message_id, current_flow_key); + Dce2Smb2RequestTrackerPtr read_request = find_request(message_id, current_flow_key); if (!read_request) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, GET_CURRENT_PACKET, "SMB2_COM_READ_RESP: request tracker missing\n"); dce2_smb_stats.v2_read_rtrkr_misng++; do_not_delete_tree = false; @@ -370,8 +375,8 @@ void Dce2Smb2TreeTracker::process_read_response(const uint64_t message_id, } else { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, - GET_CURRENT_PACKET, "SMB2_COM_READ_RESP: file tracker missing\n"); + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + GET_CURRENT_PACKET, "SMB2_COM_READ_RESP: file tracker missing\n"); } do_not_delete_tree = false; } @@ -383,16 +388,23 @@ void Dce2Smb2TreeTracker::process_read_request(const uint64_t message_id, const Smb2ReadRequestHdr* read_req_hdr = (const Smb2ReadRequestHdr*)smb_data; uint64_t file_id = alignedNtohq((const uint64_t*)(&(read_req_hdr->fileId_persistent))); uint64_t offset = alignedNtohq((const uint64_t*)(&(read_req_hdr->offset))); - Dce2Smb2RequestTracker* read_request = new Dce2Smb2RequestTracker(file_id, offset); + Dce2Smb2RequestTrackerPtr read_request = std::make_shared(file_id, + offset); if (!store_request(message_id, current_flow_key, read_request)) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_CRITICAL_LEVEL, - GET_CURRENT_PACKET, "SMB2_COM_READ_REQ: store failed\n"); - delete read_request; + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_CRITICAL_LEVEL, + GET_CURRENT_PACKET, "SMB2_COM_READ_REQ: store failed\n"); } do_not_delete_tree = true; Dce2Smb2FileTrackerPtr file_tracker = find_file(file_id); - Dce2Smb2SessionData* current_flow = parent_session->get_flow(current_flow_key); + Packet* p = DetectionEngine::get_current_packet(); + Flow* flow = p->flow; + Dce2SmbFlowData* current_flow_data = (Dce2SmbFlowData*)(flow->get_flow_data( + Dce2SmbFlowData::inspector_id)); + if (!current_flow_data) + return; + Dce2Smb2SessionData* current_flow = + (Dce2Smb2SessionData*)current_flow_data->get_smb_session_data(); if (file_tracker) { SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, @@ -413,9 +425,16 @@ void Dce2Smb2TreeTracker::process_write_request(const uint64_t message_id, const uint8_t* smb_data = (const uint8_t*)smb_header + SMB2_HEADER_LENGTH; const Smb2WriteRequestHdr* write_req_hdr = (const Smb2WriteRequestHdr*)smb_data; uint64_t file_id = alignedNtohq((const uint64_t*)(&(write_req_hdr->fileId_persistent))); - Dce2Smb2SessionData* current_flow = parent_session->get_flow(current_flow_key); + Packet* p = DetectionEngine::get_current_packet(); + Flow* flow = p->flow; + Dce2SmbFlowData* current_flow_data = (Dce2SmbFlowData*)(flow->get_flow_data( + Dce2SmbFlowData::inspector_id)); + if (!current_flow_data) + return; + Dce2Smb2SessionData* current_flow = + (Dce2Smb2SessionData*)current_flow_data->get_smb_session_data(); if ((alignedNtohs((const uint16_t*)(&(write_req_hdr->data_offset))) + - (const uint8_t*)smb_header > end) and current_flow) + (const uint8_t*)smb_header > end)) { SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, GET_CURRENT_PACKET, "SMB2_COM_WRITE_REQ: bad offset\n"); @@ -423,12 +442,11 @@ void Dce2Smb2TreeTracker::process_write_request(const uint64_t message_id, *current_flow->get_dce2_session_data()); } //track this request to clean up opened file in case of error response - Dce2Smb2RequestTracker* write_request = new Dce2Smb2RequestTracker(file_id); + Dce2Smb2RequestTrackerPtr write_request = std::make_shared(file_id); if (!store_request(message_id, current_flow_key, write_request)) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, - GET_CURRENT_PACKET, "SMB2_COM_WRITE_REQ: store failed\n"); - delete write_request; + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + GET_CURRENT_PACKET, "SMB2_COM_WRITE_REQ: store failed\n"); } const uint8_t* file_data = (const uint8_t*)write_req_hdr + SMB2_WRITE_REQUEST_STRUC_SIZE - 1; do_not_delete_tree = true; @@ -452,14 +470,14 @@ void Dce2Smb2TreeTracker::process_write_request(const uint64_t message_id, } else { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, - GET_CURRENT_PACKET,"SMB2_COM_WRITE_REQ: file tracker missing\n"); + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + GET_CURRENT_PACKET,"SMB2_COM_WRITE_REQ: file tracker missing\n"); } do_not_delete_tree = false; } void Dce2Smb2TreeTracker::process_ioctl_command(const uint8_t command_type, - const uint32_t current_flow_key, const Smb2Hdr* smb_header, const uint8_t* end) + const Smb2Hdr* smb_header, const uint8_t* end) { const uint8_t* smb_data = (const uint8_t*)smb_header + SMB2_HEADER_LENGTH; const uint8_t structure_size = (command_type == SMB2_CMD_TYPE_REQUEST) ? @@ -467,7 +485,7 @@ void Dce2Smb2TreeTracker::process_ioctl_command(const uint8_t command_type, if (SMB2_CMD_TYPE_REQUEST == command_type) { const Smb2IoctlRequestHdr* ioctl_req = (const Smb2IoctlRequestHdr*)smb_data; - if ((ioctl_req->ctl_code != FSCTL_PIPE_PEEK) and (ioctl_req->ctl_code != + if ((ioctl_req->ctl_code != FSCTL_PIPE_PEEK)and (ioctl_req->ctl_code != FSCTL_PIPE_WAIT) and (ioctl_req->ctl_code != FSCTL_PIPE_TRANSCEIVE)) { return; @@ -477,7 +495,7 @@ void Dce2Smb2TreeTracker::process_ioctl_command(const uint8_t command_type, if (SMB2_CMD_TYPE_RESPONSE == command_type) { const Smb2IoctlResponseHdr* ioctl_response = (const Smb2IoctlResponseHdr*)smb_data; - if ((ioctl_response->ctl_code != FSCTL_PIPE_PEEK) and (ioctl_response->ctl_code != + if ((ioctl_response->ctl_code != FSCTL_PIPE_PEEK)and (ioctl_response->ctl_code != FSCTL_PIPE_WAIT) and (ioctl_response->ctl_code != FSCTL_PIPE_TRANSCEIVE)) { return; @@ -485,7 +503,7 @@ void Dce2Smb2TreeTracker::process_ioctl_command(const uint8_t command_type, } const uint8_t* file_data = (const uint8_t*)smb_data + structure_size - 1; int data_size = end - file_data; - Dce2Smb2SessionData* current_flow = parent_session->get_flow(current_flow_key); + Packet* p = DetectionEngine::get_current_packet(); if (data_size > UINT16_MAX) { data_size = UINT16_MAX; @@ -493,7 +511,7 @@ void Dce2Smb2TreeTracker::process_ioctl_command(const uint8_t command_type, if (co_tracker) { parent_session->co_tracker_mutex.lock(); - DCE2_CoProcess(current_flow->get_dce2_session_data(), co_tracker, file_data, data_size); + DCE2_CoProcess(get_dce2_session_data(p->flow), co_tracker, file_data, data_size); parent_session->co_tracker_mutex.unlock(); } } @@ -501,15 +519,22 @@ void Dce2Smb2TreeTracker::process_ioctl_command(const uint8_t command_type, void Dce2Smb2TreeTracker::process(uint16_t command, uint8_t command_type, const Smb2Hdr* smb_header, const uint8_t* end, const uint32_t current_flow_key) { - Dce2Smb2SessionData* current_flow = parent_session->get_flow(current_flow_key); tree_tracker_mutex.lock(); size_t pending_requests = active_requests.size(); tree_tracker_mutex.unlock(); + Packet* p = DetectionEngine::get_current_packet(); + Flow* flow = p->flow; + Dce2SmbFlowData* current_flow_data = (Dce2SmbFlowData*)(flow->get_flow_data( + Dce2SmbFlowData::inspector_id)); + if (!current_flow_data) + return; + Dce2Smb2SessionData* current_flow = + (Dce2Smb2SessionData*)current_flow_data->get_smb_session_data(); if (SMB2_CMD_TYPE_REQUEST == command_type and current_flow and pending_requests >= current_flow->get_max_outstanding_requests()) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, - GET_CURRENT_PACKET, "%s_REQ: max req exceeded\n", smb2_command_string[command]); + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + GET_CURRENT_PACKET, "%s_REQ: max req exceeded\n", smb2_command_string[command]); dce_alert(GID_DCE2, DCE2_SMB_MAX_REQS_EXCEEDED, (dce2CommonStats*)&dce2_smb_stats, *current_flow->get_dce2_session_data()); return; @@ -523,15 +548,16 @@ void Dce2Smb2TreeTracker::process(uint16_t command, uint8_t command_type, if (SMB2_CMD_TYPE_ERROR_RESPONSE == command_type) { dce2_smb_stats.v2_crt_err_resp++; - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, - GET_CURRENT_PACKET, "%s_RESP: error\n", smb2_command_string[command]); + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, + GET_CURRENT_PACKET, "%s_RESP: error\n", smb2_command_string[command]); } else if (SMB2_CMD_TYPE_REQUEST == command_type) { if (SMB2_SHARE_TYPE_DISK != share_type) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, - GET_CURRENT_PACKET, "%s_REQ: processed for ipc share\n", smb2_command_string[command]); + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, + GET_CURRENT_PACKET, "%s_REQ: processed for ipc share\n", + smb2_command_string[command]); dce2_smb_stats.v2_crt_req_ipc++; } process_create_request(message_id, current_flow_key, smb_header, end); @@ -549,10 +575,10 @@ void Dce2Smb2TreeTracker::process(uint16_t command, uint8_t command_type, if (SMB2_CMD_TYPE_ERROR_RESPONSE == command_type) { dce2_smb_stats.v2_read_err_resp++; - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, - GET_CURRENT_PACKET, "%s_RESP: error\n", smb2_command_string[command]); + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, + GET_CURRENT_PACKET, "%s_RESP: error\n", smb2_command_string[command]); do_not_delete_tree = true; - Dce2Smb2RequestTracker* request = find_request(message_id, current_flow_key); + Dce2Smb2RequestTrackerPtr request = find_request(message_id, current_flow_key); if (request) close_file(request->get_file_id(), true); do_not_delete_tree = false; @@ -566,10 +592,10 @@ void Dce2Smb2TreeTracker::process(uint16_t command, uint8_t command_type, if (SMB2_CMD_TYPE_ERROR_RESPONSE == command_type) { dce2_smb_stats.v2_wrt_err_resp++; - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, GET_CURRENT_PACKET, "%s_RESP: error\n", smb2_command_string[command]); do_not_delete_tree = true; - Dce2Smb2RequestTracker* request = find_request(message_id, current_flow_key); + Dce2Smb2RequestTrackerPtr request = find_request(message_id, current_flow_key); if (request) close_file(request->get_file_id(), true); do_not_delete_tree = false; @@ -580,12 +606,12 @@ void Dce2Smb2TreeTracker::process(uint16_t command, uint8_t command_type, case SMB2_COM_IOCTL: if (SMB2_CMD_TYPE_ERROR_RESPONSE == command_type) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, GET_CURRENT_PACKET, "%s_RESP: error\n", smb2_command_string[command]); } else if (SMB2_SHARE_TYPE_DISK != share_type) { - process_ioctl_command(command_type, current_flow_key, smb_header, end); + process_ioctl_command(command_type, smb_header, end); } break; } @@ -607,23 +633,12 @@ Dce2Smb2TreeTracker::~Dce2Smb2TreeTracker(void) tree_tracker_mutex.lock(); - if (active_requests.size()) - { - for (auto it_request : active_requests) - { - delete it_request.second; - } - } - for (auto it_file : opened_files) { - get_parent()->clean_file_context_from_flow(it_file.second->get_file_id(), - it_file.second->get_file_name_hash()); it_file.second->get_parent().reset(); parent_session->decrease_size(sizeof(Dce2Smb2FileTracker)); } tree_tracker_mutex.unlock(); - } diff --git a/src/service_inspectors/dce_rpc/dce_smb2_tree.h b/src/service_inspectors/dce_rpc/dce_smb2_tree.h index 0df0b3f4b..cec38f807 100644 --- a/src/service_inspectors/dce_rpc/dce_smb2_tree.h +++ b/src/service_inspectors/dce_rpc/dce_smb2_tree.h @@ -29,6 +29,8 @@ #include "dce_smb2_file.h" #include "dce_smb2_request.h" +using Dce2Smb2RequestTrackerPtr = std::shared_ptr; + uint64_t Smb2Mid(const Smb2Hdr* hdr); class Dce2Smb2SessionTracker; @@ -43,8 +45,8 @@ public: Dce2Smb2TreeTracker(uint32_t tree_id_v, Dce2Smb2SessionTracker* p_session, uint8_t sharetype) : tree_id(tree_id_v), share_type(sharetype), parent_session(p_session) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, - GET_CURRENT_PACKET, "tree tracker %" PRIu32 " created\n", tree_id); + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, + GET_CURRENT_PACKET, "tree tracker %" PRIu32 " created\n", tree_id); if (share_type != SMB2_SHARE_TYPE_DISK) { co_tracker = (DCE2_CoTracker*)snort_calloc(sizeof(DCE2_CoTracker)); @@ -62,7 +64,7 @@ public: void close_file(uint64_t, bool); void close_all_files(); Dce2Smb2FileTrackerPtr find_file(uint64_t); - Dce2Smb2RequestTracker* find_request(const uint64_t, const uint32_t); + Dce2Smb2RequestTrackerPtr find_request(const uint64_t, const uint32_t); void process(uint16_t, uint8_t, const Smb2Hdr*, const uint8_t*, const uint32_t); Dce2Smb2SessionTracker* get_parent() { return parent_session; } DCE2_CoTracker* get_cotracker() { return co_tracker; } @@ -81,9 +83,9 @@ private: void process_write_request(const uint64_t, const uint32_t, const Smb2Hdr*, const uint8_t*); uint64_t get_durable_file_id(const Smb2CreateRequestHdr*, const uint8_t*); bool remove_request(const uint64_t, const uint32_t); - void process_ioctl_command(const uint8_t, const uint32_t, const Smb2Hdr*, const uint8_t*); + void process_ioctl_command(const uint8_t, const Smb2Hdr*, const uint8_t*); bool store_request(const uint64_t message_id, const uint32_t current_flow_key, - Dce2Smb2RequestTracker* request) + Dce2Smb2RequestTrackerPtr request) { Smb2MessageKey message_key = { message_id, current_flow_key, 0 }; std::lock_guard guard(tree_tracker_mutex); @@ -101,7 +103,7 @@ private: using Dce2Smb2TreeTrackerPtr = std::shared_ptr; using Dce2Smb2TreeTrackerMap = - std::unordered_map >; + std::unordered_map >; #endif diff --git a/src/service_inspectors/dce_rpc/dce_smb_common.cc b/src/service_inspectors/dce_rpc/dce_smb_common.cc index 59023c1ff..3b9d08272 100644 --- a/src/service_inspectors/dce_rpc/dce_smb_common.cc +++ b/src/service_inspectors/dce_rpc/dce_smb_common.cc @@ -161,12 +161,23 @@ DCE2_SsnData* get_dce2_session_data(snort::Flow* flow) inline FileContext* get_smb_file_context(const Packet* p) { FileFlows* file_flows = FileFlows::get_file_flows(p->flow); - return file_flows ? file_flows->get_current_file_context() : nullptr; + if (file_flows) + { + std::lock_guard guard(file_flows->file_flow_context_mutex); + return file_flows->get_current_file_context(); + } + else + return nullptr; } FileContext* get_smb_file_context(Flow* flow, uint64_t file_id, uint64_t multi_file_processing_id, bool to_create) { + if (!flow) + { + dce2_smb_stats.v2_inv_file_ctx_err++; + return nullptr; + } FileFlows* file_flows = FileFlows::get_file_flows(flow); if ( !file_flows ) @@ -175,6 +186,7 @@ FileContext* get_smb_file_context(Flow* flow, uint64_t file_id, return nullptr; } + std::lock_guard guard(file_flows->file_flow_context_mutex); return file_flows->get_file_context(file_id, to_create, multi_file_processing_id); } diff --git a/src/service_inspectors/dce_rpc/dce_smb_common.h b/src/service_inspectors/dce_rpc/dce_smb_common.h index 1d579318d..f171ca001 100644 --- a/src/service_inspectors/dce_rpc/dce_smb_common.h +++ b/src/service_inspectors/dce_rpc/dce_smb_common.h @@ -205,6 +205,7 @@ struct dce2SmbStats PegCount total_smb2_sessions; PegCount total_encrypted_sessions; PegCount total_mc_sessions; + PegCount ignore_dup_sessions; }; enum DCE2_SmbVersion diff --git a/src/service_inspectors/dce_rpc/dce_smb_module.cc b/src/service_inspectors/dce_rpc/dce_smb_module.cc index 54801f26a..c96770d66 100644 --- a/src/service_inspectors/dce_rpc/dce_smb_module.cc +++ b/src/service_inspectors/dce_rpc/dce_smb_module.cc @@ -194,6 +194,7 @@ static const PegInfo dce2_smb_pegs[] = { CountType::SUM, "total_smb2_sessions", "total smb2 sessions" }, { CountType::SUM, "total_encrypted_sessions", "total encrypted sessions" }, { CountType::SUM, "total_mc_sessions", "total multichannel sessions" }, + { CountType::SUM, "ignore_dup_sessions", "total smb req/resp dropped because of dup msg id" }, { CountType::END, nullptr, nullptr } }; diff --git a/src/service_inspectors/dce_rpc/dce_smb_utils.cc b/src/service_inspectors/dce_rpc/dce_smb_utils.cc index 81c36bc6e..047f73098 100644 --- a/src/service_inspectors/dce_rpc/dce_smb_utils.cc +++ b/src/service_inspectors/dce_rpc/dce_smb_utils.cc @@ -1303,7 +1303,9 @@ static FileContext* DCE2_get_main_file_context() { FileFlows* file_flows = FileFlows::get_file_flows(DetectionEngine::get_current_packet()->flow); if (file_flows) + { return file_flows->get_current_file_context(); + } else return nullptr; } @@ -1420,6 +1422,10 @@ static void DCE2_SmbFinishFileAPI(DCE2_SmbSsnData* ssd) return; FileFlows* file_flows = FileFlows::get_file_flows(p->flow); + if (!file_flows) + { + return; + } bool upload = (ftracker->ff_file_direction == DCE2_SMB_FILE_DIRECTION__UPLOAD); if (get_file_processed_size(p->flow) != 0) @@ -1429,8 +1435,11 @@ static void DCE2_SmbFinishFileAPI(DCE2_SmbSsnData* ssd) if ((ftracker->ff_file_size == 0) && (ftracker->ff_bytes_processed != 0)) { - if (file_flows->file_process(p, nullptr, 0, SNORT_FILE_END, upload, - ftracker->file_name_hash)) + file_flows->file_flow_context_mutex.lock(); + bool resault = file_flows->file_process(p, nullptr, 0, SNORT_FILE_END, upload, + ftracker->file_name_hash); + file_flows->file_flow_context_mutex.unlock(); + if (resault) { if (upload) { @@ -1502,6 +1511,7 @@ static DCE2_Ret DCE2_SmbFileAPIProcess(DCE2_SmbSsnData* ssd, if (!file_flows) return DCE2_RET__ERROR; + std::lock_guard guard(file_flows->file_flow_context_mutex); if (!file_flows->file_process(p, data_ptr, (int)data_len, position, upload, ftracker->file_name_hash)) { @@ -1720,8 +1730,7 @@ void DCE2_SmbProcessFileData(DCE2_SmbSsnData* ssd, ((ftracker->ff_file_offset == ftracker->ff_bytes_processed) && ((file_data_depth == 0) || (ftracker->ff_bytes_processed < (uint64_t)file_data_depth)))) { - set_file_data(data_ptr, (data_len > UINT16_MAX) ? UINT16_MAX : (uint16_t)data_len, - ftracker->file_key.file_id); + set_file_data(data_ptr, (data_len > UINT16_MAX) ? UINT16_MAX : (uint16_t)data_len); DCE2_FileDetect(); set_file_data(nullptr, 0); }