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.
pull/11165/head
Jason Ish 2 years ago
parent 86f9e43068
commit c8fa454cb2

@ -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"

@ -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);

@ -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);

@ -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;

@ -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 {

@ -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
*/

Loading…
Cancel
Save