]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #3315: dce_rpc: Handling cleanup path and race conditions for dce traffic
authorBhargava Jandhyala (bjandhya) <bjandhya@cisco.com>
Thu, 24 Mar 2022 06:03:43 +0000 (06:03 +0000)
committerBhargava Jandhyala (bjandhya) <bjandhya@cisco.com>
Thu, 24 Mar 2022 06:03:43 +0000 (06:03 +0000)
Merge in SNORT/snort3 from ~BSACHDEV/snort3:smb_ss_crash_master to master

Squashed commit of the following:

commit eecf1f19ed1f5f61306fa35a1cbb576bb9666d46
Author: bsachdev <bsachdev@cisco.com>
Date:   Mon Mar 7 04:14:37 2022 -0500

    dce_rpc: Handling cleanup path and race conditions for dce traffic

Signed-off-by: bsachdev <bsachdev@cisco.com>
src/service_inspectors/dce_rpc/dce_smb2.cc
src/service_inspectors/dce_rpc/dce_smb2.h
src/service_inspectors/dce_rpc/dce_smb2_file.cc
src/service_inspectors/dce_rpc/dce_smb2_file.h
src/service_inspectors/dce_rpc/dce_smb2_request.h
src/service_inspectors/dce_rpc/dce_smb2_session.cc
src/service_inspectors/dce_rpc/dce_smb2_session.h
src/service_inspectors/dce_rpc/dce_smb2_session_cache.h
src/service_inspectors/dce_rpc/dce_smb2_tree.cc
src/service_inspectors/dce_rpc/dce_smb2_tree.h
src/service_inspectors/dce_rpc/dce_smb_utils.cc

index 8a485b690045b15deea159e2f6e4cdb2a30a0c42..92352d916811f014bcb2d43981fbc97867cad84c 100644 (file)
@@ -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<std::mutex> 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");
index 44c52d0344484b96340aa8718200625cee52a0d6..beaf91ceb3d715e8b9df4401d42e701389b1ff2c 100644 (file)
@@ -299,6 +299,10 @@ using Dce2Smb2SessionTrackerPtr = std::shared_ptr<Dce2Smb2SessionTracker>;
 using Dce2Smb2SessionTrackerMap =
     std::unordered_map<uint64_t, Dce2Smb2SessionTrackerPtr, std::hash<uint64_t> >;
 
+using Dce2Smb2FileTrackerPtr = std::shared_ptr<Dce2Smb2FileTracker>;
+using Dce2Smb2FileTrackerMap =
+    std::unordered_map<uint64_t, Dce2Smb2FileTrackerPtr, std::hash<uint64_t> >;
+
 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<std::mutex> 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;
index 4e5da6d39c693ced1dec36a4834a6161370b3d97..b994613ed59186e32618e21146d4e7fe978a2ad2 100644 (file)
 #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 <mutex>
 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<bool, Dce2Smb2SessionData*> Dce2Smb2FileTracker::update_processing_flow(
-    Dce2Smb2SessionData* current_flow)
+    Dce2Smb2SessionData* current_flow,Dce2Smb2SessionTrackerPtr session_tracker)
 {
     std::lock_guard<std::mutex> 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;
 }
 
index 8d3abfe6397fec125625d7accc1ee09a5f948a0f..4aed699bfb04a99472ddd2cf52ae917ddf11f343 100644 (file)
@@ -24,6 +24,7 @@
 // This provides file tracker for SMBv2
 
 #include "dce_smb2.h"
+#include <atomic>
 
 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<std::mutex> 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<uint32_t, tcp_flow_state, std::hash<uint32_t> > get_flow_state_map()
+    {
+        return flow_state;
+    }
 
 private:
     void file_detect();
-    std::pair<bool, Dce2Smb2SessionData*> update_processing_flow(Dce2Smb2SessionData* = nullptr);
+    std::pair<bool, Dce2Smb2SessionData*> 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<uint64_t, Dce2Smb2FileTracker*, std::hash<uint64_t> >;
+using Dce2Smb2FileTrackerPtr = std::shared_ptr<Dce2Smb2FileTracker>;
+using Dce2Smb2FileTrackerMap =
+    std::unordered_map<uint64_t, Dce2Smb2FileTrackerPtr, std::hash<uint64_t> >;
 
 #endif
 
index 7c064a12dad5b048e4162bb53323aeccde85ded6..1ea75309fc0e01fd7cdf5b63f663c25520c13279 100644 (file)
@@ -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);
     }
index cf975e53af3b607d7fc82a0f4bd50a444c2b242b..a2665b267275959392b6e1c6b02eb0b891fcbb93 100644 (file)
@@ -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<Dce2Smb2TreeTracker*> all_trees;
     connected_trees_mutex.lock();
index 79eb74aca604c603701782a139b265fb6cea8957..382347e5eb771092ec7d1df14296d475c674101e 100644 (file)
@@ -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; 
index 82a699ef2f33b366b780915d42de3958734718a9..fca5d3159bf6e18ab5e7a94579a0da4dbe7a6672 100644 (file)
@@ -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);
+            }
         }
     }
 
index 4cb1094382032098bd482dbee7d82539b05e071c..154ad4813199c97a486db462cfd823d4c04d7994 100644 (file)
@@ -25,6 +25,7 @@
 #include "dce_smb2_tree.h"
 
 #include "dce_smb2_session.h"
+#include <memory>
 
 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<Dce2Smb2FileTracker> ftracker =  std::make_shared<Dce2Smb2FileTracker> (
+        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<std::mutex> 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));
     }
 
index f5f7a15a5aae7c5b4b8c1067b6af05c6dafaa045..d679d6d0a67ff01570eb06945dd2fdd25c0307ea 100644 (file)
@@ -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<bool> do_not_delete_tree { false };
+    void set_parent(Dce2Smb2SessionTracker* session_tracker) { parent_session = session_tracker; }
 
 private:
     void process_set_info_request(const Smb2Hdr*);
index 9c3fe2dab21ec768f5e61bc0199f17bff2680b3a..1052f5e3d29a9abff77544929c57fbf8186baf3b 100644 (file)
@@ -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
     {