void FileFlows::set_current_file_context(FileContext* ctx)
{
// If we finished processing a file context object last time, delete it
- if (current_context_delete_pending)
+ if (current_context_delete_pending and (current_context != ctx))
{
delete current_context;
current_context_delete_pending = false;
{
const uint8_t* smb_data = (const uint8_t*)smb_hdr + SMB2_HEADER_LENGTH;
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);
// Macro and shorthand to save some repetitive code
// Should only be used in this function
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) \
+ { \
+ session->set_do_not_delete(false); \
+ session->set_prev_comand(SMB2_COM_MAX); \
+ } \
return; \
} \
}
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", \
smb2_command_string[command]); \
+ if (session) \
+ { \
+ session->set_do_not_delete(false); \
+ session->set_prev_comand(SMB2_COM_MAX); \
+ } \
return; \
} \
}
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) \
+ { \
+ session->set_do_not_delete(false); \
+ session->set_prev_comand(SMB2_COM_MAX); \
+ } \
return; \
}
- uint16_t command = alignedNtohs(&(smb_hdr->command));
- uint64_t session_id = Smb2Sid(smb_hdr);
SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, GET_CURRENT_PACKET,
"%s : flow %" PRIu32 " mid %" PRIu64 " sid %" PRIu64 " tid %" PRIu32 "\n",
(command < SMB2_COM_MAX ? smb2_command_string[command] : "unknown"),
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->set_do_not_delete(false);
+ return;
+ }
+
+ if (session)
+ {
+ session->set_do_not_delete(true);
+ session->set_prev_comand(command);
+ }
+
// Try to find the session.
// The case when session is not available will be handled per command.
- Dce2Smb2SessionTrackerPtr session = find_session(session_id);
-
switch (command)
{
//commands processed by flow
dce2_smb_stats.v2_msgs_uninspected++;
break;
}
+ if (session)
+ {
+ session->set_prev_comand(SMB2_COM_MAX);
+ session->set_do_not_delete(false);
+ }
}
// This is the main entry point for SMB2 processing.
Packet* p = DetectionEngine::get_current_packet();
const uint8_t* data_ptr = p->data;
uint16_t data_len = p->dsize;
+ Dce2Smb2SessionTrackerPtr session = nullptr;
// Process the header
if (p->is_pdu_start())
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);
return;
}
if (next_command_offset)
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);
return;
}
}
}
else
{
+ if ( tcp_file_tracker )
+ {
+ session = find_session(tcp_file_tracker->get_session_id());
+ if (session)
+ session->set_do_not_delete(true);
+ }
tcp_file_tracker_mutex.lock();
if ( tcp_file_tracker and tcp_file_tracker->accepting_raw_data_from(flow_key))
{
}
tcp_file_tracker_mutex.unlock();
}
+ if (session)
+ session->set_do_not_delete(false);
}
void Dce2Smb2SessionData::set_reassembled_data(uint8_t* nb_ptr, uint16_t co_len)
Dce2Smb2FileTracker(const Dce2Smb2FileTracker& arg) = delete;
Dce2Smb2FileTracker& operator=(const Dce2Smb2FileTracker& arg) = delete;
- Dce2Smb2FileTracker(uint64_t file_idv, const uint32_t flow_key, Dce2Smb2TreeTracker* p_tree) :
+ Dce2Smb2FileTracker(uint64_t file_idv, const uint32_t flow_key, Dce2Smb2TreeTracker* p_tree,
+ uint64_t sid) :
ignore(true), file_name_len(0), file_flow_key(flow_key),
file_id(file_idv), file_size(0), file_name_hash(0), file_name(nullptr),
- direction(FILE_DOWNLOAD), parent_tree(p_tree)
+ 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,
"file tracker %" PRIu64 " created\n", file_id);
void set_direction(FileDirection dir) { direction = dir; }
Dce2Smb2TreeTracker* get_parent() { return parent_tree; }
uint64_t get_file_id() { return file_id; }
+ uint64_t get_session_id() { return session_id; }
private:
void file_detect();
FileDirection direction;
Dce2Smb2TreeTracker* parent_tree;
std::unordered_map<uint32_t, tcp_flow_state, std::hash<uint32_t> > flow_state;
+ uint64_t session_id;
std::mutex process_file_mutex;
std::mutex flow_state_mutex;
};
void Dce2Smb2SessionTracker::clean_file_context_from_flow(Dce2Smb2FileTracker* file_tracker,
uint64_t file_id, uint64_t file_name_hash)
{
+ attached_flows_mutex.lock();
for (auto it_flow : attached_flows)
{
snort::FileFlows* file_flows = snort::FileFlows::get_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();
}
void Dce2Smb2SessionTracker::increase_size(const size_t size)
// Session Tracker is created and destroyed only from session cache
Dce2Smb2SessionTracker::~Dce2Smb2SessionTracker()
{
+ if (!(fcfs_mutex.try_lock()))
+ return;
+
+ if (do_not_delete )
+ {
+ // Dont prune the session in LRU Cache
+ smb2_session_cache.find_id(get_key());
+ fcfs_mutex.unlock();
+ return;
+ }
if (smb_module_is_up and (snort::is_packet_thread()))
{
SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID,
{
delete tree;
}
-
+ do_not_delete = false;
+ fcfs_mutex.unlock();
}
session_id = key.sid;
session_key = key;
reload_prune = false;
- SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, GET_CURRENT_PACKET,
+ do_not_delete = false;
+ command_prev = SMB2_COM_MAX;
+ SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, GET_CURRENT_PACKET,
"session tracker %" PRIu64 "created\n", session_id);
}
void process(const uint16_t, uint8_t, const Smb2Hdr*, const uint8_t*, const uint32_t);
void increase_size(const size_t size);
void decrease_size(const size_t size);
- void set_reload_prune() { reload_prune = true; }
+ void set_reload_prune(bool flag) { reload_prune = flag; }
+ uint64_t get_session_id() { return session_id; }
+ void set_do_not_delete(bool flag) { do_not_delete = flag; }
+ 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; }
private:
+ // do_not_delete is to make sure when we are in processing we should not delete the context
+ // which is being processed
+ bool do_not_delete;
Dce2Smb2TreeTracker* find_tree_for_message(const uint64_t, const uint32_t);
uint64_t session_id;
+ //to keep the tab of previous command
+ uint16_t command_prev;
Smb2SessionKey session_key;
Dce2Smb2SessionDataMap attached_flows;
Dce2Smb2TreeTrackerMap connected_trees;
std::atomic<bool> reload_prune;
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
+ // is being hit by two different paths
+ std::mutex fcfs_mutex;
};
#endif
using Data = std::shared_ptr<Value>;
+ Data find_id(Key key)
+ {
+ Data session = this->find(key);
+ return session;
+ }
+
Data find_session(Key key, Dce2Smb2SessionData* ssd)
{
- flow_mutex.lock();
Data session = this->find(key);
if (session)
session->attach_flow(ssd->get_flow_key(), ssd);
- flow_mutex.unlock();
return session;
}
Data find_else_create_session(Key& key, Dce2Smb2SessionData* ssd)
{
Data new_session = Data(new Value(key));
- flow_mutex.lock();
Data session = this->find_else_insert(key, new_session, nullptr);
session->attach_flow(ssd->get_flow_key(), ssd);
- flow_mutex.unlock();
return session;
}
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();
+ list_iter->second->set_reload_prune(true);
decrease_size(list_iter->second.get());
map.erase(list_iter->first);
list.erase(list_iter);
using LruBase::max_size;
using LruBase::stats;
using LruListIter = typename LruBase::LruListIter;
- std::mutex flow_mutex;
void increase_size(Value* value_ptr=nullptr) override
{
if (value_ptr) current_size += sizeof(*value_ptr);
Dce2Smb2FileTracker* Dce2Smb2TreeTracker::open_file(const uint64_t file_id,
const uint32_t current_flow_key)
{
- Dce2Smb2FileTracker* ftracker = new Dce2Smb2FileTracker(file_id, current_flow_key, this);
+ Dce2Smb2FileTracker* ftracker = new 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();
#include "dce_smb_module.h"
#include "dce_smb_utils.h"
#include "dce_smb2_session_cache.h"
+#include "main/thread_config.h"
#define DCE_SMB_PROTOCOL_ID "netbios-ssn"
dce2SmbProtoConf config;
mod->get_data(config);
size_t max_smb_mem = DCE2_ScSmbMemcap(&config);
+ uint16_t num_threads = ThreadConfig::get_instance_max();
smb_module_is_up = true;
- smb2_session_cache.reload_prune(max_smb_mem);
+ smb2_session_cache.reload_prune(max_smb_mem*num_threads);
return new Dce2Smb(config);
}