"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"
/* 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);
#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
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);
/** 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;
*/
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);
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);
}
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;
*/
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);
}
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;
}
static uint64_t GetInstructionCount(lua_State *L)
{
- SCLuaSbState *ctx = GetContext(L);
+ SCLuaSbState *ctx = SCLuaSbGetContext(L);
if (ctx != NULL) {
return ctx->instruction_count;
}
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 {
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 {
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);
}
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 {
#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
uint64_t instruction_count;
uint64_t instruction_limit;
uint64_t hook_instruction_count;
+
+ /* Errors. */
+ bool blocked_function_error;
} SCLuaSbState;
/*
*/
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
*/