From: Bhargava Jandhyala (bjandhya) Date: Thu, 24 Mar 2022 06:03:43 +0000 (+0000) Subject: Pull request #3315: dce_rpc: Handling cleanup path and race conditions for dce traffic X-Git-Tag: 3.1.27.0~16 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=77f1cab5264aebb376dbe4db29899575b380b301;p=thirdparty%2Fsnort3.git Pull request #3315: dce_rpc: Handling cleanup path and race conditions for dce traffic Merge in SNORT/snort3 from ~BSACHDEV/snort3:smb_ss_crash_master to master Squashed commit of the following: commit eecf1f19ed1f5f61306fa35a1cbb576bb9666d46 Author: bsachdev Date: Mon Mar 7 04:14:37 2022 -0500 dce_rpc: Handling cleanup path and race conditions for dce traffic Signed-off-by: bsachdev --- diff --git a/src/service_inspectors/dce_rpc/dce_smb2.cc b/src/service_inspectors/dce_rpc/dce_smb2.cc index 8a485b690..92352d916 100644 --- a/src/service_inspectors/dce_rpc/dce_smb2.cc +++ b/src/service_inspectors/dce_rpc/dce_smb2.cc @@ -109,22 +109,36 @@ Dce2Smb2SessionData::Dce2Smb2SessionData(const Packet* p, dce2_smb_stats.total_smb2_sessions++; } -Dce2Smb2SessionData::~Dce2Smb2SessionData() +Dce2Smb2SessionData::~Dce2Smb2SessionData(void) { session_data_mutex.lock(); for (auto it_session : connected_sessions) { it_session.second->detach_flow(flow_key); } + + 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(); } void Dce2Smb2SessionData::reset_matching_tcp_file_tracker( - Dce2Smb2FileTracker* file_tracker) + Dce2Smb2FileTrackerPtr file_tracker) { std::lock_guard guard(tcp_file_tracker_mutex); if (tcp_file_tracker == file_tracker) - tcp_file_tracker = nullptr; + { + 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; + } + else + return; + } } Smb2SessionKey Dce2Smb2SessionData::get_session_key(uint64_t session_id) @@ -187,7 +201,7 @@ void Dce2Smb2SessionData::process_command(const Smb2Hdr* smb_hdr, uint16_t structure_size = alignedNtohs((const uint16_t*)smb_data); uint16_t command = alignedNtohs(&(smb_hdr->command)); uint64_t session_id = Smb2Sid(smb_hdr); - Dce2Smb2SessionTrackerPtr session = find_session(session_id); + Dce2Smb2SessionTrackerPtr session; // Macro and shorthand to save some repetitive code // Should only be used in this function @@ -239,7 +253,7 @@ void Dce2Smb2SessionData::process_command(const Smb2Hdr* smb_hdr, SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL \ , 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); \ @@ -253,9 +267,10 @@ 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 - if (command == SMB2_COM_CLOSE and (session and session->get_prev_command() != SMB2_COM_MAX)) + session = find_session(session_id); + if ((command == SMB2_COM_CLOSE or command == + SMB2_COM_TREE_DISCONNECT) and (session and session->get_prev_command() != SMB2_COM_MAX)) { - session->set_do_not_delete(false); return; } @@ -522,7 +537,7 @@ void Dce2Smb2SessionData::process() { SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, p, "Encrypted header is received \n"); - Dce2Smb2SessionTrackerPtr session = find_session(sid); + session = find_session(sid); if (session) { bool flag = session->get_encryption_flag(); @@ -579,18 +594,29 @@ void Dce2Smb2SessionData::process() { if ( tcp_file_tracker ) { - session = find_session(tcp_file_tracker->get_session_id()); - if (session) - session->set_do_not_delete(true); + session = find_session (tcp_file_tracker->get_session_id()); + if (session) + session->set_do_not_delete(true); } + else + return; tcp_file_tracker_mutex.lock(); - if ( tcp_file_tracker and tcp_file_tracker->accepting_raw_data_from(flow_key)) + 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", tcp_file_tracker->get_file_id()); - tcp_file_tracker->process_data(flow_key, data_ptr, data_len); + tcp_file_tracker->process_data(flow_key, data_ptr, data_len, session); tcp_file_tracker->stop_accepting_raw_data_from(flow_key); } + else if (tcp_file_tracker and tcp_file_tracker.use_count() == 1) + { + 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; + } + } else { SMB_DEBUG(dce_smb_trace,DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, p, "not processing raw data\n"); diff --git a/src/service_inspectors/dce_rpc/dce_smb2.h b/src/service_inspectors/dce_rpc/dce_smb2.h index 44c52d034..beaf91ceb 100644 --- a/src/service_inspectors/dce_rpc/dce_smb2.h +++ b/src/service_inspectors/dce_rpc/dce_smb2.h @@ -299,6 +299,10 @@ using Dce2Smb2SessionTrackerPtr = std::shared_ptr; using Dce2Smb2SessionTrackerMap = std::unordered_map >; +using Dce2Smb2FileTrackerPtr = std::shared_ptr; +using Dce2Smb2FileTrackerMap = + std::unordered_map >; + PADDING_GUARD_BEGIN struct Smb2SessionKey { @@ -447,23 +451,29 @@ public: void process() override; void remove_session(uint64_t, bool = false); void handle_retransmit(FilePosition, FileVerdict) override { } - void reset_matching_tcp_file_tracker(Dce2Smb2FileTracker*); + 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(Dce2Smb2FileTracker* file_tracker) + void set_tcp_file_tracker(Dce2Smb2FileTrackerPtr file_tracker) { std::lock_guard guard(session_data_mutex); tcp_file_tracker = file_tracker; } + Dce2Smb2FileTrackerPtr get_tcp_file_tracker() + { + return tcp_file_tracker; + } + + Dce2Smb2SessionTrackerPtr find_session(uint64_t); + private: void process_command(const Smb2Hdr*, const uint8_t*); Smb2SessionKey get_session_key(uint64_t); Dce2Smb2SessionTrackerPtr create_session(uint64_t); - Dce2Smb2SessionTrackerPtr find_session(uint64_t); + Dce2Smb2FileTrackerPtr tcp_file_tracker; uint32_t flow_key; - Dce2Smb2FileTracker* tcp_file_tracker; Dce2Smb2SessionTrackerMap connected_sessions; std::mutex session_data_mutex; std::mutex tcp_file_tracker_mutex; diff --git a/src/service_inspectors/dce_rpc/dce_smb2_file.cc b/src/service_inspectors/dce_rpc/dce_smb2_file.cc index 4e5da6d39..b994613ed 100644 --- a/src/service_inspectors/dce_rpc/dce_smb2_file.cc +++ b/src/service_inspectors/dce_rpc/dce_smb2_file.cc @@ -28,14 +28,16 @@ #include "hash/hash_key_operations.h" #include "dce_co.h" +#include "dce_smb2.h" #include "dce_smb2_session.h" #include "dce_smb2_tree.h" +#include using namespace snort; #define UNKNOWN_FILE_SIZE (~0) -void Dce2Smb2FileTracker::accept_raw_data_from(Dce2Smb2SessionData* flow, uint64_t offset) +void Dce2Smb2FileTracker::accept_raw_data_from(Dce2Smb2SessionData* flow, uint64_t offset, Dce2Smb2FileTrackerPtr file_tracker) { if (flow) { @@ -49,7 +51,7 @@ void Dce2Smb2FileTracker::accept_raw_data_from(Dce2Smb2SessionData* flow, uint64 } current_flow_state.pdu_state = DCE2_SMB_PDU_STATE__RAW_DATA; - flow->set_tcp_file_tracker(this); + flow->set_tcp_file_tracker(file_tracker); } } void Dce2Smb2FileTracker::stop_accepting_raw_data_from(uint32_t current_flow_key) @@ -67,11 +69,16 @@ inline void Dce2Smb2FileTracker::file_detect() } std::pair Dce2Smb2FileTracker::update_processing_flow( - Dce2Smb2SessionData* current_flow) + Dce2Smb2SessionData* current_flow,Dce2Smb2SessionTrackerPtr session_tracker) { std::lock_guard guard(process_file_mutex); bool switched = false; - Dce2Smb2SessionData* processing_flow = parent_tree->get_parent()->get_flow(file_flow_key); + 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); + if (!processing_flow) { switched = true; @@ -131,7 +138,9 @@ bool Dce2Smb2FileTracker::close(const uint32_t current_flow_key) FileContext* file = get_smb_file_context(flow, file_name_hash, file_id, false); if (file) file->set_file_size(file_size); - return (!process_data(current_flow_key, nullptr, 0)); + + Dce2Smb2SessionTrackerPtr ses_ptr = processing_flow->find_session(session_id); + return (!process_data(current_flow_key, nullptr, 0,ses_ptr)); } return true; } @@ -144,26 +153,61 @@ 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(); - return process_data(current_flow_key, file_data, data_size); -} - -bool Dce2Smb2FileTracker::process_data(const uint32_t current_flow_key, const uint8_t* file_data, - uint32_t data_size) -{ - Dce2Smb2SessionData* current_flow = parent_tree->get_parent()->get_flow(current_flow_key); - if (!current_flow) - return true; - + Dce2Smb2SessionTracker *sess = parent_tree->get_parent(); 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 + { + return false; + } + if (data_size > UINT16_MAX) { data_size = UINT16_MAX; } - DCE2_CoProcess(current_flow->get_dce2_session_data(), parent_tree->get_cotracker(), - file_data, data_size); + 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); 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); +} + +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; + } int64_t file_detection_depth = current_flow->get_smb_file_depth(); int64_t detection_size = 0; @@ -193,6 +237,7 @@ 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; } @@ -203,7 +248,7 @@ bool Dce2Smb2FileTracker::process_data(const uint32_t current_flow_key, const ui &dce2_smb_stats, *(current_flow->get_dce2_session_data())); } - auto updated_flow = update_processing_flow(current_flow); + 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 %" @@ -214,6 +259,7 @@ bool Dce2Smb2FileTracker::process_data(const uint32_t current_flow_key, const ui 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); return true; } @@ -232,6 +278,7 @@ bool Dce2Smb2FileTracker::process_data(const uint32_t current_flow_key, const ui 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; } @@ -239,20 +286,16 @@ 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); return true; } -Dce2Smb2FileTracker::~Dce2Smb2FileTracker() +Dce2Smb2FileTracker::~Dce2Smb2FileTracker(void) { - if (smb_module_is_up and (is_packet_thread())) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, GET_CURRENT_PACKET, "file tracker %" PRIu64 - " file name hash %" PRIu64 " terminating\n", file_id, file_name_hash); - } - if (file_name) snort_free((void*)file_name); - parent_tree->get_parent()->clean_file_context_from_flow(this, file_id, file_name_hash); + file_name = nullptr; + parent_tree = nullptr; } diff --git a/src/service_inspectors/dce_rpc/dce_smb2_file.h b/src/service_inspectors/dce_rpc/dce_smb2_file.h index 8d3abfe63..4aed699bf 100644 --- a/src/service_inspectors/dce_rpc/dce_smb2_file.h +++ b/src/service_inspectors/dce_rpc/dce_smb2_file.h @@ -24,6 +24,7 @@ // This provides file tracker for SMBv2 #include "dce_smb2.h" +#include class Dce2Smb2TreeTracker; @@ -54,10 +55,10 @@ public: ~Dce2Smb2FileTracker(); bool process_data(const uint32_t, const uint8_t*, uint32_t, const uint64_t, uint64_t); - bool process_data(const uint32_t, const uint8_t*, uint32_t); + bool process_data(const uint32_t, const uint8_t*, uint32_t, Dce2Smb2SessionTrackerPtr); bool close(const uint32_t); void set_info(char*, uint16_t, uint64_t); - void accept_raw_data_from(Dce2Smb2SessionData*, uint64_t = 0); + void accept_raw_data_from(Dce2Smb2SessionData*, uint64_t, Dce2Smb2FileTrackerPtr); bool accepting_raw_data_from(uint32_t current_flow_key) { std::lock_guard guard(flow_state_mutex); @@ -67,12 +68,19 @@ public: void set_direction(FileDirection dir) { direction = dir; } Dce2Smb2TreeTracker* get_parent() { return parent_tree; } + void set_parent(Dce2Smb2TreeTracker* pt) { parent_tree = pt; } uint64_t get_file_id() { return file_id; } + uint64_t get_file_name_hash() { return file_name_hash; } uint64_t get_session_id() { return session_id; } + std::unordered_map > get_flow_state_map() + { + return flow_state; + } private: void file_detect(); - std::pair update_processing_flow(Dce2Smb2SessionData* = nullptr); + std::pair update_processing_flow(Dce2Smb2SessionData* = nullptr, + Dce2Smb2SessionTrackerPtr session_tracker = nullptr); bool ignore; uint16_t file_name_len; uint32_t file_flow_key; @@ -88,8 +96,9 @@ private: std::mutex flow_state_mutex; }; -using Dce2Smb2FileTrackerMap = - std::unordered_map >; +using Dce2Smb2FileTrackerPtr = std::shared_ptr; +using Dce2Smb2FileTrackerMap = + 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 7c064a12d..1ea75309f 100644 --- a/src/service_inspectors/dce_rpc/dce_smb2_request.h +++ b/src/service_inspectors/dce_rpc/dce_smb2_request.h @@ -48,10 +48,6 @@ public: ~Dce2Smb2RequestTracker() { - if (smb_module_is_up and (snort::is_packet_thread())) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, GET_CURRENT_PACKET, "request tracker terminating\n"); - } if (fname) snort_free(fname); } diff --git a/src/service_inspectors/dce_rpc/dce_smb2_session.cc b/src/service_inspectors/dce_rpc/dce_smb2_session.cc index cf975e53a..a2665b267 100644 --- a/src/service_inspectors/dce_rpc/dce_smb2_session.cc +++ b/src/service_inspectors/dce_rpc/dce_smb2_session.cc @@ -83,16 +83,11 @@ void Dce2Smb2SessionTracker::process(const uint16_t command, uint8_t command_typ } break; case SMB2_COM_TREE_DISCONNECT: - if (tree) - { - delete tree; - connected_trees_mutex.lock(); - connected_trees.erase(tree_id); - connected_trees_mutex.unlock(); - } - else - dce2_smb_stats.v2_tree_discn_ignored++; - break; + { + if (!tree) + dce2_smb_stats.v2_tree_discn_ignored++; + } + break; //for all other cases, tree tracker should handle the command case SMB2_COM_CREATE: @@ -157,9 +152,10 @@ Dce2Smb2TreeTracker* Dce2Smb2SessionTracker::connect_tree(const uint32_t tree_id return tree; } -void Dce2Smb2SessionTracker::clean_file_context_from_flow(Dce2Smb2FileTracker* file_tracker, - uint64_t file_id, uint64_t file_name_hash) +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) { @@ -167,9 +163,9 @@ void Dce2Smb2SessionTracker::clean_file_context_from_flow(Dce2Smb2FileTracker* f it_flow.second->get_tcp_flow(), false); if (file_flows) file_flows->remove_processed_file_context(file_name_hash, file_id); - it_flow.second->reset_matching_tcp_file_tracker(file_tracker); } attached_flows_mutex.unlock(); + set_do_not_delete(false); } void Dce2Smb2SessionTracker::increase_size(const size_t size) @@ -191,7 +187,7 @@ void Dce2Smb2SessionTracker::unlink() } // Session Tracker is created and destroyed only from session cache -Dce2Smb2SessionTracker::~Dce2Smb2SessionTracker() +Dce2Smb2SessionTracker::~Dce2Smb2SessionTracker(void) { if (!(fcfs_mutex.try_lock())) return; @@ -203,12 +199,6 @@ Dce2Smb2SessionTracker::~Dce2Smb2SessionTracker() fcfs_mutex.unlock(); return; } - if (smb_module_is_up and (snort::is_packet_thread())) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, - TRACE_DEBUG_LEVEL, GET_CURRENT_PACKET, - "session tracker %" PRIu64 " terminating\n", session_id); - } std::vector all_trees; connected_trees_mutex.lock(); diff --git a/src/service_inspectors/dce_rpc/dce_smb2_session.h b/src/service_inspectors/dce_rpc/dce_smb2_session.h index 79eb74aca..382347e5e 100644 --- a/src/service_inspectors/dce_rpc/dce_smb2_session.h +++ b/src/service_inspectors/dce_rpc/dce_smb2_session.h @@ -67,7 +67,7 @@ public: } Smb2SessionKey get_key() { return session_key; } - void clean_file_context_from_flow(Dce2Smb2FileTracker*, uint64_t, uint64_t); + 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); @@ -79,6 +79,7 @@ public: bool get_do_not_delete() { return do_not_delete; } 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; 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 82a699ef2..fca5d3159 100644 --- a/src/service_inspectors/dce_rpc/dce_smb2_session_cache.h +++ b/src/service_inspectors/dce_rpc/dce_smb2_session_cache.h @@ -95,11 +95,19 @@ public: data.emplace_back(list_iter->second); // increase reference count // This instructs the session_tracker to take a lock before detaching // from ssd, when it is getting destroyed. - list_iter->second->set_reload_prune(true); - decrease_size(list_iter->second.get()); - map.erase(list_iter->first); - list.erase(list_iter); - ++stats.reload_prunes; + if (!list_iter->second->get_do_not_delete()) + { + list_iter->second->set_reload_prune(true); + decrease_size(list_iter->second.get()); + map.erase(list_iter->first); + list.erase(list_iter); + ++stats.reload_prunes; + } + else + { + // Move entry to front of LruList + list.splice(list.begin(), list, list_iter); + } } } diff --git a/src/service_inspectors/dce_rpc/dce_smb2_tree.cc b/src/service_inspectors/dce_rpc/dce_smb2_tree.cc index 4cb109438..154ad4813 100644 --- a/src/service_inspectors/dce_rpc/dce_smb2_tree.cc +++ b/src/service_inspectors/dce_rpc/dce_smb2_tree.cc @@ -25,6 +25,7 @@ #include "dce_smb2_tree.h" #include "dce_smb2_session.h" +#include using namespace snort; @@ -36,11 +37,11 @@ uint64_t Smb2Mid(const Smb2Hdr* hdr) return alignedNtohq(&(hdr->message_id)); } -Dce2Smb2FileTracker* Dce2Smb2TreeTracker::open_file(const uint64_t file_id, +Dce2Smb2FileTrackerPtr Dce2Smb2TreeTracker::open_file(const uint64_t file_id, const uint32_t current_flow_key) { - Dce2Smb2FileTracker* ftracker = new Dce2Smb2FileTracker(file_id, current_flow_key, this, - this->get_parent()->get_session_id()); + std::shared_ptr ftracker = std::make_shared ( + file_id, current_flow_key, this, this->get_parent()->get_session_id()); tree_tracker_mutex.lock(); opened_files.insert(std::make_pair(file_id, ftracker)); tree_tracker_mutex.unlock(); @@ -48,7 +49,7 @@ Dce2Smb2FileTracker* Dce2Smb2TreeTracker::open_file(const uint64_t file_id, return ftracker; } -Dce2Smb2FileTracker* Dce2Smb2TreeTracker::find_file(uint64_t file_id) +Dce2Smb2FileTrackerPtr Dce2Smb2TreeTracker::find_file(uint64_t file_id) { std::lock_guard guard(tree_tracker_mutex); auto it_file = opened_files.find(file_id); @@ -63,12 +64,12 @@ void Dce2Smb2TreeTracker::close_file(uint64_t file_id, bool destroy) auto it_file = opened_files.find(file_id); if (it_file != opened_files.end()) { - Dce2Smb2FileTracker* file = it_file->second; + Dce2Smb2FileTrackerPtr file = it_file->second; + it_file->second->set_parent(nullptr); if (opened_files.erase(file_id) and destroy) { parent_session->decrease_size(sizeof(Dce2Smb2FileTracker)); tree_tracker_mutex.unlock(); - delete file; return; } } @@ -108,7 +109,9 @@ void Dce2Smb2TreeTracker::process_set_info_request(const Smb2Hdr* smb_header) uint64_t file_size = alignedNtohq((const uint64_t*)((const uint8_t*) set_info_hdr + SMB2_SET_INFO_REQUEST_STRUC_SIZE - 1)); uint64_t file_id = alignedNtohq(&(set_info_hdr->fileId_persistent)); - Dce2Smb2FileTracker* file_tracker = find_file(file_id); + + do_not_delete_tree = true; + Dce2Smb2FileTrackerPtr file_tracker = find_file(file_id); if (file_tracker) file_tracker->set_info(nullptr, 0, file_size); else @@ -118,6 +121,7 @@ void Dce2Smb2TreeTracker::process_set_info_request(const Smb2Hdr* smb_header) GET_CURRENT_PACKET, "%s_REQ: ftracker missing\n", smb2_command_string[SMB2_COM_SET_INFO]); } + do_not_delete_tree = false; } else { @@ -134,20 +138,32 @@ 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)); - Dce2Smb2FileTracker* file_tracker = find_file(file_id); + + 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", smb2_command_string[SMB2_COM_CLOSE], file_id); + do_not_delete_tree = false; return; } if (file_tracker->close(current_flow_key)) - close_file(file_id); + close_file(file_id, true); + + do_not_delete_tree = false; if (share_type != SMB2_SHARE_TYPE_DISK) - DCE2_CoCleanTracker(co_tracker); + { + if (co_tracker != nullptr) + { + DCE2_CoCleanTracker(co_tracker); + snort_free((void*)co_tracker); + co_tracker = nullptr; + } + } } uint64_t Dce2Smb2TreeTracker::get_durable_file_id( @@ -208,14 +224,15 @@ void Dce2Smb2TreeTracker::process_create_response(const uint64_t message_id, 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]); - close_file(file_id); + close_file(file_id, true); } else { + do_not_delete_tree = true; Dce2Smb2RequestTracker* create_request = find_request(message_id, current_flow_key); if (create_request) { - Dce2Smb2FileTracker* file_tracker = find_file(file_id); + Dce2Smb2FileTrackerPtr file_tracker = find_file(file_id); if (!file_tracker) file_tracker = open_file(file_id, current_flow_key); @@ -231,6 +248,7 @@ void Dce2Smb2TreeTracker::process_create_response(const uint64_t message_id, smb2_command_string[SMB2_COM_CREATE]); dce2_smb_stats.v2_crt_rtrkr_misng++; } + do_not_delete_tree = false; } } @@ -278,7 +296,8 @@ void Dce2Smb2TreeTracker::process_create_request(const uint64_t message_id, { SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, GET_CURRENT_PACKET, "requested file_id %lu\n", file_id); - Dce2Smb2FileTracker* file_tracker = find_file(file_id); + do_not_delete_tree = true; + Dce2Smb2FileTrackerPtr file_tracker = find_file(file_id); if (!file_tracker) { file_tracker = open_file(file_id, current_flow_key); @@ -287,6 +306,7 @@ void Dce2Smb2TreeTracker::process_create_request(const uint64_t message_id, file_tracker->set_info(file_name, name_len, 0); } } + do_not_delete_tree = false; } } @@ -296,15 +316,6 @@ void Dce2Smb2TreeTracker::process_read_response(const uint64_t message_id, const uint8_t* smb_data = (const uint8_t*)smb_header + SMB2_HEADER_LENGTH; const Smb2ReadResponseHdr* read_resp_hdr = (const Smb2ReadResponseHdr*)smb_data; - Dce2Smb2RequestTracker* read_request = find_request(message_id, current_flow_key); - if (!read_request) - { - 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++; - return; - } - uint16_t data_offset = alignedNtohs((const uint16_t*)(&(read_resp_hdr->data_offset))); Dce2Smb2SessionData* current_flow = parent_session->get_flow(current_flow_key); if (data_offset + (const uint8_t*)smb_header > end) @@ -315,7 +326,20 @@ void Dce2Smb2TreeTracker::process_read_response(const uint64_t message_id, dce_alert(GID_DCE2, DCE2_SMB_BAD_OFF, (dce2CommonStats*)&dce2_smb_stats, *current_flow->get_dce2_session_data()); } - Dce2Smb2FileTracker* file_tracker = find_file(read_request->get_file_id()); + + do_not_delete_tree = true; + + Dce2Smb2RequestTracker* read_request = find_request(message_id, current_flow_key); + if (!read_request) + { + 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; + return; + } + + Dce2Smb2FileTrackerPtr file_tracker = find_file(read_request->get_file_id()); if (file_tracker) { const uint8_t* file_data = (const uint8_t*)read_resp_hdr + @@ -329,7 +353,7 @@ void Dce2Smb2TreeTracker::process_read_response(const uint64_t message_id, { if ((uint32_t)data_size < alignedNtohl((const uint32_t*)&(read_resp_hdr->length))) { - file_tracker->accept_raw_data_from(current_flow); + file_tracker->accept_raw_data_from(current_flow, 0, file_tracker); } } } @@ -338,6 +362,7 @@ void Dce2Smb2TreeTracker::process_read_response(const uint64_t message_id, 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; } void Dce2Smb2TreeTracker::process_read_request(const uint64_t message_id, @@ -354,19 +379,21 @@ void Dce2Smb2TreeTracker::process_read_request(const uint64_t message_id, GET_CURRENT_PACKET, "SMB2_COM_READ_REQ: store failed\n"); delete read_request; } - Dce2Smb2FileTracker* file_tracker = find_file(file_id); + do_not_delete_tree = true; + Dce2Smb2FileTrackerPtr file_tracker = find_file(file_id); Dce2Smb2SessionData* current_flow = parent_session->get_flow(current_flow_key); if (file_tracker) { SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, GET_CURRENT_PACKET, "SMB2_COM_READ_REQ: start accepting Raw Data\n"); - file_tracker->accept_raw_data_from(current_flow,offset); + file_tracker->accept_raw_data_from(current_flow,offset, file_tracker); } else { SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, GET_CURRENT_PACKET, "SMB2_COM_READ_REQ: file tracker missing\n"); } + do_not_delete_tree = false; } void Dce2Smb2TreeTracker::process_write_request(const uint64_t message_id, @@ -393,7 +420,8 @@ void Dce2Smb2TreeTracker::process_write_request(const uint64_t message_id, delete write_request; } const uint8_t* file_data = (const uint8_t*)write_req_hdr + SMB2_WRITE_REQUEST_STRUC_SIZE - 1; - Dce2Smb2FileTracker* file_tracker = find_file(file_id); + do_not_delete_tree = true; + Dce2Smb2FileTrackerPtr file_tracker = find_file(file_id); if (file_tracker) { file_tracker->set_direction(FILE_UPLOAD); @@ -407,7 +435,7 @@ void Dce2Smb2TreeTracker::process_write_request(const uint64_t message_id, { if ((uint32_t)data_size < alignedNtohl((const uint32_t*)&(write_req_hdr->length))) { - file_tracker->accept_raw_data_from(current_flow); + file_tracker->accept_raw_data_from(current_flow, 0, file_tracker); } } } @@ -416,6 +444,7 @@ void Dce2Smb2TreeTracker::process_write_request(const uint64_t message_id, 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, @@ -432,8 +461,12 @@ void Dce2Smb2TreeTracker::process_ioctl_command(const uint8_t command_type, { data_size = UINT16_MAX; } - - DCE2_CoProcess(current_flow->get_dce2_session_data(), co_tracker, file_data, data_size); + if (co_tracker) + { + parent_session->co_tracker_mutex.lock(); + DCE2_CoProcess(current_flow->get_dce2_session_data(), co_tracker, file_data, data_size); + parent_session->co_tracker_mutex.unlock(); + } } void Dce2Smb2TreeTracker::process(uint16_t command, uint8_t command_type, @@ -489,9 +522,11 @@ void Dce2Smb2TreeTracker::process(uint16_t command, uint8_t 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]); + do_not_delete_tree = true; Dce2Smb2RequestTracker* request = find_request(message_id, current_flow_key); if (request) - close_file(request->get_file_id()); + close_file(request->get_file_id(), true); + do_not_delete_tree = false; } else if (SMB2_CMD_TYPE_REQUEST == command_type) process_read_request(message_id, current_flow_key, smb_header); @@ -504,9 +539,11 @@ void Dce2Smb2TreeTracker::process(uint16_t command, uint8_t command_type, dce2_smb_stats.v2_wrt_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]); + do_not_delete_tree = true; Dce2Smb2RequestTracker* request = find_request(message_id, current_flow_key); if (request) - close_file(request->get_file_id()); + close_file(request->get_file_id(), true); + do_not_delete_tree = false; } else if (SMB2_CMD_TYPE_REQUEST == command_type) process_write_request(message_id, current_flow_key, smb_header, end); @@ -527,13 +564,10 @@ void Dce2Smb2TreeTracker::process(uint16_t command, uint8_t command_type, remove_request(message_id, current_flow_key); } -Dce2Smb2TreeTracker::~Dce2Smb2TreeTracker() +Dce2Smb2TreeTracker::~Dce2Smb2TreeTracker(void) { - if (smb_module_is_up and (is_packet_thread())) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, - GET_CURRENT_PACKET, "tree tracker %" PRIu32 " terminating\n", tree_id); - } + if (do_not_delete_tree == true) + return; if (co_tracker != nullptr) { @@ -546,25 +580,17 @@ Dce2Smb2TreeTracker::~Dce2Smb2TreeTracker() if (active_requests.size()) { - if (smb_module_is_up and (is_packet_thread())) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, - GET_CURRENT_PACKET, "cleanup pending requests for below MIDs:\n"); - } for (auto it_request : active_requests) { - if (smb_module_is_up and (is_packet_thread())) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, - GET_CURRENT_PACKET, "mid %" PRIu64 "\n", it_request.first.mid); - } delete it_request.second; } } for (auto it_file : opened_files) { - delete it_file.second; + get_parent()->clean_file_context_from_flow(it_file.second->get_file_id(), + it_file.second->get_file_name_hash()); + it_file.second->set_parent(nullptr); parent_session->decrease_size(sizeof(Dce2Smb2FileTracker)); } diff --git a/src/service_inspectors/dce_rpc/dce_smb2_tree.h b/src/service_inspectors/dce_rpc/dce_smb2_tree.h index f5f7a15a5..d679d6d0a 100644 --- a/src/service_inspectors/dce_rpc/dce_smb2_tree.h +++ b/src/service_inspectors/dce_rpc/dce_smb2_tree.h @@ -58,15 +58,17 @@ public: ~Dce2Smb2TreeTracker(); - Dce2Smb2FileTracker* open_file(const uint64_t, const uint32_t); - void close_file(uint64_t, bool=true); - Dce2Smb2FileTracker* find_file(uint64_t); + Dce2Smb2FileTrackerPtr open_file(const uint64_t, const uint32_t); + void close_file(uint64_t, bool); + Dce2Smb2FileTrackerPtr find_file(uint64_t); Dce2Smb2RequestTracker* 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; } uint32_t get_tree_id() { return tree_id; } uint8_t get_share_type() { return share_type; } + std::atomic do_not_delete_tree { false }; + void set_parent(Dce2Smb2SessionTracker* session_tracker) { parent_session = session_tracker; } private: void process_set_info_request(const Smb2Hdr*); diff --git a/src/service_inspectors/dce_rpc/dce_smb_utils.cc b/src/service_inspectors/dce_rpc/dce_smb_utils.cc index 9c3fe2dab..1052f5e3d 100644 --- a/src/service_inspectors/dce_rpc/dce_smb_utils.cc +++ b/src/service_inspectors/dce_rpc/dce_smb_utils.cc @@ -951,7 +951,8 @@ DCE2_Ret DCE2_SmbProcessRequestData(DCE2_SmbSsnData* ssd, if (data_len > UINT16_MAX) data_len = UINT16_MAX; - DCE2_CoProcess(&ssd->sd, ftracker->fp_co_tracker, data_ptr, (uint16_t)data_len); + if (ftracker->fp_co_tracker) + DCE2_CoProcess(&ssd->sd, ftracker->fp_co_tracker, data_ptr, (uint16_t)data_len); if (!ftracker->fp_used) ftracker->fp_used = true; @@ -978,8 +979,8 @@ DCE2_Ret DCE2_SmbProcessResponseData(DCE2_SmbSsnData* ssd, // Maximum possible fragment length is 16 bit if (data_len > UINT16_MAX) data_len = UINT16_MAX; - - DCE2_CoProcess(&ssd->sd, ftracker->fp_co_tracker, data_ptr, (uint16_t)data_len); + if (ftracker->fp_co_tracker) + DCE2_CoProcess(&ssd->sd, ftracker->fp_co_tracker, data_ptr, (uint16_t)data_len); } else {