]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #1252 in SNORT/snort3 from single_lua_state to master
authorMike Stepanek (mstepane) <mstepane@cisco.com>
Mon, 4 Jun 2018 17:23:23 +0000 (13:23 -0400)
committerMike Stepanek (mstepane) <mstepane@cisco.com>
Mon, 4 Jun 2018 17:23:23 +0000 (13:23 -0400)
Squashed commit of the following:

commit 362352dfbed54bd82759ba661573705781e6ad3b
Author: Masud Hasan <mashasan@cisco.com>
Date:   Wed May 30 14:11:13 2018 -0400

    appid: Single lua-state per thread

src/network_inspectors/appid/client_plugins/client_discovery.cc
src/network_inspectors/appid/lua_detector_api.cc
src/network_inspectors/appid/lua_detector_api.h
src/network_inspectors/appid/lua_detector_module.cc
src/network_inspectors/appid/lua_detector_module.h
src/network_inspectors/appid/service_plugins/service_discovery.cc

index 382c1ff46df9b13223779157e016041d1dff0c31..7676422fe636ac953050c199800e04ea28d3c6ad 100644 (file)
@@ -159,10 +159,9 @@ static int pattern_match(void* id, void* /*unused_tree*/, int match_end_pos, voi
             {
                 cam = match_free_list;
                 match_free_list = cam->next;
-                memset(cam, 0, sizeof(*cam));
             }
             else
-                cam = (ClientAppMatch*)snort_calloc(sizeof(ClientAppMatch));
+                cam = (ClientAppMatch*)snort_alloc(sizeof(ClientAppMatch));
 
             cam->count = 1;
             cam->detector =  static_cast<const ClientDetector*>(pd->service);
index 9f23efb8feb083692e39e3994568d23b87a277be..31ba4973c2b468a7bfd174fdb668b2fa17fcf556 100644 (file)
@@ -128,29 +128,29 @@ static inline int convert_string_to_address(const char* string, SfIp* address)
 //  return - a detector instance or none
 static int service_init(lua_State* L)
 {
-    // FIXIT-H - most of this probably not useful anymore...
     auto& ud = *UserData<LuaServiceDetector>::check(L, DETECTOR, 1);
 
     // auto pServiceName = luaL_checkstring(L, 2);
     auto pValidator = luaL_checkstring(L, 3);
     auto pFini = luaL_checkstring(L, 4);
 
-    lua_getglobal(L, pValidator);
-    lua_getglobal(L, pFini);
-
-    if ( lua_isfunction(L, -1) && lua_isfunction(L, -2) )
+    lua_getfield(L, LUA_REGISTRYINDEX, ud->lsd.package_info.name.c_str());
+    lua_getfield(L, -1, pValidator);
+    if (lua_isfunction(L, -1))
     {
-        lua_pop(L, 2);
-        return 1;
+        lua_pop(L, 1);
+        lua_getfield(L, -1, pFini);
+        if (lua_isfunction(L, -1))
+        {
+            lua_pop(L, 1);
+            return 1;
+        }
     }
-    else
-    {
-        ErrorMessage("%s: attempted setting validator/fini to non-function\n",
-            ud->get_name().c_str());
 
-        lua_pop(L, 2);
-        return 0;
-    }
+    ErrorMessage("%s: attempted setting validator/fini to non-function\n",
+        ud->get_name().c_str());
+    lua_pop(L, 1);
+    return 0;
 }
 
 // Register a pattern for fast pattern matching. Lua detector calls this function to register a
@@ -403,8 +403,8 @@ static int service_set_validator(lua_State* L)
     auto& ud = *UserData<LuaServiceDetector>::check(L, DETECTOR, 1);
 
     const char* pValidator = lua_tostring(L, 2);
-    lua_getglobal(L, pValidator);
-
+    lua_getfield(L, LUA_REGISTRYINDEX, ud->lsd.package_info.name.c_str());
+    lua_getfield(L, -1, pValidator);
     if (!lua_isfunction(L, -1))
     {
         ErrorMessage("%s: attempted setting validator to non-function\n",
@@ -1457,7 +1457,6 @@ static int detector_add_length_app_cache(lua_State* L)
 {
     int i;
     const char* str_ptr;
-    LengthKey length_sequence;
     int index = 1;
 
     UserData<AppIdDetector>::check(L, DETECTOR, index);
@@ -1477,8 +1476,8 @@ static int detector_add_length_app_cache(lua_State* L)
         return 1;
     }
 
-    memset(&length_sequence, 0, sizeof(length_sequence));
-
+    LengthKey length_sequence;
+    memset(length_sequence.sequence, 0, sizeof(length_sequence.sequence));
     length_sequence.proto        = proto;
     length_sequence.sequence_cnt = sequence_cnt;
 
@@ -2335,18 +2334,19 @@ int register_detector(lua_State* L)
     return 1;                         /* return methods on the stack */
 }
 
-LuaStateDescriptor::~LuaStateDescriptor()
-{
-    // release the reference of the userdata on the lua side
-    if ( detector_user_data_ref != LUA_REFNIL )
-        luaL_unref(my_lua_state, LUA_REGISTRYINDEX, detector_user_data_ref);
-    lua_close(my_lua_state);
-}
-
 int LuaStateDescriptor::lua_validate(AppIdDiscoveryArgs& args)
 {
     Profile lua_detector_context(luaCustomPerfStats);
 
+    auto my_lua_state = lua_detector_mgr? lua_detector_mgr->L : nullptr;
+    if (!my_lua_state)
+    {
+        ErrorMessage("lua detector %s: no LUA state\n", package_info.name.c_str());
+        return APPID_ENULL;
+    }
+
+    // get the table for this chunk (env)
+    lua_getfield(my_lua_state, LUA_REGISTRYINDEX, package_info.name.c_str());
     ldp.data = args.data;
     ldp.size = args.size;
     ldp.dir = args.dir;
@@ -2354,15 +2354,25 @@ int LuaStateDescriptor::lua_validate(AppIdDiscoveryArgs& args)
     ldp.pkt = args.pkt;
     const char* validateFn = package_info.validateFunctionName.c_str();
 
-    if ( (!validateFn) || !lua_checkstack(my_lua_state, 1) )
+    if ( (!validateFn) || (validateFn[0] == '\0'))
     {
-        ErrorMessage("lua detector %s: invalid LUA %s\n",
-            package_info.name.c_str(), lua_tostring(my_lua_state, -1));
         ldp.pkt = nullptr;
-        return APPID_ENULL;
+        return APPID_NOMATCH;
+    }
+    else if ( !lua_checkstack(my_lua_state, 1) )
+    {
+        static bool logged_stack_error = false;
+        if (!logged_stack_error)
+        {
+            logged_stack_error = true;
+            ErrorMessage("lua detector %s: LUA stack can not grow, %s\n",
+                package_info.name.c_str(), lua_tostring(my_lua_state, -1));
+        }
+        ldp.pkt = nullptr;
+        return APPID_ENOMEM;
     }
 
-    lua_getglobal(my_lua_state, validateFn);
+    lua_getfield(my_lua_state, -1, validateFn); // get the function we want to call
 
     if ( lua_pcall(my_lua_state, 0, 1, 0) )
     {
@@ -2403,7 +2413,6 @@ static inline void init_lsd(LuaStateDescriptor* lsd, const std::string& detector
     lsd->package_info.name = detector_name;
     lua_pop(L, 1);    // pop client table
     lua_pop(L, 1);    // pop DetectorPackageInfo table
-    lsd->my_lua_state = L;
 }
 
 static inline bool lua_params_validator(LuaDetectorParameters& ldp, bool packet_context)
index 8a408dd5784cde0aaf6652ca5611629b8efae08f..74e02b797c3c88fe7876f4322c979244ffc1a7a3 100644 (file)
@@ -75,11 +75,8 @@ struct LuaDetectorParameters
 class LuaStateDescriptor
 {
 public:
-    LuaStateDescriptor() = default;
-    virtual ~LuaStateDescriptor();
-
     LuaDetectorParameters ldp;
-    lua_State* my_lua_state= nullptr;
+    // FIXIT-M: RELOAD - When reload is supported, update this whenever lua-state is changed
     int detector_user_data_ref = 0;    // key into LUA_REGISTRYINDEX
     DetectorPackageInfo package_info;
     unsigned int service_id = APP_ID_UNKNOWN;
index 4a603b7328ceda408b51848460976978dc1b33e1..889634c89f273591f943c96ae779e8282909b496 100644 (file)
@@ -44,7 +44,7 @@
 #define AVG_LUA_TRACKER_SIZE_IN_BYTES 740
 #define MAX_MEMORY_FOR_LUA_DETECTORS (512 * 1024 * 1024)
 
-static THREAD_LOCAL LuaDetectorManager* lua_detector_mgr;
+THREAD_LOCAL LuaDetectorManager* lua_detector_mgr = nullptr;
 static THREAD_LOCAL SF_LIST allocated_detector_flow_list;
 
 bool get_lua_field(lua_State* L, int table, const char* field, std::string& out)
@@ -144,26 +144,32 @@ LuaDetectorManager::LuaDetectorManager(AppIdConfig& config) :
     init_chp_glossary();
     sflist_init(&allocated_detector_flow_list);
     allocated_detectors.clear();
+    L = create_lua_state(config.mod_config);
 }
 
 LuaDetectorManager::~LuaDetectorManager()
 {
-    for ( auto& detector : allocated_detectors )
+    auto L = lua_detector_mgr? lua_detector_mgr->L : nullptr;
+    if (L)
     {
-        LuaStateDescriptor* lsd = detector->validate_lua_state(false);
-        auto L = lsd->my_lua_state;
-
-        lua_getglobal(L, lsd->package_info.cleanFunctionName.c_str());
-        if ( lua_isfunction(L, -1) )
+        for ( auto& detector : allocated_detectors )
         {
-            /*first parameter is DetectorUserData */
-            lua_rawgeti(L, LUA_REGISTRYINDEX, lsd->detector_user_data_ref);
-            if ( lua_pcall(L, 1, 1, 0) )
+            LuaStateDescriptor* lsd = detector->validate_lua_state(false);
+
+            lua_getfield(L, LUA_REGISTRYINDEX, lsd->package_info.name.c_str());
+            lua_getfield(L, -1, lsd->package_info.cleanFunctionName.c_str());
+            if ( lua_isfunction(L, -1) )
             {
-                ErrorMessage("Could not cleanup the %s client app element: %s\n",
-                    lsd->package_info.name.c_str(), lua_tostring(L, -1));
+                //first parameter is DetectorUserData
+                lua_rawgeti(L, LUA_REGISTRYINDEX, lsd->detector_user_data_ref);
+                if ( lua_pcall(L, 1, 1, 0) )
+                {
+                    ErrorMessage("Could not cleanup the %s client app element: %s\n",
+                        lsd->package_info.name.c_str(), lua_tostring(L, -1));
+                }
             }
         }
+        lua_close(L);
     }
 
     sflist_static_free_all(&allocated_detector_flow_list, free_detector_flow);
@@ -173,21 +179,35 @@ LuaDetectorManager::~LuaDetectorManager()
 
 void LuaDetectorManager::initialize(AppIdConfig& config)
 {
-    static bool lua_detectors_listed = false;
+    // FIXIT-M: RELOAD - When reload is supported, remove this line which prevents re-initialize
+    if (lua_detector_mgr)
+        return;
 
     lua_detector_mgr = new LuaDetectorManager(config);
+    if (!lua_detector_mgr->L)
+        FatalError("Error - appid: can not create new luaState, instance=%u\n", get_instance_id());
+
     lua_detector_mgr->initialize_lua_detectors();
     lua_detector_mgr->activate_lua_detectors();
-    if (config.mod_config->debug && !lua_detectors_listed)
-    {
+
+    if (config.mod_config->debug)
         lua_detector_mgr->list_lua_detectors();
-        lua_detectors_listed = false;
-    }
 }
 
 void LuaDetectorManager::terminate()
 {
+    if (!lua_detector_mgr)
+        return;
+
+    // release the reference of the userdata on the lua side
+    for (auto ld : lua_detector_mgr->allocated_detectors)
+    {
+        LuaStateDescriptor* lsd = ld->validate_lua_state(false);
+        if (lsd->detector_user_data_ref != LUA_REFNIL)
+            luaL_unref(lua_detector_mgr->L, LUA_REGISTRYINDEX, lsd->detector_user_data_ref);
+    }
     delete lua_detector_mgr;
+    lua_detector_mgr = nullptr;
 }
 
 void LuaDetectorManager::add_detector_flow(DetectorFlow* df)
@@ -211,7 +231,7 @@ void LuaDetectorManager::free_detector_flows()
 static inline void set_lua_tracker_size(lua_State* L, uint32_t numTrackers)
 {
     /*change flow tracker size according to available memory calculation */
-    lua_getglobal(L, "hostServiceTrackerModule");
+    lua_getfield(L, -1, "hostServiceTrackerModule");
     if (lua_istable(L, -1))
     {
         lua_getfield(L, -1, "setHostServiceTrackerSize");
@@ -227,7 +247,7 @@ static inline void set_lua_tracker_size(lua_State* L, uint32_t numTrackers)
     lua_pop(L, 1);
 
     // change flow tracker size according to available memory calculation
-    lua_getglobal(L, "flowTrackerModule");
+    lua_getfield(L, -1, "flowTrackerModule");
     if (lua_istable(L, -1))
     {
         lua_getfield(L, -1, "setFlowTrackerSize");
@@ -254,7 +274,6 @@ static inline uint32_t compute_lua_tracker_size(uint64_t rnaMemory, uint32_t num
            numTrackers;
 }
 
-// FIXIT-M lifetime of detector is easy to misuse with this idiom
 // Leaves 1 value (the Detector userdata) at the top of the stack
 static AppIdDetector* create_lua_detector(lua_State* L, const char* detectorName, bool is_custom)
 {
@@ -262,7 +281,8 @@ static AppIdDetector* create_lua_detector(lua_State* L, const char* detectorName
     IpProtocol proto = IpProtocol::PROTO_NOT_SET;
 
     Lua::ManageStack mgr(L);
-    lua_getglobal(L, "DetectorPackageInfo");
+    lua_getfield(L, LUA_REGISTRYINDEX, detectorName);
+    lua_getfield(L, -1, "DetectorPackageInfo");
     get_lua_field(L, -1, "name", detector_name);
     if ( !get_lua_field(L, -1, "proto", proto) )
     {
@@ -304,35 +324,42 @@ static AppIdDetector* create_lua_detector(lua_State* L, const char* detectorName
 
 void LuaDetectorManager::load_detector(char* detector_filename, bool isCustom)
 {
-    char detectorName[MAX_LUA_DETECTOR_FILENAME_LEN];
-
-    lua_State* L = create_lua_state(config.mod_config);
-
-    if ( !L )
+    if (luaL_loadfile(L, detector_filename))
     {
-        static bool logged = false;
-        if ( !logged )
-        {
-            ErrorMessage("Error - appid: can not create new luaState\n");
-            logged = true;
-        }
+        ErrorMessage("Error - appid: can not load Lua detector %s : %s\n",
+            detector_filename, lua_tostring(L, -1));
         return;
     }
 
-    if ( luaL_loadfile(L, detector_filename) || lua_pcall(L, 0, 0, 0) )
+    // FIXIT-M: RELOAD - When reload is supported, we might need to make these unique
+    // from one reload to the next reload, e.g., "odp_FOO_1", "odp_FOO_2", etc.
+    // Alternatively, conflicts between reload may be avoided if a new lua state is
+    // created separately, then swapped and free old state.
+    char detectorName[MAX_LUA_DETECTOR_FILENAME_LEN];
+    snprintf(detectorName, MAX_LUA_DETECTOR_FILENAME_LEN, "%s_%s",
+        (isCustom ? "custom" : "odp"), basename(detector_filename));
+
+    // create a new function environment and store it in the registry
+    lua_newtable(L); // create _ENV tables
+    lua_newtable(L); // create metatable
+    lua_getglobal(L, "_G"); // push the value of the global name
+    lua_setfield(L, -2, "__index"); // pop and get the global table
+    lua_setmetatable(L, -2); // pop and set global as the metatable
+    lua_pushvalue(L, -1); // push a copy of the element on the top
+    lua_setfield(L, LUA_REGISTRYINDEX, detectorName); // push to registry with unique name
+
+    // set the environment for the loaded script and execute it
+    lua_setfenv(L, -2);
+    if (lua_pcall(L, 0, 0, 0))
     {
-        ErrorMessage("Error - appid: loading Lua detector: %s : %s\n",
+        ErrorMessage("Error - appid: can not set env of Lua detector %s : %s\n",
             detector_filename, lua_tostring(L, -1));
-        lua_close(L);
         return;
     }
 
-    snprintf(detectorName, MAX_LUA_DETECTOR_FILENAME_LEN, "%s_%s",
-        (isCustom ? "custom" : "cisco"), basename(detector_filename));
     AppIdDetector* detector = create_lua_detector(L, detectorName, isCustom);
-    allocated_detectors.push_front(detector);
-    num_lua_detectors++;
-
+    if (detector)
+        allocated_detectors.push_front(detector);
 }
 
 void LuaDetectorManager::load_lua_detectors(const char* path, bool isCustom)
@@ -368,6 +395,7 @@ void LuaDetectorManager::initialize_lua_detectors()
 
     snprintf(path, sizeof(path), "%s/odp/lua", dir);
     load_lua_detectors(path, false);
+    num_odp_detectors = allocated_detectors.size();
 
     snprintf(path, sizeof(path), "%s/custom/lua", dir);
     load_lua_detectors(path, true);
@@ -375,11 +403,14 @@ void LuaDetectorManager::initialize_lua_detectors()
 
 void LuaDetectorManager::activate_lua_detectors()
 {
+    uint32_t lua_tracker_size = compute_lua_tracker_size(MAX_MEMORY_FOR_LUA_DETECTORS,
+        allocated_detectors.size());
+
     for ( auto ld : allocated_detectors )
     {
         LuaStateDescriptor* lsd = ld->validate_lua_state(false);
-        auto L = lsd->my_lua_state;
-        lua_getglobal(L, lsd->package_info.initFunctionName.c_str());
+        lua_getfield(L, LUA_REGISTRYINDEX, lsd->package_info.name.c_str());
+        lua_getfield(L, -1, lsd->package_info.initFunctionName.c_str());
         if (!lua_isfunction(L, -1))
         {
             ErrorMessage("Detector %s: does not contain DetectorInit() function\n",
@@ -391,43 +422,20 @@ void LuaDetectorManager::activate_lua_detectors()
         lua_rawgeti(L, LUA_REGISTRYINDEX, lsd->detector_user_data_ref);
 
         /*second parameter is a table containing configuration stuff. */
-        // ... which is empty.???
         lua_newtable(L);
         if ( lua_pcall(L, 2, 1, 0) )
             ErrorMessage("Could not initialize the %s client app element: %s\n",
                 ld->get_name().c_str(), lua_tostring(L, -1));
 
-        ++num_active_lua_detectors;
-    }
-
-    lua_tracker_size = compute_lua_tracker_size(MAX_MEMORY_FOR_LUA_DETECTORS,
-        num_active_lua_detectors);
-    for ( auto& ld : allocated_detectors )
-    {
-        LuaStateDescriptor* lsd = ld->validate_lua_state(false);
-        set_lua_tracker_size(lsd->my_lua_state, lua_tracker_size);
+        lua_getfield(L, LUA_REGISTRYINDEX, lsd->package_info.name.c_str());
+        set_lua_tracker_size(L, lua_tracker_size);
     }
 }
 
 void LuaDetectorManager::list_lua_detectors()
 {
-    // FIXIT-L make these perf counters
-    size_t totalMem = 0;
-
-    if ( allocated_detectors.empty() )
-        return;
-
-    LogMessage("Lua Detector Stats:\n");
-
-    for ( auto& ld : allocated_detectors )
-    {
-        LuaStateDescriptor* lsd = ld->validate_lua_state(false);
-        size_t mem = lua_gc(lsd->my_lua_state, LUA_GCCOUNT, 0);
-        totalMem += mem;
-        LogMessage("\tDetector %s: Lua Memory usage %zu kb\n", ld->get_name().c_str(), mem);
-    }
-
-    LogMessage("Lua Stats total detectors: %zu\n", allocated_detectors.size());
-    LogMessage("Lua Stats total memory usage %zu kb\n", totalMem);
+    LogMessage("AppId Lua-Detector Stats: instance %u, odp detectors %zu, custom detectors %zu,"
+        " total memory %d kb\n", get_instance_id(), num_odp_detectors,
+        (allocated_detectors.size() - num_odp_detectors), lua_gc(L, LUA_GCCOUNT, 0));
 }
 
index 0fb6d9b30b480bc8e19f02de68fe8ab3177cb63e..d411f197875fc1c86c9b738499f863633793c462 100644 (file)
@@ -29,6 +29,7 @@
 #include <lua.hpp>
 #include <lua/lua.h>
 
+#include "main/thread.h"
 #include "protocols/protocol_ids.h"
 
 class AppIdConfig;
@@ -48,6 +49,8 @@ public:
     static void terminate();
     static void add_detector_flow(DetectorFlow*);
     static void free_detector_flows();
+    // FIXIT-M: RELOAD - When reload is supported, move this variable to a separate location
+    lua_State* L;
 
 private:
     void initialize_lua_detectors();
@@ -58,12 +61,10 @@ private:
 
     AppIdConfig& config;
     std::list<AppIdDetector*> allocated_detectors;
-
-    // FIXIT-L make these perf counters
-    uint32_t lua_tracker_size = 0;
-    uint32_t num_lua_detectors = 0;
-    uint32_t num_active_lua_detectors = 0;
+    size_t num_odp_detectors = 0;
 };
 
+extern THREAD_LOCAL LuaDetectorManager* lua_detector_mgr;
+
 #endif
 
index a20092daa74b65bc1708e6d4dc76b8c319681343..a6836beadd7d515bf87cb6eb6c3e8a239bfb5a7c 100644 (file)
@@ -465,7 +465,9 @@ int ServiceDiscovery::identify_service(AppIdSession& asd, Packet* p, AppidSessio
     if ( asd.service_detector )
     {
         ret = asd.service_detector->validate(args);
-        if (ret == APPID_NOT_COMPATIBLE)
+        if (ret == APPID_NOMATCH)
+            got_fail_service = true;
+        else if (ret == APPID_NOT_COMPATIBLE)
             got_incompatible_service = true;
         asd.service_search_state = SESSION_SERVICE_SEARCH_STATE::PENDING;
         if (appidDebug->is_active())
@@ -528,7 +530,8 @@ int ServiceDiscovery::identify_service(AppIdSession& asd, Packet* p, AppidSessio
     {
         if (!sds)
             sds = AppIdServiceState::add(ip, proto, port, asd.is_decrypted());
-        if (appidDebug->is_active())
+        // Don't log this if fail service is not due to empty list
+        if (appidDebug->is_active() and !(got_fail_service and asd.service_detector))
             LogMessage("AppIdDbg %s No service %s\n", appidDebug->get_debug_session(),
                 got_fail_service? "candidate" : "detector");
         got_fail_service = true;