1 /* Copyright (C) 2007-2020 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
24 #include "suricata-common.h"
25 #include "suricata.h"
26 #include "debug.h"
27 #include "detect.h"
28 #include "flow.h"
29 #include "flow-private.h"
30 #include "flow-util.h"
31 #include "flow-worker.h"
32 #include "conf.h"
33 #include "conf-yaml-loader.h"
34 #include "datasets.h"
35
36 #include "app-layer-parser.h"
37 #include "app-layer-htp.h"
38
39 #include "detect-parse.h"
40 #include "detect-engine-sigorder.h"
41
42 #include "detect-engine-siggroup.h"
43 #include "detect-engine-address.h"
44 #include "detect-engine-port.h"
45 #include "detect-engine-prefilter.h"
46 #include "detect-engine-mpm.h"
47 #include "detect-engine-iponly.h"
48 #include "detect-engine-tag.h"
49
50 #include "detect-engine-file.h"
51
52 #include "detect-engine.h"
53 #include "detect-engine-state.h"
54 #include "detect-engine-payload.h"
55 #include "detect-byte-extract.h"
56 #include "detect-content.h"
57 #include "detect-uricontent.h"
58 #include "detect-tcphdr.h"
59 #include "detect-engine-threshold.h"
60 #include "detect-engine-content-inspection.h"
61
62 #include "detect-engine-loader.h"
63
64 #include "util-classification-config.h"
65 #include "util-reference-config.h"
66 #include "util-threshold-config.h"
67 #include "util-error.h"
68 #include "util-hash.h"
69 #include "util-byte.h"
70 #include "util-debug.h"
71 #include "util-unittest.h"
72 #include "util-action.h"
73 #include "util-magic.h"
74 #include "util-signal.h"
75 #include "util-spm.h"
76 #include "util-device.h"
77 #include "util-var-name.h"
78 #include "util-profiling.h"
79 #include "util-validate.h"
80
81 #include "tm-threads.h"
82 #include "runmodes.h"
83
84 #include "reputation.h"
85
86 #define DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT 3000
87
88 static DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload(
89 ThreadVars *tv, DetectEngineCtx *new_de_ctx, int mt);
90
91 static int DetectEngineCtxLoadConf(DetectEngineCtx *);
92
93 static DetectEngineMasterCtx g_master_de_ctx = { SCMUTEX_INITIALIZER,
94 0, 99, NULL, NULL, TENANT_SELECTOR_UNKNOWN, NULL, NULL, 0};
95
96 static uint32_t TenantIdHash(HashTable *h, void *data, uint16_t data_len);
97 static char TenantIdCompare(void *d1, uint16_t d1_len, void *d2, uint16_t d2_len);
98 static void TenantIdFree(void *d);
99 static uint32_t DetectEngineTentantGetIdFromLivedev(const void *ctx, const Packet *p);
100 static uint32_t DetectEngineTentantGetIdFromVlanId(const void *ctx, const Packet *p);
101 static uint32_t DetectEngineTentantGetIdFromPcap(const void *ctx, const Packet *p);
102
103 static DetectEngineAppInspectionEngine *g_app_inspect_engines = NULL;
104 static DetectEnginePktInspectionEngine *g_pkt_inspect_engines = NULL;
105
106 SCEnumCharMap det_ctx_event_table[] = {
107 #ifdef UNITTESTS
108 { "TEST", DET_CTX_EVENT_TEST },
109 #endif
110 { "NO_MEMORY", FILE_DECODER_EVENT_NO_MEM },
111 { "INVALID_SWF_LENGTH", FILE_DECODER_EVENT_INVALID_SWF_LENGTH },
112 { "INVALID_SWF_VERSION", FILE_DECODER_EVENT_INVALID_SWF_VERSION },
113 { "Z_DATA_ERROR", FILE_DECODER_EVENT_Z_DATA_ERROR },
114 { "Z_STREAM_ERROR", FILE_DECODER_EVENT_Z_STREAM_ERROR },
115 { "Z_BUF_ERROR", FILE_DECODER_EVENT_Z_BUF_ERROR },
116 { "Z_UNKNOWN_ERROR", FILE_DECODER_EVENT_Z_UNKNOWN_ERROR },
117 { "LZMA_DECODER_ERROR", FILE_DECODER_EVENT_LZMA_DECODER_ERROR },
118 { "LZMA_MEMLIMIT_ERROR", FILE_DECODER_EVENT_LZMA_MEMLIMIT_ERROR },
119 { "LZMA_OPTIONS_ERROR", FILE_DECODER_EVENT_LZMA_OPTIONS_ERROR },
120 { "LZMA_FORMAT_ERROR", FILE_DECODER_EVENT_LZMA_FORMAT_ERROR },
121 { "LZMA_DATA_ERROR", FILE_DECODER_EVENT_LZMA_DATA_ERROR },
122 { "LZMA_BUF_ERROR", FILE_DECODER_EVENT_LZMA_BUF_ERROR },
123 { "LZMA_UNKNOWN_ERROR", FILE_DECODER_EVENT_LZMA_UNKNOWN_ERROR },
124 {
125 "TOO_MANY_BUFFERS",
126 DETECT_EVENT_TOO_MANY_BUFFERS,
127 },
128 { NULL, -1 },
129 };
130
131 /** \brief register inspect engine at start up time
132 *
133 * \note errors are fatal */
DetectPktInspectEngineRegister(const char * name,InspectionBufferGetPktDataPtr GetPktData,InspectionBufferPktInspectFunc Callback)134 void DetectPktInspectEngineRegister(const char *name,
135 InspectionBufferGetPktDataPtr GetPktData,
136 InspectionBufferPktInspectFunc Callback)
137 {
138 DetectBufferTypeRegister(name);
139 const int sm_list = DetectBufferTypeGetByName(name);
140 if (sm_list == -1) {
141 FatalError(SC_ERR_INITIALIZATION,
142 "failed to register inspect engine %s", name);
143 }
144
145 if ((sm_list < DETECT_SM_LIST_MATCH) || (sm_list >= SHRT_MAX) ||
146 (Callback == NULL))
147 {
148 SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid arguments");
149 BUG_ON(1);
150 }
151
152 DetectEnginePktInspectionEngine *new_engine = SCCalloc(1, sizeof(*new_engine));
153 if (unlikely(new_engine == NULL)) {
154 FatalError(SC_ERR_INITIALIZATION,
155 "failed to register inspect engine %s: %s", name, strerror(errno));
156 }
157 new_engine->sm_list = sm_list;
158 new_engine->sm_list_base = sm_list;
159 new_engine->v1.Callback = Callback;
160 new_engine->v1.GetData = GetPktData;
161
162 if (g_pkt_inspect_engines == NULL) {
163 g_pkt_inspect_engines = new_engine;
164 } else {
165 DetectEnginePktInspectionEngine *t = g_pkt_inspect_engines;
166 while (t->next != NULL) {
167 t = t->next;
168 }
169
170 t->next = new_engine;
171 }
172 }
173
174 /** \brief register inspect engine at start up time
175 *
176 * \note errors are fatal */
DetectAppLayerInspectEngineRegister(const char * name,AppProto alproto,uint32_t dir,int progress,InspectEngineFuncPtr Callback)177 void DetectAppLayerInspectEngineRegister(const char *name,
178 AppProto alproto, uint32_t dir,
179 int progress, InspectEngineFuncPtr Callback)
180 {
181 if (AppLayerParserIsEnabled(alproto)) {
182 if (!AppLayerParserSupportsTxDetectFlags(alproto)) {
183 FatalError(SC_ERR_INITIALIZATION,
184 "Inspect engine registered for app-layer protocol without "
185 "TX detect flag support: %s", AppProtoToString(alproto));
186 }
187 }
188 DetectBufferTypeRegister(name);
189 const int sm_list = DetectBufferTypeGetByName(name);
190 if (sm_list == -1) {
191 FatalError(SC_ERR_INITIALIZATION,
192 "failed to register inspect engine %s", name);
193 }
194
195 if ((alproto >= ALPROTO_FAILED) ||
196 (!(dir == SIG_FLAG_TOSERVER || dir == SIG_FLAG_TOCLIENT)) ||
197 (sm_list < DETECT_SM_LIST_MATCH) || (sm_list >= SHRT_MAX) ||
198 (progress < 0 || progress >= SHRT_MAX) ||
199 (Callback == NULL))
200 {
201 SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid arguments");
202 BUG_ON(1);
203 }
204
205 int direction;
206 if (dir == SIG_FLAG_TOSERVER) {
207 direction = 0;
208 } else {
209 direction = 1;
210 }
211
212 DetectEngineAppInspectionEngine *new_engine = SCMalloc(sizeof(DetectEngineAppInspectionEngine));
213 if (unlikely(new_engine == NULL)) {
214 exit(EXIT_FAILURE);
215 }
216 memset(new_engine, 0, sizeof(*new_engine));
217 new_engine->alproto = alproto;
218 new_engine->dir = direction;
219 new_engine->sm_list = sm_list;
220 new_engine->progress = progress;
221 new_engine->Callback = Callback;
222
223 if (g_app_inspect_engines == NULL) {
224 g_app_inspect_engines = new_engine;
225 } else {
226 DetectEngineAppInspectionEngine *t = g_app_inspect_engines;
227 while (t->next != NULL) {
228 t = t->next;
229 }
230
231 t->next = new_engine;
232 }
233 }
234
235 /** \brief register inspect engine at start up time
236 *
237 * \note errors are fatal */
DetectAppLayerInspectEngineRegister2(const char * name,AppProto alproto,uint32_t dir,int progress,InspectEngineFuncPtr2 Callback2,InspectionBufferGetDataPtr GetData)238 void DetectAppLayerInspectEngineRegister2(const char *name,
239 AppProto alproto, uint32_t dir, int progress,
240 InspectEngineFuncPtr2 Callback2,
241 InspectionBufferGetDataPtr GetData)
242 {
243 DetectBufferTypeRegister(name);
244 const int sm_list = DetectBufferTypeGetByName(name);
245 if (sm_list == -1) {
246 FatalError(SC_ERR_INITIALIZATION,
247 "failed to register inspect engine %s", name);
248 }
249
250 if ((alproto >= ALPROTO_FAILED) ||
251 (!(dir == SIG_FLAG_TOSERVER || dir == SIG_FLAG_TOCLIENT)) ||
252 (sm_list < DETECT_SM_LIST_MATCH) || (sm_list >= SHRT_MAX) ||
253 (progress < 0 || progress >= SHRT_MAX) ||
254 (Callback2 == NULL))
255 {
256 SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid arguments");
257 BUG_ON(1);
258 } else if (Callback2 == DetectEngineInspectBufferGeneric && GetData == NULL) {
259 SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid arguments: must register "
260 "GetData with DetectEngineInspectBufferGeneric");
261 BUG_ON(1);
262 }
263
264 int direction;
265 if (dir == SIG_FLAG_TOSERVER) {
266 direction = 0;
267 } else {
268 direction = 1;
269 }
270
271 DetectEngineAppInspectionEngine *new_engine = SCMalloc(sizeof(DetectEngineAppInspectionEngine));
272 if (unlikely(new_engine == NULL)) {
273 exit(EXIT_FAILURE);
274 }
275 memset(new_engine, 0, sizeof(*new_engine));
276 new_engine->alproto = alproto;
277 new_engine->dir = direction;
278 new_engine->sm_list = sm_list;
279 new_engine->sm_list_base = sm_list;
280 new_engine->progress = progress;
281 new_engine->v2.Callback = Callback2;
282 new_engine->v2.GetData = GetData;
283
284 if (g_app_inspect_engines == NULL) {
285 g_app_inspect_engines = new_engine;
286 } else {
287 DetectEngineAppInspectionEngine *t = g_app_inspect_engines;
288 while (t->next != NULL) {
289 t = t->next;
290 }
291
292 t->next = new_engine;
293 }
294 }
295
296 /* copy an inspect engine with transforms to a new list id. */
DetectAppLayerInspectEngineCopy(DetectEngineCtx * de_ctx,int sm_list,int new_list,const DetectEngineTransforms * transforms)297 static void DetectAppLayerInspectEngineCopy(
298 DetectEngineCtx *de_ctx,
299 int sm_list, int new_list,
300 const DetectEngineTransforms *transforms)
301 {
302 const DetectEngineAppInspectionEngine *t = g_app_inspect_engines;
303 while (t) {
304 if (t->sm_list == sm_list) {
305 DetectEngineAppInspectionEngine *new_engine = SCCalloc(1, sizeof(DetectEngineAppInspectionEngine));
306 if (unlikely(new_engine == NULL)) {
307 exit(EXIT_FAILURE);
308 }
309 new_engine->alproto = t->alproto;
310 new_engine->dir = t->dir;
311 new_engine->sm_list = new_list; /* use new list id */
312 new_engine->sm_list_base = sm_list;
313 new_engine->progress = t->progress;
314 new_engine->Callback = t->Callback;
315 new_engine->v2 = t->v2;
316 new_engine->v2.transforms = transforms; /* assign transforms */
317
318 if (de_ctx->app_inspect_engines == NULL) {
319 de_ctx->app_inspect_engines = new_engine;
320 } else {
321 DetectEngineAppInspectionEngine *list = de_ctx->app_inspect_engines;
322 while (list->next != NULL) {
323 list = list->next;
324 }
325
326 list->next = new_engine;
327 }
328 }
329 t = t->next;
330 }
331 }
332
333 /* copy inspect engines from global registrations to de_ctx list */
DetectAppLayerInspectEngineCopyListToDetectCtx(DetectEngineCtx * de_ctx)334 static void DetectAppLayerInspectEngineCopyListToDetectCtx(DetectEngineCtx *de_ctx)
335 {
336 const DetectEngineAppInspectionEngine *t = g_app_inspect_engines;
337 while (t) {
338 DetectEngineAppInspectionEngine *new_engine = SCCalloc(1, sizeof(DetectEngineAppInspectionEngine));
339 if (unlikely(new_engine == NULL)) {
340 exit(EXIT_FAILURE);
341 }
342 new_engine->alproto = t->alproto;
343 new_engine->dir = t->dir;
344 new_engine->sm_list = t->sm_list;
345 new_engine->sm_list_base = t->sm_list;
346 new_engine->progress = t->progress;
347 new_engine->Callback = t->Callback;
348 new_engine->v2 = t->v2;
349
350 if (de_ctx->app_inspect_engines == NULL) {
351 de_ctx->app_inspect_engines = new_engine;
352 } else {
353 DetectEngineAppInspectionEngine *list = de_ctx->app_inspect_engines;
354 while (list->next != NULL) {
355 list = list->next;
356 }
357
358 list->next = new_engine;
359 }
360
361 t = t->next;
362 }
363 }
364
365 /* copy an inspect engine with transforms to a new list id. */
DetectPktInspectEngineCopy(DetectEngineCtx * de_ctx,int sm_list,int new_list,const DetectEngineTransforms * transforms)366 static void DetectPktInspectEngineCopy(
367 DetectEngineCtx *de_ctx,
368 int sm_list, int new_list,
369 const DetectEngineTransforms *transforms)
370 {
371 const DetectEnginePktInspectionEngine *t = g_pkt_inspect_engines;
372 while (t) {
373 if (t->sm_list == sm_list) {
374 DetectEnginePktInspectionEngine *new_engine = SCCalloc(1, sizeof(DetectEnginePktInspectionEngine));
375 if (unlikely(new_engine == NULL)) {
376 exit(EXIT_FAILURE);
377 }
378 new_engine->sm_list = new_list; /* use new list id */
379 new_engine->sm_list_base = sm_list;
380 new_engine->v1 = t->v1;
381 new_engine->v1.transforms = transforms; /* assign transforms */
382
383 if (de_ctx->pkt_inspect_engines == NULL) {
384 de_ctx->pkt_inspect_engines = new_engine;
385 } else {
386 DetectEnginePktInspectionEngine *list = de_ctx->pkt_inspect_engines;
387 while (list->next != NULL) {
388 list = list->next;
389 }
390
391 list->next = new_engine;
392 }
393 }
394 t = t->next;
395 }
396 }
397
398 /* copy inspect engines from global registrations to de_ctx list */
DetectPktInspectEngineCopyListToDetectCtx(DetectEngineCtx * de_ctx)399 static void DetectPktInspectEngineCopyListToDetectCtx(DetectEngineCtx *de_ctx)
400 {
401 const DetectEnginePktInspectionEngine *t = g_pkt_inspect_engines;
402 while (t) {
403 SCLogDebug("engine %p", t);
404 DetectEnginePktInspectionEngine *new_engine = SCCalloc(1, sizeof(DetectEnginePktInspectionEngine));
405 if (unlikely(new_engine == NULL)) {
406 exit(EXIT_FAILURE);
407 }
408 new_engine->sm_list = t->sm_list;
409 new_engine->sm_list_base = t->sm_list;
410 new_engine->v1 = t->v1;
411
412 if (de_ctx->pkt_inspect_engines == NULL) {
413 de_ctx->pkt_inspect_engines = new_engine;
414 } else {
415 DetectEnginePktInspectionEngine *list = de_ctx->pkt_inspect_engines;
416 while (list->next != NULL) {
417 list = list->next;
418 }
419
420 list->next = new_engine;
421 }
422
423 t = t->next;
424 }
425 }
426
427 /** \internal
428 * \brief append the stream inspection
429 *
430 * If stream inspection is MPM, then prepend it.
431 */
AppendStreamInspectEngine(Signature * s,SigMatchData * stream,int direction,uint32_t id)432 static void AppendStreamInspectEngine(Signature *s, SigMatchData *stream, int direction, uint32_t id)
433 {
434 bool prepend = false;
435
436 DetectEngineAppInspectionEngine *new_engine = SCCalloc(1, sizeof(DetectEngineAppInspectionEngine));
437 if (unlikely(new_engine == NULL)) {
438 exit(EXIT_FAILURE);
439 }
440 if (SigMatchListSMBelongsTo(s, s->init_data->mpm_sm) == DETECT_SM_LIST_PMATCH) {
441 SCLogDebug("stream is mpm");
442 prepend = true;
443 new_engine->mpm = true;
444 }
445 new_engine->alproto = ALPROTO_UNKNOWN; /* all */
446 new_engine->dir = direction;
447 new_engine->stream = true;
448 new_engine->sm_list = DETECT_SM_LIST_PMATCH;
449 new_engine->sm_list_base = DETECT_SM_LIST_PMATCH;
450 new_engine->smd = stream;
451 new_engine->Callback = DetectEngineInspectStream;
452 new_engine->progress = 0;
453
454 /* append */
455 if (s->app_inspect == NULL) {
456 s->app_inspect = new_engine;
457 new_engine->id = DE_STATE_FLAG_BASE; /* id is used as flag in stateful detect */
458 } else if (prepend) {
459 new_engine->next = s->app_inspect;
460 s->app_inspect = new_engine;
461 new_engine->id = id;
462
463 } else {
464 DetectEngineAppInspectionEngine *a = s->app_inspect;
465 while (a->next != NULL) {
466 a = a->next;
467 }
468
469 a->next = new_engine;
470 new_engine->id = id;
471 }
472 SCLogDebug("sid %u: engine %p/%u added", s->id, new_engine, new_engine->id);
473 }
474
475 /**
476 * \note for the file inspect engine, the id DE_STATE_ID_FILE_INSPECT
477 * is assigned.
478 */
DetectEngineAppInspectionEngine2Signature(DetectEngineCtx * de_ctx,Signature * s)479 int DetectEngineAppInspectionEngine2Signature(DetectEngineCtx *de_ctx, Signature *s)
480 {
481 const int nlists = s->init_data->smlists_array_size;
482 SigMatchData *ptrs[nlists];
483 memset(&ptrs, 0, (nlists * sizeof(SigMatchData *)));
484
485 const int mpm_list = s->init_data->mpm_sm ?
486 SigMatchListSMBelongsTo(s, s->init_data->mpm_sm) :
487 -1;
488
489 const int files_id = DetectBufferTypeGetByName("files");
490
491 /* convert lists to SigMatchData arrays */
492 int i = 0;
493 for (i = DETECT_SM_LIST_DYNAMIC_START; i < nlists; i++) {
494 if (s->init_data->smlists[i] == NULL)
495 continue;
496
497 ptrs[i] = SigMatchList2DataArray(s->init_data->smlists[i]);
498 SCLogDebug("ptrs[%d] is set", i);
499 }
500
501 /* set up pkt inspect engines */
502 const DetectEnginePktInspectionEngine *e = de_ctx->pkt_inspect_engines;
503 while (e != NULL) {
504 SCLogDebug("e %p sm_list %u nlists %u ptrs[] %p", e, e->sm_list, nlists, e->sm_list < nlists ? ptrs[e->sm_list] : NULL);
505 if (e->sm_list < nlists && ptrs[e->sm_list] != NULL) {
506 bool prepend = false;
507
508 DetectEnginePktInspectionEngine *new_engine = SCCalloc(1, sizeof(DetectEnginePktInspectionEngine));
509 if (unlikely(new_engine == NULL)) {
510 exit(EXIT_FAILURE);
511 }
512 if (mpm_list == e->sm_list) {
513 SCLogDebug("%s is mpm", DetectBufferTypeGetNameById(de_ctx, e->sm_list));
514 prepend = true;
515 new_engine->mpm = true;
516 }
517
518 new_engine->sm_list = e->sm_list;
519 new_engine->sm_list_base = e->sm_list_base;
520 new_engine->smd = ptrs[new_engine->sm_list];
521 new_engine->v1 = e->v1;
522 SCLogDebug("sm_list %d new_engine->v1 %p/%p/%p",
523 new_engine->sm_list, new_engine->v1.Callback,
524 new_engine->v1.GetData, new_engine->v1.transforms);
525
526 if (s->pkt_inspect == NULL) {
527 s->pkt_inspect = new_engine;
528 } else if (prepend) {
529 new_engine->next = s->pkt_inspect;
530 s->pkt_inspect = new_engine;
531 } else {
532 DetectEnginePktInspectionEngine *a = s->pkt_inspect;
533 while (a->next != NULL) {
534 a = a->next;
535 }
536 new_engine->next = a->next;
537 a->next = new_engine;
538 }
539 }
540 e = e->next;
541 }
542
543 bool head_is_mpm = false;
544 uint32_t last_id = DE_STATE_FLAG_BASE;
545 const DetectEngineAppInspectionEngine *t = de_ctx->app_inspect_engines;
546 while (t != NULL) {
547 bool prepend = false;
548
549 if (t->sm_list >= nlists)
550 goto next;
551
552 if (ptrs[t->sm_list] == NULL)
553 goto next;
554
555 SCLogDebug("ptrs[%d] is set", t->sm_list);
556
557 if (t->alproto == ALPROTO_UNKNOWN) {
558 /* special case, inspect engine applies to all protocols */
559 } else if (s->alproto != ALPROTO_UNKNOWN && !AppProtoEquals(s->alproto, t->alproto))
560 goto next;
561
562 if (s->flags & SIG_FLAG_TOSERVER && !(s->flags & SIG_FLAG_TOCLIENT)) {
563 if (t->dir == 1)
564 goto next;
565 } else if (s->flags & SIG_FLAG_TOCLIENT && !(s->flags & SIG_FLAG_TOSERVER)) {
566 if (t->dir == 0)
567 goto next;
568 }
569 DetectEngineAppInspectionEngine *new_engine = SCCalloc(1, sizeof(DetectEngineAppInspectionEngine));
570 if (unlikely(new_engine == NULL)) {
571 exit(EXIT_FAILURE);
572 }
573 if (mpm_list == t->sm_list) {
574 SCLogDebug("%s is mpm", DetectBufferTypeGetNameById(de_ctx, t->sm_list));
575 prepend = true;
576 head_is_mpm = true;
577 new_engine->mpm = true;
578 }
579
580 new_engine->alproto = t->alproto;
581 new_engine->dir = t->dir;
582 new_engine->sm_list = t->sm_list;
583 new_engine->sm_list_base = t->sm_list_base;
584 new_engine->smd = ptrs[new_engine->sm_list];
585 new_engine->Callback = t->Callback;
586 new_engine->progress = t->progress;
587 new_engine->v2 = t->v2;
588 SCLogDebug("sm_list %d new_engine->v2 %p/%p/%p",
589 new_engine->sm_list, new_engine->v2.Callback,
590 new_engine->v2.GetData, new_engine->v2.transforms);
591
592 if (s->app_inspect == NULL) {
593 s->app_inspect = new_engine;
594 if (new_engine->sm_list == files_id) {
595 SCLogDebug("sid %u: engine %p/%u is FILE ENGINE", s->id, new_engine, new_engine->id);
596 new_engine->id = DE_STATE_ID_FILE_INSPECT;
597 } else {
598 new_engine->id = DE_STATE_FLAG_BASE; /* id is used as flag in stateful detect */
599 }
600
601 /* prepend engine if forced or if our engine has a lower progress. */
602 } else if (prepend || (!head_is_mpm && s->app_inspect->progress > new_engine->progress)) {
603 new_engine->next = s->app_inspect;
604 s->app_inspect = new_engine;
605 if (new_engine->sm_list == files_id) {
606 SCLogDebug("sid %u: engine %p/%u is FILE ENGINE", s->id, new_engine, new_engine->id);
607 new_engine->id = DE_STATE_ID_FILE_INSPECT;
608 } else {
609 new_engine->id = ++last_id;
610 }
611
612 } else {
613 DetectEngineAppInspectionEngine *a = s->app_inspect;
614 while (a->next != NULL) {
615 if (a->next && a->next->progress > new_engine->progress) {
616 break;
617 }
618
619 a = a->next;
620 }
621
622 new_engine->next = a->next;
623 a->next = new_engine;
624 if (new_engine->sm_list == files_id) {
625 SCLogDebug("sid %u: engine %p/%u is FILE ENGINE", s->id, new_engine, new_engine->id);
626 new_engine->id = DE_STATE_ID_FILE_INSPECT;
627 } else {
628 new_engine->id = ++last_id;
629 }
630 }
631
632 SCLogDebug("sid %u: engine %p/%u added", s->id, new_engine, new_engine->id);
633
634 s->init_data->init_flags |= SIG_FLAG_INIT_STATE_MATCH;
635 next:
636 t = t->next;
637 }
638
639 if ((s->init_data->init_flags & SIG_FLAG_INIT_STATE_MATCH) &&
640 s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL)
641 {
642 /* if engine is added multiple times, we pass it the same list */
643 SigMatchData *stream = SigMatchList2DataArray(s->init_data->smlists[DETECT_SM_LIST_PMATCH]);
644 BUG_ON(stream == NULL);
645 if (s->flags & SIG_FLAG_TOSERVER && !(s->flags & SIG_FLAG_TOCLIENT)) {
646 AppendStreamInspectEngine(s, stream, 0, last_id + 1);
647 } else if (s->flags & SIG_FLAG_TOCLIENT && !(s->flags & SIG_FLAG_TOSERVER)) {
648 AppendStreamInspectEngine(s, stream, 1, last_id + 1);
649 } else {
650 AppendStreamInspectEngine(s, stream, 0, last_id + 1);
651 AppendStreamInspectEngine(s, stream, 1, last_id + 1);
652 }
653
654 if (s->init_data->init_flags & SIG_FLAG_INIT_NEED_FLUSH) {
655 SCLogDebug("set SIG_FLAG_FLUSH on %u", s->id);
656 s->flags |= SIG_FLAG_FLUSH;
657 }
658 }
659
660 #ifdef DEBUG
661 const DetectEngineAppInspectionEngine *iter = s->app_inspect;
662 while (iter) {
663 SCLogDebug("%u: engine %s id %u progress %d %s", s->id,
664 DetectBufferTypeGetNameById(de_ctx, iter->sm_list), iter->id,
665 iter->progress,
666 iter->sm_list == mpm_list ? "MPM":"");
667 iter = iter->next;
668 }
669 #endif
670 return 0;
671 }
672
673 /** \brief free app inspect engines for a signature
674 *
675 * For lists that are registered multiple times, like http_header and
676 * http_cookie, making the engines owner of the lists is complicated.
677 * Multiple engines in a sig may be pointing to the same list. To
678 * address this the 'free' code needs to be extra careful about not
679 * double freeing, so it takes an approach to first fill an array
680 * of the to-free pointers before freeing them.
681 */
DetectEngineAppInspectionEngineSignatureFree(DetectEngineCtx * de_ctx,Signature * s)682 void DetectEngineAppInspectionEngineSignatureFree(DetectEngineCtx *de_ctx, Signature *s)
683 {
684 int nlists = 0;
685
686 DetectEngineAppInspectionEngine *ie = s->app_inspect;
687 while (ie) {
688 nlists = MAX(ie->sm_list + 1, nlists);
689 ie = ie->next;
690 }
691 DetectEnginePktInspectionEngine *e = s->pkt_inspect;
692 while (e) {
693 nlists = MAX(e->sm_list + 1, nlists);
694 e = e->next;
695 }
696 if (nlists == 0) {
697 BUG_ON(s->pkt_inspect);
698 return;
699 }
700
701 SigMatchData *ptrs[nlists];
702 memset(&ptrs, 0, (nlists * sizeof(SigMatchData *)));
703
704 /* free engines and put smd in the array */
705 ie = s->app_inspect;
706 while (ie) {
707 DetectEngineAppInspectionEngine *next = ie->next;
708 BUG_ON(ptrs[ie->sm_list] != NULL && ptrs[ie->sm_list] != ie->smd);
709 ptrs[ie->sm_list] = ie->smd;
710 SCFree(ie);
711 ie = next;
712 }
713 e = s->pkt_inspect;
714 while (e) {
715 DetectEnginePktInspectionEngine *next = e->next;
716 ptrs[e->sm_list] = e->smd;
717 SCFree(e);
718 e = next;
719 }
720
721 /* free the smds */
722 for (int i = 0; i < nlists; i++)
723 {
724 if (ptrs[i] == NULL)
725 continue;
726
727 SigMatchData *smd = ptrs[i];
728 while(1) {
729 if (sigmatch_table[smd->type].Free != NULL) {
730 sigmatch_table[smd->type].Free(de_ctx, smd->ctx);
731 }
732 if (smd->is_last)
733 break;
734 smd++;
735 }
736 SCFree(ptrs[i]);
737 }
738 }
739
740 /* code for registering buffers */
741
742 #include "util-hash-lookup3.h"
743
744 static HashListTable *g_buffer_type_hash = NULL;
745 static int g_buffer_type_id = DETECT_SM_LIST_DYNAMIC_START;
746 static int g_buffer_type_reg_closed = 0;
747
748 static DetectEngineTransforms no_transforms = {
749 .transforms[0] = {0, NULL},
750 .cnt = 0,
751 };
752
DetectBufferTypeMaxId(void)753 int DetectBufferTypeMaxId(void)
754 {
755 return g_buffer_type_id;
756 }
757
DetectBufferTypeHashFunc(HashListTable * ht,void * data,uint16_t datalen)758 static uint32_t DetectBufferTypeHashFunc(HashListTable *ht, void *data, uint16_t datalen)
759 {
760 const DetectBufferType *map = (DetectBufferType *)data;
761 uint32_t hash = 0;
762
763 hash = hashlittle_safe(map->string, strlen(map->string), 0);
764 hash += hashlittle_safe((uint8_t *)&map->transforms, sizeof(map->transforms), 0);
765 hash %= ht->array_size;
766
767 return hash;
768 }
769
DetectBufferTypeCompareFunc(void * data1,uint16_t len1,void * data2,uint16_t len2)770 static char DetectBufferTypeCompareFunc(void *data1, uint16_t len1, void *data2,
771 uint16_t len2)
772 {
773 DetectBufferType *map1 = (DetectBufferType *)data1;
774 DetectBufferType *map2 = (DetectBufferType *)data2;
775
776 int r = (strcmp(map1->string, map2->string) == 0);
777 r &= (memcmp((uint8_t *)&map1->transforms, (uint8_t *)&map2->transforms, sizeof(map2->transforms)) == 0);
778 return r;
779 }
780
DetectBufferTypeFreeFunc(void * data)781 static void DetectBufferTypeFreeFunc(void *data)
782 {
783 DetectBufferType *map = (DetectBufferType *)data;
784
785 if (map == NULL) {
786 return;
787 }
788
789 /* Release transformation option memory, if any */
790 for (int i = 0; i < map->transforms.cnt; i++) {
791 if (map->transforms.transforms[i].options == NULL)
792 continue;
793 if (sigmatch_table[map->transforms.transforms[i].transform].Free == NULL) {
794 SCLogError(SC_ERR_UNIMPLEMENTED,
795 "%s allocates transform option memory but has no free routine",
796 sigmatch_table[map->transforms.transforms[i].transform].name);
797 continue;
798 }
799 sigmatch_table[map->transforms.transforms[i].transform].Free(NULL, map->transforms.transforms[i].options);
800 }
801
802 SCFree(map);
803 }
804
DetectBufferTypeInit(void)805 static int DetectBufferTypeInit(void)
806 {
807 BUG_ON(g_buffer_type_hash);
808 g_buffer_type_hash = HashListTableInit(256,
809 DetectBufferTypeHashFunc,
810 DetectBufferTypeCompareFunc,
811 DetectBufferTypeFreeFunc);
812 if (g_buffer_type_hash == NULL)
813 return -1;
814
815 return 0;
816 }
817 #if 0
818 static void DetectBufferTypeFree(void)
819 {
820 if (g_buffer_type_hash == NULL)
821 return;
822
823 HashListTableFree(g_buffer_type_hash);
824 g_buffer_type_hash = NULL;
825 return;
826 }
827 #endif
DetectBufferTypeAdd(const char * string)828 static int DetectBufferTypeAdd(const char *string)
829 {
830 DetectBufferType *map = SCCalloc(1, sizeof(*map));
831 if (map == NULL)
832 return -1;
833
834 map->string = string;
835 map->id = g_buffer_type_id++;
836
837 BUG_ON(HashListTableAdd(g_buffer_type_hash, (void *)map, 0) != 0);
838 SCLogDebug("buffer %s registered with id %d", map->string, map->id);
839 return map->id;
840 }
841
DetectBufferTypeLookupByName(const char * string)842 static DetectBufferType *DetectBufferTypeLookupByName(const char *string)
843 {
844 DetectBufferType map = { (char *)string, NULL, 0, 0, 0, 0, false, NULL, NULL, no_transforms };
845
846 DetectBufferType *res = HashListTableLookup(g_buffer_type_hash, &map, 0);
847 return res;
848 }
849
DetectBufferTypeRegister(const char * name)850 int DetectBufferTypeRegister(const char *name)
851 {
852 BUG_ON(g_buffer_type_reg_closed);
853 if (g_buffer_type_hash == NULL)
854 DetectBufferTypeInit();
855
856 DetectBufferType *exists = DetectBufferTypeLookupByName(name);
857 if (!exists) {
858 return DetectBufferTypeAdd(name);
859 } else {
860 return exists->id;
861 }
862 }
863
DetectBufferTypeSupportsPacket(const char * name)864 void DetectBufferTypeSupportsPacket(const char *name)
865 {
866 BUG_ON(g_buffer_type_reg_closed);
867 DetectBufferTypeRegister(name);
868 DetectBufferType *exists = DetectBufferTypeLookupByName(name);
869 BUG_ON(!exists);
870 exists->packet = TRUE;
871 SCLogDebug("%p %s -- %d supports packet inspection", exists, name, exists->id);
872 }
873
DetectBufferTypeSupportsMpm(const char * name)874 void DetectBufferTypeSupportsMpm(const char *name)
875 {
876 BUG_ON(g_buffer_type_reg_closed);
877 DetectBufferTypeRegister(name);
878 DetectBufferType *exists = DetectBufferTypeLookupByName(name);
879 BUG_ON(!exists);
880 exists->mpm = TRUE;
881 SCLogDebug("%p %s -- %d supports mpm", exists, name, exists->id);
882 }
883
DetectBufferTypeSupportsTransformations(const char * name)884 void DetectBufferTypeSupportsTransformations(const char *name)
885 {
886 BUG_ON(g_buffer_type_reg_closed);
887 DetectBufferTypeRegister(name);
888 DetectBufferType *exists = DetectBufferTypeLookupByName(name);
889 BUG_ON(!exists);
890 exists->supports_transforms = true;
891 SCLogDebug("%p %s -- %d supports transformations", exists, name, exists->id);
892 }
893
DetectBufferTypeGetByName(const char * name)894 int DetectBufferTypeGetByName(const char *name)
895 {
896 DetectBufferType *exists = DetectBufferTypeLookupByName(name);
897 if (!exists) {
898 return -1;
899 }
900 return exists->id;
901 }
902
DetectBufferTypeGetNameById(const DetectEngineCtx * de_ctx,const int id)903 const char *DetectBufferTypeGetNameById(const DetectEngineCtx *de_ctx, const int id)
904 {
905 BUG_ON(id < 0 || (uint32_t)id >= de_ctx->buffer_type_map_elements);
906 BUG_ON(de_ctx->buffer_type_map == NULL);
907
908 if (de_ctx->buffer_type_map[id] == NULL)
909 return NULL;
910
911 return de_ctx->buffer_type_map[id]->string;
912 }
913
DetectBufferTypeGetById(const DetectEngineCtx * de_ctx,const int id)914 static const DetectBufferType *DetectBufferTypeGetById(const DetectEngineCtx *de_ctx, const int id)
915 {
916 BUG_ON(id < 0 || (uint32_t)id >= de_ctx->buffer_type_map_elements);
917 BUG_ON(de_ctx->buffer_type_map == NULL);
918
919 return de_ctx->buffer_type_map[id];
920 }
921
DetectBufferTypeSetDescriptionByName(const char * name,const char * desc)922 void DetectBufferTypeSetDescriptionByName(const char *name, const char *desc)
923 {
924 DetectBufferType *exists = DetectBufferTypeLookupByName(name);
925 if (!exists) {
926 return;
927 }
928 exists->description = desc;
929 }
930
DetectBufferTypeGetDescriptionById(const DetectEngineCtx * de_ctx,const int id)931 const char *DetectBufferTypeGetDescriptionById(const DetectEngineCtx *de_ctx, const int id)
932 {
933 const DetectBufferType *exists = DetectBufferTypeGetById(de_ctx, id);
934 if (!exists) {
935 return NULL;
936 }
937 return exists->description;
938 }
939
DetectBufferTypeGetDescriptionByName(const char * name)940 const char *DetectBufferTypeGetDescriptionByName(const char *name)
941 {
942 const DetectBufferType *exists = DetectBufferTypeLookupByName(name);
943 if (!exists) {
944 return NULL;
945 }
946 return exists->description;
947 }
948
DetectBufferTypeSupportsPacketGetById(const DetectEngineCtx * de_ctx,const int id)949 bool DetectBufferTypeSupportsPacketGetById(const DetectEngineCtx *de_ctx, const int id)
950 {
951 const DetectBufferType *map = DetectBufferTypeGetById(de_ctx, id);
952 if (map == NULL)
953 return FALSE;
954 SCLogDebug("map %p id %d packet? %d", map, id, map->packet);
955 return map->packet;
956 }
957
DetectBufferTypeSupportsMpmGetById(const DetectEngineCtx * de_ctx,const int id)958 bool DetectBufferTypeSupportsMpmGetById(const DetectEngineCtx *de_ctx, const int id)
959 {
960 const DetectBufferType *map = DetectBufferTypeGetById(de_ctx, id);
961 if (map == NULL)
962 return FALSE;
963 SCLogDebug("map %p id %d mpm? %d", map, id, map->mpm);
964 return map->mpm;
965 }
966
DetectBufferTypeRegisterSetupCallback(const char * name,void (* SetupCallback)(const DetectEngineCtx *,Signature *))967 void DetectBufferTypeRegisterSetupCallback(const char *name,
968 void (*SetupCallback)(const DetectEngineCtx *, Signature *))
969 {
970 BUG_ON(g_buffer_type_reg_closed);
971 DetectBufferTypeRegister(name);
972 DetectBufferType *exists = DetectBufferTypeLookupByName(name);
973 BUG_ON(!exists);
974 exists->SetupCallback = SetupCallback;
975 }
976
DetectBufferRunSetupCallback(const DetectEngineCtx * de_ctx,const int id,Signature * s)977 void DetectBufferRunSetupCallback(const DetectEngineCtx *de_ctx,
978 const int id, Signature *s)
979 {
980 const DetectBufferType *map = DetectBufferTypeGetById(de_ctx, id);
981 if (map && map->SetupCallback) {
982 map->SetupCallback(de_ctx, s);
983 }
984 }
985
DetectBufferTypeRegisterValidateCallback(const char * name,bool (* ValidateCallback)(const Signature *,const char ** sigerror))986 void DetectBufferTypeRegisterValidateCallback(const char *name,
987 bool (*ValidateCallback)(const Signature *, const char **sigerror))
988 {
989 BUG_ON(g_buffer_type_reg_closed);
990 DetectBufferTypeRegister(name);
991 DetectBufferType *exists = DetectBufferTypeLookupByName(name);
992 BUG_ON(!exists);
993 exists->ValidateCallback = ValidateCallback;
994 }
995
DetectBufferRunValidateCallback(const DetectEngineCtx * de_ctx,const int id,const Signature * s,const char ** sigerror)996 bool DetectBufferRunValidateCallback(const DetectEngineCtx *de_ctx,
997 const int id, const Signature *s, const char **sigerror)
998 {
999 const DetectBufferType *map = DetectBufferTypeGetById(de_ctx, id);
1000 if (map && map->ValidateCallback) {
1001 return map->ValidateCallback(s, sigerror);
1002 }
1003 return TRUE;
1004 }
1005
DetectBufferSetActiveList(Signature * s,const int list)1006 int DetectBufferSetActiveList(Signature *s, const int list)
1007 {
1008 BUG_ON(s->init_data == NULL);
1009
1010 if (s->init_data->list && s->init_data->transforms.cnt) {
1011 return -1;
1012 }
1013 s->init_data->list = list;
1014 s->init_data->list_set = true;
1015
1016 return 0;
1017 }
1018
DetectBufferGetActiveList(DetectEngineCtx * de_ctx,Signature * s)1019 int DetectBufferGetActiveList(DetectEngineCtx *de_ctx, Signature *s)
1020 {
1021 BUG_ON(s->init_data == NULL);
1022
1023 if (s->init_data->list && s->init_data->transforms.cnt) {
1024 if (s->init_data->list == DETECT_SM_LIST_NOTSET ||
1025 s->init_data->list < DETECT_SM_LIST_DYNAMIC_START) {
1026 SCLogError(SC_ERR_INVALID_SIGNATURE, "previous transforms not consumed "
1027 "(list: %u, transform_cnt %u)", s->init_data->list,
1028 s->init_data->transforms.cnt);
1029 SCReturnInt(-1);
1030 }
1031
1032 SCLogDebug("buffer %d has transform(s) registered: %d",
1033 s->init_data->list, s->init_data->transforms.cnt);
1034 int new_list = DetectBufferTypeGetByIdTransforms(de_ctx, s->init_data->list,
1035 s->init_data->transforms.transforms, s->init_data->transforms.cnt);
1036 if (new_list == -1) {
1037 SCReturnInt(-1);
1038 }
1039 SCLogDebug("new_list %d", new_list);
1040 s->init_data->list = new_list;
1041 s->init_data->list_set = false;
1042 // reset transforms now that we've set up the list
1043 s->init_data->transforms.cnt = 0;
1044 }
1045
1046 SCReturnInt(0);
1047 }
1048
InspectionBufferClean(DetectEngineThreadCtx * det_ctx)1049 void InspectionBufferClean(DetectEngineThreadCtx *det_ctx)
1050 {
1051 /* single buffers */
1052 for (uint32_t i = 0; i < det_ctx->inspect.to_clear_idx; i++)
1053 {
1054 const uint32_t idx = det_ctx->inspect.to_clear_queue[i];
1055 InspectionBuffer *buffer = &det_ctx->inspect.buffers[idx];
1056 buffer->inspect = NULL;
1057 }
1058 det_ctx->inspect.to_clear_idx = 0;
1059
1060 /* multi buffers */
1061 for (uint32_t i = 0; i < det_ctx->multi_inspect.to_clear_idx; i++)
1062 {
1063 const uint32_t idx = det_ctx->multi_inspect.to_clear_queue[i];
1064 InspectionBufferMultipleForList *mbuffer = &det_ctx->multi_inspect.buffers[idx];
1065 for (uint32_t x = 0; x <= mbuffer->max; x++) {
1066 InspectionBuffer *buffer = &mbuffer->inspection_buffers[x];
1067 buffer->inspect = NULL;
1068 }
1069 mbuffer->init = 0;
1070 mbuffer->max = 0;
1071 }
1072 det_ctx->multi_inspect.to_clear_idx = 0;
1073 }
1074
InspectionBufferGet(DetectEngineThreadCtx * det_ctx,const int list_id)1075 InspectionBuffer *InspectionBufferGet(DetectEngineThreadCtx *det_ctx, const int list_id)
1076 {
1077 return &det_ctx->inspect.buffers[list_id];
1078 }
1079
InspectionBufferGetMulti(DetectEngineThreadCtx * det_ctx,const int list_id)1080 static InspectionBufferMultipleForList *InspectionBufferGetMulti(
1081 DetectEngineThreadCtx *det_ctx, const int list_id)
1082 {
1083 InspectionBufferMultipleForList *buffer = &det_ctx->multi_inspect.buffers[list_id];
1084 if (!buffer->init) {
1085 det_ctx->multi_inspect.to_clear_queue[det_ctx->multi_inspect.to_clear_idx++] = list_id;
1086 buffer->init = 1;
1087 }
1088 return buffer;
1089 }
1090
1091 /** \brief for a InspectionBufferMultipleForList get a InspectionBuffer
1092 * \param fb the multiple buffer array
1093 * \param local_id the index to get a buffer
1094 * \param buffer the inspect buffer or NULL in case of error */
InspectionBufferMultipleForListGet(DetectEngineThreadCtx * det_ctx,const int list_id,const uint32_t local_id)1095 InspectionBuffer *InspectionBufferMultipleForListGet(
1096 DetectEngineThreadCtx *det_ctx, const int list_id, const uint32_t local_id)
1097 {
1098 if (unlikely(local_id >= 1024)) {
1099 DetectEngineSetEvent(det_ctx, DETECT_EVENT_TOO_MANY_BUFFERS);
1100 return NULL;
1101 }
1102
1103 InspectionBufferMultipleForList *fb = InspectionBufferGetMulti(det_ctx, list_id);
1104
1105 if (local_id >= fb->size) {
1106 uint32_t old_size = fb->size;
1107 uint32_t new_size = local_id + 1;
1108 uint32_t grow_by = new_size - old_size;
1109 SCLogDebug("size is %u, need %u, so growing by %u", old_size, new_size, grow_by);
1110
1111 SCLogDebug("fb->inspection_buffers %p", fb->inspection_buffers);
1112 void *ptr = SCRealloc(fb->inspection_buffers, (local_id + 1) * sizeof(InspectionBuffer));
1113 if (ptr == NULL)
1114 return NULL;
1115
1116 InspectionBuffer *to_zero = (InspectionBuffer *)ptr + old_size;
1117 SCLogDebug("ptr %p to_zero %p", ptr, to_zero);
1118 memset((uint8_t *)to_zero, 0, (grow_by * sizeof(InspectionBuffer)));
1119 fb->inspection_buffers = ptr;
1120 fb->size = new_size;
1121 }
1122
1123 fb->max = MAX(fb->max, local_id);
1124 InspectionBuffer *buffer = &fb->inspection_buffers[local_id];
1125 SCLogDebug("using file_data buffer %p", buffer);
1126 #ifdef DEBUG_VALIDATION
1127 buffer->multi = true;
1128 #endif
1129 return buffer;
1130 }
1131
InspectionBufferInit(InspectionBuffer * buffer,uint32_t initial_size)1132 void InspectionBufferInit(InspectionBuffer *buffer, uint32_t initial_size)
1133 {
1134 memset(buffer, 0, sizeof(*buffer));
1135 buffer->buf = SCCalloc(initial_size, sizeof(uint8_t));
1136 if (buffer->buf != NULL) {
1137 buffer->size = initial_size;
1138 }
1139 }
1140
1141 /** \brief setup the buffer with our initial data */
InspectionBufferSetupMulti(InspectionBuffer * buffer,const DetectEngineTransforms * transforms,const uint8_t * data,const uint32_t data_len)1142 void InspectionBufferSetupMulti(InspectionBuffer *buffer, const DetectEngineTransforms *transforms,
1143 const uint8_t *data, const uint32_t data_len)
1144 {
1145 DEBUG_VALIDATE_BUG_ON(!buffer->multi);
1146 buffer->inspect = buffer->orig = data;
1147 buffer->inspect_len = buffer->orig_len = data_len;
1148 buffer->len = 0;
1149
1150 InspectionBufferApplyTransforms(buffer, transforms);
1151 }
1152
1153 /** \brief setup the buffer with our initial data */
InspectionBufferSetup(DetectEngineThreadCtx * det_ctx,const int list_id,InspectionBuffer * buffer,const uint8_t * data,const uint32_t data_len)1154 void InspectionBufferSetup(DetectEngineThreadCtx *det_ctx, const int list_id,
1155 InspectionBuffer *buffer, const uint8_t *data, const uint32_t data_len)
1156 {
1157 #ifdef DEBUG_VALIDATION
1158 DEBUG_VALIDATE_BUG_ON(buffer->multi);
1159 DEBUG_VALIDATE_BUG_ON(buffer != InspectionBufferGet(det_ctx, list_id));
1160 #endif
1161 if (buffer->inspect == NULL) {
1162 #ifdef UNITTESTS
1163 if (det_ctx && list_id != -1)
1164 #endif
1165 det_ctx->inspect.to_clear_queue[det_ctx->inspect.to_clear_idx++] = list_id;
1166 }
1167 buffer->inspect = buffer->orig = data;
1168 buffer->inspect_len = buffer->orig_len = data_len;
1169 buffer->len = 0;
1170 }
1171
InspectionBufferFree(InspectionBuffer * buffer)1172 void InspectionBufferFree(InspectionBuffer *buffer)
1173 {
1174 if (buffer->buf != NULL) {
1175 SCFree(buffer->buf);
1176 }
1177 memset(buffer, 0, sizeof(*buffer));
1178 }
1179
1180 /**
1181 * \brief make sure that the buffer has at least 'min_size' bytes
1182 * Expand the buffer if necessary
1183 */
InspectionBufferCheckAndExpand(InspectionBuffer * buffer,uint32_t min_size)1184 void InspectionBufferCheckAndExpand(InspectionBuffer *buffer, uint32_t min_size)
1185 {
1186 if (likely(buffer->size >= min_size))
1187 return;
1188
1189 uint32_t new_size = (buffer->size == 0) ? 4096 : buffer->size;
1190 while (new_size < min_size) {
1191 new_size *= 2;
1192 }
1193
1194 void *ptr = SCRealloc(buffer->buf, new_size);
1195 if (ptr != NULL) {
1196 buffer->buf = ptr;
1197 buffer->size = new_size;
1198 }
1199 }
1200
InspectionBufferCopy(InspectionBuffer * buffer,uint8_t * buf,uint32_t buf_len)1201 void InspectionBufferCopy(InspectionBuffer *buffer, uint8_t *buf, uint32_t buf_len)
1202 {
1203 InspectionBufferCheckAndExpand(buffer, buf_len);
1204
1205 if (buffer->size) {
1206 uint32_t copy_size = MIN(buf_len, buffer->size);
1207 memcpy(buffer->buf, buf, copy_size);
1208 buffer->inspect = buffer->buf;
1209 buffer->inspect_len = copy_size;
1210 }
1211 }
1212
1213 /** \brief Check content byte array compatibility with transforms
1214 *
1215 * The "content" array is presented to the transforms so that each
1216 * transform may validate that it's compatible with the transform.
1217 *
1218 * When a transform indicates the byte array is incompatible, none of the
1219 * subsequent transforms, if any, are invoked. This means the first positive
1220 * validation result terminates the loop.
1221 *
1222 * \param de_ctx Detection engine context.
1223 * \param sm_list The SM list id.
1224 * \param content The byte array being validated
1225 * \param namestr returns the name of the transform that is incompatible with
1226 * content.
1227 *
1228 * \retval true (false) If any of the transforms indicate the byte array is
1229 * (is not) compatible.
1230 **/
DetectBufferTypeValidateTransform(DetectEngineCtx * de_ctx,int sm_list,const uint8_t * content,uint16_t content_len,const char ** namestr)1231 bool DetectBufferTypeValidateTransform(DetectEngineCtx *de_ctx, int sm_list,
1232 const uint8_t *content, uint16_t content_len, const char **namestr)
1233 {
1234 const DetectBufferType *dbt = DetectBufferTypeGetById(de_ctx, sm_list);
1235 BUG_ON(dbt == NULL);
1236
1237 for (int i = 0; i < dbt->transforms.cnt; i++) {
1238 const TransformData *t = &dbt->transforms.transforms[i];
1239 if (!sigmatch_table[t->transform].TransformValidate)
1240 continue;
1241
1242 if (sigmatch_table[t->transform].TransformValidate(content, content_len, t->options)) {
1243 continue;
1244 }
1245
1246 if (namestr) {
1247 *namestr = sigmatch_table[t->transform].name;
1248 }
1249
1250 return false;
1251 }
1252
1253 return true;
1254 }
1255
InspectionBufferApplyTransforms(InspectionBuffer * buffer,const DetectEngineTransforms * transforms)1256 void InspectionBufferApplyTransforms(InspectionBuffer *buffer,
1257 const DetectEngineTransforms *transforms)
1258 {
1259 if (transforms) {
1260 for (int i = 0; i < DETECT_TRANSFORMS_MAX; i++) {
1261 const int id = transforms->transforms[i].transform;
1262 if (id == 0)
1263 break;
1264 BUG_ON(sigmatch_table[id].Transform == NULL);
1265 sigmatch_table[id].Transform(buffer, transforms->transforms[i].options);
1266 SCLogDebug("applied transform %s", sigmatch_table[id].name);
1267 }
1268 }
1269 }
1270
DetectBufferTypeSetupDetectEngine(DetectEngineCtx * de_ctx)1271 static void DetectBufferTypeSetupDetectEngine(DetectEngineCtx *de_ctx)
1272 {
1273 const int size = g_buffer_type_id;
1274 BUG_ON(!(size > 0));
1275
1276 de_ctx->buffer_type_map = SCCalloc(size, sizeof(DetectBufferType *));
1277 BUG_ON(!de_ctx->buffer_type_map);
1278 de_ctx->buffer_type_map_elements = size;
1279 SCLogDebug("de_ctx->buffer_type_map %p with %u members", de_ctx->buffer_type_map, size);
1280
1281 SCLogDebug("DETECT_SM_LIST_DYNAMIC_START %u", DETECT_SM_LIST_DYNAMIC_START);
1282 HashListTableBucket *b = HashListTableGetListHead(g_buffer_type_hash);
1283 while (b) {
1284 DetectBufferType *map = HashListTableGetListData(b);
1285 de_ctx->buffer_type_map[map->id] = map;
1286 SCLogDebug("name %s id %d mpm %s packet %s -- %s. "
1287 "Callbacks: Setup %p Validate %p", map->string, map->id,
1288 map->mpm ? "true" : "false", map->packet ? "true" : "false",
1289 map->description, map->SetupCallback, map->ValidateCallback);
1290 b = HashListTableGetListNext(b);
1291 }
1292
1293 de_ctx->buffer_type_hash = HashListTableInit(256,
1294 DetectBufferTypeHashFunc,
1295 DetectBufferTypeCompareFunc,
1296 DetectBufferTypeFreeFunc);
1297 if (de_ctx->buffer_type_hash == NULL) {
1298 BUG_ON(1);
1299 }
1300 de_ctx->buffer_type_id = g_buffer_type_id;
1301
1302 PrefilterInit(de_ctx);
1303 DetectMpmInitializeAppMpms(de_ctx);
1304 DetectAppLayerInspectEngineCopyListToDetectCtx(de_ctx);
1305 DetectMpmInitializePktMpms(de_ctx);
1306 DetectPktInspectEngineCopyListToDetectCtx(de_ctx);
1307 }
1308
DetectBufferTypeFreeDetectEngine(DetectEngineCtx * de_ctx)1309 static void DetectBufferTypeFreeDetectEngine(DetectEngineCtx *de_ctx)
1310 {
1311 if (de_ctx) {
1312 if (de_ctx->buffer_type_map)
1313 SCFree(de_ctx->buffer_type_map);
1314 if (de_ctx->buffer_type_hash)
1315 HashListTableFree(de_ctx->buffer_type_hash);
1316
1317 DetectEngineAppInspectionEngine *ilist = de_ctx->app_inspect_engines;
1318 while (ilist) {
1319 DetectEngineAppInspectionEngine *next = ilist->next;
1320 SCFree(ilist);
1321 ilist = next;
1322 }
1323 DetectBufferMpmRegistery *mlist = de_ctx->app_mpms_list;
1324 while (mlist) {
1325 DetectBufferMpmRegistery *next = mlist->next;
1326 SCFree(mlist);
1327 mlist = next;
1328 }
1329 DetectEnginePktInspectionEngine *plist = de_ctx->pkt_inspect_engines;
1330 while (plist) {
1331 DetectEnginePktInspectionEngine *next = plist->next;
1332 SCFree(plist);
1333 plist = next;
1334 }
1335 DetectBufferMpmRegistery *pmlist = de_ctx->pkt_mpms_list;
1336 while (pmlist) {
1337 DetectBufferMpmRegistery *next = pmlist->next;
1338 SCFree(pmlist);
1339 pmlist = next;
1340 }
1341 PrefilterDeinit(de_ctx);
1342 }
1343 }
1344
DetectBufferTypeCloseRegistration(void)1345 void DetectBufferTypeCloseRegistration(void)
1346 {
1347 BUG_ON(g_buffer_type_hash == NULL);
1348
1349 g_buffer_type_reg_closed = 1;
1350 }
1351
DetectBufferTypeGetByIdTransforms(DetectEngineCtx * de_ctx,const int id,TransformData * transforms,int transform_cnt)1352 int DetectBufferTypeGetByIdTransforms(DetectEngineCtx *de_ctx, const int id,
1353 TransformData *transforms, int transform_cnt)
1354 {
1355 const DetectBufferType *base_map = DetectBufferTypeGetById(de_ctx, id);
1356 if (!base_map) {
1357 return -1;
1358 }
1359 if (!base_map->supports_transforms) {
1360 SCLogError(SC_ERR_INVALID_SIGNATURE, "buffer '%s' does not support transformations",
1361 base_map->string);
1362 return -1;
1363 }
1364
1365 SCLogDebug("base_map %s", base_map->string);
1366
1367 DetectEngineTransforms t;
1368 memset(&t, 0, sizeof(t));
1369 for (int i = 0; i < transform_cnt; i++) {
1370 t.transforms[i] = transforms[i];
1371 }
1372 t.cnt = transform_cnt;
1373
1374 DetectBufferType lookup_map = { (char *)base_map->string, NULL, 0, 0, 0, 0, false, NULL, NULL, t };
1375 DetectBufferType *res = HashListTableLookup(de_ctx->buffer_type_hash, &lookup_map, 0);
1376
1377 SCLogDebug("res %p", res);
1378 if (res != NULL) {
1379 return res->id;
1380 }
1381
1382 DetectBufferType *map = SCCalloc(1, sizeof(*map));
1383 if (map == NULL)
1384 return -1;
1385
1386 map->string = base_map->string;
1387 map->id = de_ctx->buffer_type_id++;
1388 map->parent_id = base_map->id;
1389 map->transforms = t;
1390 map->mpm = base_map->mpm;
1391 map->packet = base_map->packet;
1392 map->SetupCallback = base_map->SetupCallback;
1393 map->ValidateCallback = base_map->ValidateCallback;
1394 if (map->packet) {
1395 DetectPktMpmRegisterByParentId(de_ctx,
1396 map->id, map->parent_id, &map->transforms);
1397 } else {
1398 DetectAppLayerMpmRegisterByParentId(de_ctx,
1399 map->id, map->parent_id, &map->transforms);
1400 }
1401
1402 BUG_ON(HashListTableAdd(de_ctx->buffer_type_hash, (void *)map, 0) != 0);
1403 SCLogDebug("buffer %s registered with id %d, parent %d", map->string, map->id, map->parent_id);
1404
1405 if (map->id >= 0 && (uint32_t)map->id >= de_ctx->buffer_type_map_elements) {
1406 void *ptr = SCRealloc(de_ctx->buffer_type_map, (map->id + 1) * sizeof(DetectBufferType *));
1407 BUG_ON(ptr == NULL);
1408 SCLogDebug("de_ctx->buffer_type_map resized to %u (was %u)", (map->id + 1), de_ctx->buffer_type_map_elements);
1409 de_ctx->buffer_type_map = ptr;
1410 de_ctx->buffer_type_map[map->id] = map;
1411 de_ctx->buffer_type_map_elements = map->id + 1;
1412
1413 if (map->packet) {
1414 DetectPktInspectEngineCopy(de_ctx, map->parent_id, map->id,
1415 &map->transforms);
1416 } else {
1417 DetectAppLayerInspectEngineCopy(de_ctx, map->parent_id, map->id,
1418 &map->transforms);
1419 }
1420 }
1421 return map->id;
1422 }
1423
1424 /* returns false if no match, true if match */
DetectEngineInspectRulePacketMatches(DetectEngineThreadCtx * det_ctx,const DetectEnginePktInspectionEngine * engine,const Signature * s,Packet * p,uint8_t * _alert_flags)1425 static int DetectEngineInspectRulePacketMatches(
1426 DetectEngineThreadCtx *det_ctx,
1427 const DetectEnginePktInspectionEngine *engine,
1428 const Signature *s,
1429 Packet *p, uint8_t *_alert_flags)
1430 {
1431 SCEnter();
1432
1433 /* run the packet match functions */
1434 KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_MATCH);
1435 const SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_MATCH];
1436
1437 SCLogDebug("running match functions, sm %p", smd);
1438 while (1) {
1439 KEYWORD_PROFILING_START;
1440 if (sigmatch_table[smd->type].Match(det_ctx, p, s, smd->ctx) <= 0) {
1441 KEYWORD_PROFILING_END(det_ctx, smd->type, 0);
1442 SCLogDebug("no match");
1443 return false;
1444 }
1445 KEYWORD_PROFILING_END(det_ctx, smd->type, 1);
1446 if (smd->is_last) {
1447 SCLogDebug("match and is_last");
1448 break;
1449 }
1450 smd++;
1451 }
1452 return true;
1453 }
1454
DetectEngineInspectRulePayloadMatches(DetectEngineThreadCtx * det_ctx,const DetectEnginePktInspectionEngine * engine,const Signature * s,Packet * p,uint8_t * alert_flags)1455 static int DetectEngineInspectRulePayloadMatches(
1456 DetectEngineThreadCtx *det_ctx,
1457 const DetectEnginePktInspectionEngine *engine,
1458 const Signature *s, Packet *p, uint8_t *alert_flags)
1459 {
1460 SCEnter();
1461
1462 DetectEngineCtx *de_ctx = det_ctx->de_ctx;
1463
1464 KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_PMATCH);
1465 /* if we have stream msgs, inspect against those first,
1466 * but not for a "dsize" signature */
1467 if (s->flags & SIG_FLAG_REQUIRE_STREAM) {
1468 int pmatch = 0;
1469 if (p->flags & PKT_DETECT_HAS_STREAMDATA) {
1470 pmatch = DetectEngineInspectStreamPayload(de_ctx, det_ctx, s, p->flow, p);
1471 if (pmatch) {
1472 det_ctx->flags |= DETECT_ENGINE_THREAD_CTX_STREAM_CONTENT_MATCH;
1473 *alert_flags |= PACKET_ALERT_FLAG_STREAM_MATCH;
1474 }
1475 }
1476 /* no match? then inspect packet payload */
1477 if (pmatch == 0) {
1478 SCLogDebug("no match in stream, fall back to packet payload");
1479
1480 /* skip if we don't have to inspect the packet and segment was
1481 * added to stream */
1482 if (!(s->flags & SIG_FLAG_REQUIRE_PACKET) && (p->flags & PKT_STREAM_ADD)) {
1483 return false;
1484 }
1485 if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, p->flow, p) != 1) {
1486 return false;
1487 }
1488 }
1489 } else {
1490 if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, p->flow, p) != 1) {
1491 return false;
1492 }
1493 }
1494 return true;
1495 }
1496
DetectEnginePktInspectionRun(ThreadVars * tv,DetectEngineThreadCtx * det_ctx,const Signature * s,Flow * f,Packet * p,uint8_t * alert_flags)1497 bool DetectEnginePktInspectionRun(ThreadVars *tv,
1498 DetectEngineThreadCtx *det_ctx, const Signature *s,
1499 Flow *f, Packet *p,
1500 uint8_t *alert_flags)
1501 {
1502 SCEnter();
1503
1504 for (DetectEnginePktInspectionEngine *e = s->pkt_inspect; e != NULL; e = e->next) {
1505 if (e->v1.Callback(det_ctx, e, s, p, alert_flags) == false) {
1506 SCLogDebug("sid %u: e %p Callback returned false", s->id, e);
1507 return false;
1508 }
1509 SCLogDebug("sid %u: e %p Callback returned true", s->id, e);
1510 }
1511
1512 SCLogDebug("sid %u: returning true", s->id);
1513 return true;
1514 }
1515
1516 /**
1517 * \param data pointer to SigMatchData. Allowed to be NULL.
1518 */
DetectEnginePktInspectionAppend(Signature * s,InspectionBufferPktInspectFunc Callback,SigMatchData * data,const int list_id)1519 static int DetectEnginePktInspectionAppend(Signature *s, InspectionBufferPktInspectFunc Callback,
1520 SigMatchData *data, const int list_id)
1521 {
1522 DetectEnginePktInspectionEngine *e = SCCalloc(1, sizeof(*e));
1523 if (e == NULL)
1524 return -1;
1525
1526 e->sm_list = list_id;
1527 e->sm_list_base = list_id;
1528 e->v1.Callback = Callback;
1529 e->smd = data;
1530
1531 if (s->pkt_inspect == NULL) {
1532 s->pkt_inspect = e;
1533 } else {
1534 DetectEnginePktInspectionEngine *a = s->pkt_inspect;
1535 while (a->next != NULL) {
1536 a = a->next;
1537 }
1538 a->next = e;
1539 }
1540 return 0;
1541 }
1542
DetectEnginePktInspectionSetup(Signature * s)1543 int DetectEnginePktInspectionSetup(Signature *s)
1544 {
1545 /* only handle PMATCH here if we're not an app inspect rule */
1546 if (s->sm_arrays[DETECT_SM_LIST_PMATCH] && (s->init_data->init_flags & SIG_FLAG_INIT_STATE_MATCH) == 0) {
1547 if (DetectEnginePktInspectionAppend(
1548 s, DetectEngineInspectRulePayloadMatches, NULL, DETECT_SM_LIST_PMATCH) < 0)
1549 return -1;
1550 SCLogDebug("sid %u: DetectEngineInspectRulePayloadMatches appended", s->id);
1551 }
1552
1553 if (s->sm_arrays[DETECT_SM_LIST_MATCH]) {
1554 if (DetectEnginePktInspectionAppend(
1555 s, DetectEngineInspectRulePacketMatches, NULL, DETECT_SM_LIST_MATCH) < 0)
1556 return -1;
1557 SCLogDebug("sid %u: DetectEngineInspectRulePacketMatches appended", s->id);
1558 }
1559
1560 return 0;
1561 }
1562
1563 /* code to control the main thread to do a reload */
1564
1565 enum DetectEngineSyncState {
1566 IDLE, /**< ready to start a reload */
1567 RELOAD, /**< command main thread to do the reload */
1568 };
1569
1570
1571 typedef struct DetectEngineSyncer_ {
1572 SCMutex m;
1573 enum DetectEngineSyncState state;
1574 } DetectEngineSyncer;
1575
1576 static DetectEngineSyncer detect_sync = { SCMUTEX_INITIALIZER, IDLE };
1577
1578 /* tell main to start reloading */
DetectEngineReloadStart(void)1579 int DetectEngineReloadStart(void)
1580 {
1581 int r = 0;
1582 SCMutexLock(&detect_sync.m);
1583 if (detect_sync.state == IDLE) {
1584 detect_sync.state = RELOAD;
1585 } else {
1586 r = -1;
1587 }
1588 SCMutexUnlock(&detect_sync.m);
1589 return r;
1590 }
1591
1592 /* main thread checks this to see if it should start */
DetectEngineReloadIsStart(void)1593 int DetectEngineReloadIsStart(void)
1594 {
1595 int r = 0;
1596 SCMutexLock(&detect_sync.m);
1597 if (detect_sync.state == RELOAD) {
1598 r = 1;
1599 }
1600 SCMutexUnlock(&detect_sync.m);
1601 return r;
1602 }
1603
1604 /* main thread sets done when it's done */
DetectEngineReloadSetIdle(void)1605 void DetectEngineReloadSetIdle(void)
1606 {
1607 SCMutexLock(&detect_sync.m);
1608 detect_sync.state = IDLE;
1609 SCMutexUnlock(&detect_sync.m);
1610 }
1611
1612 /* caller loops this until it returns 1 */
DetectEngineReloadIsIdle(void)1613 int DetectEngineReloadIsIdle(void)
1614 {
1615 int r = 0;
1616 SCMutexLock(&detect_sync.m);
1617 if (detect_sync.state == IDLE) {
1618 r = 1;
1619 }
1620 SCMutexUnlock(&detect_sync.m);
1621 return r;
1622 }
1623
1624 /** \brief Do the content inspection & validation for a signature
1625 *
1626 * \param de_ctx Detection engine context
1627 * \param det_ctx Detection engine thread context
1628 * \param s Signature to inspect
1629 * \param sm SigMatch to inspect
1630 * \param f Flow
1631 * \param flags app layer flags
1632 * \param state App layer state
1633 *
1634 * \retval 0 no match
1635 * \retval 1 match
1636 */
DetectEngineInspectGenericList(ThreadVars * tv,const DetectEngineCtx * de_ctx,DetectEngineThreadCtx * det_ctx,const Signature * s,const SigMatchData * smd,Flow * f,const uint8_t flags,void * alstate,void * txv,uint64_t tx_id)1637 int DetectEngineInspectGenericList(ThreadVars *tv,
1638 const DetectEngineCtx *de_ctx,
1639 DetectEngineThreadCtx *det_ctx,
1640 const Signature *s, const SigMatchData *smd,
1641 Flow *f, const uint8_t flags,
1642 void *alstate, void *txv, uint64_t tx_id)
1643 {
1644 SCLogDebug("running match functions, sm %p", smd);
1645 if (smd != NULL) {
1646 while (1) {
1647 int match = 0;
1648 KEYWORD_PROFILING_START;
1649 match = sigmatch_table[smd->type].
1650 AppLayerTxMatch(det_ctx, f, flags, alstate, txv, s, smd->ctx);
1651 KEYWORD_PROFILING_END(det_ctx, smd->type, (match == 1));
1652 if (match == 0)
1653 return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
1654 if (match == 2) {
1655 return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH;
1656 }
1657
1658 if (smd->is_last)
1659 break;
1660 smd++;
1661 }
1662 }
1663
1664 return DETECT_ENGINE_INSPECT_SIG_MATCH;
1665 }
1666
1667
1668 /**
1669 * \brief Do the content inspection & validation for a signature
1670 *
1671 * \param de_ctx Detection engine context
1672 * \param det_ctx Detection engine thread context
1673 * \param s Signature to inspect
1674 * \param f Flow
1675 * \param flags app layer flags
1676 * \param state App layer state
1677 *
1678 * \retval 0 no match.
1679 * \retval 1 match.
1680 * \retval 2 Sig can't match.
1681 */
DetectEngineInspectBufferGeneric(DetectEngineCtx * de_ctx,DetectEngineThreadCtx * det_ctx,const DetectEngineAppInspectionEngine * engine,const Signature * s,Flow * f,uint8_t flags,void * alstate,void * txv,uint64_t tx_id)1682 int DetectEngineInspectBufferGeneric(
1683 DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
1684 const DetectEngineAppInspectionEngine *engine,
1685 const Signature *s,
1686 Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
1687 {
1688 const int list_id = engine->sm_list;
1689 SCLogDebug("running inspect on %d", list_id);
1690
1691 const bool eof = (AppLayerParserGetStateProgress(f->proto, f->alproto, txv, flags) > engine->progress);
1692
1693 SCLogDebug("list %d mpm? %s transforms %p",
1694 engine->sm_list, engine->mpm ? "true" : "false", engine->v2.transforms);
1695
1696 /* if prefilter didn't already run, we need to consider transformations */
1697 const DetectEngineTransforms *transforms = NULL;
1698 if (!engine->mpm) {
1699 transforms = engine->v2.transforms;
1700 }
1701
1702 const InspectionBuffer *buffer = engine->v2.GetData(det_ctx, transforms,
1703 f, flags, txv, list_id);
1704 if (unlikely(buffer == NULL)) {
1705 return eof ? DETECT_ENGINE_INSPECT_SIG_CANT_MATCH :
1706 DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
1707 }
1708
1709 const uint32_t data_len = buffer->inspect_len;
1710 const uint8_t *data = buffer->inspect;
1711 const uint64_t offset = buffer->inspect_offset;
1712
1713 uint8_t ci_flags = eof ? DETECT_CI_FLAGS_END : 0;
1714 ci_flags |= (offset == 0 ? DETECT_CI_FLAGS_START : 0);
1715 ci_flags |= buffer->flags;
1716
1717 det_ctx->discontinue_matching = 0;
1718 det_ctx->buffer_offset = 0;
1719 det_ctx->inspection_recursion_counter = 0;
1720
1721 /* Inspect all the uricontents fetched on each
1722 * transaction at the app layer */
1723 int r = DetectEngineContentInspection(de_ctx, det_ctx,
1724 s, engine->smd,
1725 NULL, f,
1726 (uint8_t *)data, data_len, offset, ci_flags,
1727 DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE);
1728 if (r == 1) {
1729 return DETECT_ENGINE_INSPECT_SIG_MATCH;
1730 } else {
1731 return eof ? DETECT_ENGINE_INSPECT_SIG_CANT_MATCH :
1732 DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
1733 }
1734 }
1735
1736 /**
1737 * \brief Do the content inspection & validation for a signature
1738 *
1739 * \param de_ctx Detection engine context
1740 * \param det_ctx Detection engine thread context
1741 * \param s Signature to inspect
1742 * \param p Packet
1743 *
1744 * \retval 0 no match.
1745 * \retval 1 match.
1746 */
DetectEngineInspectPktBufferGeneric(DetectEngineThreadCtx * det_ctx,const DetectEnginePktInspectionEngine * engine,const Signature * s,Packet * p,uint8_t * _alert_flags)1747 int DetectEngineInspectPktBufferGeneric(
1748 DetectEngineThreadCtx *det_ctx,
1749 const DetectEnginePktInspectionEngine *engine,
1750 const Signature *s, Packet *p, uint8_t *_alert_flags)
1751 {
1752 const int list_id = engine->sm_list;
1753 SCLogDebug("running inspect on %d", list_id);
1754
1755 SCLogDebug("list %d transforms %p",
1756 engine->sm_list, engine->v1.transforms);
1757
1758 /* if prefilter didn't already run, we need to consider transformations */
1759 const DetectEngineTransforms *transforms = NULL;
1760 if (!engine->mpm) {
1761 transforms = engine->v1.transforms;
1762 }
1763
1764 const InspectionBuffer *buffer = engine->v1.GetData(det_ctx, transforms, p,
1765 list_id);
1766 if (unlikely(buffer == NULL)) {
1767 return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
1768 }
1769
1770 const uint32_t data_len = buffer->inspect_len;
1771 const uint8_t *data = buffer->inspect;
1772 const uint64_t offset = 0;
1773
1774 uint8_t ci_flags = DETECT_CI_FLAGS_START|DETECT_CI_FLAGS_END;
1775 ci_flags |= buffer->flags;
1776
1777 det_ctx->discontinue_matching = 0;
1778 det_ctx->buffer_offset = 0;
1779 det_ctx->inspection_recursion_counter = 0;
1780
1781 /* Inspect all the uricontents fetched on each
1782 * transaction at the app layer */
1783 int r = DetectEngineContentInspection(det_ctx->de_ctx, det_ctx,
1784 s, engine->smd,
1785 p, p->flow,
1786 (uint8_t *)data, data_len, offset, ci_flags,
1787 DETECT_ENGINE_CONTENT_INSPECTION_MODE_HEADER);
1788 if (r == 1) {
1789 return DETECT_ENGINE_INSPECT_SIG_MATCH;
1790 } else {
1791 return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
1792 }
1793 }
1794
1795
1796 /* nudge capture loops to wake up */
BreakCapture(void)1797 static void BreakCapture(void)
1798 {
1799 SCMutexLock(&tv_root_lock);
1800 for (ThreadVars *tv = tv_root[TVT_PPT]; tv != NULL; tv = tv->next) {
1801 if ((tv->tmm_flags & TM_FLAG_RECEIVE_TM) == 0) {
1802 continue;
1803 }
1804 /* find the correct slot */
1805 for (TmSlot *s = tv->tm_slots; s != NULL; s = s->slot_next) {
1806 if (suricata_ctl_flags != 0) {
1807 SCMutexUnlock(&tv_root_lock);
1808 return;
1809 }
1810
1811 TmModule *tm = TmModuleGetById(s->tm_id);
1812 if (!(tm->flags & TM_FLAG_RECEIVE_TM)) {
1813 continue;
1814 }
1815
1816 /* signal capture method that we need a packet. */
1817 TmThreadsSetFlag(tv, THV_CAPTURE_INJECT_PKT);
1818 /* if the method supports it, BreakLoop. Otherwise we rely on
1819 * the capture method's recv timeout */
1820 if (tm->PktAcqLoop && tm->PktAcqBreakLoop) {
1821 tm->PktAcqBreakLoop(tv, SC_ATOMIC_GET(s->slot_data));
1822 }
1823 break;
1824 }
1825 }
1826 SCMutexUnlock(&tv_root_lock);
1827 }
1828
1829 /** \internal
1830 * \brief inject a pseudo packet into each detect thread that doesn't use the
1831 * new det_ctx yet
1832 */
InjectPackets(ThreadVars ** detect_tvs,DetectEngineThreadCtx ** new_det_ctx,int no_of_detect_tvs)1833 static void InjectPackets(ThreadVars **detect_tvs,
1834 DetectEngineThreadCtx **new_det_ctx,
1835 int no_of_detect_tvs)
1836 {
1837 /* inject a fake packet if the detect thread isn't using the new ctx yet,
1838 * this speeds up the process */
1839 for (int i = 0; i < no_of_detect_tvs; i++) {
1840 if (SC_ATOMIC_GET(new_det_ctx[i]->so_far_used_by_detect) != 1) {
1841 if (detect_tvs[i]->inq != NULL) {
1842 Packet *p = PacketGetFromAlloc();
1843 if (p != NULL) {
1844 p->flags |= PKT_PSEUDO_STREAM_END;
1845 PKT_SET_SRC(p, PKT_SRC_DETECT_RELOAD_FLUSH);
1846 PacketQueue *q = detect_tvs[i]->inq->pq;
1847 SCMutexLock(&q->mutex_q);
1848 PacketEnqueue(q, p);
1849 SCCondSignal(&q->cond_q);
1850 SCMutexUnlock(&q->mutex_q);
1851 }
1852 }
1853 }
1854 }
1855 }
1856
1857 /** \internal
1858 * \brief Update detect threads with new detect engine
1859 *
1860 * Atomically update each detect thread with a new thread context
1861 * that is associated to the new detection engine(s).
1862 *
1863 * If called in unix socket mode, it's possible that we don't have
1864 * detect threads yet.
1865 *
1866 * \retval -1 error
1867 * \retval 0 no detection threads
1868 * \retval 1 successful reload
1869 */
DetectEngineReloadThreads(DetectEngineCtx * new_de_ctx)1870 static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx)
1871 {
1872 SCEnter();
1873 uint32_t i = 0;
1874
1875 /* count detect threads in use */
1876 uint32_t no_of_detect_tvs = TmThreadCountThreadsByTmmFlags(TM_FLAG_DETECT_TM);
1877 /* can be zero in unix socket mode */
1878 if (no_of_detect_tvs == 0) {
1879 return 0;
1880 }
1881
1882 /* prepare swap structures */
1883 DetectEngineThreadCtx *old_det_ctx[no_of_detect_tvs];
1884 DetectEngineThreadCtx *new_det_ctx[no_of_detect_tvs];
1885 ThreadVars *detect_tvs[no_of_detect_tvs];
1886 memset(old_det_ctx, 0x00, (no_of_detect_tvs * sizeof(DetectEngineThreadCtx *)));
1887 memset(new_det_ctx, 0x00, (no_of_detect_tvs * sizeof(DetectEngineThreadCtx *)));
1888 memset(detect_tvs, 0x00, (no_of_detect_tvs * sizeof(ThreadVars *)));
1889
1890 /* start the process of swapping detect threads ctxs */
1891
1892 /* get reference to tv's and setup new_det_ctx array */
1893 SCMutexLock(&tv_root_lock);
1894 for (ThreadVars *tv = tv_root[TVT_PPT]; tv != NULL; tv = tv->next) {
1895 if ((tv->tmm_flags & TM_FLAG_DETECT_TM) == 0) {
1896 continue;
1897 }
1898 for (TmSlot *s = tv->tm_slots; s != NULL; s = s->slot_next) {
1899 TmModule *tm = TmModuleGetById(s->tm_id);
1900 if (!(tm->flags & TM_FLAG_DETECT_TM)) {
1901 continue;
1902 }
1903
1904 if (suricata_ctl_flags != 0) {
1905 SCMutexUnlock(&tv_root_lock);
1906 goto error;
1907 }
1908
1909 old_det_ctx[i] = FlowWorkerGetDetectCtxPtr(SC_ATOMIC_GET(s->slot_data));
1910 detect_tvs[i] = tv;
1911
1912 new_det_ctx[i] = DetectEngineThreadCtxInitForReload(tv, new_de_ctx, 1);
1913 if (new_det_ctx[i] == NULL) {
1914 SCLogError(SC_ERR_LIVE_RULE_SWAP, "Detect engine thread init "
1915 "failure in live rule swap. Let's get out of here");
1916 SCMutexUnlock(&tv_root_lock);
1917 goto error;
1918 }
1919 SCLogDebug("live rule swap created new det_ctx - %p and de_ctx "
1920 "- %p\n", new_det_ctx[i], new_de_ctx);
1921 i++;
1922 break;
1923 }
1924 }
1925 BUG_ON(i != no_of_detect_tvs);
1926
1927 /* atomically replace the det_ctx data */
1928 i = 0;
1929 for (ThreadVars *tv = tv_root[TVT_PPT]; tv != NULL; tv = tv->next) {
1930 if ((tv->tmm_flags & TM_FLAG_DETECT_TM) == 0) {
1931 continue;
1932 }
1933 for (TmSlot *s = tv->tm_slots; s != NULL; s = s->slot_next) {
1934 TmModule *tm = TmModuleGetById(s->tm_id);
1935 if (!(tm->flags & TM_FLAG_DETECT_TM)) {
1936 continue;
1937 }
1938 SCLogDebug("swapping new det_ctx - %p with older one - %p",
1939 new_det_ctx[i], SC_ATOMIC_GET(s->slot_data));
1940 FlowWorkerReplaceDetectCtx(SC_ATOMIC_GET(s->slot_data), new_det_ctx[i++]);
1941 break;
1942 }
1943 }
1944 SCMutexUnlock(&tv_root_lock);
1945
1946 /* threads now all have new data, however they may not have started using
1947 * it and may still use the old data */
1948
1949 SCLogDebug("Live rule swap has swapped %d old det_ctx's with new ones, "
1950 "along with the new de_ctx", no_of_detect_tvs);
1951
1952 InjectPackets(detect_tvs, new_det_ctx, no_of_detect_tvs);
1953
1954 for (i = 0; i < no_of_detect_tvs; i++) {
1955 int break_out = 0;
1956 usleep(1000);
1957 while (SC_ATOMIC_GET(new_det_ctx[i]->so_far_used_by_detect) != 1) {
1958 if (suricata_ctl_flags != 0) {
1959 break_out = 1;
1960 break;
1961 }
1962
1963 BreakCapture();
1964 usleep(1000);
1965 }
1966 if (break_out)
1967 break;
1968 SCLogDebug("new_det_ctx - %p used by detect engine", new_det_ctx[i]);
1969 }
1970
1971 /* this is to make sure that if someone initiated shutdown during a live
1972 * rule swap, the live rule swap won't clean up the old det_ctx and
1973 * de_ctx, till all detect threads have stopped working and sitting
1974 * silently after setting RUNNING_DONE flag and while waiting for
1975 * THV_DEINIT flag */
1976 if (i != no_of_detect_tvs) { // not all threads we swapped
1977 for (ThreadVars *tv = tv_root[TVT_PPT]; tv != NULL; tv = tv->next) {
1978 if ((tv->tmm_flags & TM_FLAG_DETECT_TM) == 0) {
1979 continue;
1980 }
1981
1982 while (!TmThreadsCheckFlag(tv, THV_RUNNING_DONE)) {
1983 usleep(100);
1984 }
1985 }
1986 }
1987
1988 /* free all the ctxs */
1989 for (i = 0; i < no_of_detect_tvs; i++) {
1990 SCLogDebug("Freeing old_det_ctx - %p used by detect",
1991 old_det_ctx[i]);
1992 DetectEngineThreadCtxDeinit(NULL, old_det_ctx[i]);
1993 }
1994
1995 SRepReloadComplete();
1996
1997 return 1;
1998
1999 error:
2000 for (i = 0; i < no_of_detect_tvs; i++) {
2001 if (new_det_ctx[i] != NULL)
2002 DetectEngineThreadCtxDeinit(NULL, new_det_ctx[i]);
2003 }
2004 return -1;
2005 }
2006
DetectEngineCtxInitReal(enum DetectEngineType type,const char * prefix)2007 static DetectEngineCtx *DetectEngineCtxInitReal(enum DetectEngineType type, const char *prefix)
2008 {
2009 DetectEngineCtx *de_ctx = SCMalloc(sizeof(DetectEngineCtx));
2010 if (unlikely(de_ctx == NULL))
2011 goto error;
2012
2013 memset(de_ctx,0,sizeof(DetectEngineCtx));
2014 memset(&de_ctx->sig_stat, 0, sizeof(SigFileLoaderStat));
2015 TAILQ_INIT(&de_ctx->sig_stat.failed_sigs);
2016 de_ctx->sigerror = NULL;
2017 de_ctx->type = type;
2018
2019 if (type == DETECT_ENGINE_TYPE_DD_STUB || type == DETECT_ENGINE_TYPE_MT_STUB) {
2020 de_ctx->version = DetectEngineGetVersion();
2021 SCLogDebug("stub %u with version %u", type, de_ctx->version);
2022 return de_ctx;
2023 }
2024
2025 if (prefix != NULL) {
2026 strlcpy(de_ctx->config_prefix, prefix, sizeof(de_ctx->config_prefix));
2027 }
2028
2029 if (ConfGetBool("engine.init-failure-fatal", (int *)&(de_ctx->failure_fatal)) != 1) {
2030 SCLogDebug("ConfGetBool could not load the value.");
2031 }
2032
2033 de_ctx->mpm_matcher = PatternMatchDefaultMatcher();
2034 de_ctx->spm_matcher = SinglePatternMatchDefaultMatcher();
2035 SCLogConfig("pattern matchers: MPM: %s, SPM: %s",
2036 mpm_table[de_ctx->mpm_matcher].name,
2037 spm_table[de_ctx->spm_matcher].name);
2038
2039 de_ctx->spm_global_thread_ctx = SpmInitGlobalThreadCtx(de_ctx->spm_matcher);
2040 if (de_ctx->spm_global_thread_ctx == NULL) {
2041 SCLogDebug("Unable to alloc SpmGlobalThreadCtx.");
2042 goto error;
2043 }
2044
2045 if (DetectEngineCtxLoadConf(de_ctx) == -1) {
2046 goto error;
2047 }
2048
2049 SigGroupHeadHashInit(de_ctx);
2050 MpmStoreInit(de_ctx);
2051 ThresholdHashInit(de_ctx);
2052 DetectParseDupSigHashInit(de_ctx);
2053 DetectAddressMapInit(de_ctx);
2054 DetectMetadataHashInit(de_ctx);
2055 DetectBufferTypeSetupDetectEngine(de_ctx);
2056
2057 /* init iprep... ignore errors for now */
2058 (void)SRepInit(de_ctx);
2059
2060 SCClassConfLoadClassficationConfigFile(de_ctx, NULL);
2061 SCRConfLoadReferenceConfigFile(de_ctx, NULL);
2062
2063 if (ActionInitConfig() < 0) {
2064 goto error;
2065 }
2066
2067 de_ctx->version = DetectEngineGetVersion();
2068 VarNameStoreSetupStaging(de_ctx->version);
2069 SCLogDebug("dectx with version %u", de_ctx->version);
2070 return de_ctx;
2071 error:
2072 if (de_ctx != NULL) {
2073 DetectEngineCtxFree(de_ctx);
2074 }
2075 return NULL;
2076
2077 }
2078
DetectEngineCtxInitStubForMT(void)2079 DetectEngineCtx *DetectEngineCtxInitStubForMT(void)
2080 {
2081 return DetectEngineCtxInitReal(DETECT_ENGINE_TYPE_MT_STUB, NULL);
2082 }
2083
DetectEngineCtxInitStubForDD(void)2084 DetectEngineCtx *DetectEngineCtxInitStubForDD(void)
2085 {
2086 return DetectEngineCtxInitReal(DETECT_ENGINE_TYPE_DD_STUB, NULL);
2087 }
2088
DetectEngineCtxInit(void)2089 DetectEngineCtx *DetectEngineCtxInit(void)
2090 {
2091 return DetectEngineCtxInitReal(DETECT_ENGINE_TYPE_NORMAL, NULL);
2092 }
2093
DetectEngineCtxInitWithPrefix(const char * prefix)2094 DetectEngineCtx *DetectEngineCtxInitWithPrefix(const char *prefix)
2095 {
2096 if (prefix == NULL || strlen(prefix) == 0)
2097 return DetectEngineCtxInit();
2098 else
2099 return DetectEngineCtxInitReal(DETECT_ENGINE_TYPE_NORMAL, prefix);
2100 }
2101
DetectEngineCtxFreeThreadKeywordData(DetectEngineCtx * de_ctx)2102 static void DetectEngineCtxFreeThreadKeywordData(DetectEngineCtx *de_ctx)
2103 {
2104 DetectEngineThreadKeywordCtxItem *item = de_ctx->keyword_list;
2105 while (item) {
2106 DetectEngineThreadKeywordCtxItem *next = item->next;
2107 SCFree(item);
2108 item = next;
2109 }
2110 de_ctx->keyword_list = NULL;
2111 }
2112
DetectEngineCtxFreeFailedSigs(DetectEngineCtx * de_ctx)2113 static void DetectEngineCtxFreeFailedSigs(DetectEngineCtx *de_ctx)
2114 {
2115 SigString *item = NULL;
2116 SigString *sitem;
2117
2118 TAILQ_FOREACH_SAFE(item, &de_ctx->sig_stat.failed_sigs, next, sitem) {
2119 SCFree(item->filename);
2120 SCFree(item->sig_str);
2121 if (item->sig_error) {
2122 SCFree(item->sig_error);
2123 }
2124 TAILQ_REMOVE(&de_ctx->sig_stat.failed_sigs, item, next);
2125 SCFree(item);
2126 }
2127 }
2128
2129 /**
2130 * \brief Free a DetectEngineCtx::
2131 *
2132 * \param de_ctx DetectEngineCtx:: to be freed
2133 */
DetectEngineCtxFree(DetectEngineCtx * de_ctx)2134 void DetectEngineCtxFree(DetectEngineCtx *de_ctx)
2135 {
2136
2137 if (de_ctx == NULL)
2138 return;
2139
2140 #ifdef PROFILING
2141 if (de_ctx->profile_ctx != NULL) {
2142 SCProfilingRuleDestroyCtx(de_ctx->profile_ctx);
2143 de_ctx->profile_ctx = NULL;
2144 }
2145 if (de_ctx->profile_keyword_ctx != NULL) {
2146 SCProfilingKeywordDestroyCtx(de_ctx);//->profile_keyword_ctx);
2147 // de_ctx->profile_keyword_ctx = NULL;
2148 }
2149 if (de_ctx->profile_sgh_ctx != NULL) {
2150 SCProfilingSghDestroyCtx(de_ctx);
2151 }
2152 SCProfilingPrefilterDestroyCtx(de_ctx);
2153 #endif
2154
2155 /* Normally the hashes are freed elsewhere, but
2156 * to be sure look at them again here.
2157 */
2158 SigGroupHeadHashFree(de_ctx);
2159 MpmStoreFree(de_ctx);
2160 DetectParseDupSigHashFree(de_ctx);
2161 SCSigSignatureOrderingModuleCleanup(de_ctx);
2162 ThresholdContextDestroy(de_ctx);
2163 SigCleanSignatures(de_ctx);
2164 if (de_ctx->sig_array)
2165 SCFree(de_ctx->sig_array);
2166
2167 SCClassConfDeInitContext(de_ctx);
2168 SCRConfDeInitContext(de_ctx);
2169
2170 SigGroupCleanup(de_ctx);
2171
2172 SpmDestroyGlobalThreadCtx(de_ctx->spm_global_thread_ctx);
2173
2174 MpmFactoryDeRegisterAllMpmCtxProfiles(de_ctx);
2175
2176 DetectEngineCtxFreeThreadKeywordData(de_ctx);
2177 SRepDestroy(de_ctx);
2178 DetectEngineCtxFreeFailedSigs(de_ctx);
2179
2180 DetectAddressMapFree(de_ctx);
2181 DetectMetadataHashFree(de_ctx);
2182
2183 /* if we have a config prefix, remove the config from the tree */
2184 if (strlen(de_ctx->config_prefix) > 0) {
2185 /* remove config */
2186 ConfNode *node = ConfGetNode(de_ctx->config_prefix);
2187 if (node != NULL) {
2188 ConfNodeRemove(node); /* frees node */
2189 }
2190 #if 0
2191 ConfDump();
2192 #endif
2193 }
2194
2195 DetectPortCleanupList(de_ctx, de_ctx->tcp_whitelist);
2196 DetectPortCleanupList(de_ctx, de_ctx->udp_whitelist);
2197
2198 DetectBufferTypeFreeDetectEngine(de_ctx);
2199 /* freed our var name hash */
2200 VarNameStoreFree(de_ctx->version);
2201
2202 SCFree(de_ctx);
2203 //DetectAddressGroupPrintMemory();
2204 //DetectSigGroupPrintMemory();
2205 //DetectPortPrintMemory();
2206 }
2207
2208 /** \brief Function that load DetectEngineCtx config for grouping sigs
2209 * used by the engine
2210 * \retval 0 if no config provided, 1 if config was provided
2211 * and loaded successfully
2212 */
DetectEngineCtxLoadConf(DetectEngineCtx * de_ctx)2213 static int DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx)
2214 {
2215 uint8_t profile = ENGINE_PROFILE_MEDIUM;
2216 const char *max_uniq_toclient_groups_str = NULL;
2217 const char *max_uniq_toserver_groups_str = NULL;
2218 const char *sgh_mpm_context = NULL;
2219 const char *de_ctx_profile = NULL;
2220
2221 (void)ConfGet("detect.profile", &de_ctx_profile);
2222 (void)ConfGet("detect.sgh-mpm-context", &sgh_mpm_context);
2223
2224 ConfNode *de_ctx_custom = ConfGetNode("detect-engine");
2225 ConfNode *opt = NULL;
2226
2227 if (de_ctx_custom != NULL) {
2228 TAILQ_FOREACH(opt, &de_ctx_custom->head, next) {
2229 if (de_ctx_profile == NULL) {
2230 if (opt->val && strcmp(opt->val, "profile") == 0) {
2231 de_ctx_profile = opt->head.tqh_first->val;
2232 }
2233 }
2234
2235 if (sgh_mpm_context == NULL) {
2236 if (opt->val && strcmp(opt->val, "sgh-mpm-context") == 0) {
2237 sgh_mpm_context = opt->head.tqh_first->val;
2238 }
2239 }
2240 }
2241 }
2242
2243 if (de_ctx_profile != NULL) {
2244 if (strcmp(de_ctx_profile, "low") == 0 ||
2245 strcmp(de_ctx_profile, "lowest") == 0) { // legacy
2246 profile = ENGINE_PROFILE_LOW;
2247 } else if (strcmp(de_ctx_profile, "medium") == 0) {
2248 profile = ENGINE_PROFILE_MEDIUM;
2249 } else if (strcmp(de_ctx_profile, "high") == 0 ||
2250 strcmp(de_ctx_profile, "highest") == 0) { // legacy
2251 profile = ENGINE_PROFILE_HIGH;
2252 } else if (strcmp(de_ctx_profile, "custom") == 0) {
2253 profile = ENGINE_PROFILE_CUSTOM;
2254 } else {
2255 SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY,
2256 "invalid value for detect.profile: '%s'. "
2257 "Valid options: low, medium, high and custom.",
2258 de_ctx_profile);
2259 return -1;
2260 }
2261
2262 SCLogDebug("Profile for detection engine groups is \"%s\"", de_ctx_profile);
2263 } else {
2264 SCLogDebug("Profile for detection engine groups not provided "
2265 "at suricata.yaml. Using default (\"medium\").");
2266 }
2267
2268 /* detect-engine.sgh-mpm-context option parsing */
2269 if (sgh_mpm_context == NULL || strcmp(sgh_mpm_context, "auto") == 0) {
2270 /* for now, since we still haven't implemented any intelligence into
2271 * understanding the patterns and distributing mpm_ctx across sgh */
2272 if (de_ctx->mpm_matcher == MPM_AC || de_ctx->mpm_matcher == MPM_AC_KS ||
2273 #ifdef BUILD_HYPERSCAN
2274 de_ctx->mpm_matcher == MPM_HS ||
2275 #endif
2276 de_ctx->mpm_matcher == MPM_AC_BS) {
2277 de_ctx->sgh_mpm_ctx_cnf = ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE;
2278 } else {
2279 de_ctx->sgh_mpm_ctx_cnf = ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL;
2280 }
2281 } else {
2282 if (strcmp(sgh_mpm_context, "single") == 0) {
2283 de_ctx->sgh_mpm_ctx_cnf = ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE;
2284 } else if (strcmp(sgh_mpm_context, "full") == 0) {
2285 de_ctx->sgh_mpm_ctx_cnf = ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL;
2286 } else {
2287 SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "You have supplied an "
2288 "invalid conf value for detect-engine.sgh-mpm-context-"
2289 "%s", sgh_mpm_context);
2290 exit(EXIT_FAILURE);
2291 }
2292 }
2293
2294 if (run_mode == RUNMODE_UNITTEST) {
2295 de_ctx->sgh_mpm_ctx_cnf = ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL;
2296 }
2297
2298 /* parse profile custom-values */
2299 opt = NULL;
2300 switch (profile) {
2301 case ENGINE_PROFILE_LOW:
2302 de_ctx->max_uniq_toclient_groups = 15;
2303 de_ctx->max_uniq_toserver_groups = 25;
2304 break;
2305
2306 case ENGINE_PROFILE_HIGH:
2307 de_ctx->max_uniq_toclient_groups = 75;
2308 de_ctx->max_uniq_toserver_groups = 75;
2309 break;
2310
2311 case ENGINE_PROFILE_CUSTOM:
2312 (void)ConfGet("detect.custom-values.toclient-groups",
2313 &max_uniq_toclient_groups_str);
2314 (void)ConfGet("detect.custom-values.toserver-groups",
2315 &max_uniq_toserver_groups_str);
2316
2317 if (de_ctx_custom != NULL) {
2318 TAILQ_FOREACH(opt, &de_ctx_custom->head, next) {
2319 if (opt->val && strcmp(opt->val, "custom-values") == 0) {
2320 if (max_uniq_toclient_groups_str == NULL) {
2321 max_uniq_toclient_groups_str = (char *)ConfNodeLookupChildValue
2322 (opt->head.tqh_first, "toclient-sp-groups");
2323 }
2324 if (max_uniq_toclient_groups_str == NULL) {
2325 max_uniq_toclient_groups_str = (char *)ConfNodeLookupChildValue
2326 (opt->head.tqh_first, "toclient-groups");
2327 }
2328 if (max_uniq_toserver_groups_str == NULL) {
2329 max_uniq_toserver_groups_str = (char *)ConfNodeLookupChildValue
2330 (opt->head.tqh_first, "toserver-dp-groups");
2331 }
2332 if (max_uniq_toserver_groups_str == NULL) {
2333 max_uniq_toserver_groups_str = (char *)ConfNodeLookupChildValue
2334 (opt->head.tqh_first, "toserver-groups");
2335 }
2336 }
2337 }
2338 }
2339 if (max_uniq_toclient_groups_str != NULL) {
2340 if (StringParseUint16(&de_ctx->max_uniq_toclient_groups, 10,
2341 strlen(max_uniq_toclient_groups_str),
2342 (const char *)max_uniq_toclient_groups_str) <= 0)
2343 {
2344 de_ctx->max_uniq_toclient_groups = 20;
2345
2346 SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for "
2347 "toclient-groups failed, using %u",
2348 max_uniq_toclient_groups_str,
2349 de_ctx->max_uniq_toclient_groups);
2350 }
2351 } else {
2352 de_ctx->max_uniq_toclient_groups = 20;
2353 }
2354 SCLogConfig("toclient-groups %u", de_ctx->max_uniq_toclient_groups);
2355
2356 if (max_uniq_toserver_groups_str != NULL) {
2357 if (StringParseUint16(&de_ctx->max_uniq_toserver_groups, 10,
2358 strlen(max_uniq_toserver_groups_str),
2359 (const char *)max_uniq_toserver_groups_str) <= 0)
2360 {
2361 de_ctx->max_uniq_toserver_groups = 40;
2362
2363 SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for "
2364 "toserver-groups failed, using %u",
2365 max_uniq_toserver_groups_str,
2366 de_ctx->max_uniq_toserver_groups);
2367 }
2368 } else {
2369 de_ctx->max_uniq_toserver_groups = 40;
2370 }
2371 SCLogConfig("toserver-groups %u", de_ctx->max_uniq_toserver_groups);
2372 break;
2373
2374 /* Default (or no config provided) is profile medium */
2375 case ENGINE_PROFILE_MEDIUM:
2376 case ENGINE_PROFILE_UNKNOWN:
2377 default:
2378 de_ctx->max_uniq_toclient_groups = 20;
2379 de_ctx->max_uniq_toserver_groups = 40;
2380 break;
2381 }
2382
2383 intmax_t value = 0;
2384 if (ConfGetInt("detect.inspection-recursion-limit", &value) == 1)
2385 {
2386 if (value >= 0 && value <= INT_MAX) {
2387 de_ctx->inspection_recursion_limit = (int)value;
2388 }
2389
2390 /* fall back to old config parsing */
2391 } else {
2392 ConfNode *insp_recursion_limit_node = NULL;
2393 char *insp_recursion_limit = NULL;
2394
2395 if (de_ctx_custom != NULL) {
2396 opt = NULL;
2397 TAILQ_FOREACH(opt, &de_ctx_custom->head, next) {
2398 if (opt->val && strcmp(opt->val, "inspection-recursion-limit") != 0)
2399 continue;
2400
2401 insp_recursion_limit_node = ConfNodeLookupChild(opt, opt->val);
2402 if (insp_recursion_limit_node == NULL) {
2403 SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Error retrieving conf "
2404 "entry for detect-engine:inspection-recursion-limit");
2405 break;
2406 }
2407 insp_recursion_limit = insp_recursion_limit_node->val;
2408 SCLogDebug("Found detect-engine.inspection-recursion-limit - %s:%s",
2409 insp_recursion_limit_node->name, insp_recursion_limit_node->val);
2410 break;
2411 }
2412
2413 if (insp_recursion_limit != NULL) {
2414 if (StringParseInt32(&de_ctx->inspection_recursion_limit, 10,
2415 0, (const char *)insp_recursion_limit) < 0) {
2416 SCLogWarning(SC_ERR_INVALID_VALUE, "Invalid value for "
2417 "detect-engine.inspection-recursion-limit: %s "
2418 "resetting to %d", insp_recursion_limit,
2419 DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT);
2420 de_ctx->inspection_recursion_limit =
2421 DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT;
2422 }
2423 } else {
2424 de_ctx->inspection_recursion_limit =
2425 DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT;
2426 }
2427 }
2428 }
2429
2430 if (de_ctx->inspection_recursion_limit == 0)
2431 de_ctx->inspection_recursion_limit = -1;
2432
2433 SCLogDebug("de_ctx->inspection_recursion_limit: %d",
2434 de_ctx->inspection_recursion_limit);
2435
2436 /* parse port grouping whitelisting settings */
2437
2438 const char *ports = NULL;
2439 (void)ConfGet("detect.grouping.tcp-whitelist", &ports);
2440 if (ports) {
2441 SCLogConfig("grouping: tcp-whitelist %s", ports);
2442 } else {
2443 ports = "53, 80, 139, 443, 445, 1433, 3306, 3389, 6666, 6667, 8080";
2444 SCLogConfig("grouping: tcp-whitelist (default) %s", ports);
2445
2446 }
2447 if (DetectPortParse(de_ctx, &de_ctx->tcp_whitelist, ports) != 0) {
2448 SCLogWarning(SC_ERR_INVALID_YAML_CONF_ENTRY, "'%s' is not a valid value "
2449 "for detect.grouping.tcp-whitelist", ports);
2450 }
2451 DetectPort *x = de_ctx->tcp_whitelist;
2452 for ( ; x != NULL; x = x->next) {
2453 if (x->port != x->port2) {
2454 SCLogWarning(SC_ERR_INVALID_YAML_CONF_ENTRY, "'%s' is not a valid value "
2455 "for detect.grouping.tcp-whitelist: only single ports allowed", ports);
2456 DetectPortCleanupList(de_ctx, de_ctx->tcp_whitelist);
2457 de_ctx->tcp_whitelist = NULL;
2458 break;
2459 }
2460 }
2461
2462 ports = NULL;
2463 (void)ConfGet("detect.grouping.udp-whitelist", &ports);
2464 if (ports) {
2465 SCLogConfig("grouping: udp-whitelist %s", ports);
2466 } else {
2467 ports = "53, 135, 5060";
2468 SCLogConfig("grouping: udp-whitelist (default) %s", ports);
2469
2470 }
2471 if (DetectPortParse(de_ctx, &de_ctx->udp_whitelist, ports) != 0) {
2472 SCLogWarning(SC_ERR_INVALID_YAML_CONF_ENTRY, "'%s' is not a valid value "
2473 "forr detect.grouping.udp-whitelist", ports);
2474 }
2475 for (x = de_ctx->udp_whitelist; x != NULL; x = x->next) {
2476 if (x->port != x->port2) {
2477 SCLogWarning(SC_ERR_INVALID_YAML_CONF_ENTRY, "'%s' is not a valid value "
2478 "for detect.grouping.udp-whitelist: only single ports allowed", ports);
2479 DetectPortCleanupList(de_ctx, de_ctx->udp_whitelist);
2480 de_ctx->udp_whitelist = NULL;
2481 break;
2482 }
2483 }
2484
2485 de_ctx->prefilter_setting = DETECT_PREFILTER_MPM;
2486 const char *pf_setting = NULL;
2487 if (ConfGet("detect.prefilter.default", &pf_setting) == 1 && pf_setting) {
2488 if (strcasecmp(pf_setting, "mpm") == 0) {
2489 de_ctx->prefilter_setting = DETECT_PREFILTER_MPM;
2490 } else if (strcasecmp(pf_setting, "auto") == 0) {
2491 de_ctx->prefilter_setting = DETECT_PREFILTER_AUTO;
2492 }
2493 }
2494 switch (de_ctx->prefilter_setting) {
2495 case DETECT_PREFILTER_MPM:
2496 SCLogConfig("prefilter engines: MPM");
2497 break;
2498 case DETECT_PREFILTER_AUTO:
2499 SCLogConfig("prefilter engines: MPM and keywords");
2500 break;
2501 }
2502
2503 return 0;
2504 }
2505
2506 /*
2507 * getting & (re)setting the internal sig i
2508 */
2509
2510 //inline uint32_t DetectEngineGetMaxSigId(DetectEngineCtx *de_ctx)
2511 //{
2512 // return de_ctx->signum;
2513 //}
2514
DetectEngineResetMaxSigId(DetectEngineCtx * de_ctx)2515 void DetectEngineResetMaxSigId(DetectEngineCtx *de_ctx)
2516 {
2517 de_ctx->signum = 0;
2518 }
2519
DetectEngineThreadCtxInitGlobalKeywords(DetectEngineThreadCtx * det_ctx)2520 static int DetectEngineThreadCtxInitGlobalKeywords(DetectEngineThreadCtx *det_ctx)
2521 {
2522 const DetectEngineMasterCtx *master = &g_master_de_ctx;
2523
2524 if (master->keyword_id > 0) {
2525 // coverity[suspicious_sizeof : FALSE]
2526 det_ctx->global_keyword_ctxs_array = (void **)SCCalloc(master->keyword_id, sizeof(void *));
2527 if (det_ctx->global_keyword_ctxs_array == NULL) {
2528 SCLogError(SC_ERR_DETECT_PREPARE, "setting up thread local detect ctx");
2529 return TM_ECODE_FAILED;
2530 }
2531 det_ctx->global_keyword_ctxs_size = master->keyword_id;
2532
2533 const DetectEngineThreadKeywordCtxItem *item = master->keyword_list;
2534 while (item) {
2535 det_ctx->global_keyword_ctxs_array[item->id] = item->InitFunc(item->data);
2536 if (det_ctx->global_keyword_ctxs_array[item->id] == NULL) {
2537 SCLogError(SC_ERR_DETECT_PREPARE, "setting up thread local detect ctx "
2538 "for keyword \"%s\" failed", item->name);
2539 return TM_ECODE_FAILED;
2540 }
2541 item = item->next;
2542 }
2543 }
2544 return TM_ECODE_OK;
2545 }
2546
DetectEngineThreadCtxDeinitGlobalKeywords(DetectEngineThreadCtx * det_ctx)2547 static void DetectEngineThreadCtxDeinitGlobalKeywords(DetectEngineThreadCtx *det_ctx)
2548 {
2549 if (det_ctx->global_keyword_ctxs_array == NULL ||
2550 det_ctx->global_keyword_ctxs_size == 0) {
2551 return;
2552 }
2553
2554 const DetectEngineMasterCtx *master = &g_master_de_ctx;
2555 if (master->keyword_id > 0) {
2556 const DetectEngineThreadKeywordCtxItem *item = master->keyword_list;
2557 while (item) {
2558 if (det_ctx->global_keyword_ctxs_array[item->id] != NULL)
2559 item->FreeFunc(det_ctx->global_keyword_ctxs_array[item->id]);
2560
2561 item = item->next;
2562 }
2563 det_ctx->global_keyword_ctxs_size = 0;
2564 SCFree(det_ctx->global_keyword_ctxs_array);
2565 det_ctx->global_keyword_ctxs_array = NULL;
2566 }
2567 }
2568
DetectEngineThreadCtxInitKeywords(DetectEngineCtx * de_ctx,DetectEngineThreadCtx * det_ctx)2569 static int DetectEngineThreadCtxInitKeywords(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx)
2570 {
2571 if (de_ctx->keyword_id > 0) {
2572 // coverity[suspicious_sizeof : FALSE]
2573 det_ctx->keyword_ctxs_array = SCMalloc(de_ctx->keyword_id * sizeof(void *));
2574 if (det_ctx->keyword_ctxs_array == NULL) {
2575 SCLogError(SC_ERR_DETECT_PREPARE, "setting up thread local detect ctx");
2576 return TM_ECODE_FAILED;
2577 }
2578
2579 memset(det_ctx->keyword_ctxs_array, 0x00, de_ctx->keyword_id * sizeof(void *));
2580
2581 det_ctx->keyword_ctxs_size = de_ctx->keyword_id;
2582
2583 DetectEngineThreadKeywordCtxItem *item = de_ctx->keyword_list;
2584 while (item) {
2585 det_ctx->keyword_ctxs_array[item->id] = item->InitFunc(item->data);
2586 if (det_ctx->keyword_ctxs_array[item->id] == NULL) {
2587 SCLogError(SC_ERR_DETECT_PREPARE, "setting up thread local detect ctx "
2588 "for keyword \"%s\" failed", item->name);
2589 return TM_ECODE_FAILED;
2590 }
2591 item = item->next;
2592 }
2593 }
2594 return TM_ECODE_OK;
2595 }
2596
DetectEngineThreadCtxDeinitKeywords(DetectEngineCtx * de_ctx,DetectEngineThreadCtx * det_ctx)2597 static void DetectEngineThreadCtxDeinitKeywords(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx)
2598 {
2599 if (de_ctx->keyword_id > 0) {
2600 DetectEngineThreadKeywordCtxItem *item = de_ctx->keyword_list;
2601 while (item) {
2602 if (det_ctx->keyword_ctxs_array[item->id] != NULL)
2603 item->FreeFunc(det_ctx->keyword_ctxs_array[item->id]);
2604
2605 item = item->next;
2606 }
2607 det_ctx->keyword_ctxs_size = 0;
2608 SCFree(det_ctx->keyword_ctxs_array);
2609 det_ctx->keyword_ctxs_array = NULL;
2610 }
2611 }
2612
2613 /** NOTE: master MUST be locked before calling this */
DetectEngineThreadCtxInitForMT(ThreadVars * tv,DetectEngineThreadCtx * det_ctx)2614 static TmEcode DetectEngineThreadCtxInitForMT(ThreadVars *tv, DetectEngineThreadCtx *det_ctx)
2615 {
2616 DetectEngineMasterCtx *master = &g_master_de_ctx;
2617 DetectEngineTenantMapping *map_array = NULL;
2618 uint32_t map_array_size = 0;
2619 uint32_t map_cnt = 0;
2620 int max_tenant_id = 0;
2621 DetectEngineCtx *list = master->list;
2622 HashTable *mt_det_ctxs_hash = NULL;
2623
2624 if (master->tenant_selector == TENANT_SELECTOR_UNKNOWN) {
2625 SCLogError(SC_ERR_MT_NO_SELECTOR, "no tenant selector set: "
2626 "set using multi-detect.selector");
2627 return TM_ECODE_FAILED;
2628 }
2629
2630 uint32_t tcnt = 0;
2631 while (list) {
2632 if (list->tenant_id > max_tenant_id)
2633 max_tenant_id = list->tenant_id;
2634
2635 list = list->next;
2636 tcnt++;
2637 }
2638
2639 mt_det_ctxs_hash = HashTableInit(tcnt * 2, TenantIdHash, TenantIdCompare, TenantIdFree);
2640 if (mt_det_ctxs_hash == NULL) {
2641 goto error;
2642 }
2643
2644 if (tcnt == 0) {
2645 SCLogInfo("no tenants left, or none registered yet");
2646 } else {
2647 max_tenant_id++;
2648
2649 DetectEngineTenantMapping *map = master->tenant_mapping_list;
2650 while (map) {
2651 map_cnt++;
2652 map = map->next;
2653 }
2654
2655 if (map_cnt > 0) {
2656 map_array_size = map_cnt + 1;
2657
2658 map_array = SCCalloc(map_array_size, sizeof(*map_array));
2659 if (map_array == NULL)
2660 goto error;
2661
2662 /* fill the array */
2663 map_cnt = 0;
2664 map = master->tenant_mapping_list;
2665 while (map) {
2666 if (map_cnt >= map_array_size) {
2667 goto error;
2668 }
2669 map_array[map_cnt].traffic_id = map->traffic_id;
2670 map_array[map_cnt].tenant_id = map->tenant_id;
2671 map_cnt++;
2672 map = map->next;
2673 }
2674
2675 }
2676
2677 /* set up hash for tenant lookup */
2678 list = master->list;
2679 while (list) {
2680 SCLogDebug("tenant-id %u", list->tenant_id);
2681 if (list->tenant_id != 0) {
2682 DetectEngineThreadCtx *mt_det_ctx = DetectEngineThreadCtxInitForReload(tv, list, 0);
2683 if (mt_det_ctx == NULL)
2684 goto error;
2685 if (HashTableAdd(mt_det_ctxs_hash, mt_det_ctx, 0) != 0) {
2686 goto error;
2687 }
2688 }
2689 list = list->next;
2690 }
2691 }
2692
2693 det_ctx->mt_det_ctxs_hash = mt_det_ctxs_hash;
2694 mt_det_ctxs_hash = NULL;
2695
2696 det_ctx->mt_det_ctxs_cnt = max_tenant_id;
2697
2698 det_ctx->tenant_array = map_array;
2699 det_ctx->tenant_array_size = map_array_size;
2700
2701 switch (master->tenant_selector) {
2702 case TENANT_SELECTOR_UNKNOWN:
2703 SCLogDebug("TENANT_SELECTOR_UNKNOWN");
2704 break;
2705 case TENANT_SELECTOR_VLAN:
2706 det_ctx->TenantGetId = DetectEngineTentantGetIdFromVlanId;
2707 SCLogDebug("TENANT_SELECTOR_VLAN");
2708 break;
2709 case TENANT_SELECTOR_LIVEDEV:
2710 det_ctx->TenantGetId = DetectEngineTentantGetIdFromLivedev;
2711 SCLogDebug("TENANT_SELECTOR_LIVEDEV");
2712 break;
2713 case TENANT_SELECTOR_DIRECT:
2714 det_ctx->TenantGetId = DetectEngineTentantGetIdFromPcap;
2715 SCLogDebug("TENANT_SELECTOR_DIRECT");
2716 break;
2717 }
2718
2719 return TM_ECODE_OK;
2720 error:
2721 if (map_array != NULL)
2722 SCFree(map_array);
2723 if (mt_det_ctxs_hash != NULL)
2724 HashTableFree(mt_det_ctxs_hash);
2725
2726 return TM_ECODE_FAILED;
2727 }
2728
2729 /** \internal
2730 * \brief Helper for DetectThread setup functions
2731 */
ThreadCtxDoInit(DetectEngineCtx * de_ctx,DetectEngineThreadCtx * det_ctx)2732 static TmEcode ThreadCtxDoInit (DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx)
2733 {
2734 PatternMatchThreadPrepare(&det_ctx->mtc, de_ctx->mpm_matcher);
2735 PatternMatchThreadPrepare(&det_ctx->mtcs, de_ctx->mpm_matcher);
2736 PatternMatchThreadPrepare(&det_ctx->mtcu, de_ctx->mpm_matcher);
2737
2738 PmqSetup(&det_ctx->pmq);
2739
2740 det_ctx->spm_thread_ctx = SpmMakeThreadCtx(de_ctx->spm_global_thread_ctx);
2741 if (det_ctx->spm_thread_ctx == NULL) {
2742 return TM_ECODE_FAILED;
2743 }
2744
2745 /* sized to the max of our sgh settings. A max setting of 0 implies that all
2746 * sgh's have: sgh->non_pf_store_cnt == 0 */
2747 if (de_ctx->non_pf_store_cnt_max > 0) {
2748 det_ctx->non_pf_id_array = SCCalloc(de_ctx->non_pf_store_cnt_max, sizeof(SigIntId));
2749 BUG_ON(det_ctx->non_pf_id_array == NULL);
2750 }
2751
2752 /* IP-ONLY */
2753 DetectEngineIPOnlyThreadInit(de_ctx,&det_ctx->io_ctx);
2754
2755 /* DeState */
2756 if (de_ctx->sig_array_len > 0) {
2757 det_ctx->match_array_len = de_ctx->sig_array_len;
2758 det_ctx->match_array = SCMalloc(det_ctx->match_array_len * sizeof(Signature *));
2759 if (det_ctx->match_array == NULL) {
2760 return TM_ECODE_FAILED;
2761 }
2762 memset(det_ctx->match_array, 0,
2763 det_ctx->match_array_len * sizeof(Signature *));
2764
2765 RuleMatchCandidateTxArrayInit(det_ctx, de_ctx->sig_array_len);
2766 }
2767
2768 /* byte_extract storage */
2769 det_ctx->byte_values = SCMalloc(sizeof(*det_ctx->byte_values) *
2770 (de_ctx->byte_extract_max_local_id + 1));
2771 if (det_ctx->byte_values == NULL) {
2772 return TM_ECODE_FAILED;
2773 }
2774
2775 /* Allocate space for base64 decoded data. */
2776 if (de_ctx->base64_decode_max_len) {
2777 det_ctx->base64_decoded = SCMalloc(de_ctx->base64_decode_max_len);
2778 if (det_ctx->base64_decoded == NULL) {
2779 return TM_ECODE_FAILED;
2780 }
2781 det_ctx->base64_decoded_len_max = de_ctx->base64_decode_max_len;
2782 det_ctx->base64_decoded_len = 0;
2783 }
2784
2785 det_ctx->inspect.buffers_size = de_ctx->buffer_type_id;
2786 det_ctx->inspect.buffers = SCCalloc(det_ctx->inspect.buffers_size, sizeof(InspectionBuffer));
2787 if (det_ctx->inspect.buffers == NULL) {
2788 return TM_ECODE_FAILED;
2789 }
2790 det_ctx->inspect.to_clear_queue = SCCalloc(det_ctx->inspect.buffers_size, sizeof(uint32_t));
2791 if (det_ctx->inspect.to_clear_queue == NULL) {
2792 return TM_ECODE_FAILED;
2793 }
2794 det_ctx->inspect.to_clear_idx = 0;
2795
2796 det_ctx->multi_inspect.buffers_size = de_ctx->buffer_type_id;
2797 det_ctx->multi_inspect.buffers = SCCalloc(det_ctx->multi_inspect.buffers_size, sizeof(InspectionBufferMultipleForList));
2798 if (det_ctx->multi_inspect.buffers == NULL) {
2799 return TM_ECODE_FAILED;
2800 }
2801 det_ctx->multi_inspect.to_clear_queue = SCCalloc(det_ctx->multi_inspect.buffers_size, sizeof(uint32_t));
2802 if (det_ctx->multi_inspect.to_clear_queue == NULL) {
2803 return TM_ECODE_FAILED;
2804 }
2805 det_ctx->multi_inspect.to_clear_idx = 0;
2806
2807
2808 DetectEngineThreadCtxInitKeywords(de_ctx, det_ctx);
2809 DetectEngineThreadCtxInitGlobalKeywords(det_ctx);
2810 #ifdef PROFILING
2811 SCProfilingRuleThreadSetup(de_ctx->profile_ctx, det_ctx);
2812 SCProfilingKeywordThreadSetup(de_ctx->profile_keyword_ctx, det_ctx);
2813 SCProfilingPrefilterThreadSetup(de_ctx->profile_prefilter_ctx, det_ctx);
2814 SCProfilingSghThreadSetup(de_ctx->profile_sgh_ctx, det_ctx);
2815 #endif
2816 SC_ATOMIC_INIT(det_ctx->so_far_used_by_detect);
2817
2818 return TM_ECODE_OK;
2819 }
2820
2821 /** \brief initialize thread specific detection engine context
2822 *
2823 * \note there is a special case when using delayed detect. In this case the
2824 * function is called twice per thread. The first time the rules are not
2825 * yet loaded. de_ctx->delayed_detect_initialized will be 0. The 2nd
2826 * time they will be loaded. de_ctx->delayed_detect_initialized will be 1.
2827 * This is needed to do the per thread counter registration before the
2828 * packet runtime starts. In delayed detect mode, the first call will
2829 * return a NULL ptr through the data ptr.
2830 *
2831 * \param tv ThreadVars for this thread
2832 * \param initdata pointer to de_ctx
2833 * \param data[out] pointer to store our thread detection ctx
2834 *
2835 * \retval TM_ECODE_OK if all went well
2836 * \retval TM_ECODE_FAILED on serious errors
2837 */
DetectEngineThreadCtxInit(ThreadVars * tv,void * initdata,void ** data)2838 TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
2839 {
2840 DetectEngineThreadCtx *det_ctx = SCMalloc(sizeof(DetectEngineThreadCtx));
2841 if (unlikely(det_ctx == NULL))
2842 return TM_ECODE_FAILED;
2843 memset(det_ctx, 0, sizeof(DetectEngineThreadCtx));
2844
2845 det_ctx->tv = tv;
2846 det_ctx->de_ctx = DetectEngineGetCurrent();
2847 if (det_ctx->de_ctx == NULL) {
2848 #ifdef UNITTESTS
2849 if (RunmodeIsUnittests()) {
2850 det_ctx->de_ctx = (DetectEngineCtx *)initdata;
2851 } else {
2852 DetectEngineThreadCtxDeinit(tv, det_ctx);
2853 return TM_ECODE_FAILED;
2854 }
2855 #else
2856 DetectEngineThreadCtxDeinit(tv, det_ctx);
2857 return TM_ECODE_FAILED;
2858 #endif
2859 }
2860
2861 if (det_ctx->de_ctx->type == DETECT_ENGINE_TYPE_NORMAL ||
2862 det_ctx->de_ctx->type == DETECT_ENGINE_TYPE_TENANT)
2863 {
2864 if (ThreadCtxDoInit(det_ctx->de_ctx, det_ctx) != TM_ECODE_OK) {
2865 DetectEngineThreadCtxDeinit(tv, det_ctx);
2866 return TM_ECODE_FAILED;
2867 }
2868 }
2869
2870 /** alert counter setup */
2871 det_ctx->counter_alerts = StatsRegisterCounter("detect.alert", tv);
2872 #ifdef PROFILING
2873 det_ctx->counter_mpm_list = StatsRegisterAvgCounter("detect.mpm_list", tv);
2874 det_ctx->counter_nonmpm_list = StatsRegisterAvgCounter("detect.nonmpm_list", tv);
2875 det_ctx->counter_fnonmpm_list = StatsRegisterAvgCounter("detect.fnonmpm_list", tv);
2876 det_ctx->counter_match_list = StatsRegisterAvgCounter("detect.match_list", tv);
2877 #endif
2878
2879 if (DetectEngineMultiTenantEnabled()) {
2880 if (DetectEngineThreadCtxInitForMT(tv, det_ctx) != TM_ECODE_OK) {
2881 DetectEngineThreadCtxDeinit(tv, det_ctx);
2882 return TM_ECODE_FAILED;
2883 }
2884 }
2885
2886 /* pass thread data back to caller */
2887 *data = (void *)det_ctx;
2888
2889 return TM_ECODE_OK;
2890 }
2891
2892 /**
2893 * \internal
2894 * \brief initialize a det_ctx for reload cases
2895 * \param new_de_ctx the new detection engine
2896 * \param mt flag to indicate if MT should be set up for this det_ctx
2897 * this should only be done for the 'root' det_ctx
2898 *
2899 * \retval det_ctx detection engine thread ctx or NULL in case of error
2900 */
DetectEngineThreadCtxInitForReload(ThreadVars * tv,DetectEngineCtx * new_de_ctx,int mt)2901 static DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload(
2902 ThreadVars *tv, DetectEngineCtx *new_de_ctx, int mt)
2903 {
2904 DetectEngineThreadCtx *det_ctx = SCMalloc(sizeof(DetectEngineThreadCtx));
2905 if (unlikely(det_ctx == NULL))
2906 return NULL;
2907 memset(det_ctx, 0, sizeof(DetectEngineThreadCtx));
2908
2909 det_ctx->tenant_id = new_de_ctx->tenant_id;
2910 det_ctx->tv = tv;
2911 det_ctx->de_ctx = DetectEngineReference(new_de_ctx);
2912 if (det_ctx->de_ctx == NULL) {
2913 SCFree(det_ctx);
2914 return NULL;
2915 }
2916
2917 /* most of the init happens here */
2918 if (det_ctx->de_ctx->type == DETECT_ENGINE_TYPE_NORMAL ||
2919 det_ctx->de_ctx->type == DETECT_ENGINE_TYPE_TENANT)
2920 {
2921 if (ThreadCtxDoInit(det_ctx->de_ctx, det_ctx) != TM_ECODE_OK) {
2922 DetectEngineDeReference(&det_ctx->de_ctx);
2923 SCFree(det_ctx);
2924 return NULL;
2925 }
2926 }
2927
2928 /** alert counter setup */
2929 det_ctx->counter_alerts = StatsRegisterCounter("detect.alert", tv);
2930 #ifdef PROFILING
2931 uint16_t counter_mpm_list = StatsRegisterAvgCounter("detect.mpm_list", tv);
2932 uint16_t counter_nonmpm_list = StatsRegisterAvgCounter("detect.nonmpm_list", tv);
2933 uint16_t counter_fnonmpm_list = StatsRegisterAvgCounter("detect.fnonmpm_list", tv);
2934 uint16_t counter_match_list = StatsRegisterAvgCounter("detect.match_list", tv);
2935 det_ctx->counter_mpm_list = counter_mpm_list;
2936 det_ctx->counter_nonmpm_list = counter_nonmpm_list;
2937 det_ctx->counter_fnonmpm_list = counter_fnonmpm_list;
2938 det_ctx->counter_match_list = counter_match_list;
2939 #endif
2940
2941 if (mt && DetectEngineMultiTenantEnabled()) {
2942 if (DetectEngineThreadCtxInitForMT(tv, det_ctx) != TM_ECODE_OK) {
2943 DetectEngineDeReference(&det_ctx->de_ctx);
2944 SCFree(det_ctx);
2945 return NULL;
2946 }
2947 }
2948
2949 return det_ctx;
2950 }
2951
DetectEngineThreadCtxFree(DetectEngineThreadCtx * det_ctx)2952 static void DetectEngineThreadCtxFree(DetectEngineThreadCtx *det_ctx)
2953 {
2954 #if DEBUG
2955 SCLogDebug("PACKET PKT_STREAM_ADD: %"PRIu64, det_ctx->pkt_stream_add_cnt);
2956
2957 SCLogDebug("PAYLOAD MPM %"PRIu64"/%"PRIu64, det_ctx->payload_mpm_cnt, det_ctx->payload_mpm_size);
2958 SCLogDebug("STREAM MPM %"PRIu64"/%"PRIu64, det_ctx->stream_mpm_cnt, det_ctx->stream_mpm_size);
2959
2960 SCLogDebug("PAYLOAD SIG %"PRIu64"/%"PRIu64, det_ctx->payload_persig_cnt, det_ctx->payload_persig_size);
2961 SCLogDebug("STREAM SIG %"PRIu64"/%"PRIu64, det_ctx->stream_persig_cnt, det_ctx->stream_persig_size);
2962 #endif
2963
2964 if (det_ctx->tenant_array != NULL) {
2965 SCFree(det_ctx->tenant_array);
2966 det_ctx->tenant_array = NULL;
2967 }
2968
2969 #ifdef PROFILING
2970 SCProfilingRuleThreadCleanup(det_ctx);
2971 SCProfilingKeywordThreadCleanup(det_ctx);
2972 SCProfilingPrefilterThreadCleanup(det_ctx);
2973 SCProfilingSghThreadCleanup(det_ctx);
2974 #endif
2975
2976 DetectEngineIPOnlyThreadDeinit(&det_ctx->io_ctx);
2977
2978 /** \todo get rid of this static */
2979 if (det_ctx->de_ctx != NULL) {
2980 PatternMatchThreadDestroy(&det_ctx->mtc, det_ctx->de_ctx->mpm_matcher);
2981 PatternMatchThreadDestroy(&det_ctx->mtcs, det_ctx->de_ctx->mpm_matcher);
2982 PatternMatchThreadDestroy(&det_ctx->mtcu, det_ctx->de_ctx->mpm_matcher);
2983 }
2984
2985 PmqFree(&det_ctx->pmq);
2986
2987 if (det_ctx->spm_thread_ctx != NULL) {
2988 SpmDestroyThreadCtx(det_ctx->spm_thread_ctx);
2989 }
2990
2991 if (det_ctx->non_pf_id_array != NULL)
2992 SCFree(det_ctx->non_pf_id_array);
2993
2994 if (det_ctx->match_array != NULL)
2995 SCFree(det_ctx->match_array);
2996
2997 RuleMatchCandidateTxArrayFree(det_ctx);
2998
2999 if (det_ctx->byte_values != NULL)
3000 SCFree(det_ctx->byte_values);
3001
3002 /* Decoded base64 data. */
3003 if (det_ctx->base64_decoded != NULL) {
3004 SCFree(det_ctx->base64_decoded);
3005 }
3006
3007 if (det_ctx->inspect.buffers) {
3008 for (uint32_t i = 0; i < det_ctx->inspect.buffers_size; i++) {
3009 InspectionBufferFree(&det_ctx->inspect.buffers[i]);
3010 }
3011 SCFree(det_ctx->inspect.buffers);
3012 }
3013 if (det_ctx->inspect.to_clear_queue) {
3014 SCFree(det_ctx->inspect.to_clear_queue);
3015 }
3016 if (det_ctx->multi_inspect.buffers) {
3017 for (uint32_t i = 0; i < det_ctx->multi_inspect.buffers_size; i++) {
3018 InspectionBufferMultipleForList *fb = &det_ctx->multi_inspect.buffers[i];
3019 for (uint32_t x = 0; x < fb->size; x++) {
3020 InspectionBufferFree(&fb->inspection_buffers[x]);
3021 }
3022 SCFree(fb->inspection_buffers);
3023 }
3024 SCFree(det_ctx->multi_inspect.buffers);
3025 }
3026 if (det_ctx->multi_inspect.to_clear_queue) {
3027 SCFree(det_ctx->multi_inspect.to_clear_queue);
3028 }
3029
3030 DetectEngineThreadCtxDeinitGlobalKeywords(det_ctx);
3031 if (det_ctx->de_ctx != NULL) {
3032 DetectEngineThreadCtxDeinitKeywords(det_ctx->de_ctx, det_ctx);
3033 #ifdef UNITTESTS
3034 if (!RunmodeIsUnittests() || det_ctx->de_ctx->ref_cnt > 0)
3035 DetectEngineDeReference(&det_ctx->de_ctx);
3036 #else
3037 DetectEngineDeReference(&det_ctx->de_ctx);
3038 #endif
3039 }
3040
3041 AppLayerDecoderEventsFreeEvents(&det_ctx->decoder_events);
3042
3043 SCFree(det_ctx);
3044 }
3045
DetectEngineThreadCtxDeinit(ThreadVars * tv,void * data)3046 TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data)
3047 {
3048 DetectEngineThreadCtx *det_ctx = (DetectEngineThreadCtx *)data;
3049
3050 if (det_ctx == NULL) {
3051 SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "argument \"data\" NULL");
3052 return TM_ECODE_OK;
3053 }
3054
3055 if (det_ctx->mt_det_ctxs_hash != NULL) {
3056 HashTableFree(det_ctx->mt_det_ctxs_hash);
3057 det_ctx->mt_det_ctxs_hash = NULL;
3058 }
3059 DetectEngineThreadCtxFree(det_ctx);
3060
3061 return TM_ECODE_OK;
3062 }
3063
DetectEngineThreadCtxInfo(ThreadVars * t,DetectEngineThreadCtx * det_ctx)3064 void DetectEngineThreadCtxInfo(ThreadVars *t, DetectEngineThreadCtx *det_ctx)
3065 {
3066 /* XXX */
3067 PatternMatchThreadPrint(&det_ctx->mtc, det_ctx->de_ctx->mpm_matcher);
3068 PatternMatchThreadPrint(&det_ctx->mtcu, det_ctx->de_ctx->mpm_matcher);
3069 }
3070
3071 /** \brief Register Thread keyword context Funcs
3072 *
3073 * \param de_ctx detection engine to register in
3074 * \param name keyword name for error printing
3075 * \param InitFunc function ptr
3076 * \param data keyword init data to pass to Func. Can be NULL.
3077 * \param FreeFunc function ptr
3078 * \param mode 0 normal (ctx per keyword instance) 1 shared (one ctx per det_ct)
3079 *
3080 * \retval id for retrieval of ctx at runtime
3081 * \retval -1 on error
3082 *
3083 * \note make sure "data" remains valid and it free'd elsewhere. It's
3084 * recommended to store it in the keywords global ctx so that
3085 * it's freed when the de_ctx is freed.
3086 */
DetectRegisterThreadCtxFuncs(DetectEngineCtx * de_ctx,const char * name,void * (* InitFunc)(void *),void * data,void (* FreeFunc)(void *),int mode)3087 int DetectRegisterThreadCtxFuncs(DetectEngineCtx *de_ctx, const char *name, void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *), int mode)
3088 {
3089 BUG_ON(de_ctx == NULL || InitFunc == NULL || FreeFunc == NULL);
3090
3091 if (mode) {
3092 DetectEngineThreadKeywordCtxItem *item = de_ctx->keyword_list;
3093 while (item != NULL) {
3094 if (strcmp(name, item->name) == 0) {
3095 return item->id;
3096 }
3097
3098 item = item->next;
3099 }
3100 }
3101
3102 DetectEngineThreadKeywordCtxItem *item = SCMalloc(sizeof(DetectEngineThreadKeywordCtxItem));
3103 if (unlikely(item == NULL))
3104 return -1;
3105 memset(item, 0x00, sizeof(DetectEngineThreadKeywordCtxItem));
3106
3107 item->InitFunc = InitFunc;
3108 item->FreeFunc = FreeFunc;
3109 item->data = data;
3110 item->name = name;
3111
3112 item->next = de_ctx->keyword_list;
3113 de_ctx->keyword_list = item;
3114 item->id = de_ctx->keyword_id++;
3115
3116 return item->id;
3117 }
3118
3119 /** \brief Remove Thread keyword context registration
3120 *
3121 * \param de_ctx detection engine to deregister from
3122 * \param det_ctx detection engine thread context to deregister from
3123 * \param data keyword init data to pass to Func. Can be NULL.
3124 * \param name keyword name for error printing
3125 *
3126 * \retval 1 Item unregistered
3127 * \retval 0 otherwise
3128 *
3129 * \note make sure "data" remains valid and it free'd elsewhere. It's
3130 * recommended to store it in the keywords global ctx so that
3131 * it's freed when the de_ctx is freed.
3132 */
DetectUnregisterThreadCtxFuncs(DetectEngineCtx * de_ctx,DetectEngineThreadCtx * det_ctx,void * data,const char * name)3133 int DetectUnregisterThreadCtxFuncs(DetectEngineCtx *de_ctx,
3134 DetectEngineThreadCtx *det_ctx, void *data, const char *name)
3135 {
3136 BUG_ON(de_ctx == NULL);
3137
3138 DetectEngineThreadKeywordCtxItem *item = de_ctx->keyword_list;
3139 DetectEngineThreadKeywordCtxItem *prev_item = NULL;
3140 while (item != NULL) {
3141 if (strcmp(name, item->name) == 0 && (data == item->data)) {
3142 if (prev_item == NULL)
3143 de_ctx->keyword_list = item->next;
3144 else
3145 prev_item->next = item->next;
3146 if (det_ctx)
3147 item->FreeFunc(det_ctx->keyword_ctxs_array[item->id]);
3148 SCFree(item);
3149 return 1;
3150 }
3151 prev_item = item;
3152 item = item->next;
3153 }
3154 return 0;
3155 }
3156 /** \brief Retrieve thread local keyword ctx by id
3157 *
3158 * \param det_ctx detection engine thread ctx to retrieve the ctx from
3159 * \param id id of the ctx returned by DetectRegisterThreadCtxInitFunc at
3160 * keyword init.
3161 *
3162 * \retval ctx or NULL on error
3163 */
DetectThreadCtxGetKeywordThreadCtx(DetectEngineThreadCtx * det_ctx,int id)3164 void *DetectThreadCtxGetKeywordThreadCtx(DetectEngineThreadCtx *det_ctx, int id)
3165 {
3166 if (id < 0 || id > det_ctx->keyword_ctxs_size || det_ctx->keyword_ctxs_array == NULL)
3167 return NULL;
3168
3169 return det_ctx->keyword_ctxs_array[id];
3170 }
3171
3172
3173 /** \brief Register Thread keyword context Funcs (Global)
3174 *
3175 * IDs stay static over reloads and between tenants
3176 *
3177 * \param name keyword name for error printing
3178 * \param InitFunc function ptr
3179 * \param FreeFunc function ptr
3180 *
3181 * \retval id for retrieval of ctx at runtime
3182 * \retval -1 on error
3183 */
DetectRegisterThreadCtxGlobalFuncs(const char * name,void * (* InitFunc)(void *),void * data,void (* FreeFunc)(void *))3184 int DetectRegisterThreadCtxGlobalFuncs(const char *name,
3185 void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *))
3186 {
3187 int id;
3188 BUG_ON(InitFunc == NULL || FreeFunc == NULL);
3189
3190 DetectEngineMasterCtx *master = &g_master_de_ctx;
3191
3192 /* if already registered, return existing id */
3193 DetectEngineThreadKeywordCtxItem *item = master->keyword_list;
3194 while (item != NULL) {
3195 if (strcmp(name, item->name) == 0) {
3196 id = item->id;
3197 return id;
3198 }
3199
3200 item = item->next;
3201 }
3202
3203 item = SCCalloc(1, sizeof(*item));
3204 if (unlikely(item == NULL)) {
3205 return -1;
3206 }
3207 item->InitFunc = InitFunc;
3208 item->FreeFunc = FreeFunc;
3209 item->name = name;
3210 item->data = data;
3211
3212 item->next = master->keyword_list;
3213 master->keyword_list = item;
3214 item->id = master->keyword_id++;
3215
3216 id = item->id;
3217 return id;
3218 }
3219
3220 /** \brief Retrieve thread local keyword ctx by id
3221 *
3222 * \param det_ctx detection engine thread ctx to retrieve the ctx from
3223 * \param id id of the ctx returned by DetectRegisterThreadCtxInitFunc at
3224 * keyword init.
3225 *
3226 * \retval ctx or NULL on error
3227 */
DetectThreadCtxGetGlobalKeywordThreadCtx(DetectEngineThreadCtx * det_ctx,int id)3228 void *DetectThreadCtxGetGlobalKeywordThreadCtx(DetectEngineThreadCtx *det_ctx, int id)
3229 {
3230 if (id < 0 || id > det_ctx->global_keyword_ctxs_size ||
3231 det_ctx->global_keyword_ctxs_array == NULL) {
3232 return NULL;
3233 }
3234
3235 return det_ctx->global_keyword_ctxs_array[id];
3236 }
3237
3238 /** \brief Check if detection is enabled
3239 * \retval bool true or false */
DetectEngineEnabled(void)3240 int DetectEngineEnabled(void)
3241 {
3242 DetectEngineMasterCtx *master = &g_master_de_ctx;
3243 SCMutexLock(&master->lock);
3244
3245 if (master->list == NULL) {
3246 SCMutexUnlock(&master->lock);
3247 return 0;
3248 }
3249
3250 SCMutexUnlock(&master->lock);
3251 return 1;
3252 }
3253
DetectEngineGetVersion(void)3254 uint32_t DetectEngineGetVersion(void)
3255 {
3256 uint32_t version;
3257 DetectEngineMasterCtx *master = &g_master_de_ctx;
3258 SCMutexLock(&master->lock);
3259 version = master->version;
3260 SCMutexUnlock(&master->lock);
3261 return version;
3262 }
3263
DetectEngineBumpVersion(void)3264 void DetectEngineBumpVersion(void)
3265 {
3266 DetectEngineMasterCtx *master = &g_master_de_ctx;
3267 SCMutexLock(&master->lock);
3268 master->version++;
3269 SCLogDebug("master version now %u", master->version);
3270 SCMutexUnlock(&master->lock);
3271 }
3272
DetectEngineGetCurrent(void)3273 DetectEngineCtx *DetectEngineGetCurrent(void)
3274 {
3275 DetectEngineMasterCtx *master = &g_master_de_ctx;
3276 SCMutexLock(&master->lock);
3277
3278 DetectEngineCtx *de_ctx = master->list;
3279 while (de_ctx) {
3280 if (de_ctx->type == DETECT_ENGINE_TYPE_NORMAL ||
3281 de_ctx->type == DETECT_ENGINE_TYPE_DD_STUB ||
3282 de_ctx->type == DETECT_ENGINE_TYPE_MT_STUB)
3283 {
3284 de_ctx->ref_cnt++;
3285 SCLogDebug("de_ctx %p ref_cnt %u", de_ctx, de_ctx->ref_cnt);
3286 SCMutexUnlock(&master->lock);
3287 return de_ctx;
3288 }
3289 de_ctx = de_ctx->next;
3290 }
3291
3292 SCMutexUnlock(&master->lock);
3293 return NULL;
3294 }
3295
DetectEngineReference(DetectEngineCtx * de_ctx)3296 DetectEngineCtx *DetectEngineReference(DetectEngineCtx *de_ctx)
3297 {
3298 if (de_ctx == NULL)
3299 return NULL;
3300 de_ctx->ref_cnt++;
3301 return de_ctx;
3302 }
3303
3304 /** TODO locking? Not needed if this is a one time setting at startup */
DetectEngineMultiTenantEnabled(void)3305 int DetectEngineMultiTenantEnabled(void)
3306 {
3307 DetectEngineMasterCtx *master = &g_master_de_ctx;
3308 return (master->multi_tenant_enabled);
3309 }
3310
3311 /** \internal
3312 * \brief load a tenant from a yaml file
3313 *
3314 * \param tenant_id the tenant id by which the config is known
3315 * \param filename full path of a yaml file
3316 * \param loader_id id of loader thread or -1
3317 *
3318 * \retval 0 ok
3319 * \retval -1 failed
3320 */
DetectEngineMultiTenantLoadTenant(uint32_t tenant_id,const char * filename,int loader_id)3321 static int DetectEngineMultiTenantLoadTenant(uint32_t tenant_id, const char *filename, int loader_id)
3322 {
3323 DetectEngineCtx *de_ctx = NULL;
3324 char prefix[64];
3325
3326 snprintf(prefix, sizeof(prefix), "multi-detect.%d", tenant_id);
3327
3328 #ifdef OS_WIN32
3329 struct _stat st;
3330 if(_stat(filename, &st) != 0) {
3331 #else
3332 struct stat st;
3333 if(stat(filename, &st) != 0) {
3334 #endif /* OS_WIN32 */
3335 SCLogError(SC_ERR_FOPEN, "failed to stat file %s", filename);
3336 goto error;
3337 }
3338
3339 de_ctx = DetectEngineGetByTenantId(tenant_id);
3340 if (de_ctx != NULL) {
3341 SCLogError(SC_ERR_MT_DUPLICATE_TENANT, "tenant %u already registered",
3342 tenant_id);
3343 DetectEngineDeReference(&de_ctx);
3344 goto error;
3345 }
3346
3347 ConfNode *node = ConfGetNode(prefix);
3348 if (node == NULL) {
3349 SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to properly setup yaml %s", filename);
3350 goto error;
3351 }
3352
3353 de_ctx = DetectEngineCtxInitWithPrefix(prefix);
3354 if (de_ctx == NULL) {
3355 SCLogError(SC_ERR_INITIALIZATION, "initializing detection engine "
3356 "context failed.");
3357 goto error;
3358 }
3359 SCLogDebug("de_ctx %p with prefix %s", de_ctx, de_ctx->config_prefix);
3360
3361 de_ctx->type = DETECT_ENGINE_TYPE_TENANT;
3362 de_ctx->tenant_id = tenant_id;
3363 de_ctx->loader_id = loader_id;
3364
3365 if (SigLoadSignatures(de_ctx, NULL, 0) < 0) {
3366 SCLogError(SC_ERR_NO_RULES_LOADED, "Loading signatures failed.");
3367 goto error;
3368 }
3369
3370 DetectEngineAddToMaster(de_ctx);
3371
3372 return 0;
3373
3374 error:
3375 if (de_ctx != NULL) {
3376 DetectEngineCtxFree(de_ctx);
3377 }
3378 return -1;
3379 }
3380
3381 static int DetectEngineMultiTenantReloadTenant(uint32_t tenant_id, const char *filename, int reload_cnt)
3382 {
3383 DetectEngineCtx *old_de_ctx = DetectEngineGetByTenantId(tenant_id);
3384 if (old_de_ctx == NULL) {
3385 SCLogError(SC_ERR_INITIALIZATION, "tenant detect engine not found");
3386 return -1;
3387 }
3388
3389 char prefix[64];
3390 snprintf(prefix, sizeof(prefix), "multi-detect.%d.reload.%d", tenant_id, reload_cnt);
3391 reload_cnt++;
3392 SCLogDebug("prefix %s", prefix);
3393
3394 if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) {
3395 SCLogError(SC_ERR_INITIALIZATION,"failed to load yaml");
3396 goto error;
3397 }
3398
3399 ConfNode *node = ConfGetNode(prefix);
3400 if (node == NULL) {
3401 SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to properly setup yaml %s", filename);
3402 goto error;
3403 }
3404
3405 DetectEngineCtx *new_de_ctx = DetectEngineCtxInitWithPrefix(prefix);
3406 if (new_de_ctx == NULL) {
3407 SCLogError(SC_ERR_INITIALIZATION, "initializing detection engine "
3408 "context failed.");
3409 goto error;
3410 }
3411 SCLogDebug("de_ctx %p with prefix %s", new_de_ctx, new_de_ctx->config_prefix);
3412
3413 new_de_ctx->type = DETECT_ENGINE_TYPE_TENANT;
3414 new_de_ctx->tenant_id = tenant_id;
3415 new_de_ctx->loader_id = old_de_ctx->loader_id;
3416
3417 if (SigLoadSignatures(new_de_ctx, NULL, 0) < 0) {
3418 SCLogError(SC_ERR_NO_RULES_LOADED, "Loading signatures failed.");
3419 goto error;
3420 }
3421
3422 DetectEngineAddToMaster(new_de_ctx);
3423
3424 /* move to free list */
3425 DetectEngineMoveToFreeList(old_de_ctx);
3426 DetectEngineDeReference(&old_de_ctx);
3427 return 0;
3428
3429 error:
3430 DetectEngineDeReference(&old_de_ctx);
3431 return -1;
3432 }
3433
3434
3435 typedef struct TenantLoaderCtx_ {
3436 uint32_t tenant_id;
3437 int reload_cnt; /**< used by reload */
3438 const char *yaml;
3439 } TenantLoaderCtx;
3440
3441 static int DetectLoaderFuncLoadTenant(void *vctx, int loader_id)
3442 {
3443 TenantLoaderCtx *ctx = (TenantLoaderCtx *)vctx;
3444
3445 SCLogDebug("loader %d", loader_id);
3446 if (DetectEngineMultiTenantLoadTenant(ctx->tenant_id, ctx->yaml, loader_id) != 0) {
3447 return -1;
3448 }
3449 return 0;
3450 }
3451
3452 static int DetectLoaderSetupLoadTenant(uint32_t tenant_id, const char *yaml)
3453 {
3454 TenantLoaderCtx *t = SCCalloc(1, sizeof(*t));
3455 if (t == NULL)
3456 return -ENOMEM;
3457
3458 t->tenant_id = tenant_id;
3459 t->yaml = yaml;
3460
3461 return DetectLoaderQueueTask(-1, DetectLoaderFuncLoadTenant, t);
3462 }
3463
3464 static int DetectLoaderFuncReloadTenant(void *vctx, int loader_id)
3465 {
3466 TenantLoaderCtx *ctx = (TenantLoaderCtx *)vctx;
3467
3468 SCLogDebug("loader_id %d", loader_id);
3469
3470 if (DetectEngineMultiTenantReloadTenant(ctx->tenant_id, ctx->yaml, ctx->reload_cnt) != 0) {
3471 return -1;
3472 }
3473 return 0;
3474 }
3475
3476 static int DetectLoaderSetupReloadTenant(uint32_t tenant_id, const char *yaml, int reload_cnt)
3477 {
3478 DetectEngineCtx *old_de_ctx = DetectEngineGetByTenantId(tenant_id);
3479 if (old_de_ctx == NULL)
3480 return -ENOENT;
3481 int loader_id = old_de_ctx->loader_id;
3482 DetectEngineDeReference(&old_de_ctx);
3483
3484 TenantLoaderCtx *t = SCCalloc(1, sizeof(*t));
3485 if (t == NULL)
3486 return -ENOMEM;
3487
3488 t->tenant_id = tenant_id;
3489 t->yaml = yaml;
3490 t->reload_cnt = reload_cnt;
3491
3492 SCLogDebug("loader_id %d", loader_id);
3493
3494 return DetectLoaderQueueTask(loader_id, DetectLoaderFuncReloadTenant, t);
3495 }
3496
3497 /** \brief Load a tenant and wait for loading to complete
3498 */
3499 int DetectEngineLoadTenantBlocking(uint32_t tenant_id, const char *yaml)
3500 {
3501 int r = DetectLoaderSetupLoadTenant(tenant_id, yaml);
3502 if (r < 0)
3503 return r;
3504
3505 if (DetectLoadersSync() != 0)
3506 return -1;
3507
3508 return 0;
3509 }
3510
3511 /** \brief Reload a tenant and wait for loading to complete
3512 */
3513 int DetectEngineReloadTenantBlocking(uint32_t tenant_id, const char *yaml, int reload_cnt)
3514 {
3515 int r = DetectLoaderSetupReloadTenant(tenant_id, yaml, reload_cnt);
3516 if (r < 0)
3517 return r;
3518
3519 if (DetectLoadersSync() != 0)
3520 return -1;
3521
3522 return 0;
3523 }
3524
3525 static int DetectEngineMultiTenantSetupLoadLivedevMappings(const ConfNode *mappings_root_node,
3526 bool failure_fatal)
3527 {
3528 ConfNode *mapping_node = NULL;
3529
3530 int mapping_cnt = 0;
3531 if (mappings_root_node != NULL) {
3532 TAILQ_FOREACH(mapping_node, &mappings_root_node->head, next) {
3533 ConfNode *tenant_id_node = ConfNodeLookupChild(mapping_node, "tenant-id");
3534 if (tenant_id_node == NULL)
3535 goto bad_mapping;
3536 ConfNode *device_node = ConfNodeLookupChild(mapping_node, "device");
3537 if (device_node == NULL)
3538 goto bad_mapping;
3539
3540 uint32_t tenant_id = 0;
3541 if (StringParseUint32(&tenant_id, 10, strlen(tenant_id_node->val),
3542 tenant_id_node->val) < 0)
3543 {
3544 SCLogError(SC_ERR_INVALID_ARGUMENT, "tenant-id "
3545 "of %s is invalid", tenant_id_node->val);
3546 goto bad_mapping;
3547 }
3548
3549 const char *dev = device_node->val;
3550 LiveDevice *ld = LiveGetDevice(dev);
3551 if (ld == NULL) {
3552 SCLogWarning(SC_ERR_MT_NO_MAPPING, "device %s not found", dev);
3553 goto bad_mapping;
3554 }
3555
3556 if (ld->tenant_id_set) {
3557 SCLogWarning(SC_ERR_MT_NO_MAPPING, "device %s already mapped to tenant-id %u",
3558 dev, ld->tenant_id);
3559 goto bad_mapping;
3560 }
3561
3562 ld->tenant_id = tenant_id;
3563 ld->tenant_id_set = true;
3564
3565 if (DetectEngineTentantRegisterLivedev(tenant_id, ld->id) != 0) {
3566 goto error;
3567 }
3568
3569 SCLogConfig("device %s connected to tenant-id %u", dev, tenant_id);
3570 mapping_cnt++;
3571 continue;
3572
3573 bad_mapping:
3574 if (failure_fatal)
3575 goto error;
3576 }
3577 }
3578 SCLogConfig("%d device - tenant-id mappings defined", mapping_cnt);
3579 return mapping_cnt;
3580
3581 error:
3582 return 0;
3583 }
3584
3585 static int DetectEngineMultiTenantSetupLoadVlanMappings(const ConfNode *mappings_root_node,
3586 bool failure_fatal)
3587 {
3588 ConfNode *mapping_node = NULL;
3589
3590 int mapping_cnt = 0;
3591 if (mappings_root_node != NULL) {
3592 TAILQ_FOREACH(mapping_node, &mappings_root_node->head, next) {
3593 ConfNode *tenant_id_node = ConfNodeLookupChild(mapping_node, "tenant-id");
3594 if (tenant_id_node == NULL)
3595 goto bad_mapping;
3596 ConfNode *vlan_id_node = ConfNodeLookupChild(mapping_node, "vlan-id");
3597 if (vlan_id_node == NULL)
3598 goto bad_mapping;
3599
3600 uint32_t tenant_id = 0;
3601 if (StringParseUint32(&tenant_id, 10, strlen(tenant_id_node->val),
3602 tenant_id_node->val) < 0)
3603 {
3604 SCLogError(SC_ERR_INVALID_ARGUMENT, "tenant-id "
3605 "of %s is invalid", tenant_id_node->val);
3606 goto bad_mapping;
3607 }
3608
3609 uint16_t vlan_id = 0;
3610 if (StringParseUint16(&vlan_id, 10, strlen(vlan_id_node->val),
3611 vlan_id_node->val) < 0)
3612 {
3613 SCLogError(SC_ERR_INVALID_ARGUMENT, "vlan-id "
3614 "of %s is invalid", vlan_id_node->val);
3615 goto bad_mapping;
3616 }
3617 if (vlan_id == 0 || vlan_id >= 4095) {
3618 SCLogError(SC_ERR_INVALID_ARGUMENT, "vlan-id "
3619 "of %s is invalid. Valid range 1-4094.", vlan_id_node->val);
3620 goto bad_mapping;
3621 }
3622
3623 if (DetectEngineTentantRegisterVlanId(tenant_id, (uint32_t)vlan_id) != 0) {
3624 goto error;
3625 }
3626 SCLogConfig("vlan %u connected to tenant-id %u", vlan_id, tenant_id);
3627 mapping_cnt++;
3628 continue;
3629
3630 bad_mapping:
3631 if (failure_fatal)
3632 goto error;
3633 }
3634 }
3635 return mapping_cnt;
3636
3637 error:
3638 return 0;
3639 }
3640
3641 /**
3642 * \brief setup multi-detect / multi-tenancy
3643 *
3644 * See if MT is enabled. If so, setup the selector, tenants and mappings.
3645 * Tenants and mappings are optional, and can also dynamically be added
3646 * and removed from the unix socket.
3647 */
3648 int DetectEngineMultiTenantSetup(void)
3649 {
3650 enum DetectEngineTenantSelectors tenant_selector = TENANT_SELECTOR_UNKNOWN;
3651 DetectEngineMasterCtx *master = &g_master_de_ctx;
3652
3653 int unix_socket = ConfUnixSocketIsEnable();
3654
3655 int failure_fatal = 0;
3656 (void)ConfGetBool("engine.init-failure-fatal", &failure_fatal);
3657
3658 int enabled = 0;
3659 (void)ConfGetBool("multi-detect.enabled", &enabled);
3660 if (enabled == 1) {
3661 DetectLoadersInit();
3662 TmModuleDetectLoaderRegister();
3663 DetectLoaderThreadSpawn();
3664 TmThreadContinueDetectLoaderThreads();
3665
3666 SCMutexLock(&master->lock);
3667 master->multi_tenant_enabled = 1;
3668
3669 const char *handler = NULL;
3670 if (ConfGet("multi-detect.selector", &handler) == 1) {
3671 SCLogConfig("multi-tenant selector type %s", handler);
3672
3673 if (strcmp(handler, "vlan") == 0) {
3674 tenant_selector = master->tenant_selector = TENANT_SELECTOR_VLAN;
3675
3676 int vlanbool = 0;
3677 if ((ConfGetBool("vlan.use-for-tracking", &vlanbool)) == 1 && vlanbool == 0) {
3678 SCLogError(SC_ERR_INVALID_VALUE, "vlan tracking is disabled, "
3679 "can't use multi-detect selector 'vlan'");
3680 SCMutexUnlock(&master->lock);
3681 goto error;
3682 }
3683
3684 } else if (strcmp(handler, "direct") == 0) {
3685 tenant_selector = master->tenant_selector = TENANT_SELECTOR_DIRECT;
3686 } else if (strcmp(handler, "device") == 0) {
3687 tenant_selector = master->tenant_selector = TENANT_SELECTOR_LIVEDEV;
3688 if (EngineModeIsIPS()) {
3689 SCLogWarning(SC_ERR_MT_NO_MAPPING,
3690 "multi-tenant 'device' mode not supported for IPS");
3691 SCMutexUnlock(&master->lock);
3692 goto error;
3693 }
3694
3695 } else {
3696 SCLogError(SC_ERR_INVALID_VALUE, "unknown value %s "
3697 "multi-detect.selector", handler);
3698 SCMutexUnlock(&master->lock);
3699 goto error;
3700 }
3701 }
3702 SCMutexUnlock(&master->lock);
3703 SCLogConfig("multi-detect is enabled (multi tenancy). Selector: %s", handler);
3704
3705 /* traffic -- tenant mappings */
3706 ConfNode *mappings_root_node = ConfGetNode("multi-detect.mappings");
3707
3708 if (tenant_selector == TENANT_SELECTOR_VLAN) {
3709 int mapping_cnt = DetectEngineMultiTenantSetupLoadVlanMappings(mappings_root_node,
3710 failure_fatal);
3711 if (mapping_cnt == 0) {
3712 /* no mappings are valid when we're in unix socket mode,
3713 * they can be added on the fly. Otherwise warn/error
3714 * depending on failure_fatal */
3715
3716 if (unix_socket) {
3717 SCLogNotice("no tenant traffic mappings defined, "
3718 "tenants won't be used until mappings are added");
3719 } else {
3720 if (failure_fatal) {
3721 SCLogError(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined");
3722 goto error;
3723 } else {
3724 SCLogWarning(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined");
3725 }
3726 }
3727 }
3728 } else if (tenant_selector == TENANT_SELECTOR_LIVEDEV) {
3729 int mapping_cnt = DetectEngineMultiTenantSetupLoadLivedevMappings(mappings_root_node,
3730 failure_fatal);
3731 if (mapping_cnt == 0) {
3732 if (failure_fatal) {
3733 SCLogError(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined");
3734 goto error;
3735 } else {
3736 SCLogWarning(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined");
3737 }
3738 }
3739 }
3740
3741 /* tenants */
3742 ConfNode *tenants_root_node = ConfGetNode("multi-detect.tenants");
3743 ConfNode *tenant_node = NULL;
3744
3745 if (tenants_root_node != NULL) {
3746 TAILQ_FOREACH(tenant_node, &tenants_root_node->head, next) {
3747 ConfNode *id_node = ConfNodeLookupChild(tenant_node, "id");
3748 if (id_node == NULL) {
3749 goto bad_tenant;
3750 }
3751 ConfNode *yaml_node = ConfNodeLookupChild(tenant_node, "yaml");
3752 if (yaml_node == NULL) {
3753 goto bad_tenant;
3754 }
3755
3756 uint32_t tenant_id = 0;
3757 if (StringParseUint32(&tenant_id, 10, strlen(id_node->val),
3758 id_node->val) < 0)
3759 {
3760 SCLogError(SC_ERR_INVALID_ARGUMENT, "tenant_id "
3761 "of %s is invalid", id_node->val);
3762 goto bad_tenant;
3763 }
3764 SCLogDebug("tenant id: %u, %s", tenant_id, yaml_node->val);
3765
3766 /* setup the yaml in this loop so that it's not done by the loader
3767 * threads. ConfYamlLoadFileWithPrefix is not thread safe. */
3768 char prefix[64];
3769 snprintf(prefix, sizeof(prefix), "multi-detect.%d", tenant_id);
3770 if (ConfYamlLoadFileWithPrefix(yaml_node->val, prefix) != 0) {
3771 SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to load yaml %s", yaml_node->val);
3772 goto bad_tenant;
3773 }
3774
3775 int r = DetectLoaderSetupLoadTenant(tenant_id, yaml_node->val);
3776 if (r < 0) {
3777 /* error logged already */
3778 goto bad_tenant;
3779 }
3780 continue;
3781
3782 bad_tenant:
3783 if (failure_fatal)
3784 goto error;
3785 }
3786 }
3787
3788 /* wait for our loaders to complete their tasks */
3789 if (DetectLoadersSync() != 0) {
3790 goto error;
3791 }
3792
3793 VarNameStoreActivateStaging();
3794
3795 } else {
3796 SCLogDebug("multi-detect not enabled (multi tenancy)");
3797 }
3798 return 0;
3799 error:
3800 return -1;
3801 }
3802
3803 static uint32_t DetectEngineTentantGetIdFromVlanId(const void *ctx, const Packet *p)
3804 {
3805 const DetectEngineThreadCtx *det_ctx = ctx;
3806 uint32_t x = 0;
3807 uint32_t vlan_id = 0;
3808
3809 if (p->vlan_idx == 0)
3810 return 0;
3811
3812 vlan_id = p->vlan_id[0];
3813
3814 if (det_ctx == NULL || det_ctx->tenant_array == NULL || det_ctx->tenant_array_size == 0)
3815 return 0;
3816
3817 /* not very efficient, but for now we're targeting only limited amounts.
3818 * Can use hash/tree approach later. */
3819 for (x = 0; x < det_ctx->tenant_array_size; x++) {
3820 if (det_ctx->tenant_array[x].traffic_id == vlan_id)
3821 return det_ctx->tenant_array[x].tenant_id;
3822 }
3823
3824 return 0;
3825 }
3826
3827 static uint32_t DetectEngineTentantGetIdFromLivedev(const void *ctx, const Packet *p)
3828 {
3829 const DetectEngineThreadCtx *det_ctx = ctx;
3830 const LiveDevice *ld = p->livedev;
3831
3832 if (ld == NULL || det_ctx == NULL)
3833 return 0;
3834
3835 SCLogDebug("using tenant-id %u for packet on device %s", ld->tenant_id, ld->dev);
3836 return ld->tenant_id;
3837 }
3838
3839 static int DetectEngineTentantRegisterSelector(enum DetectEngineTenantSelectors selector,
3840 uint32_t tenant_id, uint32_t traffic_id)
3841 {
3842 DetectEngineMasterCtx *master = &g_master_de_ctx;
3843 SCMutexLock(&master->lock);
3844
3845 if (!(master->tenant_selector == TENANT_SELECTOR_UNKNOWN || master->tenant_selector == selector)) {
3846 SCLogInfo("conflicting selector already set");
3847 SCMutexUnlock(&master->lock);
3848 return -1;
3849 }
3850
3851 DetectEngineTenantMapping *m = master->tenant_mapping_list;
3852 while (m) {
3853 if (m->traffic_id == traffic_id) {
3854 SCLogInfo("traffic id already registered");
3855 SCMutexUnlock(&master->lock);
3856 return -1;
3857 }
3858 m = m->next;
3859 }
3860
3861 DetectEngineTenantMapping *map = SCCalloc(1, sizeof(*map));
3862 if (map == NULL) {
3863 SCLogInfo("memory fail");
3864 SCMutexUnlock(&master->lock);
3865 return -1;
3866 }
3867 map->traffic_id = traffic_id;
3868 map->tenant_id = tenant_id;
3869
3870 map->next = master->tenant_mapping_list;
3871 master->tenant_mapping_list = map;
3872
3873 master->tenant_selector = selector;
3874
3875 SCLogDebug("tenant handler %u %u %u registered", selector, tenant_id, traffic_id);
3876 SCMutexUnlock(&master->lock);
3877 return 0;
3878 }
3879
3880 static int DetectEngineTentantUnregisterSelector(enum DetectEngineTenantSelectors selector,
3881 uint32_t tenant_id, uint32_t traffic_id)
3882 {
3883 DetectEngineMasterCtx *master = &g_master_de_ctx;
3884 SCMutexLock(&master->lock);
3885
3886 if (master->tenant_mapping_list == NULL) {
3887 SCMutexUnlock(&master->lock);
3888 return -1;
3889 }
3890
3891 DetectEngineTenantMapping *prev = NULL;
3892 DetectEngineTenantMapping *map = master->tenant_mapping_list;
3893 while (map) {
3894 if (map->traffic_id == traffic_id &&
3895 map->tenant_id == tenant_id)
3896 {
3897 if (prev != NULL)
3898 prev->next = map->next;
3899 else
3900 master->tenant_mapping_list = map->next;
3901
3902 map->next = NULL;
3903 SCFree(map);
3904 SCLogInfo("tenant handler %u %u %u unregistered", selector, tenant_id, traffic_id);
3905 SCMutexUnlock(&master->lock);
3906 return 0;
3907 }
3908 prev = map;
3909 map = map->next;
3910 }
3911
3912 SCMutexUnlock(&master->lock);
3913 return -1;
3914 }
3915
3916 int DetectEngineTentantRegisterLivedev(uint32_t tenant_id, int device_id)
3917 {
3918 return DetectEngineTentantRegisterSelector(TENANT_SELECTOR_LIVEDEV, tenant_id, (uint32_t)device_id);
3919 }
3920
3921 int DetectEngineTentantRegisterVlanId(uint32_t tenant_id, uint16_t vlan_id)
3922 {
3923 return DetectEngineTentantRegisterSelector(TENANT_SELECTOR_VLAN, tenant_id, (uint32_t)vlan_id);
3924 }
3925
3926 int DetectEngineTentantUnregisterVlanId(uint32_t tenant_id, uint16_t vlan_id)
3927 {
3928 return DetectEngineTentantUnregisterSelector(TENANT_SELECTOR_VLAN, tenant_id, (uint32_t)vlan_id);
3929 }
3930
3931 int DetectEngineTentantRegisterPcapFile(uint32_t tenant_id)
3932 {
3933 SCLogInfo("registering %u %d 0", TENANT_SELECTOR_DIRECT, tenant_id);
3934 return DetectEngineTentantRegisterSelector(TENANT_SELECTOR_DIRECT, tenant_id, 0);
3935 }
3936
3937 int DetectEngineTentantUnregisterPcapFile(uint32_t tenant_id)
3938 {
3939 SCLogInfo("unregistering %u %d 0", TENANT_SELECTOR_DIRECT, tenant_id);
3940 return DetectEngineTentantUnregisterSelector(TENANT_SELECTOR_DIRECT, tenant_id, 0);
3941 }
3942
3943 static uint32_t DetectEngineTentantGetIdFromPcap(const void *ctx, const Packet *p)
3944 {
3945 return p->pcap_v.tenant_id;
3946 }
3947
3948 DetectEngineCtx *DetectEngineGetByTenantId(int tenant_id)
3949 {
3950 DetectEngineMasterCtx *master = &g_master_de_ctx;
3951 SCMutexLock(&master->lock);
3952
3953 if (master->list == NULL) {
3954 SCMutexUnlock(&master->lock);
3955 return NULL;
3956 }
3957
3958 DetectEngineCtx *de_ctx = master->list;
3959 while (de_ctx) {
3960 if (de_ctx->type == DETECT_ENGINE_TYPE_TENANT &&
3961 de_ctx->tenant_id == tenant_id)
3962 {
3963 de_ctx->ref_cnt++;
3964 break;
3965 }
3966
3967 de_ctx = de_ctx->next;
3968 }
3969
3970 SCMutexUnlock(&master->lock);
3971 return de_ctx;
3972 }
3973
3974 void DetectEngineDeReference(DetectEngineCtx **de_ctx)
3975 {
3976 BUG_ON((*de_ctx)->ref_cnt == 0);
3977 (*de_ctx)->ref_cnt--;
3978 *de_ctx = NULL;
3979 }
3980
3981 static int DetectEngineAddToList(DetectEngineCtx *instance)
3982 {
3983 DetectEngineMasterCtx *master = &g_master_de_ctx;
3984
3985 if (instance == NULL)
3986 return -1;
3987
3988 if (master->list == NULL) {
3989 master->list = instance;
3990 } else {
3991 instance->next = master->list;
3992 master->list = instance;
3993 }
3994
3995 return 0;
3996 }
3997
3998 int DetectEngineAddToMaster(DetectEngineCtx *de_ctx)
3999 {
4000 int r;
4001
4002 if (de_ctx == NULL)
4003 return -1;
4004
4005 SCLogDebug("adding de_ctx %p to master", de_ctx);
4006
4007 DetectEngineMasterCtx *master = &g_master_de_ctx;
4008 SCMutexLock(&master->lock);
4009 r = DetectEngineAddToList(de_ctx);
4010 SCMutexUnlock(&master->lock);
4011 return r;
4012 }
4013
4014 int DetectEngineMoveToFreeList(DetectEngineCtx *de_ctx)
4015 {
4016 DetectEngineMasterCtx *master = &g_master_de_ctx;
4017
4018 SCMutexLock(&master->lock);
4019 DetectEngineCtx *instance = master->list;
4020 if (instance == NULL) {
4021 SCMutexUnlock(&master->lock);
4022 return -1;
4023 }
4024
4025 /* remove from active list */
4026 if (instance == de_ctx) {
4027 master->list = instance->next;
4028 } else {
4029 DetectEngineCtx *prev = instance;
4030 instance = instance->next; /* already checked first element */
4031
4032 while (instance) {
4033 DetectEngineCtx *next = instance->next;
4034
4035 if (instance == de_ctx) {
4036 prev->next = instance->next;
4037 break;
4038 }
4039
4040 prev = instance;
4041 instance = next;
4042 }
4043 if (instance == NULL) {
4044 SCMutexUnlock(&master->lock);
4045 return -1;
4046 }
4047 }
4048
4049 /* instance is now detached from list */
4050 instance->next = NULL;
4051
4052 /* add to free list */
4053 if (master->free_list == NULL) {
4054 master->free_list = instance;
4055 } else {
4056 instance->next = master->free_list;
4057 master->free_list = instance;
4058 }
4059 SCLogDebug("detect engine %p moved to free list (%u refs)", de_ctx, de_ctx->ref_cnt);
4060
4061 SCMutexUnlock(&master->lock);
4062 return 0;
4063 }
4064
4065 void DetectEnginePruneFreeList(void)
4066 {
4067 DetectEngineMasterCtx *master = &g_master_de_ctx;
4068 SCMutexLock(&master->lock);
4069
4070 DetectEngineCtx *prev = NULL;
4071 DetectEngineCtx *instance = master->free_list;
4072 while (instance) {
4073 DetectEngineCtx *next = instance->next;
4074
4075 SCLogDebug("detect engine %p has %u ref(s)", instance, instance->ref_cnt);
4076
4077 if (instance->ref_cnt == 0) {
4078 if (prev == NULL) {
4079 master->free_list = next;
4080 } else {
4081 prev->next = next;
4082 }
4083
4084 SCLogDebug("freeing detect engine %p", instance);
4085 DetectEngineCtxFree(instance);
4086 instance = NULL;
4087 }
4088
4089 prev = instance;
4090 instance = next;
4091 }
4092 SCMutexUnlock(&master->lock);
4093 }
4094
4095 static int reloads = 0;
4096
4097 /** \brief Reload the detection engine
4098 *
4099 * \param filename YAML file to load for the detect config
4100 *
4101 * \retval -1 error
4102 * \retval 0 ok
4103 */
4104 int DetectEngineReload(const SCInstance *suri)
4105 {
4106 DetectEngineCtx *new_de_ctx = NULL;
4107 DetectEngineCtx *old_de_ctx = NULL;
4108
4109 char prefix[128];
4110 memset(prefix, 0, sizeof(prefix));
4111
4112 SCLogNotice("rule reload starting");
4113
4114 if (suri->conf_filename != NULL) {
4115 snprintf(prefix, sizeof(prefix), "detect-engine-reloads.%d", reloads++);
4116 if (ConfYamlLoadFileWithPrefix(suri->conf_filename, prefix) != 0) {
4117 SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to load yaml %s",
4118 suri->conf_filename);
4119 return -1;
4120 }
4121
4122 ConfNode *node = ConfGetNode(prefix);
4123 if (node == NULL) {
4124 SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to properly setup yaml %s",
4125 suri->conf_filename);
4126 return -1;
4127 }
4128 #if 0
4129 ConfDump();
4130 #endif
4131 }
4132
4133 /* get a reference to the current de_ctx */
4134 old_de_ctx = DetectEngineGetCurrent();
4135 if (old_de_ctx == NULL)
4136 return -1;
4137 SCLogDebug("get ref to old_de_ctx %p", old_de_ctx);
4138 DatasetReload();
4139
4140 /* only reload a regular 'normal' and 'delayed detect stub' detect engines */
4141 if (!(old_de_ctx->type == DETECT_ENGINE_TYPE_NORMAL ||
4142 old_de_ctx->type == DETECT_ENGINE_TYPE_DD_STUB))
4143 {
4144 DetectEngineDeReference(&old_de_ctx);
4145 SCLogNotice("rule reload complete");
4146 return -1;
4147 }
4148
4149 /* get new detection engine */
4150 new_de_ctx = DetectEngineCtxInitWithPrefix(prefix);
4151 if (new_de_ctx == NULL) {
4152 SCLogError(SC_ERR_INITIALIZATION, "initializing detection engine "
4153 "context failed.");
4154 DetectEngineDeReference(&old_de_ctx);
4155 return -1;
4156 }
4157 if (SigLoadSignatures(new_de_ctx,
4158 suri->sig_file, suri->sig_file_exclusive) != 0) {
4159 DetectEngineCtxFree(new_de_ctx);
4160 DetectEngineDeReference(&old_de_ctx);
4161 return -1;
4162 }
4163 SCLogDebug("set up new_de_ctx %p", new_de_ctx);
4164
4165 /* add to master */
4166 DetectEngineAddToMaster(new_de_ctx);
4167
4168 /* move to old free list */
4169 DetectEngineMoveToFreeList(old_de_ctx);
4170 DetectEngineDeReference(&old_de_ctx);
4171
4172 SCLogDebug("going to reload the threads to use new_de_ctx %p", new_de_ctx);
4173 /* update the threads */
4174 DetectEngineReloadThreads(new_de_ctx);
4175 SCLogDebug("threads now run new_de_ctx %p", new_de_ctx);
4176
4177 /* walk free list, freeing the old_de_ctx */
4178 DetectEnginePruneFreeList();
4179
4180 DatasetPostReloadCleanup();
4181
4182 DetectEngineBumpVersion();
4183
4184 SCLogDebug("old_de_ctx should have been freed");
4185
4186 SCLogNotice("rule reload complete");
4187 return 0;
4188 }
4189
4190 static uint32_t TenantIdHash(HashTable *h, void *data, uint16_t data_len)
4191 {
4192 DetectEngineThreadCtx *det_ctx = (DetectEngineThreadCtx *)data;
4193 return det_ctx->tenant_id % h->array_size;
4194 }
4195
4196 static char TenantIdCompare(void *d1, uint16_t d1_len, void *d2, uint16_t d2_len)
4197 {
4198 DetectEngineThreadCtx *det1 = (DetectEngineThreadCtx *)d1;
4199 DetectEngineThreadCtx *det2 = (DetectEngineThreadCtx *)d2;
4200 return (det1->tenant_id == det2->tenant_id);
4201 }
4202
4203 static void TenantIdFree(void *d)
4204 {
4205 DetectEngineThreadCtxFree(d);
4206 }
4207
4208 int DetectEngineMTApply(void)
4209 {
4210 DetectEngineMasterCtx *master = &g_master_de_ctx;
4211 SCMutexLock(&master->lock);
4212
4213 if (master->tenant_selector == TENANT_SELECTOR_UNKNOWN) {
4214 SCLogInfo("error, no tenant selector");
4215 SCMutexUnlock(&master->lock);
4216 return -1;
4217 }
4218
4219 DetectEngineCtx *stub_de_ctx = NULL;
4220 DetectEngineCtx *list = master->list;
4221 for ( ; list != NULL; list = list->next) {
4222 SCLogDebug("list %p tenant %u", list, list->tenant_id);
4223
4224 if (list->type == DETECT_ENGINE_TYPE_NORMAL ||
4225 list->type == DETECT_ENGINE_TYPE_MT_STUB ||
4226 list->type == DETECT_ENGINE_TYPE_DD_STUB)
4227 {
4228 stub_de_ctx = list;
4229 break;
4230 }
4231 }
4232 if (stub_de_ctx == NULL) {
4233 stub_de_ctx = DetectEngineCtxInitStubForMT();
4234 if (stub_de_ctx == NULL) {
4235 SCMutexUnlock(&master->lock);
4236 return -1;
4237 }
4238
4239 if (master->list == NULL) {
4240 master->list = stub_de_ctx;
4241 } else {
4242 stub_de_ctx->next = master->list;
4243 master->list = stub_de_ctx;
4244 }
4245 }
4246
4247 /* update the threads */
4248 SCLogDebug("MT reload starting");
4249 DetectEngineReloadThreads(stub_de_ctx);
4250 SCLogDebug("MT reload done");
4251
4252 SCMutexUnlock(&master->lock);
4253
4254 /* walk free list, freeing the old_de_ctx */
4255 DetectEnginePruneFreeList();
4256
4257 SCLogDebug("old_de_ctx should have been freed");
4258 return 0;
4259 }
4260
4261 static int g_parse_metadata = 0;
4262
4263 void DetectEngineSetParseMetadata(void)
4264 {
4265 g_parse_metadata = 1;
4266 }
4267
4268 void DetectEngineUnsetParseMetadata(void)
4269 {
4270 g_parse_metadata = 0;
4271 }
4272
4273 int DetectEngineMustParseMetadata(void)
4274 {
4275 return g_parse_metadata;
4276 }
4277
4278 const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type)
4279 {
4280 switch (type) {
4281 case DETECT_SM_LIST_MATCH:
4282 return "packet";
4283 case DETECT_SM_LIST_PMATCH:
4284 return "packet/stream payload";
4285
4286 case DETECT_SM_LIST_TMATCH:
4287 return "tag";
4288
4289 case DETECT_SM_LIST_BASE64_DATA:
4290 return "base64_data";
4291
4292 case DETECT_SM_LIST_POSTMATCH:
4293 return "post-match";
4294
4295 case DETECT_SM_LIST_SUPPRESS:
4296 return "suppress";
4297 case DETECT_SM_LIST_THRESHOLD:
4298 return "threshold";
4299
4300 case DETECT_SM_LIST_MAX:
4301 return "max (internal)";
4302 }
4303 return "error";
4304 }
4305
4306 /* events api */
4307 void DetectEngineSetEvent(DetectEngineThreadCtx *det_ctx, uint8_t e)
4308 {
4309 AppLayerDecoderEventsSetEventRaw(&det_ctx->decoder_events, e);
4310 det_ctx->events++;
4311 }
4312
4313 AppLayerDecoderEvents *DetectEngineGetEvents(DetectEngineThreadCtx *det_ctx)
4314 {
4315 return det_ctx->decoder_events;
4316 }
4317
4318 int DetectEngineGetEventInfo(const char *event_name, int *event_id,
4319 AppLayerEventType *event_type)
4320 {
4321 *event_id = SCMapEnumNameToValue(event_name, det_ctx_event_table);
4322 if (*event_id == -1) {
4323 SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%s\" not present in "
4324 "det_ctx's enum map table.", event_name);
4325 /* this should be treated as fatal */
4326 return -1;
4327 }
4328 *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
4329
4330 return 0;
4331 }
4332
4333 /*************************************Unittest*********************************/
4334
4335 #ifdef UNITTESTS
4336
4337 static int DetectEngineInitYamlConf(const char *conf)
4338 {
4339 ConfCreateContextBackup();
4340 ConfInit();
4341 return ConfYamlLoadString(conf, strlen(conf));
4342 }
4343
4344 static void DetectEngineDeInitYamlConf(void)
4345 {
4346 ConfDeInit();
4347 ConfRestoreContextBackup();
4348
4349 return;
4350 }
4351
4352 static int DetectEngineTest01(void)
4353 {
4354 const char *conf =
4355 "%YAML 1.1\n"
4356 "---\n"
4357 "detect-engine:\n"
4358 " - profile: medium\n"
4359 " - custom-values:\n"
4360 " toclient_src_groups: 2\n"
4361 " toclient_dst_groups: 2\n"
4362 " toclient_sp_groups: 2\n"
4363 " toclient_dp_groups: 3\n"
4364 " toserver_src_groups: 2\n"
4365 " toserver_dst_groups: 4\n"
4366 " toserver_sp_groups: 2\n"
4367 " toserver_dp_groups: 25\n"
4368 " - inspection-recursion-limit: 0\n";
4369
4370 DetectEngineCtx *de_ctx = NULL;
4371 int result = 0;
4372
4373 if (DetectEngineInitYamlConf(conf) == -1)
4374 return 0;
4375 de_ctx = DetectEngineCtxInit();
4376 if (de_ctx == NULL)
4377 goto end;
4378
4379 result = (de_ctx->inspection_recursion_limit == -1);
4380
4381 end:
4382 if (de_ctx != NULL)
4383 DetectEngineCtxFree(de_ctx);
4384
4385 DetectEngineDeInitYamlConf();
4386
4387 return result;
4388 }
4389
4390 static int DetectEngineTest02(void)
4391 {
4392 const char *conf =
4393 "%YAML 1.1\n"
4394 "---\n"
4395 "detect-engine:\n"
4396 " - profile: medium\n"
4397 " - custom-values:\n"
4398 " toclient_src_groups: 2\n"
4399 " toclient_dst_groups: 2\n"
4400 " toclient_sp_groups: 2\n"
4401 " toclient_dp_groups: 3\n"
4402 " toserver_src_groups: 2\n"
4403 " toserver_dst_groups: 4\n"
4404 " toserver_sp_groups: 2\n"
4405 " toserver_dp_groups: 25\n"
4406 " - inspection-recursion-limit:\n";
4407
4408 DetectEngineCtx *de_ctx = NULL;
4409 int result = 0;
4410
4411 if (DetectEngineInitYamlConf(conf) == -1)
4412 return 0;
4413 de_ctx = DetectEngineCtxInit();
4414 if (de_ctx == NULL)
4415 goto end;
4416
4417 result = (de_ctx->inspection_recursion_limit == DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT);
4418
4419 end:
4420 if (de_ctx != NULL)
4421 DetectEngineCtxFree(de_ctx);
4422
4423 DetectEngineDeInitYamlConf();
4424
4425 return result;
4426 }
4427
4428 static int DetectEngineTest03(void)
4429 {
4430 const char *conf =
4431 "%YAML 1.1\n"
4432 "---\n"
4433 "detect-engine:\n"
4434 " - profile: medium\n"
4435 " - custom-values:\n"
4436 " toclient_src_groups: 2\n"
4437 " toclient_dst_groups: 2\n"
4438 " toclient_sp_groups: 2\n"
4439 " toclient_dp_groups: 3\n"
4440 " toserver_src_groups: 2\n"
4441 " toserver_dst_groups: 4\n"
4442 " toserver_sp_groups: 2\n"
4443 " toserver_dp_groups: 25\n";
4444
4445 DetectEngineCtx *de_ctx = NULL;
4446 int result = 0;
4447
4448 if (DetectEngineInitYamlConf(conf) == -1)
4449 return 0;
4450 de_ctx = DetectEngineCtxInit();
4451 if (de_ctx == NULL)
4452 goto end;
4453
4454 result = (de_ctx->inspection_recursion_limit ==
4455 DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT);
4456
4457 end:
4458 if (de_ctx != NULL)
4459 DetectEngineCtxFree(de_ctx);
4460
4461 DetectEngineDeInitYamlConf();
4462
4463 return result;
4464 }
4465
4466 static int DetectEngineTest04(void)
4467 {
4468 const char *conf =
4469 "%YAML 1.1\n"
4470 "---\n"
4471 "detect-engine:\n"
4472 " - profile: medium\n"
4473 " - custom-values:\n"
4474 " toclient_src_groups: 2\n"
4475 " toclient_dst_groups: 2\n"
4476 " toclient_sp_groups: 2\n"
4477 " toclient_dp_groups: 3\n"
4478 " toserver_src_groups: 2\n"
4479 " toserver_dst_groups: 4\n"
4480 " toserver_sp_groups: 2\n"
4481 " toserver_dp_groups: 25\n"
4482 " - inspection-recursion-limit: 10\n";
4483
4484 DetectEngineCtx *de_ctx = NULL;
4485 int result = 0;
4486
4487 if (DetectEngineInitYamlConf(conf) == -1)
4488 return 0;
4489 de_ctx = DetectEngineCtxInit();
4490 if (de_ctx == NULL)
4491 goto end;
4492
4493 result = (de_ctx->inspection_recursion_limit == 10);
4494
4495 end:
4496 if (de_ctx != NULL)
4497 DetectEngineCtxFree(de_ctx);
4498
4499 DetectEngineDeInitYamlConf();
4500
4501 return result;
4502 }
4503
4504 static int DetectEngineTest08(void)
4505 {
4506 const char *conf =
4507 "%YAML 1.1\n"
4508 "---\n"
4509 "detect-engine:\n"
4510 " - profile: custom\n"
4511 " - custom-values:\n"
4512 " toclient-groups: 23\n"
4513 " toserver-groups: 27\n";
4514
4515 DetectEngineCtx *de_ctx = NULL;
4516 int result = 0;
4517
4518 if (DetectEngineInitYamlConf(conf) == -1)
4519 return 0;
4520 de_ctx = DetectEngineCtxInit();
4521 if (de_ctx == NULL)
4522 goto end;
4523
4524 if (de_ctx->max_uniq_toclient_groups == 23 &&
4525 de_ctx->max_uniq_toserver_groups == 27)
4526 result = 1;
4527
4528 end:
4529 if (de_ctx != NULL)
4530 DetectEngineCtxFree(de_ctx);
4531
4532 DetectEngineDeInitYamlConf();
4533
4534 return result;
4535 }
4536
4537 /** \test bug 892 bad values */
4538 static int DetectEngineTest09(void)
4539 {
4540 const char *conf =
4541 "%YAML 1.1\n"
4542 "---\n"
4543 "detect-engine:\n"
4544 " - profile: custom\n"
4545 " - custom-values:\n"
4546 " toclient-groups: BA\n"
4547 " toserver-groups: BA\n"
4548 " - inspection-recursion-limit: 10\n";
4549
4550 DetectEngineCtx *de_ctx = NULL;
4551 int result = 0;
4552
4553 if (DetectEngineInitYamlConf(conf) == -1)
4554 return 0;
4555 de_ctx = DetectEngineCtxInit();
4556 if (de_ctx == NULL)
4557 goto end;
4558
4559 if (de_ctx->max_uniq_toclient_groups == 20 &&
4560 de_ctx->max_uniq_toserver_groups == 40)
4561 result = 1;
4562
4563 end:
4564 if (de_ctx != NULL)
4565 DetectEngineCtxFree(de_ctx);
4566
4567 DetectEngineDeInitYamlConf();
4568
4569 return result;
4570 }
4571
4572 #endif
4573
4574 void DetectEngineRegisterTests()
4575 {
4576 #ifdef UNITTESTS
4577 UtRegisterTest("DetectEngineTest01", DetectEngineTest01);
4578 UtRegisterTest("DetectEngineTest02", DetectEngineTest02);
4579 UtRegisterTest("DetectEngineTest03", DetectEngineTest03);
4580 UtRegisterTest("DetectEngineTest04", DetectEngineTest04);
4581 UtRegisterTest("DetectEngineTest08", DetectEngineTest08);
4582 UtRegisterTest("DetectEngineTest09", DetectEngineTest09);
4583 #endif
4584 return;
4585 }
4586