return key;
}
-Dce2Smb2SessionTracker* Dce2Smb2SessionData::find_session(uint64_t session_id)
+Dce2Smb2SessionTrackerPtr Dce2Smb2SessionData::find_session(uint64_t session_id)
{
std::lock_guard<std::mutex> guard(session_data_mutex);
auto it_session = connected_sessions.find(session_id);
if (it_session != connected_sessions.end())
{
- Dce2Smb2SessionTracker* session = it_session->second;
+ 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);
return session;
}
else
{
- Dce2Smb2SessionTracker* session = smb2_session_cache.find_session(
+ Dce2Smb2SessionTrackerPtr session = smb2_session_cache.find_session(
get_session_key(session_id), this);
if (session)
connected_sessions.insert(std::make_pair(session_id,session));
}
// Caller must ensure that the session is not already present in flow
-Dce2Smb2SessionTracker* Dce2Smb2SessionData::create_session(uint64_t session_id)
+Dce2Smb2SessionTrackerPtr Dce2Smb2SessionData::create_session(uint64_t session_id)
{
Smb2SessionKey session_key = get_session_key(session_id);
std::lock_guard<std::mutex> guard(session_data_mutex);
- Dce2Smb2SessionTracker* session = smb2_session_cache.find_else_create_session(session_key, this);
+ Dce2Smb2SessionTrackerPtr session = smb2_session_cache.find_else_create_session(session_key, this);
connected_sessions.insert(std::make_pair(session_id, session));
return session;
}
-void Dce2Smb2SessionData::remove_session(uint64_t session_id)
+void Dce2Smb2SessionData::remove_session(uint64_t session_id, bool sync)
{
+ if (sync) session_data_mutex.lock();
connected_sessions.erase(session_id);
+ if (sync) session_data_mutex.unlock();
}
void Dce2Smb2SessionData::process_command(const Smb2Hdr* smb_hdr,
flow_key, Smb2Mid(smb_hdr), session_id, Smb2Tid(smb_hdr));
// Try to find the session.
// The case when session is not available will be handled per command.
- Dce2Smb2SessionTracker* session = find_session(session_id);
+ Dce2Smb2SessionTrackerPtr session = find_session(session_id);
switch (command)
{
class Dce2Smb2FileTracker;
class Dce2Smb2SessionTracker;
+using Dce2Smb2SessionTrackerPtr = std::shared_ptr<Dce2Smb2SessionTracker>;
using Dce2Smb2SessionTrackerMap =
- std::unordered_map<uint64_t, Dce2Smb2SessionTracker*, std::hash<uint64_t> >;
+ std::unordered_map<uint64_t, Dce2Smb2SessionTrackerPtr, std::hash<uint64_t> >;
PADDING_GUARD_BEGIN
struct Smb2SessionKey
Dce2Smb2SessionData(const snort::Packet*, const dce2SmbProtoConf* proto);
~Dce2Smb2SessionData() override;
void process() override;
- void remove_session(uint64_t);
+ void remove_session(uint64_t, bool = false);
void handle_retransmit(FilePosition, FileVerdict) override { }
void reset_matching_tcp_file_tracker(Dce2Smb2FileTracker*);
void set_reassembled_data(uint8_t*, uint16_t) override;
private:
void process_command(const Smb2Hdr*, const uint8_t*);
Smb2SessionKey get_session_key(uint64_t);
- Dce2Smb2SessionTracker* create_session(uint64_t);
- Dce2Smb2SessionTracker* find_session(uint64_t);
+ Dce2Smb2SessionTrackerPtr create_session(uint64_t);
+ Dce2Smb2SessionTrackerPtr find_session(uint64_t);
uint32_t flow_key;
Dce2Smb2FileTracker* tcp_file_tracker;
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)
{
"session tracker %" PRIu64 " terminating\n", session_id);
}
+ std::vector<Dce2Smb2TreeTracker*> all_trees;
+ connected_trees_mutex.lock();
auto it_tree = connected_trees.begin();
while (it_tree != connected_trees.end())
{
- Dce2Smb2TreeTracker* tree = it_tree->second;
+ all_trees.push_back(it_tree->second);
it_tree = connected_trees.erase(it_tree);
+ }
+ connected_trees_mutex.unlock();
+
+ for (Dce2Smb2TreeTracker* tree : all_trees)
+ {
delete tree;
}
- for (auto it_flow : attached_flows)
- it_flow.second->remove_session(session_id);
}
{
session_id = key.sid;
session_key = key;
+ reload_prune = false;
debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "session tracker %" PRIu64
" created\n", session_id);
}
Smb2SessionKey get_key() { return session_key; }
void clean_file_context_from_flow(Dce2Smb2FileTracker*, 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);
void decrease_size(const size_t size);
+ void set_reload_prune() { reload_prune = true; }
private:
Dce2Smb2TreeTracker* find_tree_for_message(const uint64_t, const uint32_t);
Smb2SessionKey session_key;
Dce2Smb2SessionDataMap attached_flows;
Dce2Smb2TreeTrackerMap connected_trees;
+ std::atomic<bool> reload_prune;
std::mutex connected_trees_mutex;
std::mutex attached_flows_mutex;
};
Dce2Smb2SharedCache(const size_t initial_size) :
LruCacheShared<Key, Value, Hash, Eq, Purgatory>(initial_size) { }
- Value* find_session(Key key, Dce2Smb2SessionData* ssd)
+ using Data = std::shared_ptr<Value>;
+
+ Data find_session(Key key, Dce2Smb2SessionData* ssd)
{
flow_mutex.lock();
- Value* session = this->find(key).get();
+ Data session = this->find(key);
if (session)
session->attach_flow(ssd->get_flow_key(), ssd);
flow_mutex.unlock();
return session;
}
- Value* find_else_create_session(Key& key, Dce2Smb2SessionData* ssd)
+ Data find_else_create_session(Key& key, Dce2Smb2SessionData* ssd)
{
- std::shared_ptr<Value> new_session = std::shared_ptr<Value>(new Value(key));
+ Data new_session = Data(new Value(key));
flow_mutex.lock();
- Value* session = this->find_else_insert(key, new_session, nullptr).get();
+ Data session = this->find_else_insert(key, new_session, nullptr);
session->attach_flow(ssd->get_flow_key(), ssd);
flow_mutex.unlock();
return session;
current_size -= size;
}
+ // Since decrease_size() does not account for associated objects in smb2_session_cache,
+ // we will over-prune when we reach the new_size here, as more space will be freed up
+ // when actual objects are destroyed. We might need to do gradual pruning like how
+ // host cache does. For now over pruning is ok.
+ void reload_prune(size_t new_size)
+ {
+ Purgatory data;
+ std::lock_guard<std::mutex> cache_lock(cache_mutex);
+ max_size = new_size;
+ while (current_size > max_size && !list.empty())
+ {
+ LruListIter list_iter = --list.end();
+ 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();
+ decrease_size(list_iter->second.get());
+ map.erase(list_iter->first);
+ list.erase(list_iter);
+ ++stats.reload_prunes;
+ }
+ }
+
private:
- using LruCacheShared<Key, Value, Hash, Eq, Purgatory>::current_size;
- using LruCacheShared<Key, Value, Hash, Eq, Purgatory>::cache_mutex;
+ using LruBase = LruCacheShared<Key, Value, Hash, Eq, Purgatory>;
+ using LruBase::cache_mutex;
+ using LruBase::current_size;
+ using LruBase::list;
+ using LruBase::map;
+ using LruBase::max_size;
+ using LruBase::stats;
+ using LruListIter = typename LruBase::LruListIter;
std::mutex flow_mutex;
void increase_size(Value* value_ptr=nullptr) override
{
{
assert(current_size >= sizeof(*value_ptr) );
current_size -= sizeof(*value_ptr);
+ //This is going down, remove references from flow here
+ value_ptr->unlink();
}
}
};
mod->get_data(config);
size_t max_smb_mem = DCE2_ScSmbMemcap(&config);
smb_module_is_up = true;
- smb2_session_cache.set_max_size(max_smb_mem);
+ smb2_session_cache.reload_prune(max_smb_mem);
return new Dce2Smb(config);
}