suricata
util-lua-filelib.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 "util-lua.h"
20 #include "util-lua-common.h"
21 #include "util-lua-filelib.h"
22 
23 #include "app-layer-parser.h"
24 #include "flow.h"
25 #include "rust.h"
26 #include "util-file.h"
27 
28 #include "lua.h"
29 #include "lauxlib.h"
30 
31 static const char file_mt[] = "suricata:file:mt";
32 
33 /* the handle pins the file by (tx anchor, direction, file_track_id):
34  * parsers assign file_track_id at file open and it is unique within
35  * the tx's file container (htp/smtp per-state counters, http2 the tx
36  * id). No parser pointer is stored; the accessors resolve on demand,
37  * so a retained handle can never dangle */
38 struct LuaFile {
40  uint8_t direction;
41  uint32_t file_track_id;
42 };
43 
44 /* resolve the anchored file: the tx must still be on the live state
45  * and the file must still be in that tx's file container for the
46  * recorded direction; any miss fails closed */
47 static const File *LuaFileRefResolve(lua_State *L, const struct LuaFile *lf)
48 {
49  void *tx = NULL;
50  if (!SCLuaTxRefResolve(L, &lf->ref, &tx)) {
51  return NULL;
52  }
53  const Flow *f = LuaStateGetFlow(L);
54  if (f == NULL) {
55  return NULL;
56  }
58  if (gfs.fc == NULL) {
59  return NULL;
60  }
61  for (const File *ff = gfs.fc->head; ff != NULL; ff = ff->next) {
62  if (ff->file_track_id == lf->file_track_id) {
63  return ff;
64  }
65  }
66  return NULL;
67 }
68 
69 static int LuaFileGetFile(lua_State *L)
70 {
71  const File *file = LuaStateGetFile(L);
72  if (file == NULL) {
73  return LuaCallbackError(L, "error: no file found");
74  }
75 
76  struct LuaFile *lua_file = SCLuaNewUserData(L, SCLUA_TUD_FILE, sizeof(*lua_file));
77  if (lua_file == NULL) {
78  return LuaCallbackError(L, "error: fail to allocate user data");
79  }
80  SCLuaTxRefInit(L, &lua_file->ref, LuaStateGetTxId(L));
81  /* the registry direction is the container's direction; the
82  * packet can be the opposing one on the EOF flush */
83  lua_file->direction = LuaStateGetDirection(L) ? STREAM_TOSERVER : STREAM_TOCLIENT;
84  lua_file->file_track_id = file->file_track_id;
85 
86  luaL_getmetatable(L, file_mt);
87  lua_setmetatable(L, -2);
88 
89  return 1;
90 }
91 
92 static int LuaFileGetFileId(lua_State *L)
93 {
94  struct LuaFile *lua_file = SCLuaCheckUserData(L, 1, file_mt, SCLUA_TUD_FILE);
95  const File *file = LuaFileRefResolve(L, lua_file);
96  if (file == NULL) {
97  lua_pushnil(L);
98  return 1;
99  }
100  lua_pushinteger(L, file->file_store_id);
101 
102  return 1;
103 }
104 
105 static int LuaFileGetTxId(lua_State *L)
106 {
107  struct LuaFile *lua_file = SCLuaCheckUserData(L, 1, file_mt, SCLUA_TUD_FILE);
108  lua_pushinteger(L, (lua_Integer)lua_file->ref.tx_id);
109 
110  return 1;
111 }
112 
113 static int LuaFileGetName(lua_State *L)
114 {
115  struct LuaFile *lua_file = SCLuaCheckUserData(L, 1, file_mt, SCLUA_TUD_FILE);
116  const File *file = LuaFileRefResolve(L, lua_file);
117  if (file == NULL) {
118  lua_pushnil(L);
119  return 1;
120  }
121  lua_pushlstring(L, (char *)file->name, file->name_len);
122 
123  return 1;
124 }
125 
126 static int LuaFileGetSize(lua_State *L)
127 {
128  struct LuaFile *lua_file = SCLuaCheckUserData(L, 1, file_mt, SCLUA_TUD_FILE);
129  const File *file = LuaFileRefResolve(L, lua_file);
130  if (file == NULL) {
131  lua_pushnil(L);
132  return 1;
133  }
134  lua_pushinteger(L, FileTrackedSize(file));
135 
136  return 1;
137 }
138 
139 static int LuaFileGetMagic(lua_State *L)
140 {
141 #ifdef HAVE_MAGIC
142  struct LuaFile *lua_file = SCLuaCheckUserData(L, 1, file_mt, SCLUA_TUD_FILE);
143  const File *file = LuaFileRefResolve(L, lua_file);
144  if (file == NULL) {
145  lua_pushnil(L);
146  return 1;
147  }
148  if (file->magic != NULL) {
149  lua_pushstring(L, file->magic);
150  } else {
151  lua_pushnil(L);
152  }
153 #else
154  lua_pushnil(L);
155 #endif
156 
157  return 1;
158 }
159 
160 static void PushHex(lua_State *L, const uint8_t *buf, size_t len)
161 {
162  /* Large enough for sha256. */
163  char hex[65] = "";
164  for (size_t i = 0; i < len; i++) {
165  char one[3] = "";
166  snprintf(one, sizeof(one), "%02x", buf[i]);
167  strlcat(hex, one, sizeof(hex));
168  }
169 
170  lua_pushstring(L, hex);
171 }
172 
173 static int LuaFileGetMd5(lua_State *L)
174 {
175  struct LuaFile *lua_file = SCLuaCheckUserData(L, 1, file_mt, SCLUA_TUD_FILE);
176  const File *file = LuaFileRefResolve(L, lua_file);
177  if (file == NULL) {
178  lua_pushnil(L);
179  return 1;
180  }
181 
182  if (file->flags & FILE_MD5) {
183  PushHex(L, file->md5, sizeof(file->md5));
184  } else {
185  lua_pushnil(L);
186  }
187 
188  return 1;
189 }
190 
191 static int LuaFileGetSha1(lua_State *L)
192 {
193  struct LuaFile *lua_file = SCLuaCheckUserData(L, 1, file_mt, SCLUA_TUD_FILE);
194  const File *file = LuaFileRefResolve(L, lua_file);
195  if (file == NULL) {
196  lua_pushnil(L);
197  return 1;
198  }
199 
200  if (file->flags & FILE_SHA1) {
201  PushHex(L, file->sha1, sizeof(file->sha1));
202  } else {
203  lua_pushnil(L);
204  }
205 
206  return 1;
207 }
208 
209 static int LuaFileGetSha256(lua_State *L)
210 {
211  struct LuaFile *lua_file = SCLuaCheckUserData(L, 1, file_mt, SCLUA_TUD_FILE);
212  const File *file = LuaFileRefResolve(L, lua_file);
213  if (file == NULL) {
214  lua_pushnil(L);
215  return 1;
216  }
217 
218  if (file->flags & FILE_SHA256) {
219  PushHex(L, file->sha256, sizeof(file->sha256));
220  } else {
221  lua_pushnil(L);
222  }
223 
224  return 1;
225 }
226 
227 static int LuaFileGetState(lua_State *L)
228 {
229  struct LuaFile *lua_file = SCLuaCheckUserData(L, 1, file_mt, SCLUA_TUD_FILE);
230  const File *file = LuaFileRefResolve(L, lua_file);
231  if (file == NULL) {
232  lua_pushnil(L);
233  return 1;
234  }
235 
236  const char *state = "UNKNOWN";
237  switch (file->state) {
238  case FILE_STATE_CLOSED:
239  state = "CLOSED";
240  break;
242  state = "TRUNCATED";
243  break;
244  case FILE_STATE_ERROR:
245  state = "ERROR";
246  break;
247  case FILE_STATE_OPENED:
248  state = "OPENED";
249  break;
250  case FILE_STATE_NONE:
251  state = "NONE";
252  break;
253  case FILE_STATE_MAX:
254  break;
255  }
256 
257  lua_pushstring(L, state);
258 
259  return 1;
260 }
261 
262 static int LuaFileIsStored(lua_State *L)
263 {
264  struct LuaFile *lua_file = SCLuaCheckUserData(L, 1, file_mt, SCLUA_TUD_FILE);
265  const File *file = LuaFileRefResolve(L, lua_file);
266  if (file == NULL) {
267  lua_pushnil(L);
268  return 1;
269  }
270  lua_pushboolean(L, file->flags & FILE_STORED);
271 
272  return 1;
273 }
274 
275 static const struct luaL_Reg filelib[] = {
276  { "get_state", LuaFileGetState },
277  { "is_stored", LuaFileIsStored },
278  { "file_id", LuaFileGetFileId },
279  { "tx_id", LuaFileGetTxId },
280  { "name", LuaFileGetName },
281  { "size", LuaFileGetSize },
282  { "magic", LuaFileGetMagic },
283  { "md5", LuaFileGetMd5 },
284  { "sha1", LuaFileGetSha1 },
285  { "sha256", LuaFileGetSha256 },
286  { NULL, NULL },
287 };
288 
289 static const struct luaL_Reg filemodlib[] = {
290  { "get_file", LuaFileGetFile },
291  { NULL, NULL },
292 };
293 
295 {
296  luaL_newmetatable(L, file_mt);
297  lua_pushvalue(L, -1);
298  lua_setfield(L, -2, "__index");
299  luaL_setfuncs(L, filelib, 0);
300 
301  luaL_newlib(L, filemodlib);
302 
303  return 1;
304 }
len
uint8_t len
Definition: app-layer-dnp3.h:2
util-lua-common.h
LuaFile::ref
SCLuaTxRef ref
Definition: util-lua-filelib.c:39
LuaFile::file_track_id
uint32_t file_track_id
Definition: util-lua-filelib.c:41
util-lua-filelib.h
FILE_SHA256
#define FILE_SHA256
Definition: util-file.h:119
LuaFile
Definition: util-lua-filelib.c:38
util-lua.h
LuaCallbackError
int LuaCallbackError(lua_State *luastate, const char *msg)
Definition: util-lua-common.c:218
SCLuaTxRef_
Definition: util-lua-common.h:92
FILE_STATE_OPENED
@ FILE_STATE_OPENED
Definition: util-file.h:137
Flow_
Flow data structure.
Definition: flow.h:359
File_::state
FileState state
Definition: util-file.h:149
File_::file_store_id
uint32_t file_store_id
Definition: util-file.h:152
rust.h
FILE_STATE_TRUNCATED
@ FILE_STATE_TRUNCATED
Definition: util-file.h:140
File_::sha1
uint8_t sha1[SC_SHA1_LEN]
Definition: util-file.h:163
AppLayerParserGetTxFiles
AppLayerGetFileState AppLayerParserGetTxFiles(const Flow *f, void *tx, const uint8_t direction)
Definition: app-layer-parser.c:963
lua_State
struct lua_State lua_State
Definition: suricata-common.h:527
File_::name_len
uint16_t name_len
Definition: util-file.h:148
LuaFile::direction
uint8_t direction
Definition: util-lua-filelib.c:40
File_::md5
uint8_t md5[SC_MD5_LEN]
Definition: util-file.h:161
SCLuaTxRef_::tx_id
uint64_t tx_id
Definition: util-lua-common.h:98
File_::file_track_id
uint32_t file_track_id
Definition: util-file.h:151
SCLuaTxRefResolve
int SCLuaTxRefResolve(lua_State *L, const SCLuaTxRef *ref, void **tx)
Definition: util-lua-common.c:182
strlcat
size_t strlcat(char *, const char *src, size_t siz)
Definition: util-strlcatu.c:45
FileContainer_::head
File * head
Definition: util-file.h:38
FileTrackedSize
uint64_t FileTrackedSize(const File *file)
get the size of the file
Definition: util-file.c:325
SCLUA_TUD_FILE
@ SCLUA_TUD_FILE
Definition: util-lua-common.h:58
SCLuaCheckUserData
void * SCLuaCheckUserData(lua_State *L, int idx, const char *mt, uint32_t type_id)
Definition: util-lua-common.c:101
app-layer-parser.h
LuaStateGetDirection
int LuaStateGetDirection(lua_State *luastate)
get packet pointer from the lua state
Definition: util-lua.c:330
FILE_STATE_MAX
@ FILE_STATE_MAX
Definition: util-file.h:143
File_::name
uint8_t * name
Definition: util-file.h:155
SCLuaNewUserData
void * SCLuaNewUserData(lua_State *L, uint32_t type_id, size_t size)
Definition: util-lua-common.c:42
File_::flags
uint16_t flags
Definition: util-file.h:147
util-file.h
FILE_STATE_CLOSED
@ FILE_STATE_CLOSED
Definition: util-file.h:138
File_
Definition: util-file.h:146
LuaStateGetTxId
uint64_t LuaStateGetTxId(lua_State *luastate)
get tx id from the lua state
Definition: util-lua.c:240
AppLayerGetFileState
Definition: util-file.h:44
suricata-common.h
AppLayerGetFileState::fc
FileContainer * fc
Definition: util-file.h:45
FILE_STORED
#define FILE_STORED
Definition: util-file.h:123
File_::next
struct File_ * next
Definition: util-file.h:159
FILE_MD5
#define FILE_MD5
Definition: util-file.h:115
File_::sha256
uint8_t sha256[SC_SHA256_LEN]
Definition: util-file.h:165
LuaStateGetFile
File * LuaStateGetFile(lua_State *luastate)
get file pointer from the lua state
Definition: util-lua.c:296
LuaStateGetFlow
Flow * LuaStateGetFlow(lua_State *luastate)
get flow pointer from lua state
Definition: util-lua.c:260
FILE_SHA1
#define FILE_SHA1
Definition: util-file.h:117
SCLuaTxRefInit
void SCLuaTxRefInit(lua_State *L, SCLuaTxRef *ref, uint64_t tx_id)
Definition: util-lua-common.c:164
flow.h
FILE_STATE_ERROR
@ FILE_STATE_ERROR
Definition: util-file.h:142
FILE_STATE_NONE
@ FILE_STATE_NONE
Definition: util-file.h:136
SCLuaLoadFileLib
int SCLuaLoadFileLib(lua_State *L)
Definition: util-lua-filelib.c:294
f
Flow f
Definition: fuzz_dataset.c:32