From: Jason Ish Date: Tue, 11 Feb 2025 22:26:39 +0000 (-0600) Subject: output-lua: lua module search path configuration X-Git-Tag: suricata-8.0.0-beta1~437 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c3716ac56b606940e4ea4e4281930b53c608ec05;p=thirdparty%2Fsuricata.git output-lua: lua module search path configuration By default, use an empty search path. This gives us a predictable default. If a user needs access to external modules, the search path must be set in the configuration file. Ticket: #7169 --- diff --git a/src/output-lua.c b/src/output-lua.c index c3877ead14..f2461eb243 100644 --- a/src/output-lua.c +++ b/src/output-lua.c @@ -51,7 +51,14 @@ * it's parent_ctx->data ptr. */ typedef struct LogLuaMasterCtx_ { - char script_dir[PATH_MAX]; /**< contains script-dir */ + /** \brief Path to script directory. */ + char script_dir[PATH_MAX]; + + /** \brief Lua search path for Lua modules. */ + char path[PATH_MAX]; + + /** \brief Lua search path for C modules. */ + char cpath[PATH_MAX]; } LogLuaMasterCtx; typedef struct LogLuaCtx_ { @@ -396,6 +403,33 @@ typedef struct LogLuaScriptOptions_ { int stats; } LogLuaScriptOptions; +/** \brief Setup or clear Lua module search paths. + * + * If search paths are provided by the configuration, set them up, + * otherwise clear the default search paths. + */ +static void LuaSetPaths(lua_State *L, LogLuaMasterCtx *ctx) +{ + lua_getglobal(L, "package"); + + if (strlen(ctx->path) > 0) { + lua_pushstring(L, ctx->path); + } else { + lua_pushstring(L, ""); + } + lua_setfield(L, -2, "path"); + + if (strlen(ctx->cpath) > 0) { + lua_pushstring(L, ctx->cpath); + } else { + lua_pushstring(L, ""); + } + lua_setfield(L, -2, "cpath"); + + /* Pop package. */ + lua_pop(L, 1); +} + /** \brief load and evaluate the script * * This function parses the script, checks if all the required functions @@ -406,12 +440,14 @@ typedef struct LogLuaScriptOptions_ { * \param options struct to pass script requirements/options back to caller * \retval errcode 0 ok, -1 error */ -static int LuaScriptInit(const char *filename, LogLuaScriptOptions *options) { +static int LuaScriptInit(const char *filename, LogLuaScriptOptions *options, LogLuaMasterCtx *ctx) +{ lua_State *luastate = LuaGetState(); if (luastate == NULL) goto error; luaL_openlibs(luastate); SCLuaRequirefBuiltIns(luastate); + LuaSetPaths(luastate, ctx); int status = luaL_loadfile(luastate, filename); if (status) { @@ -537,7 +573,7 @@ error: * * \retval state Returns the set up luastate on success, NULL on error */ -static lua_State *LuaScriptSetup(const char *filename) +static lua_State *LuaScriptSetup(const char *filename, LogLuaMasterCtx *ctx) { lua_State *luastate = LuaGetState(); if (luastate == NULL) { @@ -547,6 +583,7 @@ static lua_State *LuaScriptSetup(const char *filename) luaL_openlibs(luastate); SCLuaRequirefBuiltIns(luastate); + LuaSetPaths(luastate, ctx); int status = luaL_loadfile(luastate, filename); if (status) { @@ -615,12 +652,11 @@ static OutputInitResult OutputLuaLogInitSub(ConfNode *conf, OutputCtx *parent_ct SCMutexInit(&lua_ctx->m, NULL); - const char *dir = ""; - if (parent_ctx && parent_ctx->data) { - LogLuaMasterCtx *mc = parent_ctx->data; - dir = mc->script_dir; - } + BUG_ON(parent_ctx == NULL); + LogLuaMasterCtx *mc = parent_ctx->data; + BUG_ON(mc == NULL); + const char *dir = mc->script_dir; char path[PATH_MAX] = ""; int ret = snprintf(path, sizeof(path),"%s%s%s", dir, strlen(dir) ? "/" : "", conf->val); if (ret < 0 || ret == sizeof(path)) { @@ -630,7 +666,7 @@ static OutputInitResult OutputLuaLogInitSub(ConfNode *conf, OutputCtx *parent_ct SCLogDebug("script full path %s", path); SCMutexLock(&lua_ctx->m); - lua_ctx->luastate = LuaScriptSetup(path); + lua_ctx->luastate = LuaScriptSetup(path, mc); SCMutexUnlock(&lua_ctx->m); if (lua_ctx->luastate == NULL) goto error; @@ -696,6 +732,17 @@ static OutputInitResult OutputLuaLogInit(ConfNode *conf) } LogLuaMasterCtx *master_config = output_ctx->data; strlcpy(master_config->script_dir, dir, sizeof(master_config->script_dir)); + + const char *lua_path = ConfNodeLookupChildValue(conf, "path"); + if (lua_path && strlen(lua_path) > 0) { + strlcpy(master_config->path, lua_path, sizeof(master_config->path)); + } + + const char *lua_cpath = ConfNodeLookupChildValue(conf, "cpath"); + if (lua_cpath && strlen(lua_cpath) > 0) { + strlcpy(master_config->cpath, lua_cpath, sizeof(master_config->cpath)); + } + TAILQ_INIT(&output_ctx->submodules); /* check the enables scripts and set them up as submodules */ @@ -709,7 +756,7 @@ static OutputInitResult OutputLuaLogInit(ConfNode *conf) snprintf(path, sizeof(path),"%s%s%s", dir, strlen(dir) ? "/" : "", script->val); SCLogDebug("script full path %s", path); - int r = LuaScriptInit(path, &opts); + int r = LuaScriptInit(path, &opts, master_config); if (r != 0) { SCLogError("couldn't initialize script"); goto error; diff --git a/suricata.yaml.in b/suricata.yaml.in index 46c94f0def..336c42c081 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -555,6 +555,15 @@ outputs: # https://docs.suricata.io/en/latest/output/lua-output.html - lua: enabled: no + + # By default the Lua module search paths are empty. If you plan + # to use external modules these paths will need to be set. The + # examples below are likely suitable for finding modules + # installed with a package manager on a 64 bit Linux system, but + # may need tweaking. + #path: "/usr/share/lua/5.4/?.lua;/usr/share/lua/5.4/?/init.lua;/usr/lib64/lua/5.4/?.lua;/usr/lib64/lua/5.4/?/init.lua;./?.lua;./?/init.lua" + #cpath: "/usr/lib64/lua/5.4/?.so;/usr/lib64/lua/5.4/loadall.so;./?.so" + #scripts-dir: /etc/suricata/lua-output/ scripts: # - script1.lua