suricata
util-lua-bytevarlib.c
Go to the documentation of this file.
1 /* Copyright (C) 2025 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 #include "suricata-common.h"
19 #include "detect-byte.h"
20 #include "util-lua-common.h"
21 #include "util-lua-bytevarlib.h"
22 #include "util-lua.h"
23 #include "detect-lua.h"
24 #include "detect-lua-extensions.h"
25 
26 #include "lauxlib.h"
27 
28 static const char suricata_bytevar_mt[] = "suricata:bytevar:mt";
29 
30 /* handle = slot id + the signature whose extractor may have written it */
31 typedef struct LuaBytevarHandle_ {
32  uint32_t id;
33  const Signature *sig;
35 
36 static DetectLuaData *GetLuaData(lua_State *luastate)
37 {
38  return LuaStateGetDetectLuaData(luastate);
39 }
40 
41 static int LuaBytevarMap(lua_State *L)
42 {
43  DetectLuaData *ld = GetLuaData(L);
44  if (ld == NULL) {
45  return luaL_error(L, "bytevar API not available in this context");
46  }
47  /* map() appends to the shared DetectLuaData like the flowvar/flowint
48  * register() APIs: only allowed while init() runs */
49  if (!ld->register_in_init) {
50  return luaL_error(L, "bytevar.map() must be called from init()");
51  }
52  if (!lua_islightuserdata(L, -2)) {
53  return luaL_error(L, "bytevar.map: first argument must be the signature passed to init");
54  }
55  /* only the exact signature pointer the engine passed to init() is
56  * valid; the script could forge other lightuserdata values (e.g. from
57  * the registry) and map() must fail closed */
58  if (lua_touserdata(L, -2) != (void *)ld->signature) {
59  return luaL_error(L, "bytevar.map: first argument is not the signature passed to init");
60  }
61  const Signature *s = lua_touserdata(L, -2);
62  const char *name = luaL_checkstring(L, -1);
63 
64  /* Is this name already mapped? */
65  for (uint16_t i = 0; i < ld->bytevars; i++) {
66  if (strcmp(ld->bytevar[i].name, name) == 0) {
67  lua_pushinteger(L, ld->bytevar[i].id);
68  return 1;
69  }
70  }
71 
72  if (ld->bytevars >= DETECT_LUA_MAX_BYTEVARS) {
73  return luaL_error(L, "too many bytevars mapped");
74  }
75 
77  if (!DetectByteRetrieveSMVar(name, s, -1, &idx)) {
78  return luaL_error(L, "unknown byte_extract or byte_math variable: %s", name);
79  }
80 
81  ld->bytevar[ld->bytevars].name = SCStrdup(name);
82  if (ld->bytevar[ld->bytevars].name == NULL) {
83  return luaL_error(L, "failed to allocate memory for bytevar name: %s", name);
84  }
85  ld->bytevar[ld->bytevars++].id = idx;
86 
87  return 1;
88 }
89 
90 static int LuaBytevarGet(lua_State *L)
91 {
92  const char *name = luaL_checkstring(L, 1);
93  DetectLuaData *ld = GetLuaData(L);
94  if (ld == NULL) {
95  return luaL_error(L, "internal error: no lua data");
96  }
97 
98  for (uint16_t i = 0; i < ld->bytevars; i++) {
99  if (strcmp(ld->bytevar[i].name, name) == 0) {
100  LuaBytevarHandle *handle = SCLuaNewUserData(L, SCLUA_TUD_BYTEVAR, sizeof(*handle));
101  if (handle == NULL) {
102  return LuaCallbackError(L, "error: failed to allocate user data");
103  }
104  handle->id = ld->bytevar[i].id;
105  handle->sig = ld->signature;
106  luaL_getmetatable(L, suricata_bytevar_mt);
107  lua_setmetatable(L, -2);
108  return 1;
109  }
110  }
111 
112  return luaL_error(L, "unknown bytevar: %s", name);
113 }
114 
115 static int LuaBytevarValue(lua_State *L)
116 {
117  LuaBytevarHandle *handle = SCLuaCheckUserData(L, 1, suricata_bytevar_mt, SCLUA_TUD_BYTEVAR);
118  if (handle == NULL) {
119  lua_pushnil(L);
120  return 1;
121  }
123  if (det_ctx == NULL) {
124  return LuaCallbackError(L, "internal error: no det_ctx");
125  }
126 
127  const int32_t max_id = det_ctx->de_ctx->byte_extract_max_local_id;
128  if ((int32_t)handle->id < 0 || (int32_t)handle->id > max_id) {
129  return LuaCallbackError(L, "bytevar index out of range");
130  }
131 
132  /* the slot is only valid once an extractor wrote it this detect
133  * run; an unwritten slot is stale (previous run) or uninitialized,
134  * so report it as unset rather than leaking that value to the script */
135  if (det_ctx->byte_values[handle->id].set == 0) {
136  lua_pushnil(L);
137  return 1;
138  }
139 
140  /* the local id is shared across signatures (the first extractor of
141  * every rule is slot 0): only the value this rule's extractor wrote
142  * this run is this rule's to read */
143  if (det_ctx->byte_values[handle->id].writer != handle->sig) {
144  lua_pushnil(L);
145  return 1;
146  }
147 
148  lua_pushinteger(L, det_ctx->byte_values[handle->id].value);
149  return 1;
150 }
151 
152 static const luaL_Reg bytevarlib[] = {
153  // clang-format off
154  { "map", LuaBytevarMap, },
155  { "get", LuaBytevarGet, },
156  { NULL, NULL, },
157  // clang-format on
158 };
159 
160 static const luaL_Reg bytevarmt[] = {
161  // clang-format off
162  { "value", LuaBytevarValue, },
163  { NULL, NULL, },
164  // clang-format on
165 };
166 
168 {
169  luaL_newmetatable(L, suricata_bytevar_mt);
170  lua_pushvalue(L, -1);
171  lua_setfield(L, -2, "__index");
172  luaL_setfuncs(L, bytevarmt, 0);
173 
174  luaL_newlib(L, bytevarlib);
175  return 1;
176 }
DetectLuaData::bytevars
uint16_t bytevars
Definition: detect-lua.h:56
DetectLuaData
Definition: detect-lua.h:44
DetectEngineThreadCtx_::byte_values
ByteVarSlot * byte_values
Definition: detect.h:1361
util-lua-common.h
LuaBytevarHandle_::sig
const Signature * sig
Definition: util-lua-bytevarlib.c:33
DetectLuaData::signature
const Signature * signature
Definition: detect-lua.h:48
DetectLuaDataBytevarEntry_::name
char * name
Definition: detect-lua.h:40
name
const char * name
Definition: detect-engine-proto.c:47
util-lua.h
LuaCallbackError
int LuaCallbackError(lua_State *luastate, const char *msg)
Definition: util-lua-common.c:218
LuaBytevarHandle
struct LuaBytevarHandle_ LuaBytevarHandle
ByteVarSlot_::writer
const Signature * writer
Definition: detect.h:1318
util-lua-bytevarlib.h
detect-lua.h
LuaStateGetDetCtx
DetectEngineThreadCtx * LuaStateGetDetCtx(lua_State *luastate)
get DetectEngineThreadCtx pointer from the lua state
Definition: util-lua.c:307
DetectByteIndexType
uint8_t DetectByteIndexType
Definition: detect-byte.h:28
lua_State
struct lua_State lua_State
Definition: suricata-common.h:527
DetectLuaData::register_in_init
bool register_in_init
Definition: detect-lua.h:60
LuaLoadBytevarLib
int LuaLoadBytevarLib(lua_State *L)
Definition: util-lua-bytevarlib.c:167
DetectEngineThreadCtx_
Definition: detect.h:1324
ByteVarSlot_::value
uint64_t value
Definition: detect.h:1316
DETECT_LUA_MAX_BYTEVARS
#define DETECT_LUA_MAX_BYTEVARS
Definition: detect-lua.h:37
SCLuaCheckUserData
void * SCLuaCheckUserData(lua_State *L, int idx, const char *mt, uint32_t type_id)
Definition: util-lua-common.c:101
LuaBytevarHandle_
Definition: util-lua-bytevarlib.c:31
DetectLuaData::bytevar
DetectLuaDataBytevarEntry bytevar[DETECT_LUA_MAX_BYTEVARS]
Definition: detect-lua.h:57
ByteVarSlot_::set
uint8_t set
Definition: detect.h:1317
detect-byte.h
DetectEngineCtx_::byte_extract_max_local_id
int32_t byte_extract_max_local_id
Definition: detect.h:1077
LuaStateGetDetectLuaData
DetectLuaData * LuaStateGetDetectLuaData(lua_State *luastate)
get the per-rule DetectLuaData
Definition: util-lua.c:319
SCLuaNewUserData
void * SCLuaNewUserData(lua_State *L, uint32_t type_id, size_t size)
Definition: util-lua-common.c:42
detect-lua-extensions.h
suricata-common.h
LuaBytevarHandle_::id
uint32_t id
Definition: util-lua-bytevarlib.c:32
SCStrdup
#define SCStrdup(s)
Definition: util-mem.h:56
Signature_
Signature container.
Definition: detect.h:692
DetectEngineThreadCtx_::de_ctx
DetectEngineCtx * de_ctx
Definition: detect.h:1461
DetectByteRetrieveSMVar
bool DetectByteRetrieveSMVar(const char *arg, const Signature *s, int sm_list, DetectByteIndexType *index)
Used to retrieve args from BM.
Definition: detect-byte.c:41
DetectLuaDataBytevarEntry_::id
uint32_t id
Definition: detect-lua.h:41
SCLUA_TUD_BYTEVAR
@ SCLUA_TUD_BYTEVAR
Definition: util-lua-common.h:55