]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
lua: misc cleanups in sandbox implementation
authorJason Ish <jason.ish@oisf.net>
Thu, 11 Apr 2024 17:06:29 +0000 (11:06 -0600)
committerJason Ish <jason.ish@oisf.net>
Mon, 27 May 2024 22:00:17 +0000 (16:00 -0600)
Including:
- rename guards
- SCMalloc to SCCalloc
- remove unused enum
- rename public functions to our naming standard

src/detect-lua.c
src/util-lua-sandbox.c
src/util-lua-sandbox.h

index 78a94a41295388840e4a131efc7d67abf685aad8..cab93693d4dcb09f13e927a84927195b6fcb5b5f 100644 (file)
@@ -150,7 +150,6 @@ void DetectLuaRegister(void)
 #define FLAG_DATATYPE_BUFFER                    BIT_U32(22)
 #define FLAG_ERROR_LOGGED                       BIT_U32(23)
 
-// TODO: move to config
 #define DEFAULT_LUA_ALLOC_LIMIT       500000
 #define DEFAULT_LUA_INSTRUCTION_LIMIT 500000
 
@@ -484,7 +483,7 @@ static void *DetectLuaThreadInit(void *data)
     t->alproto = lua->alproto;
     t->flags = lua->flags;
 
-    t->luastate = sb_newstate(lua->alloc_limit, lua->instruction_limit);
+    t->luastate = SCLuaSbStateNew(lua->alloc_limit, lua->instruction_limit);
     if (t->luastate == NULL) {
         SCLogError("luastate pool depleted");
         goto error;
@@ -493,7 +492,7 @@ static void *DetectLuaThreadInit(void *data)
     if (lua->allow_restricted_functions) {
         luaL_openlibs(t->luastate);
     } else {
-        sb_loadrestricted(t->luastate);
+        SCLuaSbLoadRestricted(t->luastate);
     }
 
     LuaRegisterExtensions(t->luastate);
@@ -534,7 +533,7 @@ static void *DetectLuaThreadInit(void *data)
 
 error:
     if (t->luastate != NULL)
-        sb_close(t->luastate);
+        SCLuaSbStateClose(t->luastate);
     SCFree(t);
     return NULL;
 }
@@ -544,7 +543,7 @@ static void DetectLuaThreadFree(void *ctx)
     if (ctx != NULL) {
         DetectLuaThreadData *t = (DetectLuaThreadData *)ctx;
         if (t->luastate != NULL)
-            sb_close(t->luastate);
+            SCLuaSbStateClose(t->luastate);
         SCFree(t);
     }
 }
@@ -590,13 +589,13 @@ static int DetectLuaSetupPrime(DetectEngineCtx *de_ctx, DetectLuaData *ld, const
 {
     int status;
 
-    lua_State *luastate = sb_newstate(ld->alloc_limit, ld->instruction_limit);
+    lua_State *luastate = SCLuaSbStateNew(ld->alloc_limit, ld->instruction_limit);
     if (luastate == NULL)
         return -1;
     if (ld->allow_restricted_functions) {
         luaL_openlibs(luastate);
     } else {
-        sb_loadrestricted(luastate);
+        SCLuaSbLoadRestricted(luastate);
     }
 
     /* hackish, needed to allow unittests to pass buffers as scripts instead of files */
@@ -876,10 +875,10 @@ static int DetectLuaSetupPrime(DetectEngineCtx *de_ctx, DetectLuaData *ld, const
 
     /* pop the table */
     lua_pop(luastate, 1);
-    sb_close(luastate);
+    SCLuaSbStateClose(luastate);
     return 0;
 error:
-    sb_close(luastate);
+    SCLuaSbStateClose(luastate);
     return -1;
 }
 
index f0c1b7ea0f0b11fb2fca1bf61c7410f3eaf6d0ee..2cb5ae2b7beda96c69f5a92837db3c240b31afb9 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2014-2023 Open Information Security Foundation
+/* Copyright (C) 2023-2024 Open Information Security Foundation
  *
  * You can copy, redistribute or modify this Program under the terms of
  * the GNU General Public License version 2 as published by the Free
 
 #include "util-lua-sandbox.h"
 
-typedef struct sb_block_function {
+#if !defined(SANDBOX_ALLOC_CTX)
+#define SANDBOX_CTX "SANDBOX_CTX"
+#endif
+
+typedef struct BlockedFunction {
     const char *module;
     const char *name;
-} sb_block_function;
+} BlockedFunction;
 
-static void sb_hook(lua_State *L, lua_Debug *ar);
-LUAMOD_API int luaopen_sandbox(lua_State *L);
+static void HookFunc(lua_State *L, lua_Debug *ar);
+static int OpenSandbox(lua_State *L);
 
-static void *sb_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
+/**
+ * Lua allocator function provided to lua_newstate.
+ *
+ * \param ud The pointer passed to lua_newstate
+ * \param ptr Pointer to data being allocated/reallocated/freed
+ * \param osize Original size of the block
+ * \param nsize Size of the new block
+ *
+ * See: https://www.lua.org/manual/5.4/manual.html#lua_Alloc
+ */
+static void *LuaAlloc(void *ud, void *ptr, size_t osize, size_t nsize)
 {
     (void)ud;
     (void)osize; /* not used */
-    sb_lua_state *ctx = (sb_lua_state *)ud;
+    SCLuaSbState *ctx = (SCLuaSbState *)ud;
     if (nsize == 0) {
         if (ptr != NULL) {
             // ASSERT: alloc_bytes > osize
@@ -71,32 +85,53 @@ static void *sb_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
     }
 }
 
-/*
-** These are the set of libs allowed in the restricted lua sandbox
-*/
-static const luaL_Reg sb_restrictedlibs[] = { { LUA_GNAME, luaopen_base },
-    //  {LUA_LOADLIBNAME, luaopen_package},
-    //  {LUA_COLIBNAME, luaopen_coroutine},
+/**
+ * Set of libs that are allowed and loaded into the Lua state.
+ */
+static const luaL_Reg AllowedLibs[] = {
+    // clang-format off
+    { LUA_GNAME, luaopen_base },
     { LUA_TABLIBNAME, luaopen_table },
-    //  {LUA_IOLIBNAME, luaopen_io},
-    //  {LUA_OSLIBNAME, luaopen_os},
-    { LUA_STRLIBNAME, luaopen_string }, { LUA_MATHLIBNAME, luaopen_math },
+    { LUA_STRLIBNAME, luaopen_string },
+    { LUA_MATHLIBNAME, luaopen_math },
     { LUA_UTF8LIBNAME, luaopen_utf8 },
-    { LUA_DBLIBNAME, luaopen_sandbox }, // TODO: remove this from restricted
-    { NULL, NULL } };
+
+    /* TODO: Review these libs... */
+#if 0
+    {LUA_LOADLIBNAME, luaopen_package},
+    {LUA_COLIBNAME, luaopen_coroutine},
+    {LUA_IOLIBNAME, luaopen_io},
+    {LUA_OSLIBNAME, luaopen_os},
+#endif
+
+    /* What is this for? */
+    { LUA_DBLIBNAME, OpenSandbox }, // TODO: remove this from restricted
+
+    { NULL, NULL }
+    // clang-format on
+};
 
 // TODO: should we block raw* functions?
 // TODO: Will we ever need to block a subset of functions more than one level deep?
-static const sb_block_function sb_restrictedfuncs[] = { { LUA_GNAME, "collectgarbage" },
-    { LUA_GNAME, "dofile" }, { LUA_GNAME, "getmetatable" }, { LUA_GNAME, "loadfile" },
-    { LUA_GNAME, "load" }, { LUA_GNAME, "pcall" }, { LUA_GNAME, "setmetatable" },
+static const BlockedFunction BlockedFunctions[] = {
+    // clang-format off
+    { LUA_GNAME, "collectgarbage" },
+    { LUA_GNAME, "dofile" },
+    { LUA_GNAME, "getmetatable" },
+    { LUA_GNAME, "loadfile" },
+    { LUA_GNAME, "load" }, 
+    { LUA_GNAME, "pcall" },
+    { LUA_GNAME, "setmetatable" },
     { LUA_GNAME, "xpcall" },
 
-    { LUA_STRLIBNAME, "rep" }, // TODO:  probably don't need to block this for normal restricted
-                               // since we have memory limit
-    { NULL, NULL } };
+    /* TODO:  probably don't need to block this for normal restricted
+     * since we have memory limit */
+    { LUA_STRLIBNAME, "rep" }, 
+    { NULL, NULL }
+    // clang-format on
+};
 
-static void sb_loadlibs(lua_State *L, const luaL_Reg *libs)
+static void LoadAllowedLibs(lua_State *L, const luaL_Reg *libs)
 {
     const luaL_Reg *lib;
     /* "require" functions from 'loadedlibs' and set results to global table */
@@ -106,9 +141,12 @@ static void sb_loadlibs(lua_State *L, const luaL_Reg *libs)
     }
 }
 
-static void sb_block_functions(lua_State *L, const sb_block_function *funcs)
+/**
+ * Apply function blocking by replacing blocked functions with a nil.
+ */
+static void ApplyBlockedFunctions(lua_State *L, const BlockedFunction *funcs)
 {
-    const sb_block_function *func;
+    const BlockedFunction *func;
 
     // set target functions to nil
     lua_pushglobaltable(L);
@@ -123,15 +161,15 @@ static void sb_block_functions(lua_State *L, const sb_block_function *funcs)
     lua_pop(L, 1); // remove global table
 }
 
-LUALIB_API void sb_loadrestricted(lua_State *L)
+void SCLuaSbLoadRestricted(lua_State *L)
 {
-    sb_loadlibs(L, sb_restrictedlibs);
-    sb_block_functions(L, sb_restrictedfuncs);
+    LoadAllowedLibs(L, AllowedLibs);
+    ApplyBlockedFunctions(L, BlockedFunctions);
 }
 
-lua_State *sb_newstate(uint64_t alloclimit, uint64_t instructionlimit)
+lua_State *SCLuaSbStateNew(uint64_t alloclimit, uint64_t instructionlimit)
 {
-    sb_lua_state *sb = SCMalloc(sizeof(sb_lua_state));
+    SCLuaSbState *sb = SCCalloc(1, sizeof(SCLuaSbState));
     if (sb == NULL) {
         // Out of memory.  Error code?
         return NULL;
@@ -142,9 +180,8 @@ lua_State *sb_newstate(uint64_t alloclimit, uint64_t instructionlimit)
     sb->hook_instruction_count = 100;
     sb->instruction_limit = instructionlimit;
 
-    sb->L = lua_newstate(sb_alloc, sb); /* create state */
+    sb->L = lua_newstate(LuaAlloc, sb); /* create state */
     if (sb->L == NULL) {
-        // TODO: log or error code?
         SCFree(sb);
         return NULL;
     }
@@ -153,31 +190,34 @@ lua_State *sb_newstate(uint64_t alloclimit, uint64_t instructionlimit)
     lua_pushlightuserdata(sb->L, sb);
     lua_settable(sb->L, LUA_REGISTRYINDEX);
 
-    lua_sethook(sb->L, sb_hook, LUA_MASKCOUNT, sb->hook_instruction_count);
+    lua_sethook(sb->L, HookFunc, LUA_MASKCOUNT, sb->hook_instruction_count);
     return sb->L;
 }
 
-static sb_lua_state *sb_get_ctx(lua_State *L)
+static SCLuaSbState *GetContext(lua_State *L)
 {
     lua_pushstring(L, SANDBOX_CTX);
     lua_gettable(L, LUA_REGISTRYINDEX);
-    sb_lua_state *ctx = lua_touserdata(L, -1);
+    SCLuaSbState *ctx = lua_touserdata(L, -1);
     // TODO:  log if null?
     lua_pop(L, 1);
     return ctx;
 }
 
-void sb_close(lua_State *L)
+void SCLuaSbStateClose(lua_State *L)
 {
-    sb_lua_state *sb = sb_get_ctx(L);
+    SCLuaSbState *sb = GetContext(L);
     lua_close(sb->L);
     SCFree(sb);
 }
 
-static void sb_hook(lua_State *L, lua_Debug *ar)
+/**
+ * Lua debugging hook, but used here for instruction limit counting.
+ */
+static void HookFunc(lua_State *L, lua_Debug *ar)
 {
     (void)ar;
-    sb_lua_state *sb = sb_get_ctx(L);
+    SCLuaSbState *sb = GetContext(L);
 
     sb->instruction_count += sb->hook_instruction_count;
 
@@ -187,35 +227,38 @@ static void sb_hook(lua_State *L, lua_Debug *ar)
     }
 }
 
-void sb_resetinstructioncounter(lua_State *L)
+/**
+ * Reset the instruction counter for the provided state.
+ */
+void SCLuaSbResetInstructionCounter(lua_State *L)
 {
-    sb_lua_state *sb = sb_get_ctx(L);
+    SCLuaSbState *sb = GetContext(L);
     if (sb != NULL) {
         sb->instruction_count = 0;
-        lua_sethook(L, sb_hook, LUA_MASKCOUNT, sb->hook_instruction_count);
+        lua_sethook(L, HookFunc, LUA_MASKCOUNT, sb->hook_instruction_count);
     }
 }
 
-void sb_setinstructionlimit(lua_State *L, uint64_t instruction_limit)
+static void SetInstructionCount(lua_State *L, uint64_t instruction_limit)
 {
-    sb_lua_state *ctx = sb_get_ctx(L);
+    SCLuaSbState *ctx = GetContext(L);
     if (ctx != NULL) {
         ctx->instruction_limit = instruction_limit;
     }
 }
 
-static uint64_t sb_getinstructioncount(lua_State *L)
+static uint64_t GetInstructionCount(lua_State *L)
 {
-    sb_lua_state *ctx = sb_get_ctx(L);
+    SCLuaSbState *ctx = GetContext(L);
     if (ctx != NULL) {
         return ctx->instruction_count;
     }
     return 0;
 }
 
-static int sb_Ltotalalloc(lua_State *L)
+static int L_TotalAlloc(lua_State *L)
 {
-    sb_lua_state *ctx = sb_get_ctx(L);
+    SCLuaSbState *ctx = GetContext(L);
     if (ctx != NULL) {
         lua_pushinteger(L, ctx->alloc_bytes);
     } else {
@@ -224,9 +267,9 @@ static int sb_Ltotalalloc(lua_State *L)
     return 1;
 }
 
-static int sb_Lgetalloclimit(lua_State *L)
+static int L_GetAllocLimit(lua_State *L)
 {
-    sb_lua_state *ctx = sb_get_ctx(L);
+    SCLuaSbState *ctx = GetContext(L);
     if (ctx != NULL) {
         lua_pushinteger(L, ctx->alloc_limit);
     } else {
@@ -235,34 +278,24 @@ static int sb_Lgetalloclimit(lua_State *L)
     return 1;
 }
 
-static int sb_Lsetalloclimit(lua_State *L)
+static int L_SetAllocLimit(lua_State *L)
 {
-    sb_lua_state *ctx = sb_get_ctx(L);
+    SCLuaSbState *ctx = GetContext(L);
     if (ctx != NULL) {
         ctx->alloc_limit = luaL_checkinteger(L, 1);
     }
     return 0;
 }
 
-/*
-static int sb_Lsetlevel(lua_State *L)
+static int L_GetInstructionCount(lua_State *L)
 {
-    lua_Integer level = luaL_checkinteger(L, 1);
-    lua_pushnil(L);
-    lua_setglobal(L, "debug");
-    return 0;
-}
-*/
-
-static int sb_Lgetinstructioncount(lua_State *L)
-{
-    lua_pushinteger(L, sb_getinstructioncount(L));
+    lua_pushinteger(L, GetInstructionCount(L));
     return 1;
 }
 
-static int sb_Lgetinstructionlimit(lua_State *L)
+static int L_GetInstructionLimit(lua_State *L)
 {
-    sb_lua_state *ctx = sb_get_ctx(L);
+    SCLuaSbState *ctx = GetContext(L);
     if (ctx != NULL) {
         lua_pushinteger(L, ctx->instruction_limit);
     } else {
@@ -271,30 +304,35 @@ static int sb_Lgetinstructionlimit(lua_State *L)
     return 1;
 }
 
-static int sb_Lsetinstructionlimit(lua_State *L)
+static int L_SetInstructionLimit(lua_State *L)
 {
-    sb_setinstructionlimit(L, luaL_checkinteger(L, 1));
+    SetInstructionCount(L, luaL_checkinteger(L, 1));
     return 0;
 }
 
-static int sb_Lresetinstructioncount(lua_State *L)
+static int L_ResetInstructionCount(lua_State *L)
 {
-    sb_resetinstructioncounter(L);
+    SCLuaSbResetInstructionCounter(L);
     return 0;
 }
 
-static const luaL_Reg sblib[] = { { "totalalloc", sb_Ltotalalloc },
-    { "getalloclimit", sb_Lgetalloclimit }, { "setalloclimit", sb_Lsetalloclimit },
-    // { "setlevel", sb_Lsetlevel },
-    { "instructioncount", sb_Lgetinstructioncount },
-    { "getinstructionlimit", sb_Lgetinstructionlimit },
-    { "setinstructionlimit", sb_Lsetinstructionlimit },
-    { "resetinstructioncount", sb_Lresetinstructioncount }, { NULL, NULL } };
-
-LUAMOD_API int luaopen_sandbox(lua_State *L)
+static const luaL_Reg sblib[] = {
+    // clang-format off
+    { "totalalloc", L_TotalAlloc },
+    { "getalloclimit", L_GetAllocLimit },
+    { "setalloclimit", L_SetAllocLimit },
+    { "instructioncount", L_GetInstructionCount },
+    { "getinstructionlimit", L_GetInstructionLimit },
+    { "setinstructionlimit", L_SetInstructionLimit },
+    { "resetinstructioncount", L_ResetInstructionCount },
+    { NULL, NULL }
+    // clang-format on
+};
+
+static int OpenSandbox(lua_State *L)
 {
     luaL_newlib(L, sblib);
     return 1;
 }
 
-#endif
\ No newline at end of file
+#endif
index 42ad7facf83efc558be060e40fbbd5035fd7a68e..2d285507994d402ed5367713b5d67f8c2706000e 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2014-2023 Open Information Security Foundation
+/* Copyright (C) 2023-2024 Open Information Security Foundation
  *
  * You can copy, redistribute or modify this Program under the terms of
  * the GNU General Public License version 2 as published by the Free
  * \author Jo Johnson <pyrojoe314@gmail.com>
  */
 
-#ifndef __UTIL_LUA_SANDBOX_H__
-#define __UTIL_LUA_SANDBOX_H__
+#ifndef SURICATA_UTIL_LUA_SANDBOX_H
+#define SURICATA_UTIL_LUA_SANDBOX_H
 
-#ifndef HAVE_LUA
-/* If we don't have Lua, create a typedef for sb_lua_State so the
- * exported Lua functions don't fail the build. */
-typedef void sb_lua_state;
-#else
-#include <stdlib.h>
 #include "lua.h"
 
-#if !defined(SANDBOX_ALLOC_CTX)
-#define SANDBOX_CTX "SANDBOX_CTX"
-#endif
-
 /*
  *  Lua sandbox usage:  The only needed changes to use the sandboxed lua state are
- *      to replace calls to lua_newstate and lua_close with sb_newstate and sb_close
- *      Additionally, sb_loadrestricted can be used to load a restricted set of packages
+ *      to replace calls to lua_newstate and lua_close with SCLuaSbStateNew and SCLuaSbStateClose
+ *      Additionally, SCLuaSbLoadRestricted can be used to load a restricted set of packages
  *      that prevent side effecting outside of the lua runtime
  */
 
 /*
  *  Struct to store a lua_state and the additional metadata required to sandbox it
  */
-typedef struct sb_lua_state {
+typedef struct SCLuaSbState {
     lua_State *L;
 
-    // Allocation limits
+    /* Allocation limits */
     uint64_t alloc_bytes;
     uint64_t alloc_limit;
 
-    // Execution Limits
+    /* Execution Limits */
     uint64_t instruction_count;
     uint64_t instruction_limit;
     uint64_t hook_instruction_count;
-} sb_lua_state;
-
-enum sb_level { NONE, EXTERNAL_RESTRICTED, PERFORMANCE_RESTRICTED };
+} SCLuaSbState;
 
 /*
  *  Replaces luaL_newstate.  Sets an upper bound for allocations and bytecode
@@ -70,29 +58,22 @@ enum sb_level { NONE, EXTERNAL_RESTRICTED, PERFORMANCE_RESTRICTED };
  *  instructionlimit - maximum number of lua bytecode instructions before an error is thrown
  *      A value of zero will not limit the number of instructions
  */
-lua_State *sb_newstate(uint64_t alloclimit, uint64_t instructionlimit);
+lua_State *SCLuaSbStateNew(uint64_t alloclimit, uint64_t instructionlimit);
 
 /*
- *  Replaces lua_close.  Handles freeing the sb_lua_state
+ *  Replaces lua_close.  Handles freeing the SCLuaSbState
  */
-void sb_close(lua_State *sb);
+void SCLuaSbStateClose(lua_State *sb);
 
 /*
  *  Resets the instruction counter for the sandbox to 0
  */
-void sb_resetinstructioncounter(lua_State *sb);
-
-/*
- *  Sets the maximum number of lua instructions before erroring out
- */
-void sb_setinstructionlimit(lua_State *L, uint64_t instruction_limit);
+void SCLuaSbResetInstructionCounter(lua_State *sb);
 
 /*
- *  Replaces luaL_openlibs.  Only opens allowed paackages for the sandbox and
+ *  Replaces luaL_openlibs.  Only opens allowed packages for the sandbox and
  *  masks out dangerous functions from the base.
  */
-LUALIB_API void sb_loadrestricted(lua_State *L);
-
-#endif /* HAVE_LUA */
+void SCLuaSbLoadRestricted(lua_State *L);
 
-#endif /*  __UTIL_LUA_SANDBOX_H__ */
\ No newline at end of file
+#endif /*  SURICATA_UTIL_LUA_SANDBOX_H */