Skip to content

Commit

Permalink
output-lua: lua module search path configuration
Browse files Browse the repository at this point in the history
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: OISF#7169
  • Loading branch information
jasonish committed Feb 13, 2025
1 parent d3d7f7f commit 9763c1a
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 10 deletions.
67 changes: 57 additions & 10 deletions src/output-lua.c
Original file line number Diff line number Diff line change
Expand Up @@ -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_ {
Expand Down Expand Up @@ -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
Expand All @@ -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) {
Expand Down Expand Up @@ -537,7 +573,7 @@ static int LuaScriptInit(const char *filename, LogLuaScriptOptions *options) {
*
* \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) {
Expand All @@ -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) {
Expand Down Expand Up @@ -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)) {
Expand All @@ -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;
Expand Down Expand Up @@ -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 */
Expand All @@ -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;
Expand Down
9 changes: 9 additions & 0 deletions suricata.yaml.in
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 9763c1a

Please sign in to comment.