From: Steve Chew (stechew) Date: Wed, 5 Feb 2020 16:06:46 +0000 (+0000) Subject: Merge pull request #1963 in SNORT/snort3 from ~SBAIGAL/snort3:so_reload to master X-Git-Tag: 3.0.0-268~22 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e6293b0e23bc8620560896d15930f1725db33d0e;p=thirdparty%2Fsnort3.git Merge pull request #1963 in SNORT/snort3 from ~SBAIGAL/snort3:so_reload to master Squashed commit of the following: commit 97637d76fb074ffa778a317b586c7e0446fd720d Author: Steven Baigal (sbaigal) Date: Wed Dec 18 16:02:02 2019 -0500 reload: make so_rule plugins reloadable --- diff --git a/src/ips_options/ips_so.cc b/src/ips_options/ips_so.cc index e32932b99..3e2f3e7c8 100644 --- a/src/ips_options/ips_so.cc +++ b/src/ips_options/ips_so.cc @@ -40,7 +40,7 @@ static THREAD_LOCAL ProfileStats soPerfStats; class SoOption : public IpsOption { public: - SoOption(const char*, const char*, bool, SoEvalFunc f, void* v); + SoOption(const char*, const char*, bool, SoEvalFunc f, void* v, SnortConfig*); ~SoOption() override; uint32_t hash() const override; @@ -57,10 +57,11 @@ private: bool relative_flag; SoEvalFunc func; void* data; + SnortConfig* cfg; }; SoOption::SoOption( - const char* id, const char* s, bool r, SoEvalFunc f, void* v) + const char* id, const char* s, bool r, SoEvalFunc f, void* v, SnortConfig* sc) : IpsOption(s_name) { soid = id; @@ -68,12 +69,12 @@ SoOption::SoOption( relative_flag = r; func = f; data = v; + cfg = sc; } SoOption::~SoOption() { - if ( data ) - SoManager::delete_so_data(soid, data); + SoManager::delete_so_data(soid, data, cfg); } uint32_t SoOption::hash() const @@ -142,12 +143,14 @@ public: public: string name; bool relative_flag; + SnortConfig* cfg; }; -bool SoModule::begin(const char*, int, SnortConfig*) +bool SoModule::begin(const char*, int, SnortConfig* sc) { name.clear(); relative_flag = false; + cfg = sc; return true; } @@ -191,14 +194,14 @@ static IpsOption* so_ctor(Module* p, OptTreeNode* otn) ParseError("no soid before so:%s", name); return nullptr; } - SoEvalFunc func = SoManager::get_so_eval(otn->soid, name, &data); + SoEvalFunc func = SoManager::get_so_eval(otn->soid, name, &data, m->cfg); if ( !func ) { ParseError("can't link so:%s", name); return nullptr; } - return new SoOption(otn->soid, name, relative_flag, func, data); + return new SoOption(otn->soid, name, relative_flag, func, data, m->cfg); } static void so_dtor(IpsOption* p) diff --git a/src/main.cc b/src/main.cc index fc447ace8..70b061647 100644 --- a/src/main.cc +++ b/src/main.cc @@ -329,16 +329,24 @@ int main_reload_config(lua_State* L) return 0; } const char* fname = nullptr; + const char* plugin_path = nullptr; if ( L ) { Lua::ManageStack(L, 1); fname = luaL_checkstring(L, 1); + if (lua_gettop(L) > 1) + { + plugin_path = luaL_checkstring(L, 2); +#ifdef REG_TEST + LogMessage("reload plugin_path: %s\n", plugin_path); +#endif + } } current_request->respond(".. reloading configuration\n"); SnortConfig* old = SnortConfig::get_conf(); - SnortConfig* sc = Snort::get_reload_config(fname); + SnortConfig* sc = Snort::get_reload_config(fname, plugin_path); if ( !sc ) { @@ -356,10 +364,12 @@ int main_reload_config(lua_State* L) if ( !tc ) { + // FIXIT-L it does not seem a valid check, delete old config if come to it current_request->respond("== reload failed - bad config\n"); SnortConfig::set_parser_conf(nullptr); return 0; } + PluginManager::reload_so_plugins_cleanup(sc, true); SnortConfig::set_conf(sc); proc_stats.conf_reloads++; diff --git a/src/main/help.cc b/src/main/help.cc index 1599a62b1..fa9e689a4 100644 --- a/src/main/help.cc +++ b/src/main/help.cc @@ -155,6 +155,7 @@ enum HelpType SnortConfig::set_conf(new SnortConfig); ScriptManager::load_scripts(sc->script_paths); PluginManager::load_plugins(sc->plugin_path); + PluginManager::load_so_plugins(sc); ModuleManager::init(); switch ( ht ) @@ -172,7 +173,7 @@ enum HelpType ModuleManager::dump_rules(val); break; case HT_DDR: - SoManager::dump_rule_stubs(val); + SoManager::dump_rule_stubs(val, sc); break; case HT_DFL: ModuleManager::dump_defaults(val); diff --git a/src/main/snort.cc b/src/main/snort.cc index 2b8638379..9831406d3 100644 --- a/src/main/snort.cc +++ b/src/main/snort.cc @@ -155,7 +155,7 @@ void Snort::init(int argc, char** argv) * Set the global snort_conf that will be used during run time */ sc->merge(snort_cmd_line_conf); SnortConfig::set_conf(sc); - + PluginManager::load_so_plugins(sc); #ifdef PIGLET if ( !Piglet::piglet_mode() ) #endif @@ -421,6 +421,7 @@ void Snort::cleanup() void Snort::reload_failure_cleanup(SnortConfig* sc) { + PluginManager::reload_so_plugins_cleanup(sc, false); parser_term(sc); delete sc; reloading = false; @@ -428,7 +429,7 @@ void Snort::reload_failure_cleanup(SnortConfig* sc) // FIXIT-M refactor this so startup and reload call the same core function to // instantiate things that can be reloaded -SnortConfig* Snort::get_reload_config(const char* fname) +SnortConfig* Snort::get_reload_config(const char* fname, const char* plugin_path) { reloading = true; ModuleManager::reset_errors(); @@ -445,6 +446,8 @@ SnortConfig* Snort::get_reload_config(const char* fname) return nullptr; } + PluginManager::reload_so_plugins(plugin_path, sc); + sc->setup(); #ifdef SHELL diff --git a/src/main/snort.h b/src/main/snort.h index efe5a9e75..3efeb7fc4 100644 --- a/src/main/snort.h +++ b/src/main/snort.h @@ -38,7 +38,7 @@ struct SnortConfig; class Snort { public: - static SnortConfig* get_reload_config(const char* fname); + static SnortConfig* get_reload_config(const char* fname, const char* plugin_path = nullptr); static SnortConfig* get_updated_policy(SnortConfig*, const char* fname, const char* iname); static SnortConfig* get_updated_module(SnortConfig*, const char* name); static void setup(int argc, char* argv[]); diff --git a/src/main/snort_config.cc b/src/main/snort_config.cc index 3ae8c4e39..0ff9981af 100644 --- a/src/main/snort_config.cc +++ b/src/main/snort_config.cc @@ -47,6 +47,7 @@ #include "managers/ips_manager.h" #include "managers/module_manager.h" #include "managers/mpse_manager.h" +#include "managers/so_manager.h" #include "memory/memory_config.h" #include "packet_io/sfdaq.h" #include "packet_io/sfdaq_config.h" @@ -209,6 +210,7 @@ void SnortConfig::init(const SnortConfig* const other_conf, ProtocolReference* p memset(evalOrder, 0, sizeof(evalOrder)); proto_ref = new ProtocolReference(protocol_reference); flowbits_ginit(this); + so_rules = new SoRules; } else { @@ -305,6 +307,7 @@ SnortConfig::~SnortConfig() delete memory; delete daq_config; delete proto_ref; + delete so_rules; reload_tuners.clear(); diff --git a/src/main/snort_config.h b/src/main/snort_config.h index 76b97610c..c2d69ee9c 100644 --- a/src/main/snort_config.h +++ b/src/main/snort_config.h @@ -136,12 +136,14 @@ struct HighAvailabilityConfig; struct IpsActionsConfig; struct LatencyConfig; struct MemoryConfig; +struct Plugins; struct PORT_RULE_MAP; struct RateFilterConfig; struct ReferenceSystemNode; struct RuleListNode; struct RulePortTables; struct SFDAQConfig; +struct SoRules; struct ThresholdConfig; struct VarNode; @@ -413,7 +415,8 @@ public: //Reload inspector related bool cloned = false; - + Plugins* plugins = nullptr; + SoRules* so_rules = nullptr; private: std::list reload_tuners; diff --git a/src/main/snort_module.cc b/src/main/snort_module.cc index b6b9e6841..805451e6f 100644 --- a/src/main/snort_module.cc +++ b/src/main/snort_module.cc @@ -65,6 +65,14 @@ static const Parameter s_reload[] = { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } }; +static const Parameter s_reload_w_path[] = +{ + { "filename", Parameter::PT_STRING, "(optional)", nullptr, + "[] name of file to load" }, + + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } +}; + static const Parameter s_delete[] = { { "inspector", Parameter::PT_STRING, nullptr, nullptr, @@ -98,7 +106,7 @@ static const Command snort_cmds[] = { "dump_stats", main_dump_stats, nullptr, "show summary statistics" }, { "rotate_stats", main_rotate_stats, nullptr, "roll perfmonitor log files" }, - { "reload_config", main_reload_config, s_reload, "load new configuration" }, + { "reload_config", main_reload_config, s_reload_w_path, "load new configuration" }, { "reload_policy", main_reload_policy, s_reload, "reload part or all of the default policy" }, { "reload_module", main_reload_module, s_module, "reload module" }, { "reload_daq", main_reload_daq, nullptr, "reload daq module" }, diff --git a/src/managers/plugin_manager.cc b/src/managers/plugin_manager.cc index a0ea0c35d..59b706f58 100644 --- a/src/managers/plugin_manager.cc +++ b/src/managers/plugin_manager.cc @@ -36,6 +36,7 @@ #include "helpers/directory.h" #include "helpers/markup.h" #include "log/messages.h" +#include "main/snort_config.h" #ifdef PIGLET #include "piglet/piglet_api.h" @@ -137,7 +138,6 @@ struct Plugin }; typedef std::map PlugMap; -static PlugMap plug_map; struct RefCount { @@ -149,7 +149,14 @@ struct RefCount }; typedef std::map RefMap; -static RefMap ref_map; + +struct Plugins +{ + PlugMap plug_map; + RefMap ref_map; +}; + +static Plugins s_plugins; static void set_key(string& key, Symbol* sym, const char* name) { @@ -178,8 +185,16 @@ static bool compatible_builds(const char* plug_opts) return true; } +static bool plugin_is_reloadable(const BaseApi* api) +{ + if (api->type == PT_SO_RULE) + return true; + else + return false; +} + static bool register_plugin( - const BaseApi* api, void* handle, const char* file) + const BaseApi* api, void* handle, const char* file, SnortConfig* sc) { if ( api->type >= PT_MAX ) return false; @@ -206,20 +221,22 @@ static bool register_plugin( return false; } - // validate api ? + if (sc and !plugin_is_reloadable(api)) + return false; string key; set_key(key, sym, api->name); - Plugin& p = plug_map[key]; - + Plugin& p = (sc ? sc->plugins->plug_map[key] : s_plugins.plug_map[key]); + RefMap& p_ref = (sc ? sc->plugins->ref_map : s_plugins.ref_map); if ( p.api ) { - if ( p.api->version >= api->version) + if ( p.api->version > api->version) return false; // keep the old one - if ( p.handle && !--ref_map[p.handle].count ) - dlclose(p.handle); // drop the old one + if ( p.handle && p_ref[p.handle].count ) + --p_ref[p.handle].count; + // TODO, replace/release cleanup } p.key = key; @@ -228,27 +245,26 @@ static bool register_plugin( p.source = file; if ( handle ) - ++ref_map[handle].count; + ++p_ref[handle].count; return true; } static void load_list( - const BaseApi** api, void* handle = nullptr, const char* file = "static") + const BaseApi** api, void* handle = nullptr, const char* file = "static", SnortConfig* sc = nullptr) { bool keep = false; while ( *api ) { - keep = register_plugin(*api, handle, file) || keep; - //printf("loaded %s\n", (*api)->name); + keep = register_plugin(*api, handle, file, sc) || keep; ++api; } if ( handle && !keep ) dlclose(handle); } -static bool load_lib(const char* file) +static bool load_lib(const char* file, SnortConfig* sc) { struct stat fs; void* handle; @@ -272,7 +288,7 @@ static bool load_lib(const char* file) dlclose(handle); return false; } - load_list(api, handle, file); + load_list(api, handle, file, sc); return true; } @@ -314,7 +330,7 @@ static void add_plugin(Plugin& p) break; case PT_SO_RULE: - SoManager::add_plugin((const SoApi*)p.api); + // SO rules are added later break; case PT_LOGGER: @@ -337,7 +353,7 @@ static void add_plugin(Plugin& p) } } -static void load_plugins(const std::string& paths) +static void load_plugins(const std::string& paths, SnortConfig* sc = nullptr) { struct stat sb; stringstream paths_stream(paths); @@ -358,38 +374,36 @@ static void load_plugins(const std::string& paths) Directory d(path.c_str(), lib_pattern); while ( const char* f = d.next() ) - load_lib(f); + load_lib(f, sc); } else { if ( path.find("/") == string::npos ) path = "./" + path; - load_lib(path.c_str()); + load_lib(path.c_str(), sc); } } } static void add_plugins() { - PlugMap::iterator it; - - for ( it = plug_map.begin(); it != plug_map.end(); ++it ) + for (auto it = s_plugins.plug_map.begin(); it != s_plugins.plug_map.end(); ++it ) add_plugin(it->second); } static void unload_plugins() { - for ( PlugMap::iterator it = plug_map.begin(); it != plug_map.end(); ++it ) + for (auto it = s_plugins.plug_map.begin(); it != s_plugins.plug_map.end(); ++it ) { if ( it->second.handle ) - --ref_map[it->second.handle].count; + --s_plugins.ref_map[it->second.handle].count; it->second.clear(); } #ifndef REG_TEST - for ( RefMap::iterator it = ref_map.begin(); it != ref_map.end(); ++it ) + for ( RefMap::iterator it = s_plugins.ref_map.begin(); it != s_plugins.ref_map.end(); ++it ) dlclose(it->first); #endif } @@ -417,11 +431,58 @@ void PluginManager::load_plugins(const std::string& paths) add_plugins(); } -void PluginManager::list_plugins() +void PluginManager::reload_so_plugins(const char* paths, SnortConfig* sc) +{ + sc->plugins = new Plugins; + sc->plugins->plug_map = s_plugins.plug_map; + sc->plugins->ref_map = s_plugins.ref_map; + if (paths) + ::load_plugins(paths, sc); + load_so_plugins(sc, true); +} + +void PluginManager::reload_so_plugins_cleanup(SnortConfig* sc, bool keep) { - PlugMap::iterator it; + if (!sc->plugins) + return; - for ( it = plug_map.begin(); it != plug_map.end(); ++it ) + if (keep) + { + // set the new plugins to current + s_plugins.plug_map.clear(); + s_plugins.plug_map = sc->plugins->plug_map; + sc->plugins->plug_map.clear(); + + s_plugins.ref_map.clear(); + s_plugins.ref_map = sc->plugins->ref_map; + sc->plugins->ref_map.clear(); + } + else + { + // close newly opened SO, + for (auto i = sc->plugins->ref_map.begin(); i != sc->plugins->ref_map.end(); ++i) + { + if (s_plugins.ref_map.find(i->first) == s_plugins.ref_map.end()) + dlclose(i->first); + } + sc->plugins->plug_map.clear(); + sc->plugins->ref_map.clear(); + } + delete sc->plugins; + sc->plugins = nullptr; +} + +void PluginManager::load_so_plugins(SnortConfig* sc, bool is_reload) +{ + auto p = is_reload ? sc->plugins->plug_map : s_plugins.plug_map; + for (auto it = p.begin(); it != p.end(); ++it ) + if (it->second.api->type == PT_SO_RULE) + SoManager::add_plugin((const SoApi*)it->second.api, sc); +} + +void PluginManager::list_plugins() +{ + for (auto it = s_plugins.plug_map.begin(); it != s_plugins.plug_map.end(); ++it ) { Plugin& p = it->second; cout << Markup::item(); @@ -434,9 +495,7 @@ void PluginManager::list_plugins() void PluginManager::show_plugins() { - PlugMap::iterator it; - - for ( it = plug_map.begin(); it != plug_map.end(); ++it ) + for (auto it = s_plugins.plug_map.begin(); it != s_plugins.plug_map.end(); ++it ) { Plugin& p = it->second; @@ -464,7 +523,6 @@ void PluginManager::release_plugins() ActionManager::release_plugins(); InspectorManager::release_plugins(); IpsManager::release_plugins(); - SoManager::release_plugins(); MpseManager::release_plugins(); CodecManager::release_plugins(); ConnectorManager::release_plugins(); @@ -480,9 +538,9 @@ const BaseApi* PluginManager::get_api(PlugType type, const char* name) string key; set_key(key, symbols+type, name); - const PlugMap::iterator it = plug_map.find(key); + auto it = s_plugins.plug_map.find(key); - if ( it != plug_map.end() ) + if ( it != s_plugins.plug_map.end() ) return it->second.api; return nullptr; @@ -491,7 +549,7 @@ const BaseApi* PluginManager::get_api(PlugType type, const char* name) #ifdef PIGLET PlugType PluginManager::get_type_from_name(const std::string& name) { - for ( auto it = plug_map.begin(); it != plug_map.end(); ++it ) + for ( auto it = s_plugins.plug_map.begin(); it != s_plugins.plug_map.end(); ++it ) { const auto* api = it->second.api; if ( name == api->name ) @@ -562,8 +620,7 @@ const char* PluginManager::get_available_plugins(PlugType t) { static std::string s; s.clear(); - - for ( auto it = plug_map.begin(); it != plug_map.end(); ++it ) + for ( auto it = s_plugins.plug_map.begin(); it != s_plugins.plug_map.end(); ++it ) { const auto* api = it->second.api; @@ -577,4 +634,3 @@ const char* PluginManager::get_available_plugins(PlugType t) } return s.c_str(); } - diff --git a/src/managers/plugin_manager.h b/src/managers/plugin_manager.h index a8a13d52f..7a3174210 100644 --- a/src/managers/plugin_manager.h +++ b/src/managers/plugin_manager.h @@ -67,6 +67,9 @@ public: const char* name); static const char* get_available_plugins(PlugType); + static void load_so_plugins(snort::SnortConfig*, bool is_reload = false); + static void reload_so_plugins(const char*, snort::SnortConfig*); + static void reload_so_plugins_cleanup(snort::SnortConfig*, bool); }; #endif diff --git a/src/managers/so_manager.cc b/src/managers/so_manager.cc index 1bf2b3437..1ebc92a2f 100644 --- a/src/managers/so_manager.cc +++ b/src/managers/so_manager.cc @@ -30,36 +30,34 @@ #include #include #include -#include #include #include "log/messages.h" +#include "main/snort_config.h" +#include "managers/plugin_manager.h" #include "parser/parse_so_rule.h" using namespace snort; using namespace std; -static list s_rules; - //------------------------------------------------------------------------- // plugins //------------------------------------------------------------------------- - -void SoManager::add_plugin(const SoApi* api) +SoRules::~SoRules() { - s_rules.emplace_back(api); + api.clear(); } -void SoManager::release_plugins() +void SoManager::add_plugin(const SoApi* api, SnortConfig* sc) { - s_rules.clear(); + sc->so_rules->api.emplace_back(api); } void SoManager::dump_plugins() { Dumper d("SO Rules"); - for ( auto* p : s_rules ) + for ( auto* p : SnortConfig::get_conf()->so_rules->api ) d.dump(p->base.name, p->base.version); } @@ -186,18 +184,18 @@ static const char* revert(const uint8_t* data, unsigned len) //------------------------------------------------------------------------- -static const SoApi* get_so_api(const char* soid) +static const SoApi* get_so_api(const char* soid, SnortConfig* sc = nullptr) { - for ( auto* p : s_rules ) + for ( auto* p : (sc ? sc->so_rules->api : SnortConfig::get_conf()->so_rules->api) ) if ( !strcmp(p->base.name, soid) ) return p; return nullptr; } -const char* SoManager::get_so_rule(const char* soid) +const char* SoManager::get_so_rule(const char* soid, SnortConfig* sc) { - const SoApi* api = get_so_api(soid); + const SoApi* api = get_so_api(soid, sc); if ( !api ) return nullptr; @@ -207,9 +205,9 @@ const char* SoManager::get_so_rule(const char* soid) return rule; } -SoEvalFunc SoManager::get_so_eval(const char* soid, const char* so, void** data) +SoEvalFunc SoManager::get_so_eval(const char* soid, const char* so, void** data, SnortConfig* sc) { - const SoApi* api = get_so_api(soid); + const SoApi* api = get_so_api(soid, sc); if ( !api || !api->ctor ) return nullptr; @@ -217,9 +215,11 @@ SoEvalFunc SoManager::get_so_eval(const char* soid, const char* so, void** data) return api->ctor(so, data); } -void SoManager::delete_so_data(const char* soid, void* pv) +void SoManager::delete_so_data(const char* soid, void* pv, SnortConfig* sc) { - const SoApi* api = get_so_api(soid); + if (!pv) + return; + const SoApi* api = get_so_api(soid, sc); if ( api && api->dtor ) api->dtor(pv); @@ -227,11 +227,11 @@ void SoManager::delete_so_data(const char* soid, void* pv) //------------------------------------------------------------------------- -void SoManager::dump_rule_stubs(const char*) +void SoManager::dump_rule_stubs(const char*, SnortConfig* sc) { unsigned c = 0; - for ( auto* p : s_rules ) + for ( auto* p : sc->so_rules->api ) { const char* rule = revert(p->rule, p->length); diff --git a/src/managers/so_manager.h b/src/managers/so_manager.h index ae30f0a7d..8fa938719 100644 --- a/src/managers/so_manager.h +++ b/src/managers/so_manager.h @@ -22,34 +22,38 @@ // Factory for shared object rules. // Runtime is same as for text rules. - +#include #include "framework/so_rule.h" namespace snort { struct SnortConfig; } -struct SoApi; //------------------------------------------------------------------------- +struct SoRules +{ + std::list api; + ~SoRules(); +}; class SoManager { public: - static void add_plugin(const SoApi*); + static void add_plugin(const SoApi*, snort::SnortConfig*); static void dump_plugins(); - static void release_plugins(); static void instantiate(const SoApi*); // soid is arg to soid option, so is arg to so option - static const char* get_so_rule(const char* soid); - static SoEvalFunc get_so_eval(const char* soid, const char* so, void** data); - static void delete_so_data(const char* soid, void*); + static const char* get_so_rule(const char* soid, snort::SnortConfig* sc = nullptr); + static SoEvalFunc get_so_eval(const char* soid, const char* so, + void** data, snort::SnortConfig* sc = nullptr); + static void delete_so_data(const char* soid, void*, snort::SnortConfig* sc = nullptr); static void rule_to_hex(const char* file); static void rule_to_text(const char* file); - static void dump_rule_stubs(const char*); + static void dump_rule_stubs(const char*, snort::SnortConfig*); }; #endif diff --git a/src/parser/parse_rule.cc b/src/parser/parse_rule.cc index 7afa13578..684ba679b 100644 --- a/src/parser/parse_rule.cc +++ b/src/parser/parse_rule.cc @@ -1168,7 +1168,7 @@ void parse_rule_close(SnortConfig* sc, RuleTreeNode& rtn, OptTreeNode* otn) if ( rtn.dip ) sfvar_free(rtn.dip); - const char* rule = SoManager::get_so_rule(otn->soid); + const char* rule = SoManager::get_so_rule(otn->soid, sc); IpsManager::reset_options(); if ( !rule )