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"
37 #include "detect-engine-address.h"
38 #include "detect-engine-mpm.h"
39 #include "detect-engine-siggroup.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"
54 #include "util-unittest-helper.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) {
67  SCFreeAligned(sghid->sig_array);
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 
89 static 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;
104 error:
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  */
141 static 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 
153 error:
154  SigGroupHeadFree(de_ctx, sgh);
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  */
189 static 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  */
217 static 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 
253 error:
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  */
300 {
301  if (de_ctx->sgh_hash_table == NULL)
302  return;
303 
305  de_ctx->sgh_hash_table = NULL;
306 }
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->num / 8] |= 1 << (s->num % 8);
334  (*sgh)->init->max_sig_id = MAX(s->num, (*sgh)->init->max_sig_id);
335  return 0;
336 
337 error:
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>
363 static 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 
416 error:
417  return -1;
418 }
419 
420 #ifdef HAVE_POPCNT64
421 #include <x86intrin.h>
422 static 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  */
446 void 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  */
469 bool 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->num %"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  */
671 static 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  */
689 static 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 
727  SigGroupHeadSetSigCnt(sh, 4);
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  */
749 static 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 
787  SigGroupHeadSetSigCnt(sh, 4);
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  */
816 static 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);
858  FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, src_sh, 1) == 1);
859  FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, src_sh, 2) == 0);
860  FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, src_sh, 3) == 1);
861  FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, src_sh, 4) == 0);
862  FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, src_sh, 5) == 1);
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);
869  FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, dst_sh, 1) == 1);
870  FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, dst_sh, 2) == 0);
871  FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, dst_sh, 3) == 1);
872  FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, dst_sh, 4) == 0);
873  FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, dst_sh, 5) == 1);
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  */
887 static 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 
925  SigGroupHeadSetSigCnt(sh, 4);
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  */
950 static 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 
983  AddressDebugPrint(&p->dst);
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 }
detect-tcp-flags.h
DetectEngineCtx_::sgh_hash_table
HashListTable * sgh_hash_table
Definition: detect.h:950
SIG_GROUP_HEAD_HAVEFILEMD5
#define SIG_GROUP_HEAD_HAVEFILEMD5
Definition: detect.h:1435
detect-content.h
detect-engine.h
FAIL_IF_NULL
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
util-hashlist.h
detect-engine-siggroup.h
SigGroupHead_::flags
uint16_t flags
Definition: detect.h:1573
Signature_::num
SigIntId num
Definition: detect.h:681
SigGroupHead_
Container for matching data for a signature group.
Definition: detect.h:1572
SIG_GROUP_HEAD_HAVEFILESIZE
#define SIG_GROUP_HEAD_HAVEFILESIZE
Definition: detect.h:1436
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
SigGroupHeadEqual
bool SigGroupHeadEqual(const SigGroupHead *sgha, const SigGroupHead *sghb)
Finds if two Signature Group Heads are the same.
Definition: detect-engine-siggroup.c:469
SigGroupHeadInitData_::sig_array
uint8_t * sig_array
Definition: detect.h:1546
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
AddressDebugPrint
void AddressDebugPrint(Address *a)
Debug print function for printing addresses.
Definition: decode.c:758
UTHBuildPacketSrcDst
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.
Definition: util-unittest-helper.c:406
util-hash.h
SIG_GROUP_HEAD_HAVEFILESHA1
#define SIG_GROUP_HEAD_HAVEFILESHA1
Definition: detect.h:1437
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:920
SigGroupHeadSetProtoAndDirection
void SigGroupHeadSetProtoAndDirection(SigGroupHead *sgh, uint8_t ipproto, int dir)
Definition: detect-engine-siggroup.c:486
DetectEngineCtxFree
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Definition: detect-engine.c:2799
SigPrepareStage1
int SigPrepareStage1(DetectEngineCtx *)
Preprocess signature, classify ip-only, etc, build sig array.
Definition: detect-engine-build.c:1732
SigGroupHeadPrintSigs
void SigGroupHeadPrintSigs(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
Helper function used to print the list of sids for the Signatures present in this SigGroupHead.
Definition: detect-engine-siggroup.c:503
HashListTableLookup
void * HashListTableLookup(HashListTable *ht, void *data, uint16_t datalen)
Definition: util-hashlist.c:245
DetectEngineAppendSig
Signature * DetectEngineAppendSig(DetectEngineCtx *, const char *)
Parse and append a Signature into the Detection Engine Context signature list.
Definition: detect-parse.c:3344
MAX
#define MAX(x, y)
Definition: suricata-common.h:404
SigGroupHeadSetupFiles
void SigGroupHeadSetupFiles(const DetectEngineCtx *de_ctx, SigGroupHead *sgh)
Set the need hash flag in the sgh.
Definition: detect-engine-siggroup.c:573
SignatureIsFilesizeInspecting
int SignatureIsFilesizeInspecting(const Signature *s)
Check if a signature contains the filesize keyword.
Definition: detect-engine-build.c:186
detect-engine-prefilter.h
util-unittest.h
util-unittest-helper.h
FAIL_IF_NOT
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
Definition: util-unittest.h:82
SigGroupHeadRegisterTests
void SigGroupHeadRegisterTests(void)
Definition: detect-engine-siggroup.c:995
HashListTableAdd
int HashListTableAdd(HashListTable *ht, void *data, uint16_t datalen)
Definition: util-hashlist.c:114
SigGroupHeadHashInit
int SigGroupHeadHashInit(DetectEngineCtx *de_ctx)
Initializes the hash table in the detection engine context to hold the SigGroupHeads.
Definition: detect-engine-siggroup.c:244
HashListTable_::array_size
uint32_t array_size
Definition: util-hashlist.h:41
util-memcmp.h
DetectEngineCtx_::sgh_array_size
uint32_t sgh_array_size
Definition: detect.h:990
SigGroupHeadInitData_::pkt_mpms
MpmCtx ** pkt_mpms
Definition: detect.h:1555
SignatureIsFileSha256Inspecting
int SignatureIsFileSha256Inspecting(const Signature *s)
Check if a signature contains the filesha256 keyword.
Definition: detect-engine-build.c:170
Signature_::next
struct Signature_ * next
Definition: detect.h:751
util-cidr.h
HashListTableInit
HashListTable * HashListTableInit(uint32_t size, uint32_t(*Hash)(struct HashListTable_ *, void *, uint16_t), char(*Compare)(void *, uint16_t, void *, uint16_t), void(*Free)(void *))
Definition: util-hashlist.c:35
decode.h
FAIL_IF_NOT_NULL
#define FAIL_IF_NOT_NULL(expr)
Fail a test if expression evaluates to non-NULL.
Definition: util-unittest.h:96
util-debug.h
SigGroupHeadBuildMatchArray
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.
Definition: detect-engine-siggroup.c:535
SigGroupHeadInitData_::sig_cnt
SigIntId sig_cnt
Definition: detect.h:1565
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
util-error.h
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:18
DetectEngineThreadCtx_
Definition: detect.h:1197
SigGroupHeadInitData_::tx_engines
PrefilterEngineList * tx_engines
Definition: detect.h:1560
DetectEngineGetMaxSigId
#define DetectEngineGetMaxSigId(de_ctx)
Definition: detect-engine.h:110
SCEnter
#define SCEnter(...)
Definition: util-debug.h:271
detect-engine-mpm.h
detect.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
DetectEngineThreadCtxInit
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
initialize thread specific detection engine context
Definition: detect-engine.c:3525
SigGroupHead_::init
SigGroupHeadInitData * init
Definition: detect.h:1589
SigGroupHeadInitData_::direction
uint32_t direction
Definition: detect.h:1550
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:309
PacketL4::L4Hdrs::icmpv4h
ICMPV4Hdr * icmpv4h
Definition: decode.h:454
SCReturn
#define SCReturn
Definition: util-debug.h:273
ICMPV4Hdr_::type
uint8_t type
Definition: decode-icmpv4.h:166
Packet_
Definition: decode.h:484
SCFreeAligned
#define SCFreeAligned(p)
Definition: util-mem.h:77
detect-engine-build.h
Packet_::l4
struct PacketL4 l4
Definition: decode.h:584
SCReturnPtr
#define SCReturnPtr(x, type)
Definition: util-debug.h:287
SigGroupHeadInitData_::max_sig_id
uint32_t max_sig_id
Definition: detect.h:1552
DetectEngineCtx_::sgh_array_cnt
uint32_t sgh_array_cnt
Definition: detect.h:989
SigGroupHeadAppendSig
int SigGroupHeadAppendSig(const DetectEngineCtx *de_ctx, SigGroupHead **sgh, const Signature *s)
Add a Signature to a SigGroupHead.
Definition: detect-engine-siggroup.c:319
DetectEngineCtx_::sgh_array
struct SigGroupHead_ ** sgh_array
Definition: detect.h:988
HashListTable_
Definition: util-hashlist.h:37
SigGroupHeadFree
void SigGroupHeadFree(const DetectEngineCtx *de_ctx, SigGroupHead *sgh)
Free a SigGroupHead and its members.
Definition: detect-engine-siggroup.c:163
SigGroupHeadInitData_::app_mpms
MpmCtx ** app_mpms
Definition: detect.h:1554
SignatureIsFileSha1Inspecting
int SignatureIsFileSha1Inspecting(const Signature *s)
Check if a signature contains the filesha1 keyword.
Definition: detect-engine-build.c:154
SigGroupBuild
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
Definition: detect-engine-build.c:2129
SCRealloc
#define SCRealloc(ptr, sz)
Definition: util-mem.h:50
SigGroupHeadInitData_::pkt_engines
PrefilterEngineList * pkt_engines
Definition: detect.h:1558
SigGroupHeadSetSigCnt
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...
Definition: detect-engine-siggroup.c:446
cnt
uint32_t cnt
Definition: tmqh-packetpool.h:7
suricata-common.h
SigGroupHeadStore
void SigGroupHeadStore(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
Definition: detect-engine-siggroup.c:109
SigGroupHeadInitData_::frame_engines
PrefilterEngineList * frame_engines
Definition: detect.h:1561
SigGroupHeadInitData_::payload_engines
PrefilterEngineList * payload_engines
Definition: detect.h:1559
HashListTableFree
void HashListTableFree(HashListTable *ht)
Definition: util-hashlist.c:88
SigGroupHeadInitData_::match_array
Signature ** match_array
Definition: detect.h:1568
SCMallocAligned
#define SCMallocAligned(size, align)
Definition: util-mem.h:68
SigGroupHeadInitData_::sig_size
uint32_t sig_size
Definition: detect.h:1547
PrefilterCleanupRuleGroup
void PrefilterCleanupRuleGroup(const DetectEngineCtx *de_ctx, SigGroupHead *sgh)
Definition: detect-engine-prefilter.c:493
ICMPV4Hdr_::code
uint8_t code
Definition: decode-icmpv4.h:167
DetectEngineCtx_::sig_list
Signature * sig_list
Definition: detect.h:929
SigGroupHeadHashFree
void SigGroupHeadHashFree(DetectEngineCtx *de_ctx)
Frees the hash table - DetectEngineCtx->sgh_hash_table, allocated by SigGroupHeadHashInit() function.
Definition: detect-engine-siggroup.c:299
SigGroupHeadHashAdd
int SigGroupHeadHashAdd(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
Adds a SigGroupHead to the detection engine context SigGroupHead hash table.
Definition: detect-engine-siggroup.c:266
util-validate.h
SigGroupHeadInitData_
Definition: detect.h:1543
SigGroupHeadHashLookup
SigGroupHead * SigGroupHeadHashLookup(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
Used to lookup a SigGroupHead hash from the detection engine context SigGroupHead hash table.
Definition: detect-engine-siggroup.c:283
SignatureIsFilestoring
int SignatureIsFilestoring(const Signature *s)
Check if a signature contains the filestore keyword.
Definition: detect-engine-build.c:100
SCFree
#define SCFree(p)
Definition: util-mem.h:61
SigGroupHeadInitData_::post_rule_match_engines
PrefilterEngineList * post_rule_match_engines
Definition: detect.h:1562
Signature_::id
uint32_t id
Definition: detect.h:714
detect-parse.h
src
uint16_t src
Definition: app-layer-dnp3.h:5
Signature_
Signature container.
Definition: detect.h:669
SigGroupHeadInitDataFree
void SigGroupHeadInitDataFree(SigGroupHeadInitData *sghid)
Definition: detect-engine-siggroup.c:60
SigGroupHeadContainsSigId
int SigGroupHeadContainsSigId(DetectEngineCtx *de_ctx, SigGroupHead *sgh, uint32_t sid)
Check if a SigGroupHead contains a Signature, whose sid is sent as an argument.
Definition: detect-engine-siggroup.c:623
SignatureIsFileMd5Inspecting
int SignatureIsFileMd5Inspecting(const Signature *s)
Check if a signature contains the filemd5 keyword.
Definition: detect-engine-build.c:138
PacketL4::hdrs
union PacketL4::L4Hdrs hdrs
SigGroupHeadInitData_::protos
uint8_t protos[256]
Definition: detect.h:1549
DetectEngineCtxInit
DetectEngineCtx * DetectEngineCtxInit(void)
Definition: detect-engine.c:2760
app-layer-protos.h
DetectEngineCtx_::sig_array
Signature ** sig_array
Definition: detect.h:938
Packet_::dst
Address dst
Definition: decode.h:489
detect-uricontent.h
dst
uint16_t dst
Definition: app-layer-dnp3.h:4
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SIG_GROUP_HEAD_HAVEFILESHA256
#define SIG_GROUP_HEAD_HAVEFILESHA256
Definition: detect.h:1438
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:275
SignatureIsFilemagicInspecting
int SignatureIsFilemagicInspecting(const Signature *s)
Check if a signature contains the filemagic keyword.
Definition: detect-engine-build.c:119
SigGroupHead_::filestore_cnt
uint16_t filestore_cnt
Definition: detect.h:1578
flow-var.h
PrefilterFreeEnginesList
void PrefilterFreeEnginesList(PrefilterEngineList *list)
Definition: detect-engine-prefilter.c:465
SCMemcmp
#define SCMemcmp(a, b, c)
Definition: util-memcmp.h:290
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:102
detect-engine-address.h
SigMatchSignaturesGetSgh
const SigGroupHead * SigMatchSignaturesGetSgh(const DetectEngineCtx *de_ctx, const Packet *p)
Get the SigGroupHead for a packet.
Definition: detect.c:232
SigGroupHeadCopySigs
int SigGroupHeadCopySigs(DetectEngineCtx *de_ctx, SigGroupHead *src, SigGroupHead **dst)
Copies the bitarray holding the sids from the source SigGroupHead to the destination SigGroupHead.
Definition: detect-engine-siggroup.c:390
SigGroupHeadClearSigs
int SigGroupHeadClearSigs(SigGroupHead *)
Clears the bitarray holding the sids for this SigGroupHead.
Definition: detect-engine-siggroup.c:348
SigGroupHeadInitData_::frame_mpms
MpmCtx ** frame_mpms
Definition: detect.h:1556
UTHFreePackets
void UTHFreePackets(Packet **p, int numpkts)
UTHFreePackets: function to release the allocated data from UTHBuildPacket and the packet itself.
Definition: util-unittest-helper.c:456