From: Jason Ish Date: Fri, 24 May 2024 21:26:32 +0000 (-0600) Subject: lua: add blocked functions as a special log type plus stat X-Git-Tag: suricata-8.0.0-beta1~1252 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c8fa454cb2d20d11c72853451d7ee5503f34fee8;p=thirdparty%2Fsuricata.git lua: add blocked functions as a special log type plus stat 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. --- diff --git a/etc/schema.json b/etc/schema.json index dd7f0a6fc2..25bf6ad26f 100644 --- a/etc/schema.json +++ b/etc/schema.json @@ -5240,6 +5240,10 @@ "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" diff --git a/src/detect-engine.c b/src/detect-engine.c index 60297fb7b0..19effcbbae 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -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); diff --git a/src/detect-lua.c b/src/detect-lua.c index 865df5d5ce..47cf142871 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -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); diff --git a/src/detect.h b/src/detect.h index 17556902e7..6ce0ec8883 100644 --- a/src/detect.h +++ b/src/detect.h @@ -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; diff --git a/src/util-lua-sandbox.c b/src/util-lua-sandbox.c index 690fef8881..bd59dc95d0 100644 --- a/src/util-lua-sandbox.c +++ b/src/util-lua-sandbox.c @@ -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 { diff --git a/src/util-lua-sandbox.h b/src/util-lua-sandbox.h index 94344f1970..6551016738 100644 --- a/src/util-lua-sandbox.h +++ b/src/util-lua-sandbox.h @@ -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 */