suricata
util-lua.c
Go to the documentation of this file.
1 /* Copyright (C) 2014-2022 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 /**
19  * \file
20  *
21  * \author Victor Julien <victor@inliniac.net>
22  *
23  * Common function for Lua
24  */
25 
26 #include "suricata-common.h"
27 #include "detect.h"
28 #include "pkt-var.h"
29 #include "conf.h"
30 
31 #include "threads.h"
32 #include "threadvars.h"
33 #include "tm-threads.h"
34 
35 #include "util-print.h"
36 
37 #include "util-debug.h"
38 
39 #include "output.h"
40 #include "app-layer-htp.h"
41 #include "app-layer.h"
42 #include "app-layer-parser.h"
43 #include "util-privs.h"
44 #include "util-buffer.h"
45 #include "util-proto-name.h"
46 #include "util-logopenfile.h"
47 
48 #include "lua.h"
49 #include "lualib.h"
50 #include "lauxlib.h"
51 
52 #include "util-lua.h"
53 #include "util-lua-sandbox.h"
54 #include "detect-lua-extensions.h"
55 
57 {
58  lua_State *s = NULL;
59  s = luaL_newstate();
60  return s;
61 }
62 
64 {
65  if (s != NULL) {
66  /* clear the stack */
67  while (lua_gettop(s) > 0) {
68  lua_pop(s, 1);
69  }
70  lua_close(s);
71  }
72 }
73 
74 /* key for tv (threadvars) pointer */
75 const char lua_ext_key_tv[] = "suricata:lua:tv:ptr";
76 /* key for the invocation-generation counter pointer */
77 const char lua_ext_key_invocation_gen[] = "suricata:lua:invocation:gen";
78 /* key for tx pointer */
79 const char lua_ext_key_tx[] = "suricata:lua:tx:ptr";
80 /* key for tx id */
81 const char lua_ext_key_tx_id[] = "suricata:lua:tx_id";
82 /* key for p (packet) pointer */
83 const char lua_ext_key_p[] = "suricata:lua:pkt:ptr";
84 /* key for f (flow) pointer */
85 const char lua_ext_key_flow[] = "suricata:lua:flow:ptr";
86 /* key for direction */
87 const char lua_ext_key_direction[] = "suricata:lua:direction";
88 
89 /* key for pa (packet alert) pointer */
90 const char lua_ext_key_pa[] = "suricata:lua:pkt:alert:ptr";
91 /* key for s (signature) pointer */
92 const char lua_ext_key_s[] = "suricata:lua:signature:ptr";
93 /* key for file pointer */
94 const char lua_ext_key_file[] = "suricata:lua:file:ptr";
95 /* key for DetectEngineThreadCtx pointer */
96 const char lua_ext_key_det_ctx[] = "suricata:lua:det_ctx:ptr";
97 
98 /*
99  * Registry context values are wrapped in a typed userdata instead of
100  * being stored as bare lightuserdata. In unsandboxed states the registry
101  * is script-writable, so a bare pointer can be moved between keys and
102  * re-cast by the libs (type confusion/UAF). The type id is checked on
103  * every read; a retyped value fails the check and yields NULL.
104  */
105 typedef struct SCLuaRegValue_ {
106  uint32_t type_id;
107  void *ptr;
109 
110 enum {
122 };
123 
124 static void LuaStateSetReg(lua_State *luastate, const void *key, uint32_t type_id, void *ptr)
125 {
126  lua_pushlightuserdata(luastate, (void *)key);
127  if (ptr == NULL) {
128  /* clear without allocating (this runs at state teardown, where the
129  * sandbox allocator may be over its cap): NULL a typed slot in
130  * place, drop anything else (a nil settable never inserts) */
131  lua_gettable(luastate, LUA_REGISTRYINDEX);
132  if (lua_type(luastate, -1) == LUA_TUSERDATA &&
133  lua_rawlen(luastate, -1) == sizeof(SCLuaRegValue)) {
134  SCLuaRegValue *v = (SCLuaRegValue *)lua_touserdata(luastate, -1);
135  if (v != NULL && v->type_id == type_id) {
136  v->ptr = NULL;
137  lua_pop(luastate, 1);
138  return;
139  }
140  }
141  lua_pop(luastate, 1);
142  lua_pushlightuserdata(luastate, (void *)key);
143  lua_pushnil(luastate);
144  lua_settable(luastate, LUA_REGISTRYINDEX);
145  return;
146  }
147  /* the registry survives across match calls: when the slot already
148  * holds a value of this type, update it in place instead of paying
149  * a fresh GC allocation on every set (hot path) */
150  lua_gettable(luastate, LUA_REGISTRYINDEX);
151  if (lua_type(luastate, -1) == LUA_TUSERDATA &&
152  lua_rawlen(luastate, -1) == sizeof(SCLuaRegValue)) {
153  SCLuaRegValue *v = (SCLuaRegValue *)lua_touserdata(luastate, -1);
154  if (v != NULL && v->type_id == type_id) {
155  v->ptr = ptr;
156  lua_pop(luastate, 1);
157  return;
158  }
159  }
160  lua_pop(luastate, 1);
161  lua_pushlightuserdata(luastate, (void *)key);
162  SCLuaRegValue *v = (SCLuaRegValue *)lua_newuserdata(luastate, sizeof(*v));
163  v->type_id = type_id;
164  v->ptr = ptr;
165  lua_settable(luastate, LUA_REGISTRYINDEX);
166 }
167 
168 static void *LuaStateGetReg(lua_State *luastate, const void *key, uint32_t type_id)
169 {
170  lua_pushlightuserdata(luastate, (void *)key);
171  lua_gettable(luastate, LUA_REGISTRYINDEX);
172  void *ptr = NULL;
173  /* require the exact full-userdata shape before casting: a
174  * lightuserdata or a foreign small userdata would otherwise be
175  * re-read as SCLuaRegValue (OOB ptr on a size match) */
176  if (lua_type(luastate, -1) == LUA_TUSERDATA &&
177  lua_rawlen(luastate, -1) == sizeof(SCLuaRegValue)) {
178  SCLuaRegValue *v = (SCLuaRegValue *)lua_touserdata(luastate, -1);
179  if (v != NULL && v->type_id == type_id) {
180  ptr = v->ptr;
181  }
182  }
183  lua_pop(luastate, 1);
184  return ptr;
185 }
186 
187 /** \brief get tv pointer from the lua state */
189 {
190  return (ThreadVars *)LuaStateGetReg(luastate, lua_ext_key_tv, SCLUA_REG_TV);
191 }
192 
194 {
195  /* every registry context write is one script invocation: the state's
196  * invocation generation counts them, so a handle caching
197  * invocation-local pointers can compare it as a generation (a tx
198  * cannot be freed while a script call runs) */
199  uint64_t *gen = LuaStateGetReg(luastate, lua_ext_key_invocation_gen, SCLUA_REG_INVOCATION_GEN);
200  if (gen != NULL) {
201  *gen += 1;
202  }
203  LuaStateSetReg(luastate, lua_ext_key_tv, SCLUA_REG_TV, (void *)tv);
204 }
205 
206 /* publish the state's invocation counter: the slot holds the counter's
207  * address, not the counter - the value stays C-owned (sandbox context
208  * or output ctx), so a script cannot forge a generation; a swapped or
209  * cleared slot reads as 0 and no cursor is ever trusted */
210 void LuaStateSetInvocationGen(lua_State *luastate, uint64_t *gen)
211 {
212  LuaStateSetReg(luastate, lua_ext_key_invocation_gen, SCLUA_REG_INVOCATION_GEN, (void *)gen);
213 }
214 
215 /** \brief get the current invocation generation for this state */
217 {
218  uint64_t *gen = LuaStateGetReg(luastate, lua_ext_key_invocation_gen, SCLUA_REG_INVOCATION_GEN);
219  return (gen != NULL) ? *gen : 0;
220 }
221 
222 /** \brief get packet pointer from the lua state */
224 {
225  return (Packet *)LuaStateGetReg(luastate, lua_ext_key_p, SCLUA_REG_PACKET);
226 }
227 
229 {
230  LuaStateSetReg(luastate, lua_ext_key_p, SCLUA_REG_PACKET, (void *)p);
231 }
232 
233 /** \brief get tx pointer from the lua state */
234 void *LuaStateGetTX(lua_State *luastate)
235 {
236  return LuaStateGetReg(luastate, lua_ext_key_tx, SCLUA_REG_TX);
237 }
238 
239 /** \brief get tx id from the lua state */
240 uint64_t LuaStateGetTxId(lua_State *luastate)
241 {
242  lua_pushlightuserdata(luastate, (void *)&lua_ext_key_tx_id);
243  lua_gettable(luastate, LUA_REGISTRYINDEX);
244  uint64_t tx_id = lua_tointeger(luastate, -1);
245  lua_pop(luastate, 1);
246  return tx_id;
247 }
248 void LuaStateSetTX(lua_State *luastate, void *txptr, const uint64_t tx_id)
249 {
250  LuaStateSetReg(luastate, lua_ext_key_tx, SCLUA_REG_TX, txptr);
251  if (txptr == NULL) {
252  return; /* cleared: the id is read together with the slot */
253  }
254 
255  lua_pushlightuserdata(luastate, (void *)&lua_ext_key_tx_id);
256  lua_pushinteger(luastate, tx_id);
257  lua_settable(luastate, LUA_REGISTRYINDEX);
258 }
259 
261 {
262  Flow *f = (Flow *)LuaStateGetReg(luastate, lua_ext_key_flow, SCLUA_REG_FLOW);
263 
264  return f;
265 }
266 
267 void LuaStateSetFlow(lua_State *luastate, Flow *f)
268 {
269  /* flow */
270  LuaStateSetReg(luastate, lua_ext_key_flow, SCLUA_REG_FLOW, (void *)f);
271 }
272 
273 /** \brief get packet alert pointer from the lua state */
275 {
276  return (PacketAlert *)LuaStateGetReg(luastate, lua_ext_key_pa, SCLUA_REG_PACKET_ALERT);
277 }
278 
280 {
281  LuaStateSetReg(luastate, lua_ext_key_pa, SCLUA_REG_PACKET_ALERT, (void *)pa);
282 }
283 
284 /** \brief get signature pointer from the lua state */
286 {
287  return (Signature *)LuaStateGetReg(luastate, lua_ext_key_s, SCLUA_REG_SIGNATURE);
288 }
289 
290 void LuaStateSetSignature(lua_State *luastate, const Signature *s)
291 {
292  LuaStateSetReg(luastate, lua_ext_key_s, SCLUA_REG_SIGNATURE, (void *)s);
293 }
294 
295 /** \brief get file pointer from the lua state */
297 {
298  return (File *)LuaStateGetReg(luastate, lua_ext_key_file, SCLUA_REG_FILE);
299 }
300 
301 void LuaStateSetFile(lua_State *luastate, File *file)
302 {
303  LuaStateSetReg(luastate, lua_ext_key_file, SCLUA_REG_FILE, (void *)file);
304 }
305 
306 /** \brief get DetectEngineThreadCtx pointer from the lua state */
308 {
309  return (DetectEngineThreadCtx *)LuaStateGetReg(
311 }
312 
314 {
315  LuaStateSetReg(luastate, lua_ext_key_det_ctx, SCLUA_REG_DET_CTX, (void *)det_ctx);
316 }
317 
318 /** \brief get the per-rule DetectLuaData */
320 {
321  return (DetectLuaData *)LuaStateGetReg(luastate, luaext_key_ld, SCLUA_REG_DETECT_LUA_DATA);
322 }
323 
325 {
326  LuaStateSetReg(luastate, luaext_key_ld, SCLUA_REG_DETECT_LUA_DATA, (void *)ld);
327 }
328 
329 /** \brief get packet pointer from the lua state */
331 {
332  lua_pushlightuserdata(luastate, (void *)&lua_ext_key_direction);
333  lua_gettable(luastate, LUA_REGISTRYINDEX);
334  int dir = lua_toboolean(luastate, -1);
335  lua_pop(luastate, 1);
336  return dir;
337 }
338 
339 void LuaStateSetDirection(lua_State *luastate, int direction)
340 {
341  lua_pushlightuserdata(luastate, (void *)&lua_ext_key_direction);
342  lua_pushboolean(luastate, direction);
343  lua_settable(luastate, LUA_REGISTRYINDEX);
344 }
345 
346 /** \brief dump stack from lua state to screen */
347 void LuaPrintStack(lua_State *state) {
348  int size = lua_gettop(state);
349  int i;
350 
351  for (i = 1; i <= size; i++) {
352  int type = lua_type(state, i);
353  printf("Stack size=%d, level=%d, type=%d, ", size, i, type);
354 
355  switch (type) {
356  case LUA_TFUNCTION:
357  printf("function %s", lua_tostring(state, i) ? "true" : "false");
358  break;
359  case LUA_TBOOLEAN:
360  printf("bool %s", lua_toboolean(state, i) ? "true" : "false");
361  break;
362  case LUA_TNUMBER:
363  printf("number %g", lua_tonumber(state, i));
364  break;
365  case LUA_TSTRING:
366  printf("string `%s'", lua_tostring(state, i));
367  break;
368  case LUA_TTABLE:
369  printf("table `%s'", lua_tostring(state, i));
370  break;
371  default:
372  printf("other %s", lua_typename(state, type));
373  break;
374 
375  }
376  printf("\n");
377  }
378 }
379 
380 int LuaPushStringBuffer(lua_State *luastate, const uint8_t *input, size_t input_len)
381 {
382  /* a NULL buffer is outside the lua_pushlstring contract even with
383  * zero length; push the empty string instead (and clamp the length,
384  * a NULL input has no content of its own) */
385  if (input == NULL) {
386  input = (const uint8_t *)"";
387  input_len = 0;
388  }
389  lua_pushlstring(luastate, (char *)input, input_len);
390  return 1;
391 }
392 
393 int LuaPushInteger(lua_State *luastate, lua_Integer n)
394 {
395  lua_pushinteger(luastate, n);
396  return 1;
397 }
LuaStateSetTX
void LuaStateSetTX(lua_State *luastate, void *txptr, const uint64_t tx_id)
Definition: util-lua.c:248
LuaStateSetPacket
void LuaStateSetPacket(lua_State *luastate, Packet *p)
Definition: util-lua.c:228
tm-threads.h
DetectLuaData
Definition: detect-lua.h:44
LuaStateSetThreadVars
void LuaStateSetThreadVars(lua_State *luastate, ThreadVars *tv)
Definition: util-lua.c:193
lua_ext_key_det_ctx
const char lua_ext_key_det_ctx[]
Definition: util-lua.c:96
LuaStateSetInvocationGen
void LuaStateSetInvocationGen(lua_State *luastate, uint64_t *gen)
publish the state's invocation counter (once, at state init)
Definition: util-lua.c:210
SCLUA_REG_PACKET_ALERT
@ SCLUA_REG_PACKET_ALERT
Definition: util-lua.c:116
LuaStateGetSignature
Signature * LuaStateGetSignature(lua_State *luastate)
get signature pointer from the lua state
Definition: util-lua.c:285
util-lua.h
SCLUA_REG_DET_CTX
@ SCLUA_REG_DET_CTX
Definition: util-lua.c:119
type
uint8_t type
Definition: decode-sctp.h:0
LuaGetState
lua_State * LuaGetState(void)
Definition: util-lua.c:56
threads.h
Flow_
Flow data structure.
Definition: flow.h:360
lua_ext_key_file
const char lua_ext_key_file[]
Definition: util-lua.c:94
LuaStateSetDetectLuaData
void LuaStateSetDetectLuaData(lua_State *luastate, DetectLuaData *ld)
Definition: util-lua.c:324
util-privs.h
lua_ext_key_pa
const char lua_ext_key_pa[]
Definition: util-lua.c:90
p
Packet * p
Definition: fuzz_dataset.c:30
LuaStateSetFlow
void LuaStateSetFlow(lua_State *luastate, Flow *f)
set a flow pointer in the lua state
Definition: util-lua.c:267
lua_ext_key_invocation_gen
const char lua_ext_key_invocation_gen[]
Definition: util-lua.c:77
LuaStateGetDetCtx
DetectEngineThreadCtx * LuaStateGetDetCtx(lua_State *luastate)
get DetectEngineThreadCtx pointer from the lua state
Definition: util-lua.c:307
lua_State
struct lua_State lua_State
Definition: suricata-common.h:527
SCLuaRegValue_::ptr
void * ptr
Definition: util-lua.c:107
SCLuaRegValue_::type_id
uint32_t type_id
Definition: util-lua.c:106
LuaStateGetThreadVars
ThreadVars * LuaStateGetThreadVars(lua_State *luastate)
get tv pointer from the lua state
Definition: util-lua.c:188
lua_ext_key_s
const char lua_ext_key_s[]
Definition: util-lua.c:92
app-layer-htp.h
util-debug.h
SCLuaRegValue
struct SCLuaRegValue_ SCLuaRegValue
DetectEngineThreadCtx_
Definition: detect.h:1295
LuaStateSetFile
void LuaStateSetFile(lua_State *luastate, File *file)
Definition: util-lua.c:301
util-print.h
detect.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:57
lua_ext_key_direction
const char lua_ext_key_direction[]
Definition: util-lua.c:87
pkt-var.h
SCLuaRegValue_
Definition: util-lua.c:105
app-layer-parser.h
LuaStateGetDirection
int LuaStateGetDirection(lua_State *luastate)
get packet pointer from the lua state
Definition: util-lua.c:330
LuaStateSetDetCtx
void LuaStateSetDetCtx(lua_State *luastate, DetectEngineThreadCtx *det_ctx)
Definition: util-lua.c:313
Packet_
Definition: decode.h:528
conf.h
SCLUA_REG_FILE
@ SCLUA_REG_FILE
Definition: util-lua.c:118
lua_ext_key_tx
const char lua_ext_key_tx[]
Definition: util-lua.c:79
lua_ext_key_tv
const char lua_ext_key_tv[]
Definition: util-lua.c:75
util-proto-name.h
LuaStateGetDetectLuaData
DetectLuaData * LuaStateGetDetectLuaData(lua_State *luastate)
get the per-rule DetectLuaData
Definition: util-lua.c:319
util-lua-sandbox.h
LuaStateGetTX
void * LuaStateGetTX(lua_State *luastate)
get tx pointer from the lua state
Definition: util-lua.c:234
File_
Definition: util-file.h:146
lua_ext_key_tx_id
const char lua_ext_key_tx_id[]
Definition: util-lua.c:81
LuaStateGetTxId
uint64_t LuaStateGetTxId(lua_State *luastate)
get tx id from the lua state
Definition: util-lua.c:240
detect-lua-extensions.h
suricata-common.h
LuaStateGetPacketAlert
PacketAlert * LuaStateGetPacketAlert(lua_State *luastate)
get packet alert pointer from the lua state
Definition: util-lua.c:274
LuaStateSetPacketAlert
void LuaStateSetPacketAlert(lua_State *luastate, PacketAlert *pa)
Definition: util-lua.c:279
SCLUA_REG_INVOCATION_GEN
@ SCLUA_REG_INVOCATION_GEN
Definition: util-lua.c:121
SCLUA_REG_TX
@ SCLUA_REG_TX
Definition: util-lua.c:114
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:34
SCLUA_REG_FLOW
@ SCLUA_REG_FLOW
Definition: util-lua.c:115
threadvars.h
luaext_key_ld
const char luaext_key_ld[]
Definition: detect-lua-extensions.c:45
LuaStateSetDirection
void LuaStateSetDirection(lua_State *luastate, int direction)
Definition: util-lua.c:339
lua_ext_key_p
const char lua_ext_key_p[]
Definition: util-lua.c:83
util-logopenfile.h
LuaStateGetFile
File * LuaStateGetFile(lua_State *luastate)
get file pointer from the lua state
Definition: util-lua.c:296
util-buffer.h
Signature_
Signature container.
Definition: detect.h:663
LuaPrintStack
void LuaPrintStack(lua_State *state)
dump stack from lua state to screen
Definition: util-lua.c:347
LuaStateGetFlow
Flow * LuaStateGetFlow(lua_State *luastate)
get flow pointer from lua state
Definition: util-lua.c:260
SCLUA_REG_SIGNATURE
@ SCLUA_REG_SIGNATURE
Definition: util-lua.c:117
PacketAlert_
Definition: decode.h:266
lua_ext_key_flow
const char lua_ext_key_flow[]
Definition: util-lua.c:85
SCLUA_REG_PACKET
@ SCLUA_REG_PACKET
Definition: util-lua.c:113
SCLUA_REG_DETECT_LUA_DATA
@ SCLUA_REG_DETECT_LUA_DATA
Definition: util-lua.c:120
LuaStateGetInvocationGen
uint64_t LuaStateGetInvocationGen(lua_State *luastate)
get the current invocation generation for this state
Definition: util-lua.c:216
LuaStateSetSignature
void LuaStateSetSignature(lua_State *luastate, const Signature *s)
Definition: util-lua.c:290
LuaStateGetPacket
Packet * LuaStateGetPacket(lua_State *luastate)
get packet pointer from the lua state
Definition: util-lua.c:223
SCLUA_REG_TV
@ SCLUA_REG_TV
Definition: util-lua.c:112
output.h
LuaPushInteger
int LuaPushInteger(lua_State *luastate, lua_Integer n)
Definition: util-lua.c:393
LuaReturnState
void LuaReturnState(lua_State *s)
Definition: util-lua.c:63
LuaPushStringBuffer
int LuaPushStringBuffer(lua_State *luastate, const uint8_t *input, size_t input_len)
Definition: util-lua.c:380
app-layer.h
SCLUA_REG_INVALID
@ SCLUA_REG_INVALID
Definition: util-lua.c:111
f
Flow f
Definition: fuzz_dataset.c:32