/src/suricata7/src/detect-filestore.c
Line | Count | Source |
1 | | /* Copyright (C) 2007-2021 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 | | * Implements the filestore keyword |
24 | | */ |
25 | | |
26 | | #include "suricata-common.h" |
27 | | #include "threads.h" |
28 | | #include "decode.h" |
29 | | |
30 | | #include "detect.h" |
31 | | #include "detect-parse.h" |
32 | | |
33 | | #include "detect-engine.h" |
34 | | #include "detect-engine-mpm.h" |
35 | | #include "detect-engine-state.h" |
36 | | |
37 | | #include "feature.h" |
38 | | |
39 | | #include "flow.h" |
40 | | #include "flow-var.h" |
41 | | #include "flow-util.h" |
42 | | |
43 | | #include "util-debug.h" |
44 | | #include "util-spm-bm.h" |
45 | | #include "util-unittest.h" |
46 | | #include "util-unittest-helper.h" |
47 | | |
48 | | #include "app-layer.h" |
49 | | #include "app-layer-parser.h" |
50 | | #include "app-layer-htp.h" |
51 | | |
52 | | #include "stream-tcp.h" |
53 | | |
54 | | #include "detect-filestore.h" |
55 | | |
56 | | #include "util-validate.h" |
57 | | |
58 | | /** |
59 | | * \brief Regex for parsing our flow options |
60 | | */ |
61 | 73 | #define PARSE_REGEX "^\\s*([A-z_]+)\\s*(?:,\\s*([A-z_]+))?\\s*(?:,\\s*([A-z_]+))?\\s*$" |
62 | | |
63 | | static DetectParseRegex parse_regex; |
64 | | |
65 | | static int DetectFilestoreMatch (DetectEngineThreadCtx *, |
66 | | Flow *, uint8_t, File *, const Signature *, const SigMatchCtx *); |
67 | | static int DetectFilestorePostMatch(DetectEngineThreadCtx *det_ctx, |
68 | | Packet *p, const Signature *s, const SigMatchCtx *ctx); |
69 | | static int DetectFilestoreSetup (DetectEngineCtx *, Signature *, const char *); |
70 | | static void DetectFilestoreFree(DetectEngineCtx *, void *); |
71 | | #ifdef UNITTESTS |
72 | | static void DetectFilestoreRegisterTests(void); |
73 | | #endif |
74 | | static int g_file_match_list_id = 0; |
75 | | |
76 | | /** |
77 | | * \brief Registration function for keyword: filestore |
78 | | */ |
79 | | void DetectFilestoreRegister(void) |
80 | 73 | { |
81 | 73 | sigmatch_table[DETECT_FILESTORE].name = "filestore"; |
82 | 73 | sigmatch_table[DETECT_FILESTORE].desc = "stores files to disk if the rule matched"; |
83 | 73 | sigmatch_table[DETECT_FILESTORE].url = "/rules/file-keywords.html#filestore"; |
84 | 73 | sigmatch_table[DETECT_FILESTORE].FileMatch = DetectFilestoreMatch; |
85 | 73 | sigmatch_table[DETECT_FILESTORE].Setup = DetectFilestoreSetup; |
86 | 73 | sigmatch_table[DETECT_FILESTORE].Free = DetectFilestoreFree; |
87 | | #ifdef UNITTESTS |
88 | | sigmatch_table[DETECT_FILESTORE].RegisterTests = DetectFilestoreRegisterTests; |
89 | | #endif |
90 | 73 | sigmatch_table[DETECT_FILESTORE].flags = SIGMATCH_OPTIONAL_OPT; |
91 | | |
92 | 73 | sigmatch_table[DETECT_FILESTORE_POSTMATCH].name = "__filestore__postmatch__"; |
93 | 73 | sigmatch_table[DETECT_FILESTORE_POSTMATCH].Match = DetectFilestorePostMatch; |
94 | 73 | sigmatch_table[DETECT_FILESTORE_POSTMATCH].Free = DetectFilestoreFree; |
95 | | |
96 | 73 | DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); |
97 | | |
98 | 73 | g_file_match_list_id = DetectBufferTypeRegister("files"); |
99 | 73 | } |
100 | | |
101 | | /** |
102 | | * \brief apply the post match filestore with options |
103 | | */ |
104 | | static int FilestorePostMatchWithOptions(Packet *p, Flow *f, const DetectFilestoreData *filestore, |
105 | | FileContainer *fc, uint32_t file_id, uint64_t tx_id) |
106 | 71 | { |
107 | 71 | if (filestore == NULL) { |
108 | 0 | SCReturnInt(0); |
109 | 0 | } |
110 | | |
111 | 71 | int this_file = 0; |
112 | 71 | int this_tx = 0; |
113 | 71 | int this_flow = 0; |
114 | 71 | int rule_dir = 0; |
115 | 71 | int toserver_dir = 0; |
116 | 71 | int toclient_dir = 0; |
117 | | |
118 | 71 | switch (filestore->direction) { |
119 | 71 | case FILESTORE_DIR_DEFAULT: |
120 | 71 | rule_dir = 1; |
121 | | // will use both sides if scope is not default |
122 | | // fallthrough |
123 | 71 | case FILESTORE_DIR_BOTH: |
124 | 71 | toserver_dir = 1; |
125 | 71 | toclient_dir = 1; |
126 | 71 | break; |
127 | 0 | case FILESTORE_DIR_TOSERVER: |
128 | 0 | toserver_dir = 1; |
129 | 0 | break; |
130 | 0 | case FILESTORE_DIR_TOCLIENT: |
131 | 0 | toclient_dir = 1; |
132 | 0 | break; |
133 | 71 | } |
134 | | |
135 | 71 | switch (filestore->scope) { |
136 | 71 | case FILESTORE_SCOPE_DEFAULT: |
137 | 71 | if (rule_dir) { |
138 | 71 | this_file = 1; |
139 | 71 | } else if ((p->flowflags & FLOW_PKT_TOCLIENT) && toclient_dir) { |
140 | 0 | this_file = 1; |
141 | 0 | } else if ((p->flowflags & FLOW_PKT_TOSERVER) && toserver_dir) { |
142 | 0 | this_file = 1; |
143 | 0 | } |
144 | 71 | break; |
145 | 0 | case FILESTORE_SCOPE_TX: |
146 | 0 | this_tx = 1; |
147 | 0 | break; |
148 | 0 | case FILESTORE_SCOPE_SSN: |
149 | 0 | this_flow = 1; |
150 | 0 | break; |
151 | 71 | } |
152 | | |
153 | 71 | if (this_file) { |
154 | 71 | FileStoreFileById(fc, file_id); |
155 | 71 | } else if (this_tx) { |
156 | | /* set in AppLayerTxData. Parsers and logger will propagate it to the |
157 | | * individual files, both new and current. */ |
158 | 0 | void *txv = AppLayerParserGetTx(f->proto, f->alproto, f->alstate, tx_id); |
159 | 0 | DEBUG_VALIDATE_BUG_ON(txv == NULL); |
160 | 0 | if (txv != NULL) { |
161 | 0 | AppLayerTxData *txd = AppLayerParserGetTxData(f->proto, f->alproto, txv); |
162 | 0 | if (txd != NULL) { |
163 | 0 | if (toclient_dir) { |
164 | 0 | txd->file_flags |= FLOWFILE_STORE_TC; |
165 | 0 | } |
166 | 0 | if (toserver_dir) { |
167 | 0 | txd->file_flags |= FLOWFILE_STORE_TS; |
168 | 0 | } |
169 | 0 | } |
170 | 0 | } |
171 | 0 | } else if (this_flow) { |
172 | | /* set in flow and AppLayerStateData */ |
173 | 0 | AppLayerStateData *sd = AppLayerParserGetStateData(f->proto, f->alproto, f->alstate); |
174 | 0 | if (toclient_dir) { |
175 | 0 | f->file_flags |= FLOWFILE_STORE_TC; |
176 | 0 | if (sd != NULL) { |
177 | 0 | sd->file_flags |= FLOWFILE_STORE_TC; |
178 | 0 | } |
179 | 0 | } |
180 | 0 | if (toserver_dir) { |
181 | 0 | f->file_flags |= FLOWFILE_STORE_TS; |
182 | 0 | if (sd != NULL) { |
183 | 0 | sd->file_flags |= FLOWFILE_STORE_TS; |
184 | 0 | } |
185 | 0 | } |
186 | 0 | } else { |
187 | 0 | FileStoreFileById(fc, file_id); |
188 | 0 | } |
189 | | |
190 | 71 | SCReturnInt(0); |
191 | 71 | } |
192 | | |
193 | | /** |
194 | | * \brief post-match function for filestore |
195 | | * |
196 | | * \param t thread local vars |
197 | | * \param det_ctx pattern matcher thread local data |
198 | | * \param p packet |
199 | | * |
200 | | * The match function for filestore records store candidates in the det_ctx. |
201 | | * When we are sure all parts of the signature matched, we run this function |
202 | | * to finalize the filestore. |
203 | | */ |
204 | | static int DetectFilestorePostMatch(DetectEngineThreadCtx *det_ctx, |
205 | | Packet *p, const Signature *s, const SigMatchCtx *ctx) |
206 | 60.4k | { |
207 | 60.4k | SCEnter(); |
208 | | |
209 | 60.4k | if (det_ctx->filestore_cnt == 0) { |
210 | 38.4k | SCReturnInt(0); |
211 | 38.4k | } |
212 | | |
213 | 22.0k | if ((s->filestore_ctx == NULL && !(s->flags & SIG_FLAG_FILESTORE)) || p->flow == NULL) { |
214 | 0 | #ifndef DEBUG |
215 | 0 | SCReturnInt(0); |
216 | | #else |
217 | | BUG_ON(1); |
218 | | #endif |
219 | 0 | } |
220 | | |
221 | 22.0k | if (p->flow->proto == IPPROTO_TCP && p->flow->protoctx != NULL) { |
222 | | /* set filestore depth for stream reassembling */ |
223 | 21.9k | TcpSession *ssn = (TcpSession *)p->flow->protoctx; |
224 | 21.9k | TcpSessionSetReassemblyDepth(ssn, FileReassemblyDepth()); |
225 | 21.9k | } |
226 | | |
227 | 22.0k | SCLogDebug("s->filestore_ctx %p", s->filestore_ctx); |
228 | | |
229 | 22.0k | const uint8_t flags = STREAM_FLAGS_FOR_PACKET(p); |
230 | 57.9k | for (uint16_t u = 0; u < det_ctx->filestore_cnt; u++) { |
231 | 35.8k | void *alstate = FlowGetAppState(p->flow); |
232 | 35.8k | AppLayerParserSetStreamDepthFlag( |
233 | 35.8k | p->flow->proto, p->flow->alproto, alstate, det_ctx->filestore[u].tx_id, flags); |
234 | | |
235 | 35.8k | void *txv = AppLayerParserGetTx( |
236 | 35.8k | p->flow->proto, p->flow->alproto, alstate, det_ctx->filestore[u].tx_id); |
237 | 35.8k | DEBUG_VALIDATE_BUG_ON(txv == NULL); |
238 | 35.8k | if (txv) { |
239 | 35.8k | AppLayerGetFileState files = AppLayerParserGetTxFiles(p->flow, alstate, txv, flags); |
240 | 35.8k | FileContainer *ffc_tx = files.fc; |
241 | 35.8k | DEBUG_VALIDATE_BUG_ON(ffc_tx == NULL); |
242 | 35.8k | if (ffc_tx) { |
243 | 35.8k | SCLogDebug("u %u txv %p ffc_tx %p file_id %u", u, txv, ffc_tx, |
244 | 35.8k | det_ctx->filestore[u].file_id); |
245 | | |
246 | | /* filestore for single files only */ |
247 | 35.8k | if (s->filestore_ctx == NULL) { |
248 | 35.7k | FileStoreFileById(ffc_tx, det_ctx->filestore[u].file_id); |
249 | 35.7k | } else { |
250 | 91 | FilestorePostMatchWithOptions(p, p->flow, s->filestore_ctx, ffc_tx, |
251 | 91 | det_ctx->filestore[u].file_id, det_ctx->filestore[u].tx_id); |
252 | 91 | } |
253 | 35.8k | } |
254 | 35.8k | } |
255 | 35.8k | } |
256 | 22.0k | SCReturnInt(0); |
257 | 22.0k | } |
258 | | |
259 | | /** |
260 | | * \brief match the specified filestore |
261 | | * |
262 | | * \param t thread local vars |
263 | | * \param det_ctx pattern matcher thread local data |
264 | | * \param f *LOCKED* flow |
265 | | * \param flags direction flags |
266 | | * \param file file being inspected |
267 | | * \param s signature being inspected |
268 | | * \param m sigmatch that we will cast into DetectFilestoreData |
269 | | * |
270 | | * \retval 0 no match |
271 | | * \retval 1 match |
272 | | * |
273 | | * \todo when we start supporting more protocols, the logic in this function |
274 | | * needs to be put behind a api. |
275 | | */ |
276 | | static int DetectFilestoreMatch (DetectEngineThreadCtx *det_ctx, Flow *f, |
277 | | uint8_t flags, File *file, const Signature *s, const SigMatchCtx *m) |
278 | 22.1k | { |
279 | 22.1k | uint32_t file_id = 0; |
280 | | |
281 | 22.1k | SCEnter(); |
282 | | |
283 | 22.1k | if (!RunmodeIsUnittests()) { |
284 | 22.1k | extern bool g_filedata_logger_enabled; |
285 | 22.1k | if (!g_filedata_logger_enabled) { |
286 | 0 | SCLogDebug("not storing file match: no filedata logger enabled"); |
287 | 0 | SCReturnInt(1); |
288 | 0 | } |
289 | 22.1k | } |
290 | 22.1k | if (det_ctx->filestore_cnt >= DETECT_FILESTORE_MAX) { |
291 | 169 | SCReturnInt(1); |
292 | 169 | } |
293 | | |
294 | | /* file can be NULL when a rule with filestore scope > file |
295 | | * matches. */ |
296 | 22.0k | if (file != NULL) { |
297 | 22.0k | file_id = file->file_track_id; |
298 | 22.0k | if (file->sid != NULL && s->id > 0) { |
299 | 22.0k | if (file->sid_cnt >= file->sid_max) { |
300 | 1 | void *p = SCRealloc(file->sid, sizeof(uint32_t) * (file->sid_max + 8)); |
301 | 1 | if (p == NULL) { |
302 | 0 | SCFree(file->sid); |
303 | 0 | file->sid = NULL; |
304 | 0 | file->sid_cnt = 0; |
305 | 0 | file->sid_max = 0; |
306 | 0 | goto continue_after_realloc_fail; |
307 | 1 | } else { |
308 | 1 | file->sid = p; |
309 | 1 | file->sid_max += 8; |
310 | 1 | } |
311 | 1 | } |
312 | 22.0k | file->sid[file->sid_cnt] = s->id; |
313 | 22.0k | file->sid_cnt++; |
314 | 22.0k | } |
315 | 22.0k | } |
316 | | |
317 | 22.0k | continue_after_realloc_fail: |
318 | | |
319 | 22.0k | det_ctx->filestore[det_ctx->filestore_cnt].file_id = file_id; |
320 | 22.0k | det_ctx->filestore[det_ctx->filestore_cnt].tx_id = det_ctx->tx_id; |
321 | | |
322 | 22.0k | SCLogDebug("%u, file %u, tx %"PRIu64, det_ctx->filestore_cnt, |
323 | 22.0k | det_ctx->filestore[det_ctx->filestore_cnt].file_id, |
324 | 22.0k | det_ctx->filestore[det_ctx->filestore_cnt].tx_id); |
325 | | |
326 | 22.0k | det_ctx->filestore_cnt++; |
327 | 22.0k | SCReturnInt(1); |
328 | 22.0k | } |
329 | | |
330 | | /** |
331 | | * \brief this function is used to parse filestore options |
332 | | * \brief into the current signature |
333 | | * |
334 | | * \param de_ctx pointer to the Detection Engine Context |
335 | | * \param s pointer to the Current Signature |
336 | | * \param str pointer to the user provided "filestore" option |
337 | | * |
338 | | * \retval 0 on Success |
339 | | * \retval -1 on Failure |
340 | | */ |
341 | | static int DetectFilestoreSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str) |
342 | 28.7k | { |
343 | 28.7k | SCEnter(); |
344 | | |
345 | 28.7k | static bool warn_not_configured = false; |
346 | 28.7k | static uint32_t de_version = 0; |
347 | | |
348 | 28.7k | if (de_ctx->filestore_cnt == UINT16_MAX) { |
349 | 0 | SCLogError("Cannot have more than 65535 filestore signatures"); |
350 | 0 | return -1; |
351 | 0 | } |
352 | | |
353 | | /* Check on first-time loads (includes following a reload) */ |
354 | 28.7k | if (!warn_not_configured || (de_ctx->version != de_version)) { |
355 | 3.57k | if (de_version != de_ctx->version) { |
356 | 3.57k | SCLogDebug("reload-detected; re-checking feature presence; DE version now %"PRIu32, |
357 | 3.57k | de_ctx->version); |
358 | 3.57k | } |
359 | 3.57k | if (!RequiresFeature(FEATURE_OUTPUT_FILESTORE)) { |
360 | 1 | SCLogWarning("One or more rule(s) depends on the " |
361 | 1 | "file-store output log which is not enabled. " |
362 | 1 | "Enable the output \"file-store\"."); |
363 | 1 | } |
364 | 3.57k | warn_not_configured = true; |
365 | 3.57k | de_version = de_ctx->version; |
366 | 3.57k | } |
367 | | |
368 | 28.7k | DetectFilestoreData *fd = NULL; |
369 | 28.7k | SigMatch *sm = NULL; |
370 | 28.7k | char *args[3] = {NULL,NULL,NULL}; |
371 | 28.7k | int res = 0; |
372 | 28.7k | size_t pcre2len; |
373 | 28.7k | pcre2_match_data *match = NULL; |
374 | | |
375 | | /* filestore and bypass keywords can't work together */ |
376 | 28.7k | if (s->flags & SIG_FLAG_BYPASS) { |
377 | 1 | SCLogError("filestore can't work with bypass keyword"); |
378 | 1 | return -1; |
379 | 1 | } |
380 | | |
381 | 28.7k | sm = SigMatchAlloc(); |
382 | 28.7k | if (sm == NULL) |
383 | 0 | goto error; |
384 | | |
385 | 28.7k | sm->type = DETECT_FILESTORE; |
386 | | |
387 | 28.7k | if (str != NULL && strlen(str) > 0) { |
388 | 8.41k | char str_0[32]; |
389 | 8.41k | char str_1[32]; |
390 | 8.41k | char str_2[32]; |
391 | 8.41k | SCLogDebug("str %s", str); |
392 | | |
393 | 8.41k | int ret = DetectParsePcreExec(&parse_regex, &match, str, 0, 0); |
394 | 8.41k | if (ret < 1 || ret > 4) { |
395 | 286 | SCLogError("parse error, ret %" PRId32 ", string %s", ret, str); |
396 | 286 | goto error; |
397 | 286 | } |
398 | | |
399 | 8.13k | if (ret > 1) { |
400 | 8.13k | pcre2len = sizeof(str_0); |
401 | 8.13k | res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)str_0, &pcre2len); |
402 | 8.13k | if (res < 0) { |
403 | 147 | SCLogError("pcre2_substring_copy_bynumber failed"); |
404 | 147 | goto error; |
405 | 147 | } |
406 | 7.98k | args[0] = (char *)str_0; |
407 | | |
408 | 7.98k | if (ret > 2) { |
409 | 2.02k | pcre2len = sizeof(str_1); |
410 | 2.02k | res = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)str_1, &pcre2len); |
411 | 2.02k | if (res < 0) { |
412 | 4 | SCLogError("pcre2_substring_copy_bynumber failed"); |
413 | 4 | goto error; |
414 | 4 | } |
415 | 2.02k | args[1] = (char *)str_1; |
416 | 2.02k | } |
417 | 7.97k | if (ret > 3) { |
418 | 1.22k | pcre2len = sizeof(str_2); |
419 | 1.22k | res = pcre2_substring_copy_bynumber(match, 3, (PCRE2_UCHAR8 *)str_2, &pcre2len); |
420 | 1.22k | if (res < 0) { |
421 | 10 | SCLogError("pcre2_substring_copy_bynumber failed"); |
422 | 10 | goto error; |
423 | 10 | } |
424 | 1.21k | args[2] = (char *)str_2; |
425 | 1.21k | } |
426 | 7.97k | } |
427 | | |
428 | 7.96k | fd = SCMalloc(sizeof(DetectFilestoreData)); |
429 | 7.96k | if (unlikely(fd == NULL)) |
430 | 0 | goto error; |
431 | 7.96k | memset(fd, 0x00, sizeof(DetectFilestoreData)); |
432 | | |
433 | 7.96k | if (args[0] != NULL) { |
434 | 7.96k | SCLogDebug("first arg %s", args[0]); |
435 | | |
436 | 7.96k | if (strcasecmp(args[0], "request") == 0 || |
437 | 7.76k | strcasecmp(args[0], "to_server") == 0) |
438 | 350 | { |
439 | 350 | fd->direction = FILESTORE_DIR_TOSERVER; |
440 | 350 | fd->scope = FILESTORE_SCOPE_TX; |
441 | 350 | } |
442 | 7.61k | else if (strcasecmp(args[0], "response") == 0 || |
443 | 7.13k | strcasecmp(args[0], "to_client") == 0) |
444 | 720 | { |
445 | 720 | fd->direction = FILESTORE_DIR_TOCLIENT; |
446 | 720 | fd->scope = FILESTORE_SCOPE_TX; |
447 | 720 | } |
448 | 6.89k | else if (strcasecmp(args[0], "both") == 0) |
449 | 266 | { |
450 | 266 | fd->direction = FILESTORE_DIR_BOTH; |
451 | 266 | fd->scope = FILESTORE_SCOPE_TX; |
452 | 266 | } |
453 | 7.96k | } else { |
454 | 0 | fd->direction = FILESTORE_DIR_DEFAULT; |
455 | 0 | } |
456 | | |
457 | 7.96k | if (args[1] != NULL) { |
458 | 2.01k | SCLogDebug("second arg %s", args[1]); |
459 | | |
460 | 2.01k | if (strcasecmp(args[1], "file") == 0) |
461 | 13 | { |
462 | 13 | fd->scope = FILESTORE_SCOPE_DEFAULT; |
463 | 1.99k | } else if (strcasecmp(args[1], "tx") == 0) |
464 | 150 | { |
465 | 150 | fd->scope = FILESTORE_SCOPE_TX; |
466 | 1.84k | } else if (strcasecmp(args[1], "ssn") == 0 || |
467 | 1.61k | strcasecmp(args[1], "flow") == 0) |
468 | 457 | { |
469 | 457 | fd->scope = FILESTORE_SCOPE_SSN; |
470 | 457 | } |
471 | 5.95k | } else { |
472 | 5.95k | if (fd->scope == 0) |
473 | 5.09k | fd->scope = FILESTORE_SCOPE_DEFAULT; |
474 | 5.95k | } |
475 | | |
476 | 7.96k | sm->ctx = (SigMatchCtx*)fd; |
477 | 20.3k | } else { |
478 | 20.3k | sm->ctx = (SigMatchCtx*)NULL; |
479 | 20.3k | } |
480 | | |
481 | 28.2k | if (s->alproto == ALPROTO_HTTP1 || s->alproto == ALPROTO_HTTP) { |
482 | 9.21k | AppLayerHtpNeedFileInspection(); |
483 | 9.21k | } |
484 | | |
485 | 28.2k | SigMatchAppendSMToList(s, sm, g_file_match_list_id); |
486 | 28.2k | s->filestore_ctx = (const DetectFilestoreData *)sm->ctx; |
487 | | |
488 | 28.2k | sm = SigMatchAlloc(); |
489 | 28.2k | if (unlikely(sm == NULL)) |
490 | 0 | goto error; |
491 | 28.2k | sm->type = DETECT_FILESTORE_POSTMATCH; |
492 | 28.2k | sm->ctx = NULL; |
493 | 28.2k | SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_POSTMATCH); |
494 | | |
495 | 28.2k | s->flags |= SIG_FLAG_FILESTORE; |
496 | 28.2k | de_ctx->filestore_cnt++; |
497 | | |
498 | 28.2k | if (match) |
499 | 28.2k | pcre2_match_data_free(match); |
500 | | |
501 | 28.2k | return 0; |
502 | | |
503 | 447 | error: |
504 | 447 | if (match) { |
505 | 447 | pcre2_match_data_free(match); |
506 | 447 | } |
507 | 447 | if (sm != NULL) |
508 | 447 | SCFree(sm); |
509 | 447 | return -1; |
510 | 28.2k | } |
511 | | |
512 | | static void DetectFilestoreFree(DetectEngineCtx *de_ctx, void *ptr) |
513 | 27.7k | { |
514 | 27.7k | if (ptr != NULL) { |
515 | 12.5k | SCFree(ptr); |
516 | 12.5k | } |
517 | 27.7k | } |
518 | | |
519 | | #ifdef UNITTESTS |
520 | | /* |
521 | | * The purpose of this test is to confirm that |
522 | | * filestore and bypass keywords can't |
523 | | * can't work together |
524 | | */ |
525 | | static int DetectFilestoreTest01(void) |
526 | | { |
527 | | DetectEngineCtx *de_ctx = NULL; |
528 | | int result = 1; |
529 | | |
530 | | de_ctx = DetectEngineCtxInit(); |
531 | | FAIL_IF(de_ctx == NULL); |
532 | | |
533 | | de_ctx->flags |= DE_QUIET; |
534 | | |
535 | | de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " |
536 | | "(bypass; filestore; " |
537 | | "content:\"message\"; http_host; " |
538 | | "sid:1;)"); |
539 | | FAIL_IF_NOT_NULL(de_ctx->sig_list); |
540 | | |
541 | | DetectEngineCtxFree(de_ctx); |
542 | | |
543 | | return result; |
544 | | } |
545 | | |
546 | | void DetectFilestoreRegisterTests(void) |
547 | | { |
548 | | UtRegisterTest("DetectFilestoreTest01", DetectFilestoreTest01); |
549 | | } |
550 | | #endif /* UNITTESTS */ |