]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
output-lua: lua module search path configuration
authorJason Ish <jason.ish@oisf.net>
Tue, 11 Feb 2025 22:26:39 +0000 (16:26 -0600)
committerVictor Julien <victor@inliniac.net>
Fri, 14 Feb 2025 06:44:42 +0000 (07:44 +0100)
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

src/output-lua.c
suricata.yaml.in

index c3877ead14f3d0ac9a409dd0c036fd4727fcc1cc..f2461eb243213ba8b1aad9661556b406bc554ac7 100644 (file)
  *  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;
index 46c94f0defbb1c0bfbe2e9207265dfcfd5c4ad96..336c42c081f6430e6955aa3ea3685cacffdbf819 100644 (file)
@@ -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