suricata
detect-engine-siggroup.c
Go to the documentation of this file.
1/* Copyright (C) 2007-2021 Open Information Security Foundation
2 *
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
5 * Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
17
18/**
19 * \file
20 *
21 * \author Victor Julien <victor@inliniac.net>
22 *
23 * Signature grouping part of the detection engine.
24 */
25
26#include "suricata-common.h"
27#include "decode.h"
28
29#include "flow-var.h"
30
31#include "app-layer-protos.h"
32
33#include "detect.h"
34#include "detect-parse.h"
35#include "detect-engine.h"
36#include "detect-engine-build.h"
38#include "detect-engine-mpm.h"
41
42#include "detect-content.h"
43#include "detect-uricontent.h"
44#include "detect-tcp-flags.h"
45
46#include "util-hash.h"
47#include "util-hashlist.h"
48
49#include "util-error.h"
50#include "util-debug.h"
51#include "util-validate.h"
52#include "util-cidr.h"
53#include "util-unittest.h"
55#include "util-memcmp.h"
56
57/* prototypes */
59
61{
62 if (sghid->match_array != NULL) {
63 SCFree(sghid->match_array);
64 sghid->match_array = NULL;
65 }
66 if (sghid->sig_array != NULL) {
68 sghid->sig_array = NULL;
69 }
70 if (sghid->app_mpms != NULL) {
71 SCFree(sghid->app_mpms);
72 }
73 if (sghid->pkt_mpms != NULL) {
74 SCFree(sghid->pkt_mpms);
75 }
76 if (sghid->frame_mpms != NULL) {
77 SCFree(sghid->frame_mpms);
78 }
79
85
86 SCFree(sghid);
87}
88
89static SigGroupHeadInitData *SigGroupHeadInitDataAlloc(uint32_t size)
90{
92 if (unlikely(sghid == NULL))
93 return NULL;
94
95 /* initialize the signature bitarray */
96 size = sghid->sig_size = size + 16 - (size % 16);
97 void *ptr = SCMallocAligned(sghid->sig_size, 16);
98 if (ptr == NULL)
99 goto error;
100 memset(ptr, 0, size);
101 sghid->sig_array = ptr;
102
103 return sghid;
104error:
106 return NULL;
107}
108
110{
111 void *ptmp;
112 //printf("de_ctx->sgh_array_cnt %u, de_ctx->sgh_array_size %u, de_ctx->sgh_array %p\n", de_ctx->sgh_array_cnt, de_ctx->sgh_array_size, de_ctx->sgh_array);
115 } else {
116 int increase = 16;
117 ptmp = SCRealloc(de_ctx->sgh_array,
118 sizeof(SigGroupHead *) * (increase + de_ctx->sgh_array_size));
119 if (ptmp == NULL) {
121 de_ctx->sgh_array = NULL;
122 return;
123 }
124 de_ctx->sgh_array = ptmp;
125
126 de_ctx->sgh_array_size += increase;
128 }
130}
131
132/**
133 * \brief Alloc a SigGroupHead and its signature bit_array.
134 *
135 * \param size Size of the sig_array that has to be created for this
136 * SigGroupHead.
137 *
138 * \retval sgh Pointer to the newly init SigGroupHead on success; or NULL in
139 * case of error.
140 */
141static SigGroupHead *SigGroupHeadAlloc(const DetectEngineCtx *de_ctx, uint32_t size)
142{
143 SigGroupHead *sgh = SCCalloc(1, sizeof(SigGroupHead));
144 if (unlikely(sgh == NULL))
145 return NULL;
146
147 sgh->init = SigGroupHeadInitDataAlloc(size);
148 if (sgh->init == NULL)
149 goto error;
150
151 return sgh;
152
153error:
155 return NULL;
156}
157
158/**
159 * \brief Free a SigGroupHead and its members.
160 *
161 * \param sgh Pointer to the SigGroupHead that has to be freed.
162 */
164{
165 if (sgh == NULL)
166 return;
167
168 SCLogDebug("sgh %p", sgh);
169
170 if (sgh->init != NULL) {
172 sgh->init = NULL;
173 }
174
176 SCFree(sgh);
177}
178
179/**
180 * \brief The hash function to be the used by the hash table -
181 * DetectEngineCtx->sgh_hash_table.
182 *
183 * \param ht Pointer to the hash table.
184 * \param data Pointer to the SigGroupHead.
185 * \param datalen Not used in our case.
186 *
187 * \retval hash The generated hash value.
188 */
189static uint32_t SigGroupHeadHashFunc(HashListTable *ht, void *data, uint16_t datalen)
190{
191 SigGroupHead *sgh = (SigGroupHead *)data;
192 uint32_t hash = 0;
193 uint32_t b = 0;
194
195 SCLogDebug("hashing sgh %p", sgh);
196
197 for (b = 0; b < sgh->init->sig_size; b++)
198 hash += sgh->init->sig_array[b];
199
200 hash %= ht->array_size;
201 SCLogDebug("hash %"PRIu32" (sig_size %"PRIu32")", hash, sgh->init->sig_size);
202 return hash;
203}
204
205/**
206 * \brief The Compare function to be used by the SigGroupHead hash table -
207 * DetectEngineCtx->sgh_hash_table.
208 *
209 * \param data1 Pointer to the first SigGroupHead.
210 * \param len1 Not used.
211 * \param data2 Pointer to the second SigGroupHead.
212 * \param len2 Not used.
213 *
214 * \retval 1 If the 2 SigGroupHeads sent as args match.
215 * \retval 0 If the 2 SigGroupHeads sent as args do not match.
216 */
217static char SigGroupHeadCompareFunc(void *data1, uint16_t len1, void *data2,
218 uint16_t len2)
219{
220 SigGroupHead *sgh1 = (SigGroupHead *)data1;
221 SigGroupHead *sgh2 = (SigGroupHead *)data2;
222
223 if (data1 == NULL || data2 == NULL)
224 return 0;
225
226 if (sgh1->init->sig_size != sgh2->init->sig_size)
227 return 0;
228
229 if (SCMemcmp(sgh1->init->sig_array, sgh2->init->sig_array, sgh1->init->sig_size) != 0)
230 return 0;
231
232 return 1;
233}
234
235/**
236 * \brief Initializes the hash table in the detection engine context to hold the
237 * SigGroupHeads.
238 *
239 * \param de_ctx Pointer to the detection engine context.
240 *
241 * \retval 0 On success.
242 * \retval -1 On failure.
243 */
245{
246 de_ctx->sgh_hash_table = HashListTableInit(4096, SigGroupHeadHashFunc,
247 SigGroupHeadCompareFunc, NULL);
248 if (de_ctx->sgh_hash_table == NULL)
249 goto error;
250
251 return 0;
252
253error:
254 return -1;
255}
256
257/**
258 * \brief Adds a SigGroupHead to the detection engine context SigGroupHead
259 * hash table.
260 *
261 * \param de_ctx Pointer to the detection engine context.
262 * \param sgh Pointer to the SigGroupHead.
263 *
264 * \retval ret 0 on Successfully adding the SigGroupHead; -1 on failure.
265 */
267{
268 int ret = HashListTableAdd(de_ctx->sgh_hash_table, (void *)sgh, 0);
269
270 return ret;
271}
272
273/**
274 * \brief Used to lookup a SigGroupHead hash from the detection engine context
275 * SigGroupHead hash table.
276 *
277 * \param de_ctx Pointer to the detection engine context.
278 * \param sgh Pointer to the SigGroupHead.
279 *
280 * \retval rsgh On success a pointer to the SigGroupHead if the SigGroupHead is
281 * found in the hash table; NULL on failure.
282 */
284{
285 SCEnter();
286
288 (void *)sgh, 0);
289
290 SCReturnPtr(rsgh, "SigGroupHead");
291}
292
293/**
294 * \brief Frees the hash table - DetectEngineCtx->sgh_hash_table, allocated by
295 * SigGroupHeadHashInit() function.
296 *
297 * \param de_ctx Pointer to the detection engine context.
298 */
307
308/**
309 * \brief Add a Signature to a SigGroupHead.
310 *
311 * \param de_ctx Pointer to the detection engine context.
312 * \param sgh Pointer to a SigGroupHead. Can be NULL also.
313 * \param s Pointer to the Signature that has to be added to the
314 * SigGroupHead.
315 *
316 * \retval 0 On success.
317 * \retval -1 On failure.
318 */
320 const Signature *s)
321{
322 if (de_ctx == NULL)
323 return 0;
324
325 /* see if we have a head already */
326 if (*sgh == NULL) {
327 *sgh = SigGroupHeadAlloc(de_ctx, DetectEngineGetMaxSigId(de_ctx) / 8 + 1);
328 if (*sgh == NULL)
329 goto error;
330 }
331
332 /* enable the sig in the bitarray */
333 (*sgh)->init->sig_array[s->iid / 8] |= 1 << (s->iid % 8);
334 (*sgh)->init->max_sig_id = MAX(s->iid, (*sgh)->init->max_sig_id);
335 return 0;
336
337error:
338 return -1;
339}
340
341/**
342 * \brief Clears the bitarray holding the sids for this SigGroupHead.
343 *
344 * \param sgh Pointer to the SigGroupHead.
345 *
346 * \retval 0 Always.
347 */
349{
350 if (sgh == NULL)
351 return 0;
352
353 if (sgh->init->sig_array != NULL)
354 memset(sgh->init->sig_array, 0, sgh->init->sig_size);
355
356 sgh->init->sig_cnt = 0;
357
358 return 0;
359}
360
361#ifdef __SSE2__
362#include <emmintrin.h>
363static void MergeBitarrays(const uint8_t *src, uint8_t *dst, const uint32_t size)
364{
365#define BYTES 16
366 const uint8_t *srcptr = src;
367 uint8_t *dstptr = dst;
368 for (uint32_t i = 0; i < size; i += 16) {
369 __m128i s = _mm_load_si128((const __m128i *)srcptr);
370 __m128i d = _mm_load_si128((const __m128i *)dstptr);
371 d = _mm_or_si128(s, d);
372 _mm_store_si128((__m128i *)dstptr, d);
373 srcptr += BYTES;
374 dstptr += BYTES;
375 }
376}
377#endif
378
379/**
380 * \brief Copies the bitarray holding the sids from the source SigGroupHead to
381 * the destination SigGroupHead.
382 *
383 * \param de_ctx Pointer to the detection engine context.
384 * \param src Pointer to the source SigGroupHead.
385 * \param dst Pointer to the destination SigGroupHead.
386 *
387 * \retval 0 On success.
388 * \retval -1 On failure.
389 */
391{
392 if (src == NULL || de_ctx == NULL)
393 return 0;
394
395 if (*dst == NULL) {
396 *dst = SigGroupHeadAlloc(de_ctx, DetectEngineGetMaxSigId(de_ctx) / 8 + 1);
397 if (*dst == NULL)
398 goto error;
399 }
400 DEBUG_VALIDATE_BUG_ON(src->init->sig_size != (*dst)->init->sig_size);
401
402#ifdef __SSE2__
403 MergeBitarrays(src->init->sig_array, (*dst)->init->sig_array, src->init->sig_size);
404#else
405 /* do the copy */
406 for (uint32_t idx = 0; idx < src->init->sig_size; idx++)
407 (*dst)->init->sig_array[idx] = (*dst)->init->sig_array[idx] | src->init->sig_array[idx];
408#endif
409 if (src->init->score)
410 (*dst)->init->score = MAX((*dst)->init->score, src->init->score);
411
412 if (src->init->max_sig_id)
413 (*dst)->init->max_sig_id = MAX((*dst)->init->max_sig_id, src->init->max_sig_id);
414 return 0;
415
416error:
417 return -1;
418}
419
420#ifdef HAVE_POPCNT64
421#include <x86intrin.h>
422static uint32_t Popcnt(const uint8_t *array, const uint32_t size)
423{
424 /* input needs to be a multiple of 8 for u64 casts to work */
425 DEBUG_VALIDATE_BUG_ON(size < 8);
426 DEBUG_VALIDATE_BUG_ON(size % 8);
427
428 uint32_t cnt = 0;
429 uint64_t *ptr = (uint64_t *)array;
430 for (uint64_t idx = 0; idx < size; idx += 8) {
431 cnt += _popcnt64(*ptr);
432 ptr++;
433 }
434 return cnt;
435}
436#endif
437
438/**
439 * \brief Updates the SigGroupHead->sig_cnt with the total count of all the
440 * Signatures present in this SigGroupHead.
441 *
442 * \param sgh Pointer to the SigGroupHead.
443 * \param max_idx Maximum sid of the all the Signatures present in this
444 * SigGroupHead.
445 */
446void SigGroupHeadSetSigCnt(SigGroupHead *sgh, uint32_t max_idx)
447{
448 sgh->init->max_sig_id = MAX(max_idx, sgh->init->max_sig_id);
449#ifdef HAVE_POPCNT64
450 sgh->init->sig_cnt = Popcnt(sgh->init->sig_array, sgh->init->sig_size);
451#else
452 uint32_t cnt = 0;
453 for (uint32_t sig = 0; sig < sgh->init->max_sig_id + 1; sig++) {
454 if (sgh->init->sig_array[sig / 8] & (1 << (sig % 8)))
455 cnt++;
456 }
457 sgh->init->sig_cnt = cnt;
458#endif
459}
460
461/**
462 * \brief Finds if two Signature Group Heads are the same.
463 *
464 * \param sgha First SGH to be compared
465 * \param sghb Secornd SGH to be compared
466 *
467 * \return true if they're a match, false otherwise
468 */
469bool SigGroupHeadEqual(const SigGroupHead *sgha, const SigGroupHead *sghb)
470{
471 if (sgha == NULL || sghb == NULL)
472 return false;
473
474 if (sgha->init->sig_size != sghb->init->sig_size)
475 return false;
476
477 if (sgha->init->max_sig_id != sghb->init->max_sig_id)
478 return false;
479
480 if (SCMemcmp(sgha->init->sig_array, sghb->init->sig_array, sgha->init->sig_size) != 0)
481 return false;
482
483 return true;
484}
485
487 uint8_t ipproto, int dir)
488{
489 if (sgh && sgh->init) {
490 SCLogDebug("setting proto %u and dir %d on sgh %p", ipproto, dir, sgh);
491 sgh->init->protos[ipproto] = 1;
492 sgh->init->direction |= dir;
493 }
494}
495
496/**
497 * \brief Helper function used to print the list of sids for the Signatures
498 * present in this SigGroupHead.
499 *
500 * \param de_ctx Pointer to the detection engine context.
501 * \param sgh Pointer to the SigGroupHead.
502 */
504{
505 SCEnter();
506
507 if (sgh == NULL) {
508 SCReturn;
509 }
510
511 uint32_t u;
512
513 SCLogDebug("The Signatures present in this SigGroupHead are: ");
514 for (u = 0; u < (sgh->init->sig_size * 8); u++) {
515 if (sgh->init->sig_array[u / 8] & (1 << (u % 8))) {
516 SCLogDebug("%" PRIu32, u);
517 printf("s->iid %" PRIu32 " ", u);
518 }
519 }
520
521 SCReturn;
522}
523
524/**
525 * \brief Create an array with all the internal ids of the sigs that this
526 * sig group head will check for.
527 *
528 * \param de_ctx Pointer to the detection engine context.
529 * \param sgh Pointer to the SigGroupHead.
530 * \param max_idx The maximum value of the sid in the SigGroupHead arg.
531 *
532 * \retval 0 success
533 * \retval -1 error
534 */
536 uint32_t max_idx)
537{
538 Signature *s = NULL;
539 uint32_t idx = 0;
540 uint32_t sig = 0;
541
542 if (sgh == NULL)
543 return 0;
544
545 BUG_ON(sgh->init->match_array != NULL);
546 sgh->init->max_sig_id = MAX(sgh->init->max_sig_id, max_idx);
547
548 sgh->init->match_array = SCCalloc(sgh->init->sig_cnt, sizeof(Signature *));
549 if (sgh->init->match_array == NULL)
550 return -1;
551
552 for (sig = 0; sig < sgh->init->max_sig_id + 1; sig++) {
553 if (!(sgh->init->sig_array[(sig / 8)] & (1 << (sig % 8))) )
554 continue;
555
556 s = de_ctx->sig_array[sig];
557 if (s == NULL)
558 continue;
559
560 sgh->init->match_array[idx] = s;
561 idx++;
562 }
563
564 return 0;
565}
566
567/**
568 * \brief Set the need hash flag in the sgh.
569 *
570 * \param de_ctx detection engine ctx for the signatures
571 * \param sgh sig group head to update
572 */
574{
575 if (sgh == NULL)
576 return;
577
578 for (uint32_t sig = 0; sig < sgh->init->sig_cnt; sig++) {
579 const Signature *s = sgh->init->match_array[sig];
580 if (s == NULL)
581 continue;
582
585 }
588 SCLogDebug("sgh %p has filemd5", sgh);
589 }
592 SCLogDebug("sgh %p has filesha1", sgh);
593 }
596 SCLogDebug("sgh %p has filesha256", sgh);
597 }
598#ifdef HAVE_MAGIC
600 sgh->flags |= SIG_GROUP_HEAD_HAVEFILEMAGIC;
601 }
602#endif
603 if (SignatureIsFilestoring(s)) {
604 // should be insured by caller that we do not overflow
605 DEBUG_VALIDATE_BUG_ON(sgh->filestore_cnt == UINT16_MAX);
606 sgh->filestore_cnt++;
607 }
608 }
609}
610
611/**
612 * \brief Check if a SigGroupHead contains a Signature, whose sid is sent as an
613 * argument.
614 *
615 * \param de_ctx Pointer to the detection engine context.
616 * \param sgh Pointer to the SigGroupHead that has to be checked for the
617 * presence of a Signature.
618 * \param sid The Signature id(sid) that has to be checked in the SigGroupHead.
619 *
620 * \retval 1 On successfully finding the sid in the SigGroupHead.
621 * \retval 0 If the sid is not found in the SigGroupHead
622 */
624 uint32_t sid)
625{
626 SCEnter();
627
628 uint32_t sig = 0;
629 Signature *s = NULL;
630 uint32_t max_sid = DetectEngineGetMaxSigId(de_ctx);
631
632 if (sgh == NULL) {
633 SCReturnInt(0);
634 }
635
636 for (sig = 0; sig < max_sid; sig++) {
637 if (sgh->init->sig_array == NULL) {
638 SCReturnInt(0);
639 }
640
641 /* Check if the SigGroupHead has an entry for the sid */
642 if ( !(sgh->init->sig_array[sig / 8] & (1 << (sig % 8))) )
643 continue;
644
645 /* If we have reached here, we have an entry for sid in the SigGroupHead.
646 * Retrieve the Signature from the detection engine context */
647 s = de_ctx->sig_array[sig];
648 if (s == NULL)
649 continue;
650
651 /* If the retrieved Signature matches the sid arg, we have a match */
652 if (s->id == sid) {
653 SCReturnInt(1);
654 }
655 }
656
657 SCReturnInt(0);
658}
659
660/*----------------------------------Unittests---------------------------------*/
661
662#ifdef UNITTESTS
663
665
666/**
667 * \test Check if a SigGroupHead hash table is properly allocated and
668 * deallocated when calling SigGroupHeadHashInit() and
669 * SigGroupHeadHashFree() respectively.
670 */
671static int SigGroupHeadTest01(void)
672{
674
677
680
681 PASS;
682}
683
684/**
685 * \test Check if a SigGroupHeadAppendSig() correctly appends a sid to a
686 * SigGroupHead() and SigGroupHeadContainsSigId() correctly indicates
687 * the presence of a sid.
688 */
689static int SigGroupHeadTest02(void)
690{
691 SigGroupHead *sh = NULL;
692
695
696 Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
697 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
698 "content:\"test2\"; content:\"test3\"; sid:1;)");
699 FAIL_IF_NULL(s);
700
701 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
702 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
703 "content:\"test2\"; content:\"test3\"; sid:2;)");
704 FAIL_IF_NULL(s);
705
706 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
707 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
708 "content:\"test2\"; content:\"test3\"; sid:3;)");
709 FAIL_IF_NULL(s);
710
711 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
712 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
713 "content:\"test2\"; content:\"test3\"; sid:4;)");
714 FAIL_IF_NULL(s);
715
716 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
717 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
718 "content:\"test2\"; content:\"test3\"; sid:5;)");
719 FAIL_IF_NULL(s);
720
722
726
728
729 FAIL_IF_NOT(sh->init->sig_cnt == 3);
735
737
739
740 PASS;
741}
742
743/**
744 * \test Check if a SigGroupHeadAppendSig(), correctly appends a sid to a
745 * SigGroupHead() and SigGroupHeadContainsSigId(), correctly indicates
746 * the presence of a sid and SigGroupHeadClearSigs(), correctly clears
747 * the SigGroupHead->sig_array and SigGroupHead->sig_cnt.
748 */
749static int SigGroupHeadTest03(void)
750{
751 SigGroupHead *sh = NULL;
752
755
756 Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
757 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
758 "content:\"test2\"; content:\"test3\"; sid:1;)");
759 FAIL_IF_NULL(s);
760
761 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
762 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
763 "content:\"test2\"; content:\"test3\"; sid:2;)");
764 FAIL_IF_NULL(s);
765
766 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
767 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
768 "content:\"test2\"; content:\"test3\"; sid:3;)");
769 FAIL_IF_NULL(s);
770
771 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
772 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
773 "content:\"test2\"; content:\"test3\"; sid:4;)");
774 FAIL_IF_NULL(s);
775
776 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
777 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
778 "content:\"test2\"; content:\"test3\"; sid:5;)");
779 FAIL_IF_NULL(s);
780
782
786
788
789 FAIL_IF_NOT(sh->init->sig_cnt == 3);
795
797
798 FAIL_IF_NOT(sh->init->sig_cnt == 0);
804
806
808
809 PASS;
810}
811
812/**
813 * \test Check if SigGroupHeadCopySigs(), correctly copies the sig_array from
814 * the source to the destination SigGroupHead.
815 */
816static int SigGroupHeadTest04(void)
817{
818 SigGroupHead *src_sh = NULL;
819 SigGroupHead *dst_sh = NULL;
821
823
824 Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
825 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
826 "content:\"test2\"; content:\"test3\"; sid:1;)");
827 FAIL_IF_NULL(s);
828
829 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
830 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
831 "content:\"test2\"; content:\"test3\"; sid:2;)");
832 FAIL_IF_NULL(s);
833
834 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
835 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
836 "content:\"test2\"; content:\"test3\"; sid:3;)");
837 FAIL_IF_NULL(s);
838
839 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
840 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
841 "content:\"test2\"; content:\"test3\"; sid:4;)");
842 FAIL_IF_NULL(s);
843
844 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
845 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
846 "content:\"test2\"; content:\"test3\"; sid:5;)");
847 FAIL_IF_NULL(s);
848
850
854
855 SigGroupHeadSetSigCnt(src_sh, 4);
856
857 FAIL_IF_NOT(src_sh->init->sig_cnt == 3);
863
864 SigGroupHeadCopySigs(de_ctx, src_sh, &dst_sh);
865
866 SigGroupHeadSetSigCnt(dst_sh, 4);
867
868 FAIL_IF_NOT(dst_sh->init->sig_cnt == 3);
874
875 SigGroupHeadFree(de_ctx, src_sh);
876 SigGroupHeadFree(de_ctx, dst_sh);
877
879
880 PASS;
881}
882
883/**
884 * \test Check if SigGroupHeadBuildMatchArray(), correctly updates the
885 * match array with the sids.
886 */
887static int SigGroupHeadTest05(void)
888{
889 SigGroupHead *sh = NULL;
891
893
894 Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
895 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
896 "content:\"test2\"; content:\"test3\"; sid:1;)");
897 FAIL_IF_NULL(s);
898
899 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
900 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
901 "content:\"test2\"; content:\"test3\"; sid:2;)");
902 FAIL_IF_NULL(s);
903
904 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
905 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
906 "content:\"test2\"; content:\"test3\"; sid:3;)");
907 FAIL_IF_NULL(s);
908
909 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
910 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
911 "content:\"test2\"; content:\"test3\"; sid:4;)");
912 FAIL_IF_NULL(s);
913
914 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
915 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
916 "content:\"test2\"; content:\"test3\"; sid:5;)");
917 FAIL_IF_NULL(s);
918
920
924
927
928 /* matching an array to a queue structure (sig_list) constructed by SigInit()
929
930 FAIL_IF_NOT(sh->init->match_array[0] == de_ctx->sig_list);
931 FAIL_IF_NOT(sh->init->match_array[1] == de_ctx->sig_list->next->next);
932 FAIL_IF_NOT(sh->init->match_array[2] == de_ctx->sig_list->next->next->next->next);
933 */
934
935 // matching an array to a stack structure (sig_list) constructed by DetectEngineAppendSig()
939
941
943
944 PASS;
945}
946
947/**
948 * \test ICMP(?) sig grouping bug.
949 */
950static int SigGroupHeadTest06(void)
951{
953 DetectEngineThreadCtx *det_ctx = NULL;
954 ThreadVars th_v;
955
956 memset(&th_v, 0, sizeof(ThreadVars));
957
958 Packet *p = UTHBuildPacketSrcDst(NULL, 0, IPPROTO_ICMP, "192.168.1.1", "1.2.3.4");
959 FAIL_IF_NULL(p);
960 FAIL_IF_NOT(PacketIsICMPv4(p));
961
962 p->l4.hdrs.icmpv4h->type = 5;
963 p->l4.hdrs.icmpv4h->code = 1;
964
965 /* originally ip's were
966 p.src.addr_data32[0] = 0xe08102d3;
967 p.dst.addr_data32[0] = 0x3001a8c0;
968 */
969
971
972 Signature *s = DetectEngineAppendSig(de_ctx, "alert icmp 192.168.0.0/16 any -> any any "
973 "(icode:>1; itype:11; sid:1; rev:1;)");
974 FAIL_IF_NULL(s);
975
976 s = DetectEngineAppendSig(de_ctx, "alert icmp any any -> 192.168.0.0/16 any "
977 "(icode:1; itype:5; sid:2; rev:1;)");
978 FAIL_IF_NULL(s);
979
981 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
982
984
986 FAIL_IF_NULL(sgh);
987
989 UTHFreePackets(&p, 1);
990
991 PASS;
992}
993#endif
994
996{
997#ifdef UNITTESTS
998 UtRegisterTest("SigGroupHeadTest01", SigGroupHeadTest01);
999 UtRegisterTest("SigGroupHeadTest02", SigGroupHeadTest02);
1000 UtRegisterTest("SigGroupHeadTest03", SigGroupHeadTest03);
1001 UtRegisterTest("SigGroupHeadTest04", SigGroupHeadTest04);
1002 UtRegisterTest("SigGroupHeadTest05", SigGroupHeadTest05);
1003 UtRegisterTest("SigGroupHeadTest06", SigGroupHeadTest06);
1004#endif
1005}
uint16_t dst
uint16_t src
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
int SignatureIsFilemagicInspecting(const Signature *s)
Check if a signature contains the filemagic keyword.
int SignatureIsFilestoring(const Signature *s)
Check if a signature contains the filestore keyword.
int SignatureIsFileSha256Inspecting(const Signature *s)
Check if a signature contains the filesha256 keyword.
int SignatureIsFileMd5Inspecting(const Signature *s)
Check if a signature contains the filemd5 keyword.
int SignatureIsFilesizeInspecting(const Signature *s)
Check if a signature contains the filesize keyword.
int SignatureIsFileSha1Inspecting(const Signature *s)
Check if a signature contains the filesha1 keyword.
void PrefilterFreeEnginesList(PrefilterEngineList *list)
void PrefilterCleanupRuleGroup(const DetectEngineCtx *de_ctx, SigGroupHead *sgh)
void SigGroupHeadRegisterTests(void)
SigGroupHead * SigGroupHeadHashLookup(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
Used to lookup a SigGroupHead hash from the detection engine context SigGroupHead hash table.
void SigGroupHeadPrintSigs(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
Helper function used to print the list of sids for the Signatures present in this SigGroupHead.
void SigGroupHeadStore(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
int SigGroupHeadCopySigs(DetectEngineCtx *de_ctx, SigGroupHead *src, SigGroupHead **dst)
Copies the bitarray holding the sids from the source SigGroupHead to the destination SigGroupHead.
int SigGroupHeadBuildMatchArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh, uint32_t max_idx)
Create an array with all the internal ids of the sigs that this sig group head will check for.
void SigGroupHeadInitDataFree(SigGroupHeadInitData *sghid)
int SigPrepareStage1(DetectEngineCtx *)
Preprocess signature, classify ip-only, etc, build sig array.
void SigGroupHeadSetupFiles(const DetectEngineCtx *de_ctx, SigGroupHead *sgh)
Set the need hash flag in the sgh.
int SigGroupHeadHashAdd(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
Adds a SigGroupHead to the detection engine context SigGroupHead hash table.
int SigGroupHeadContainsSigId(DetectEngineCtx *de_ctx, SigGroupHead *sgh, uint32_t sid)
Check if a SigGroupHead contains a Signature, whose sid is sent as an argument.
void SigGroupHeadSetSigCnt(SigGroupHead *sgh, uint32_t max_idx)
Updates the SigGroupHead->sig_cnt with the total count of all the Signatures present in this SigGroup...
int SigGroupHeadAppendSig(const DetectEngineCtx *de_ctx, SigGroupHead **sgh, const Signature *s)
Add a Signature to a SigGroupHead.
int SigGroupHeadHashInit(DetectEngineCtx *de_ctx)
Initializes the hash table in the detection engine context to hold the SigGroupHeads.
void SigGroupHeadHashFree(DetectEngineCtx *de_ctx)
Frees the hash table - DetectEngineCtx->sgh_hash_table, allocated by SigGroupHeadHashInit() function.
int SigGroupHeadClearSigs(SigGroupHead *)
Clears the bitarray holding the sids for this SigGroupHead.
void SigGroupHeadFree(const DetectEngineCtx *de_ctx, SigGroupHead *sgh)
Free a SigGroupHead and its members.
void SigGroupHeadSetProtoAndDirection(SigGroupHead *sgh, uint8_t ipproto, int dir)
bool SigGroupHeadEqual(const SigGroupHead *sgha, const SigGroupHead *sghb)
Finds if two Signature Group Heads are the same.
DetectEngineCtx * DetectEngineCtxInit(void)
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Signature * DetectEngineAppendSig(DetectEngineCtx *, const char *)
Parse and append a Signature into the Detection Engine Context signature list.
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
initialize thread specific detection engine context
#define DetectEngineGetMaxSigId(de_ctx)
const SigGroupHead * SigMatchSignaturesGetSgh(const DetectEngineCtx *de_ctx, const Packet *p)
Get the SigGroupHead for a packet.
Definition detect.c:282
#define SIG_GROUP_HEAD_HAVEFILESHA1
Definition detect.h:1494
#define SIG_GROUP_HEAD_HAVEFILESHA256
Definition detect.h:1495
#define SIG_GROUP_HEAD_HAVEFILESIZE
Definition detect.h:1493
#define SIG_GROUP_HEAD_HAVEFILEMD5
Definition detect.h:1492
DetectEngineCtx * de_ctx
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
#define PASS
Pass the test.
#define FAIL_IF_NOT_NULL(expr)
Fail a test if expression evaluates to non-NULL.
void AddressDebugPrint(Address *a)
Debug print function for printing addresses.
Definition decode.c:787
main detection engine ctx
Definition detect.h:932
uint32_t sgh_array_size
Definition detect.h:1002
uint32_t sgh_array_cnt
Definition detect.h:1001
struct SigGroupHead_ ** sgh_array
Definition detect.h:1000
Signature ** sig_array
Definition detect.h:950
Signature * sig_list
Definition detect.h:941
HashListTable * sgh_hash_table
Definition detect.h:962
uint32_t array_size
union PacketL4::L4Hdrs hdrs
struct PacketL4 l4
Definition decode.h:601
Address dst
Definition decode.h:506
Signature ** match_array
Definition detect.h:1625
PrefilterEngineList * frame_engines
Definition detect.h:1618
MpmCtx ** frame_mpms
Definition detect.h:1613
uint8_t * sig_array
Definition detect.h:1603
PrefilterEngineList * post_rule_match_engines
Definition detect.h:1619
PrefilterEngineList * pkt_engines
Definition detect.h:1615
PrefilterEngineList * tx_engines
Definition detect.h:1617
PrefilterEngineList * payload_engines
Definition detect.h:1616
uint8_t protos[256]
Definition detect.h:1606
Container for matching data for a signature group.
Definition detect.h:1629
SigGroupHeadInitData * init
Definition detect.h:1646
uint16_t flags
Definition detect.h:1630
uint16_t filestore_cnt
Definition detect.h:1635
Signature container.
Definition detect.h:668
SigIntId iid
Definition detect.h:680
uint32_t id
Definition detect.h:713
struct Signature_ * next
Definition detect.h:750
Per thread variable structure.
Definition threadvars.h:58
#define BUG_ON(x)
#define MAX(x, y)
uint32_t cnt
ICMPV4Hdr * icmpv4h
Definition decode.h:471
#define SCEnter(...)
Definition util-debug.h:277
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCReturnInt(x)
Definition util-debug.h:281
#define SCReturnPtr(x, type)
Definition util-debug.h:293
#define SCReturn
Definition util-debug.h:279
void * HashListTableLookup(HashListTable *ht, void *data, uint16_t datalen)
int HashListTableAdd(HashListTable *ht, void *data, uint16_t datalen)
HashListTable * HashListTableInit(uint32_t size, uint32_t(*Hash)(struct HashListTable_ *, void *, uint16_t), char(*Compare)(void *, uint16_t, void *, uint16_t), void(*Free)(void *))
void HashListTableFree(HashListTable *ht)
#define SCFreeAligned(p)
Definition util-mem.h:77
#define SCFree(p)
Definition util-mem.h:61
#define SCMallocAligned(size, align)
Definition util-mem.h:68
#define SCRealloc(ptr, sz)
Definition util-mem.h:50
#define SCCalloc(nm, sz)
Definition util-mem.h:53
#define SCMemcmp(a, b, c)
#define unlikely(expr)
void UTHFreePackets(Packet **p, int numpkts)
UTHFreePackets: function to release the allocated data from UTHBuildPacket and the packet itself.
Packet * UTHBuildPacketSrcDst(uint8_t *payload, uint16_t payload_len, uint8_t ipproto, const char *src, const char *dst)
UTHBuildPacketSrcDst is a wrapper that build packets specifying IPs and defaulting ports.
#define DEBUG_VALIDATE_BUG_ON(exp)