]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
lua: add blocked functions as a special log type plus stat
authorJason Ish <jason.ish@oisf.net>
Fri, 24 May 2024 21:26:32 +0000 (15:26 -0600)
committerJason Ish <jason.ish@oisf.net>
Mon, 27 May 2024 22:44:54 +0000 (16:44 -0600)
Distinguish between a generic Lua script error and an error created by a
function being blocked, so each is logged once respective of each other.

Also add a stat that is incremented when a script fails due to a
blocked function.

NOTE: This does not catch calls to functions that are blocked by not
having the library loaded, such as "io.open", as they are blocked by
not even loading the "io" library.

etc/schema.json
src/detect-engine.c
src/detect-lua.c
src/detect.h
src/util-lua-sandbox.c
src/util-lua-sandbox.h

index dd7f0a6fc2b43c73922e359f2d697812f5de01bd..25bf6ad26f610f87f4f42935df0e469aec3828e7 100644 (file)
                         "lua": {
                             "type": "object",
                             "properties": {
+                                "blocked_function_errors": {
+                                    "description": "Counter for Lua scripts failing due to blocked functions being called",
+                                    "type": "integer"
+                                },
                                 "errors": {
                                     "description": "Errors encountered while running Lua scripts",
                                     "type": "integer"
index 60297fb7b00541826cdadc92ff61263501c55b86..19effcbbaeb16ae8e69a2626b8c8f5227afb9809 100644 (file)
@@ -3335,6 +3335,10 @@ TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
     /* Register counter for Lua rule errors. */
     det_ctx->lua_rule_errors = StatsRegisterCounter("detect.lua.errors", tv);
 
+    /* Register a counter for Lua blocked function attempts. */
+    det_ctx->lua_blocked_function_errors =
+            StatsRegisterCounter("detect.lua.blocked_function_errors", tv);
+
 #ifdef PROFILING
     det_ctx->counter_mpm_list = StatsRegisterAvgCounter("detect.mpm_list", tv);
     det_ctx->counter_nonmpm_list = StatsRegisterAvgCounter("detect.nonmpm_list", tv);
index 865df5d5ce3bd60eb822f92440a9a16c35fb950f..47cf1428718432e6988f416beb6c87ca1912cd62 100644 (file)
@@ -123,6 +123,7 @@ void DetectLuaRegister(void)
 #define FLAG_DATATYPE_DNP3                      BIT_U32(21)
 #define FLAG_DATATYPE_BUFFER                    BIT_U32(22)
 #define FLAG_ERROR_LOGGED                       BIT_U32(23)
+#define FLAG_BLOCKED_FUNCTION_LOGGED            BIT_U32(24)
 
 #define DEFAULT_LUA_ALLOC_LIMIT       500000
 #define DEFAULT_LUA_INSTRUCTION_LIMIT 500000
@@ -175,13 +176,23 @@ static int DetectLuaRunMatch(
     SCLuaSbResetInstructionCounter(tlua->luastate);
 
     if (lua_pcall(tlua->luastate, 1, 1, 0) != 0) {
-        if (!(tlua->flags & FLAG_ERROR_LOGGED)) {
-            /* Log once per thread, the message from Lua will include
-             * the filename. */
+        SCLuaSbState *context = SCLuaSbGetContext(tlua->luastate);
+        uint32_t flag = 0;
+        if (context->blocked_function_error) {
+            StatsIncr(det_ctx->tv, det_ctx->lua_blocked_function_errors);
+            flag = FLAG_BLOCKED_FUNCTION_LOGGED;
+        } else {
+            flag = FLAG_ERROR_LOGGED;
+        }
+
+        /* Log once per thread per error type, the message from Lua
+         * will include the filename. */
+        if (!(tlua->flags & flag)) {
             SCLogWarning(
                     "Lua script failed to run successfully: %s", lua_tostring(tlua->luastate, -1));
-            tlua->flags |= FLAG_ERROR_LOGGED;
+            tlua->flags |= flag;
         }
+
         StatsIncr(det_ctx->tv, det_ctx->lua_rule_errors);
         while (lua_gettop(tlua->luastate) > 0) {
             lua_pop(tlua->luastate, 1);
index 17556902e70d91eb62aacc35f3c8ae3625a08742..6ce0ec8883ef26a2678d871a03fe66dc29a8f085 100644 (file)
@@ -1239,6 +1239,9 @@ typedef struct DetectEngineThreadCtx_ {
     /** stats id for lua rule errors */
     uint16_t lua_rule_errors;
 
+    /** stats id for lua blocked function counts */
+    uint16_t lua_blocked_function_errors;
+
 #ifdef DEBUG
     uint64_t pkt_stream_add_cnt;
     uint64_t payload_mpm_cnt;
index 690fef8881a86b433af8ed792e15f045e3402ef9..bd59dc95d06c9e58ea0e2e7ce4b706c8345df684 100644 (file)
@@ -84,6 +84,8 @@ static void *LuaAlloc(void *ud, void *ptr, size_t osize, size_t nsize)
  */
 static int LuaBlockedFunction(lua_State *L)
 {
+    SCLuaSbState *context = SCLuaSbGetContext(L);
+    context->blocked_function_error = true;
     lua_Debug ar;
     lua_getstack(L, 0, &ar);
     lua_getinfo(L, "n", &ar);
@@ -311,19 +313,24 @@ lua_State *SCLuaSbStateNew(uint64_t alloclimit, uint64_t instructionlimit)
     return sb->L;
 }
 
-static SCLuaSbState *GetContext(lua_State *L)
+/**
+ * Get the Suricata Lua sandbox context from the lua_State.
+ *
+ * Note: May return null if this Lua state was not allocated from the
+ * sandbox.
+ */
+SCLuaSbState *SCLuaSbGetContext(lua_State *L)
 {
     lua_pushstring(L, SANDBOX_CTX);
     lua_gettable(L, LUA_REGISTRYINDEX);
     SCLuaSbState *ctx = lua_touserdata(L, -1);
-    // TODO:  log if null?
     lua_pop(L, 1);
     return ctx;
 }
 
 void SCLuaSbStateClose(lua_State *L)
 {
-    SCLuaSbState *sb = GetContext(L);
+    SCLuaSbState *sb = SCLuaSbGetContext(L);
     lua_close(sb->L);
     SCFree(sb);
 }
@@ -334,7 +341,7 @@ void SCLuaSbStateClose(lua_State *L)
 static void HookFunc(lua_State *L, lua_Debug *ar)
 {
     (void)ar;
-    SCLuaSbState *sb = GetContext(L);
+    SCLuaSbState *sb = SCLuaSbGetContext(L);
 
     sb->instruction_count += sb->hook_instruction_count;
 
@@ -349,8 +356,9 @@ static void HookFunc(lua_State *L, lua_Debug *ar)
  */
 void SCLuaSbResetInstructionCounter(lua_State *L)
 {
-    SCLuaSbState *sb = GetContext(L);
+    SCLuaSbState *sb = SCLuaSbGetContext(L);
     if (sb != NULL) {
+        sb->blocked_function_error = false;
         sb->instruction_count = 0;
         lua_sethook(L, HookFunc, LUA_MASKCOUNT, sb->hook_instruction_count);
     }
@@ -358,7 +366,7 @@ void SCLuaSbResetInstructionCounter(lua_State *L)
 
 static void SetInstructionCount(lua_State *L, uint64_t instruction_limit)
 {
-    SCLuaSbState *ctx = GetContext(L);
+    SCLuaSbState *ctx = SCLuaSbGetContext(L);
     if (ctx != NULL) {
         ctx->instruction_limit = instruction_limit;
     }
@@ -366,7 +374,7 @@ static void SetInstructionCount(lua_State *L, uint64_t instruction_limit)
 
 static uint64_t GetInstructionCount(lua_State *L)
 {
-    SCLuaSbState *ctx = GetContext(L);
+    SCLuaSbState *ctx = SCLuaSbGetContext(L);
     if (ctx != NULL) {
         return ctx->instruction_count;
     }
@@ -375,7 +383,7 @@ static uint64_t GetInstructionCount(lua_State *L)
 
 static int L_TotalAlloc(lua_State *L)
 {
-    SCLuaSbState *ctx = GetContext(L);
+    SCLuaSbState *ctx = SCLuaSbGetContext(L);
     if (ctx != NULL) {
         lua_pushinteger(L, ctx->alloc_bytes);
     } else {
@@ -386,7 +394,7 @@ static int L_TotalAlloc(lua_State *L)
 
 static int L_GetAllocLimit(lua_State *L)
 {
-    SCLuaSbState *ctx = GetContext(L);
+    SCLuaSbState *ctx = SCLuaSbGetContext(L);
     if (ctx != NULL) {
         lua_pushinteger(L, ctx->alloc_limit);
     } else {
@@ -397,7 +405,7 @@ static int L_GetAllocLimit(lua_State *L)
 
 static int L_SetAllocLimit(lua_State *L)
 {
-    SCLuaSbState *ctx = GetContext(L);
+    SCLuaSbState *ctx = SCLuaSbGetContext(L);
     if (ctx != NULL) {
         ctx->alloc_limit = luaL_checkinteger(L, 1);
     }
@@ -412,7 +420,7 @@ static int L_GetInstructionCount(lua_State *L)
 
 static int L_GetInstructionLimit(lua_State *L)
 {
-    SCLuaSbState *ctx = GetContext(L);
+    SCLuaSbState *ctx = SCLuaSbGetContext(L);
     if (ctx != NULL) {
         lua_pushinteger(L, ctx->instruction_limit);
     } else {
index 94344f1970d71f291885658107361d252f952e47..6551016738fb6daeecc0cffdcab9db68218e5730 100644 (file)
@@ -25,6 +25,7 @@
 #define SURICATA_UTIL_LUA_SANDBOX_H
 
 #include "lua.h"
+#include "suricata-common.h"
 
 /*
  *  Lua sandbox usage:  The only needed changes to use the sandboxed lua state are
@@ -47,6 +48,9 @@ typedef struct SCLuaSbState {
     uint64_t instruction_count;
     uint64_t instruction_limit;
     uint64_t hook_instruction_count;
+
+    /* Errors. */
+    bool blocked_function_error;
 } SCLuaSbState;
 
 /*
@@ -65,6 +69,11 @@ lua_State *SCLuaSbStateNew(uint64_t alloclimit, uint64_t instructionlimit);
  */
 void SCLuaSbStateClose(lua_State *sb);
 
+/**
+ * Retreive the SCLuaSbState from a lua_State.
+ */
+SCLuaSbState *SCLuaSbGetContext(lua_State *L);
+
 /*
  *  Resets the instruction counter for the sandbox to 0
  */