1 /* Copyright (C) 2007-2013 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-address.h"
37 #include "detect-engine-mpm.h"
38 #include "detect-engine-siggroup.h"
39 #include "detect-engine-prefilter.h"
40
41 #include "detect-content.h"
42 #include "detect-uricontent.h"
43 #include "detect-tcp-flags.h"
44
45 #include "util-hash.h"
46 #include "util-hashlist.h"
47
48 #include "util-error.h"
49 #include "util-debug.h"
50 #include "util-cidr.h"
51 #include "util-unittest.h"
52 #include "util-unittest-helper.h"
53 #include "util-memcmp.h"
54
55 /* prototypes */
56 int SigGroupHeadClearSigs(SigGroupHead *);
57
SigGroupHeadInitDataFree(SigGroupHeadInitData * sghid)58 void SigGroupHeadInitDataFree(SigGroupHeadInitData *sghid)
59 {
60 if (sghid->sig_array != NULL) {
61 SCFree(sghid->sig_array);
62 sghid->sig_array = NULL;
63 }
64 if (sghid->app_mpms != NULL) {
65 SCFree(sghid->app_mpms);
66 }
67 if (sghid->pkt_mpms != NULL) {
68 SCFree(sghid->pkt_mpms);
69 }
70
71 PrefilterFreeEnginesList(sghid->tx_engines);
72 PrefilterFreeEnginesList(sghid->pkt_engines);
73 PrefilterFreeEnginesList(sghid->payload_engines);
74
75 SCFree(sghid);
76 }
77
SigGroupHeadInitDataAlloc(uint32_t size)78 static SigGroupHeadInitData *SigGroupHeadInitDataAlloc(uint32_t size)
79 {
80 SigGroupHeadInitData *sghid = SCMalloc(sizeof(SigGroupHeadInitData));
81 if (unlikely(sghid == NULL))
82 return NULL;
83
84 memset(sghid, 0x00, sizeof(SigGroupHeadInitData));
85
86 /* initialize the signature bitarray */
87 sghid->sig_size = size;
88 if ( (sghid->sig_array = SCMalloc(sghid->sig_size)) == NULL)
89 goto error;
90
91 memset(sghid->sig_array, 0, sghid->sig_size);
92
93 return sghid;
94 error:
95 SigGroupHeadInitDataFree(sghid);
96 return NULL;
97 }
98
SigGroupHeadStore(DetectEngineCtx * de_ctx,SigGroupHead * sgh)99 void SigGroupHeadStore(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
100 {
101 void *ptmp;
102 //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);
103 if (de_ctx->sgh_array_cnt < de_ctx->sgh_array_size) {
104 de_ctx->sgh_array[de_ctx->sgh_array_cnt] = sgh;
105 } else {
106 int increase = 16;
107 ptmp = SCRealloc(de_ctx->sgh_array,
108 sizeof(SigGroupHead *) * (increase + de_ctx->sgh_array_size));
109 if (ptmp == NULL) {
110 SCFree(de_ctx->sgh_array);
111 de_ctx->sgh_array = NULL;
112 return;
113 }
114 de_ctx->sgh_array = ptmp;
115
116 de_ctx->sgh_array_size += increase;
117 de_ctx->sgh_array[de_ctx->sgh_array_cnt] = sgh;
118 }
119 de_ctx->sgh_array_cnt++;
120 }
121
122 /**
123 * \brief Alloc a SigGroupHead and its signature bit_array.
124 *
125 * \param size Size of the sig_array that has to be created for this
126 * SigGroupHead.
127 *
128 * \retval sgh Pointer to the newly init SigGroupHead on success; or NULL in
129 * case of error.
130 */
SigGroupHeadAlloc(const DetectEngineCtx * de_ctx,uint32_t size)131 static SigGroupHead *SigGroupHeadAlloc(const DetectEngineCtx *de_ctx, uint32_t size)
132 {
133 SigGroupHead *sgh = SCMalloc(sizeof(SigGroupHead));
134 if (unlikely(sgh == NULL))
135 return NULL;
136 memset(sgh, 0, sizeof(SigGroupHead));
137
138 sgh->init = SigGroupHeadInitDataAlloc(size);
139 if (sgh->init == NULL)
140 goto error;
141
142 return sgh;
143
144 error:
145 SigGroupHeadFree(de_ctx, sgh);
146 return NULL;
147 }
148
149 /**
150 * \brief Free a SigGroupHead and its members.
151 *
152 * \param sgh Pointer to the SigGroupHead that has to be freed.
153 */
SigGroupHeadFree(const DetectEngineCtx * de_ctx,SigGroupHead * sgh)154 void SigGroupHeadFree(const DetectEngineCtx *de_ctx, SigGroupHead *sgh)
155 {
156 if (sgh == NULL)
157 return;
158
159 SCLogDebug("sgh %p", sgh);
160
161 if (sgh->match_array != NULL) {
162 SCFree(sgh->match_array);
163 sgh->match_array = NULL;
164 }
165
166 if (sgh->non_pf_other_store_array != NULL) {
167 SCFree(sgh->non_pf_other_store_array);
168 sgh->non_pf_other_store_array = NULL;
169 sgh->non_pf_other_store_cnt = 0;
170 }
171
172 if (sgh->non_pf_syn_store_array != NULL) {
173 SCFree(sgh->non_pf_syn_store_array);
174 sgh->non_pf_syn_store_array = NULL;
175 sgh->non_pf_syn_store_cnt = 0;
176 }
177
178 sgh->sig_cnt = 0;
179
180 if (sgh->init != NULL) {
181 SigGroupHeadInitDataFree(sgh->init);
182 sgh->init = NULL;
183 }
184
185 PrefilterCleanupRuleGroup(de_ctx, sgh);
186 SCFree(sgh);
187
188 return;
189 }
190
191 /**
192 * \brief The hash function to be the used by the hash table -
193 * DetectEngineCtx->sgh_hash_table.
194 *
195 * \param ht Pointer to the hash table.
196 * \param data Pointer to the SigGroupHead.
197 * \param datalen Not used in our case.
198 *
199 * \retval hash The generated hash value.
200 */
SigGroupHeadHashFunc(HashListTable * ht,void * data,uint16_t datalen)201 static uint32_t SigGroupHeadHashFunc(HashListTable *ht, void *data, uint16_t datalen)
202 {
203 SigGroupHead *sgh = (SigGroupHead *)data;
204 uint32_t hash = 0;
205 uint32_t b = 0;
206
207 SCLogDebug("hashing sgh %p", sgh);
208
209 for (b = 0; b < sgh->init->sig_size; b++)
210 hash += sgh->init->sig_array[b];
211
212 hash %= ht->array_size;
213 SCLogDebug("hash %"PRIu32" (sig_size %"PRIu32")", hash, sgh->init->sig_size);
214 return hash;
215 }
216
217 /**
218 * \brief The Compare function to be used by the SigGroupHead hash table -
219 * DetectEngineCtx->sgh_hash_table.
220 *
221 * \param data1 Pointer to the first SigGroupHead.
222 * \param len1 Not used.
223 * \param data2 Pointer to the second SigGroupHead.
224 * \param len2 Not used.
225 *
226 * \retval 1 If the 2 SigGroupHeads sent as args match.
227 * \retval 0 If the 2 SigGroupHeads sent as args do not match.
228 */
SigGroupHeadCompareFunc(void * data1,uint16_t len1,void * data2,uint16_t len2)229 static char SigGroupHeadCompareFunc(void *data1, uint16_t len1, void *data2,
230 uint16_t len2)
231 {
232 SigGroupHead *sgh1 = (SigGroupHead *)data1;
233 SigGroupHead *sgh2 = (SigGroupHead *)data2;
234
235 if (data1 == NULL || data2 == NULL)
236 return 0;
237
238 if (sgh1->init->sig_size != sgh2->init->sig_size)
239 return 0;
240
241 if (SCMemcmp(sgh1->init->sig_array, sgh2->init->sig_array, sgh1->init->sig_size) != 0)
242 return 0;
243
244 return 1;
245 }
246
247 /**
248 * \brief Initializes the hash table in the detection engine context to hold the
249 * SigGroupHeads.
250 *
251 * \param de_ctx Pointer to the detection engine context.
252 *
253 * \retval 0 On success.
254 * \retval -1 On failure.
255 */
SigGroupHeadHashInit(DetectEngineCtx * de_ctx)256 int SigGroupHeadHashInit(DetectEngineCtx *de_ctx)
257 {
258 de_ctx->sgh_hash_table = HashListTableInit(4096, SigGroupHeadHashFunc,
259 SigGroupHeadCompareFunc, NULL);
260 if (de_ctx->sgh_hash_table == NULL)
261 goto error;
262
263 return 0;
264
265 error:
266 return -1;
267 }
268
269 /**
270 * \brief Adds a SigGroupHead to the detection engine context SigGroupHead
271 * hash table.
272 *
273 * \param de_ctx Pointer to the detection engine context.
274 * \param sgh Pointer to the SigGroupHead.
275 *
276 * \retval ret 0 on Successfully adding the SigGroupHead; -1 on failure.
277 */
SigGroupHeadHashAdd(DetectEngineCtx * de_ctx,SigGroupHead * sgh)278 int SigGroupHeadHashAdd(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
279 {
280 int ret = HashListTableAdd(de_ctx->sgh_hash_table, (void *)sgh, 0);
281
282 return ret;
283 }
284
SigGroupHeadHashRemove(DetectEngineCtx * de_ctx,SigGroupHead * sgh)285 int SigGroupHeadHashRemove(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
286 {
287 return HashListTableRemove(de_ctx->sgh_hash_table, (void *)sgh, 0);
288 }
289
290 /**
291 * \brief Used to lookup a SigGroupHead hash from the detection engine context
292 * SigGroupHead hash table.
293 *
294 * \param de_ctx Pointer to the detection engine context.
295 * \param sgh Pointer to the SigGroupHead.
296 *
297 * \retval rsgh On success a pointer to the SigGroupHead if the SigGroupHead is
298 * found in the hash table; NULL on failure.
299 */
SigGroupHeadHashLookup(DetectEngineCtx * de_ctx,SigGroupHead * sgh)300 SigGroupHead *SigGroupHeadHashLookup(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
301 {
302 SCEnter();
303
304 SigGroupHead *rsgh = HashListTableLookup(de_ctx->sgh_hash_table,
305 (void *)sgh, 0);
306
307 SCReturnPtr(rsgh, "SigGroupHead");
308 }
309
310 /**
311 * \brief Frees the hash table - DetectEngineCtx->sgh_hash_table, allocated by
312 * SigGroupHeadHashInit() function.
313 *
314 * \param de_ctx Pointer to the detection engine context.
315 */
SigGroupHeadHashFree(DetectEngineCtx * de_ctx)316 void SigGroupHeadHashFree(DetectEngineCtx *de_ctx)
317 {
318 if (de_ctx->sgh_hash_table == NULL)
319 return;
320
321 HashListTableFree(de_ctx->sgh_hash_table);
322 de_ctx->sgh_hash_table = NULL;
323
324 return;
325 }
326
327 /**
328 * \brief Add a Signature to a SigGroupHead.
329 *
330 * \param de_ctx Pointer to the detection engine context.
331 * \param sgh Pointer to a SigGroupHead. Can be NULL also.
332 * \param s Pointer to the Signature that has to be added to the
333 * SigGroupHead.
334 *
335 * \retval 0 On success.
336 * \retval -1 On failure.
337 */
SigGroupHeadAppendSig(const DetectEngineCtx * de_ctx,SigGroupHead ** sgh,const Signature * s)338 int SigGroupHeadAppendSig(const DetectEngineCtx *de_ctx, SigGroupHead **sgh,
339 const Signature *s)
340 {
341 if (de_ctx == NULL)
342 return 0;
343
344 /* see if we have a head already */
345 if (*sgh == NULL) {
346 *sgh = SigGroupHeadAlloc(de_ctx, DetectEngineGetMaxSigId(de_ctx) / 8 + 1);
347 if (*sgh == NULL)
348 goto error;
349 }
350
351 /* enable the sig in the bitarray */
352 (*sgh)->init->sig_array[s->num / 8] |= 1 << (s->num % 8);
353
354 return 0;
355
356 error:
357 return -1;
358 }
359
360 /**
361 * \brief Clears the bitarray holding the sids for this SigGroupHead.
362 *
363 * \param sgh Pointer to the SigGroupHead.
364 *
365 * \retval 0 Always.
366 */
SigGroupHeadClearSigs(SigGroupHead * sgh)367 int SigGroupHeadClearSigs(SigGroupHead *sgh)
368 {
369 if (sgh == NULL)
370 return 0;
371
372 if (sgh->init->sig_array != NULL)
373 memset(sgh->init->sig_array, 0, sgh->init->sig_size);
374
375 sgh->sig_cnt = 0;
376
377 return 0;
378 }
379
380 /**
381 * \brief Copies the bitarray holding the sids from the source SigGroupHead to
382 * the destination SigGroupHead.
383 *
384 * \param de_ctx Pointer to the detection engine context.
385 * \param src Pointer to the source SigGroupHead.
386 * \param dst Pointer to the destination SigGroupHead.
387 *
388 * \retval 0 On success.
389 * \retval -1 On failure.
390 */
SigGroupHeadCopySigs(DetectEngineCtx * de_ctx,SigGroupHead * src,SigGroupHead ** dst)391 int SigGroupHeadCopySigs(DetectEngineCtx *de_ctx, SigGroupHead *src, SigGroupHead **dst)
392 {
393 uint32_t idx = 0;
394
395 if (src == NULL || de_ctx == NULL)
396 return 0;
397
398 if (*dst == NULL) {
399 *dst = SigGroupHeadAlloc(de_ctx, DetectEngineGetMaxSigId(de_ctx) / 8 + 1);
400 if (*dst == NULL)
401 goto error;
402 }
403
404 /* do the copy */
405 for (idx = 0; idx < src->init->sig_size; idx++)
406 (*dst)->init->sig_array[idx] = (*dst)->init->sig_array[idx] | src->init->sig_array[idx];
407
408 if (src->init->whitelist)
409 (*dst)->init->whitelist = MAX((*dst)->init->whitelist, src->init->whitelist);
410
411 return 0;
412
413 error:
414 return -1;
415 }
416
417 /**
418 * \brief Updates the SigGroupHead->sig_cnt with the total count of all the
419 * Signatures present in this SigGroupHead.
420 *
421 * \param sgh Pointer to the SigGroupHead.
422 * \param max_idx Maximum sid of the all the Signatures present in this
423 * SigGroupHead.
424 */
SigGroupHeadSetSigCnt(SigGroupHead * sgh,uint32_t max_idx)425 void SigGroupHeadSetSigCnt(SigGroupHead *sgh, uint32_t max_idx)
426 {
427 uint32_t sig;
428
429 sgh->sig_cnt = 0;
430 for (sig = 0; sig < max_idx + 1; sig++) {
431 if (sgh->init->sig_array[sig / 8] & (1 << (sig % 8)))
432 sgh->sig_cnt++;
433 }
434
435 return;
436 }
437
SigGroupHeadSetProtoAndDirection(SigGroupHead * sgh,uint8_t ipproto,int dir)438 void SigGroupHeadSetProtoAndDirection(SigGroupHead *sgh,
439 uint8_t ipproto, int dir)
440 {
441 if (sgh && sgh->init) {
442 SCLogDebug("setting proto %u and dir %d on sgh %p", ipproto, dir, sgh);
443 sgh->init->protos[ipproto] = 1;
444 sgh->init->direction |= dir;
445 }
446 }
447
448 /**
449 * \brief Helper function used to print the list of sids for the Signatures
450 * present in this SigGroupHead.
451 *
452 * \param de_ctx Pointer to the detection engine context.
453 * \param sgh Pointer to the SigGroupHead.
454 */
SigGroupHeadPrintSigs(DetectEngineCtx * de_ctx,SigGroupHead * sgh)455 void SigGroupHeadPrintSigs(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
456 {
457 SCEnter();
458
459 if (sgh == NULL) {
460 SCReturn;
461 }
462
463 uint32_t u;
464
465 SCLogDebug("The Signatures present in this SigGroupHead are: ");
466 for (u = 0; u < (sgh->init->sig_size * 8); u++) {
467 if (sgh->init->sig_array[u / 8] & (1 << (u % 8))) {
468 SCLogDebug("%" PRIu32, u);
469 printf("s->num %"PRIu32" ", u);
470 }
471 }
472
473 SCReturn;
474 }
475
476 /**
477 * \brief Create an array with all the internal ids of the sigs that this
478 * sig group head will check for.
479 *
480 * \param de_ctx Pointer to the detection engine context.
481 * \param sgh Pointer to the SigGroupHead.
482 * \param max_idx The maximum value of the sid in the SigGroupHead arg.
483 *
484 * \retval 0 success
485 * \retval -1 error
486 */
SigGroupHeadBuildMatchArray(DetectEngineCtx * de_ctx,SigGroupHead * sgh,uint32_t max_idx)487 int SigGroupHeadBuildMatchArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
488 uint32_t max_idx)
489 {
490 Signature *s = NULL;
491 uint32_t idx = 0;
492 uint32_t sig = 0;
493
494 if (sgh == NULL)
495 return 0;
496
497 BUG_ON(sgh->match_array != NULL);
498
499 sgh->match_array = SCMalloc(sgh->sig_cnt * sizeof(Signature *));
500 if (sgh->match_array == NULL)
501 return -1;
502
503 memset(sgh->match_array,0, sgh->sig_cnt * sizeof(Signature *));
504
505 for (sig = 0; sig < max_idx + 1; sig++) {
506 if (!(sgh->init->sig_array[(sig / 8)] & (1 << (sig % 8))) )
507 continue;
508
509 s = de_ctx->sig_array[sig];
510 if (s == NULL)
511 continue;
512
513 sgh->match_array[idx] = s;
514 idx++;
515 }
516
517 return 0;
518 }
519
520 /**
521 * \brief Set the need magic flag in the sgh.
522 *
523 * \param de_ctx detection engine ctx for the signatures
524 * \param sgh sig group head to set the flag in
525 */
SigGroupHeadSetFilemagicFlag(DetectEngineCtx * de_ctx,SigGroupHead * sgh)526 void SigGroupHeadSetFilemagicFlag(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
527 {
528 #ifdef HAVE_MAGIC
529 Signature *s = NULL;
530 uint32_t sig = 0;
531
532 if (sgh == NULL)
533 return;
534
535 for (sig = 0; sig < sgh->sig_cnt; sig++) {
536 s = sgh->match_array[sig];
537 if (s == NULL)
538 continue;
539
540 if (SignatureIsFilemagicInspecting(s)) {
541 sgh->flags |= SIG_GROUP_HEAD_HAVEFILEMAGIC;
542 break;
543 }
544 }
545 #endif
546 return;
547 }
548
549 /**
550 * \brief Set the need size flag in the sgh.
551 *
552 * \param de_ctx detection engine ctx for the signatures
553 * \param sgh sig group head to set the flag in
554 */
SigGroupHeadSetFilesizeFlag(DetectEngineCtx * de_ctx,SigGroupHead * sgh)555 void SigGroupHeadSetFilesizeFlag(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
556 {
557 Signature *s = NULL;
558 uint32_t sig = 0;
559
560 if (sgh == NULL)
561 return;
562
563 for (sig = 0; sig < sgh->sig_cnt; sig++) {
564 s = sgh->match_array[sig];
565 if (s == NULL)
566 continue;
567
568 if (SignatureIsFilesizeInspecting(s)) {
569 sgh->flags |= SIG_GROUP_HEAD_HAVEFILESIZE;
570 break;
571 }
572 }
573
574 return;
575 }
576
577 /**
578 * \brief Set the need hash flag in the sgh.
579 *
580 * \param de_ctx detection engine ctx for the signatures
581 * \param sgh sig group head to set the flag in
582 */
SigGroupHeadSetFileHashFlag(DetectEngineCtx * de_ctx,SigGroupHead * sgh)583 void SigGroupHeadSetFileHashFlag(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
584 {
585 Signature *s = NULL;
586 uint32_t sig = 0;
587
588 if (sgh == NULL)
589 return;
590
591 for (sig = 0; sig < sgh->sig_cnt; sig++) {
592 s = sgh->match_array[sig];
593 if (s == NULL)
594 continue;
595
596 if (SignatureIsFileMd5Inspecting(s)) {
597 sgh->flags |= SIG_GROUP_HEAD_HAVEFILEMD5;
598 SCLogDebug("sgh %p has filemd5", sgh);
599 break;
600 }
601
602 if (SignatureIsFileSha1Inspecting(s)) {
603 sgh->flags |= SIG_GROUP_HEAD_HAVEFILESHA1;
604 SCLogDebug("sgh %p has filesha1", sgh);
605 break;
606 }
607
608 if (SignatureIsFileSha256Inspecting(s)) {
609 sgh->flags |= SIG_GROUP_HEAD_HAVEFILESHA256;
610 SCLogDebug("sgh %p has filesha256", sgh);
611 break;
612 }
613 }
614
615 return;
616 }
617
618 /**
619 * \brief Set the filestore_cnt in the sgh.
620 *
621 * \param de_ctx detection engine ctx for the signatures
622 * \param sgh sig group head to set the counter in
623 */
SigGroupHeadSetFilestoreCount(DetectEngineCtx * de_ctx,SigGroupHead * sgh)624 void SigGroupHeadSetFilestoreCount(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
625 {
626 Signature *s = NULL;
627 uint32_t sig = 0;
628
629 if (sgh == NULL)
630 return;
631
632 for (sig = 0; sig < sgh->sig_cnt; sig++) {
633 s = sgh->match_array[sig];
634 if (s == NULL)
635 continue;
636
637 if (SignatureIsFilestoring(s)) {
638 sgh->filestore_cnt++;
639 }
640 }
641
642 return;
643 }
644
645 /** \brief build an array of rule id's for sigs with no prefilter
646 * Also updated de_ctx::non_pf_store_cnt_max to track the highest cnt
647 */
SigGroupHeadBuildNonPrefilterArray(DetectEngineCtx * de_ctx,SigGroupHead * sgh)648 int SigGroupHeadBuildNonPrefilterArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
649 {
650 Signature *s = NULL;
651 uint32_t sig = 0;
652 uint32_t non_pf = 0;
653 uint32_t non_pf_syn = 0;
654
655 if (sgh == NULL)
656 return 0;
657
658 BUG_ON(sgh->non_pf_other_store_array != NULL);
659
660 for (sig = 0; sig < sgh->sig_cnt; sig++) {
661 s = sgh->match_array[sig];
662 if (s == NULL)
663 continue;
664
665 if (!(s->flags & SIG_FLAG_PREFILTER) || (s->flags & SIG_FLAG_MPM_NEG)) {
666 if (!(DetectFlagsSignatureNeedsSynPackets(s))) {
667 non_pf++;
668 }
669 non_pf_syn++;
670 }
671 }
672
673 if (non_pf == 0 && non_pf_syn == 0) {
674 sgh->non_pf_other_store_array = NULL;
675 sgh->non_pf_syn_store_array = NULL;
676 return 0;
677 }
678
679 if (non_pf > 0) {
680 sgh->non_pf_other_store_array = SCMalloc(non_pf * sizeof(SignatureNonPrefilterStore));
681 BUG_ON(sgh->non_pf_other_store_array == NULL);
682 memset(sgh->non_pf_other_store_array, 0, non_pf * sizeof(SignatureNonPrefilterStore));
683 }
684
685 if (non_pf_syn > 0) {
686 sgh->non_pf_syn_store_array = SCMalloc(non_pf_syn * sizeof(SignatureNonPrefilterStore));
687 BUG_ON(sgh->non_pf_syn_store_array == NULL);
688 memset(sgh->non_pf_syn_store_array, 0, non_pf_syn * sizeof(SignatureNonPrefilterStore));
689 }
690
691 for (sig = 0; sig < sgh->sig_cnt; sig++) {
692 s = sgh->match_array[sig];
693 if (s == NULL)
694 continue;
695
696 if (!(s->flags & SIG_FLAG_PREFILTER) || (s->flags & SIG_FLAG_MPM_NEG)) {
697 if (!(DetectFlagsSignatureNeedsSynPackets(s))) {
698 BUG_ON(sgh->non_pf_other_store_cnt >= non_pf);
699 BUG_ON(sgh->non_pf_other_store_array == NULL);
700 sgh->non_pf_other_store_array[sgh->non_pf_other_store_cnt].id = s->num;
701 sgh->non_pf_other_store_array[sgh->non_pf_other_store_cnt].mask = s->mask;
702 sgh->non_pf_other_store_array[sgh->non_pf_other_store_cnt].alproto = s->alproto;
703 sgh->non_pf_other_store_cnt++;
704 }
705
706 BUG_ON(sgh->non_pf_syn_store_cnt >= non_pf_syn);
707 BUG_ON(sgh->non_pf_syn_store_array == NULL);
708 sgh->non_pf_syn_store_array[sgh->non_pf_syn_store_cnt].id = s->num;
709 sgh->non_pf_syn_store_array[sgh->non_pf_syn_store_cnt].mask = s->mask;
710 sgh->non_pf_syn_store_array[sgh->non_pf_syn_store_cnt].alproto = s->alproto;
711 sgh->non_pf_syn_store_cnt++;
712 }
713 }
714
715 /* track highest cnt for any sgh in our de_ctx */
716 uint32_t max = MAX(sgh->non_pf_other_store_cnt, sgh->non_pf_syn_store_cnt);
717 if (max > de_ctx->non_pf_store_cnt_max)
718 de_ctx->non_pf_store_cnt_max = max;
719
720 return 0;
721 }
722
723 /**
724 * \brief Check if a SigGroupHead contains a Signature, whose sid is sent as an
725 * argument.
726 *
727 * \param de_ctx Pointer to the detection engine context.
728 * \param sgh Pointer to the SigGroupHead that has to be checked for the
729 * presence of a Signature.
730 * \param sid The Signature id(sid) that has to be checked in the SigGroupHead.
731 *
732 * \retval 1 On successfully finding the sid in the SigGroupHead.
733 * \retval 0 If the sid is not found in the SigGroupHead
734 */
SigGroupHeadContainsSigId(DetectEngineCtx * de_ctx,SigGroupHead * sgh,uint32_t sid)735 int SigGroupHeadContainsSigId(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
736 uint32_t sid)
737 {
738 SCEnter();
739
740 uint32_t sig = 0;
741 Signature *s = NULL;
742 uint32_t max_sid = DetectEngineGetMaxSigId(de_ctx);
743
744 if (sgh == NULL) {
745 SCReturnInt(0);
746 }
747
748 for (sig = 0; sig < max_sid; sig++) {
749 if (sgh->init->sig_array == NULL) {
750 SCReturnInt(0);
751 }
752
753 /* Check if the SigGroupHead has an entry for the sid */
754 if ( !(sgh->init->sig_array[sig / 8] & (1 << (sig % 8))) )
755 continue;
756
757 /* If we have reached here, we have an entry for sid in the SigGrouHead.
758 * Retrieve the Signature from the detection engine context */
759 s = de_ctx->sig_array[sig];
760 if (s == NULL)
761 continue;
762
763 /* If the retrieved Signature matches the sid arg, we have a match */
764 if (s->id == sid) {
765 SCReturnInt(1);
766 }
767 }
768
769 SCReturnInt(0);
770 }
771
772 /*----------------------------------Unittests---------------------------------*/
773
774 #ifdef UNITTESTS
775
776 int SigAddressPrepareStage1(DetectEngineCtx *);
777
778 /**
779 * \test Check if a SigGroupHead hash table is properly allocated and
780 * deallocated when calling SigGroupHeadHashInit() and
781 * SigGroupHeadHashFree() respectively.
782 */
SigGroupHeadTest03(void)783 static int SigGroupHeadTest03(void)
784 {
785 int result = 1;
786
787 DetectEngineCtx de_ctx;
788
789 SigGroupHeadHashInit(&de_ctx);
790
791 result &= (de_ctx.sgh_hash_table != NULL);
792
793 SigGroupHeadHashFree(&de_ctx);
794
795 result &= (de_ctx.sgh_hash_table == NULL);
796
797 return result;
798 }
799
800 /**
801 * \test Check if a SigGroupHeadAppendSig() correctly appends a sid to a
802 * SigGroupHead() and SigGroupHeadContainsSigId() correctly indicates
803 * the presence of a sid.
804 */
SigGroupHeadTest06(void)805 static int SigGroupHeadTest06(void)
806 {
807 int result = 1;
808 SigGroupHead *sh = NULL;
809 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
810 Signature *prev_sig = NULL;
811
812 if (de_ctx == NULL)
813 return 0;
814
815 de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any "
816 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
817 "content:\"test2\"; content:\"test3\"; sid:1;)");
818 if (de_ctx->sig_list == NULL) {
819 result = 0;
820 goto end;
821 }
822 prev_sig = de_ctx->sig_list;
823
824 prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any "
825 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
826 "content:\"test2\"; content:\"test3\"; sid:2;)");
827 if (prev_sig->next == NULL) {
828 result = 0;
829 goto end;
830 }
831 prev_sig = prev_sig->next;
832
833 prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any "
834 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
835 "content:\"test2\"; content:\"test3\"; sid:3;)");
836 if (prev_sig->next == NULL) {
837 result = 0;
838 goto end;
839 }
840 prev_sig = prev_sig->next;
841
842 prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any "
843 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
844 "content:\"test2\"; content:\"test3\"; sid:4;)");
845 if (prev_sig->next == NULL) {
846 result = 0;
847 goto end;
848 }
849 prev_sig = prev_sig->next;
850
851 prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any "
852 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
853 "content:\"test2\"; content:\"test3\"; sid:5;)");
854 if (prev_sig->next == NULL) {
855 result = 0;
856 goto end;
857 }
858 prev_sig = prev_sig->next;
859
860 SigAddressPrepareStage1(de_ctx);
861
862 SigGroupHeadAppendSig(de_ctx, &sh, de_ctx->sig_list);
863 SigGroupHeadAppendSig(de_ctx, &sh, de_ctx->sig_list->next->next);
864 SigGroupHeadAppendSig(de_ctx, &sh, de_ctx->sig_list->next->next->next->next);
865
866 SigGroupHeadSetSigCnt(sh, 4);
867
868 result &= (sh->sig_cnt == 3);
869 result &= (SigGroupHeadContainsSigId(de_ctx, sh, 1) == 1);
870 result &= (SigGroupHeadContainsSigId(de_ctx, sh, 2) == 0);
871 result &= (SigGroupHeadContainsSigId(de_ctx, sh, 3) == 1);
872 result &= (SigGroupHeadContainsSigId(de_ctx, sh, 4) == 0);
873 result &= (SigGroupHeadContainsSigId(de_ctx, sh, 5) == 1);
874
875 SigGroupHeadFree(de_ctx, sh);
876
877 end:
878 SigCleanSignatures(de_ctx);
879 DetectEngineCtxFree(de_ctx);
880 return result;
881 }
882
883 /**
884 * \test Check if a SigGroupHeadAppendSig(), correctly appends a sid to a
885 * SigGroupHead() and SigGroupHeadContainsSigId(), correctly indicates
886 * the presence of a sid and SigGroupHeadClearSigs(), correctly clears
887 * the SigGroupHead->sig_array and SigGroupHead->sig_cnt.
888 */
SigGroupHeadTest07(void)889 static int SigGroupHeadTest07(void)
890 {
891 int result = 1;
892 SigGroupHead *sh = NULL;
893 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
894 Signature *prev_sig = NULL;
895
896 if (de_ctx == NULL)
897 return 0;
898
899 de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any "
900 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
901 "content:\"test2\"; content:\"test3\"; sid:1;)");
902 if (de_ctx->sig_list == NULL) {
903 result = 0;
904 goto end;
905 }
906 prev_sig = de_ctx->sig_list;
907
908 prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any "
909 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
910 "content:\"test2\"; content:\"test3\"; sid:2;)");
911 if (prev_sig->next == NULL) {
912 result = 0;
913 goto end;
914 }
915 prev_sig = prev_sig->next;
916
917 prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any "
918 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
919 "content:\"test2\"; content:\"test3\"; sid:3;)");
920 if (prev_sig->next == NULL) {
921 result = 0;
922 goto end;
923 }
924 prev_sig = prev_sig->next;
925
926 prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any "
927 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
928 "content:\"test2\"; content:\"test3\"; sid:4;)");
929 if (prev_sig->next == NULL) {
930 result = 0;
931 goto end;
932 }
933 prev_sig = prev_sig->next;
934
935 prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any "
936 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
937 "content:\"test2\"; content:\"test3\"; sid:5;)");
938 if (prev_sig->next == NULL) {
939 result = 0;
940 goto end;
941 }
942 prev_sig = prev_sig->next;
943
944 SigAddressPrepareStage1(de_ctx);
945
946 SigGroupHeadAppendSig(de_ctx, &sh, de_ctx->sig_list);
947 SigGroupHeadAppendSig(de_ctx, &sh, de_ctx->sig_list->next->next);
948 SigGroupHeadAppendSig(de_ctx, &sh, de_ctx->sig_list->next->next->next->next);
949
950 SigGroupHeadSetSigCnt(sh, 4);
951
952 result &= (sh->sig_cnt == 3);
953 result &= (SigGroupHeadContainsSigId(de_ctx, sh, 1) == 1);
954 result &= (SigGroupHeadContainsSigId(de_ctx, sh, 2) == 0);
955 result &= (SigGroupHeadContainsSigId(de_ctx, sh, 3) == 1);
956 result &= (SigGroupHeadContainsSigId(de_ctx, sh, 4) == 0);
957 result &= (SigGroupHeadContainsSigId(de_ctx, sh, 5) == 1);
958
959 SigGroupHeadClearSigs(sh);
960
961 result &= (sh->sig_cnt == 0);
962 result &= (SigGroupHeadContainsSigId(de_ctx, sh, 1) == 0);
963 result &= (SigGroupHeadContainsSigId(de_ctx, sh, 2) == 0);
964 result &= (SigGroupHeadContainsSigId(de_ctx, sh, 3) == 0);
965 result &= (SigGroupHeadContainsSigId(de_ctx, sh, 4) == 0);
966 result &= (SigGroupHeadContainsSigId(de_ctx, sh, 5) == 0);
967
968 SigGroupHeadFree(de_ctx, sh);
969
970 end:
971 SigCleanSignatures(de_ctx);
972 DetectEngineCtxFree(de_ctx);
973 return result;
974 }
975
976 /**
977 * \test Check if SigGroupHeadCopySigs(), correctly copies the sig_array from
978 * the source to the destination SigGroupHead.
979 */
SigGroupHeadTest08(void)980 static int SigGroupHeadTest08(void)
981 {
982 int result = 1;
983 SigGroupHead *src_sh = NULL;
984 SigGroupHead *dst_sh = NULL;
985 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
986 Signature *prev_sig = NULL;
987
988 if (de_ctx == NULL)
989 return 0;
990
991 de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any "
992 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
993 "content:\"test2\"; content:\"test3\"; sid:1;)");
994 if (de_ctx->sig_list == NULL) {
995 result = 0;
996 goto end;
997 }
998 prev_sig = de_ctx->sig_list;
999
1000 prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any "
1001 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
1002 "content:\"test2\"; content:\"test3\"; sid:2;)");
1003 if (prev_sig->next == NULL) {
1004 result = 0;
1005 goto end;
1006 }
1007 prev_sig = prev_sig->next;
1008
1009 prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any "
1010 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
1011 "content:\"test2\"; content:\"test3\"; sid:3;)");
1012 if (prev_sig->next == NULL) {
1013 result = 0;
1014 goto end;
1015 }
1016 prev_sig = prev_sig->next;
1017
1018 prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any "
1019 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
1020 "content:\"test2\"; content:\"test3\"; sid:4;)");
1021 if (prev_sig->next == NULL) {
1022 result = 0;
1023 goto end;
1024 }
1025 prev_sig = prev_sig->next;
1026
1027 prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any "
1028 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
1029 "content:\"test2\"; content:\"test3\"; sid:5;)");
1030 if (prev_sig->next == NULL) {
1031 result = 0;
1032 goto end;
1033 }
1034 prev_sig = prev_sig->next;
1035
1036 SigAddressPrepareStage1(de_ctx);
1037
1038 SigGroupHeadAppendSig(de_ctx, &src_sh, de_ctx->sig_list);
1039 SigGroupHeadAppendSig(de_ctx, &src_sh, de_ctx->sig_list->next->next);
1040 SigGroupHeadAppendSig(de_ctx, &src_sh, de_ctx->sig_list->next->next->next->next);
1041
1042 SigGroupHeadSetSigCnt(src_sh, 4);
1043
1044 result &= (src_sh->sig_cnt == 3);
1045 result &= (SigGroupHeadContainsSigId(de_ctx, src_sh, 1) == 1);
1046 result &= (SigGroupHeadContainsSigId(de_ctx, src_sh, 2) == 0);
1047 result &= (SigGroupHeadContainsSigId(de_ctx, src_sh, 3) == 1);
1048 result &= (SigGroupHeadContainsSigId(de_ctx, src_sh, 4) == 0);
1049 result &= (SigGroupHeadContainsSigId(de_ctx, src_sh, 5) == 1);
1050
1051 SigGroupHeadCopySigs(de_ctx, src_sh, &dst_sh);
1052
1053 SigGroupHeadSetSigCnt(dst_sh, 4);
1054
1055 result &= (dst_sh->sig_cnt == 3);
1056 result &= (SigGroupHeadContainsSigId(de_ctx, dst_sh, 1) == 1);
1057 result &= (SigGroupHeadContainsSigId(de_ctx, dst_sh, 2) == 0);
1058 result &= (SigGroupHeadContainsSigId(de_ctx, dst_sh, 3) == 1);
1059 result &= (SigGroupHeadContainsSigId(de_ctx, dst_sh, 4) == 0);
1060 result &= (SigGroupHeadContainsSigId(de_ctx, dst_sh, 5) == 1);
1061
1062 SigGroupHeadFree(de_ctx, src_sh);
1063 SigGroupHeadFree(de_ctx, dst_sh);
1064
1065 end:
1066 SigCleanSignatures(de_ctx);
1067 DetectEngineCtxFree(de_ctx);
1068 return result;
1069 }
1070
1071 /**
1072 * \test Check if SigGroupHeadBuildMatchArray(), correctly updates the
1073 * match array with the sids.
1074 */
SigGroupHeadTest09(void)1075 static int SigGroupHeadTest09(void)
1076 {
1077 int result = 1;
1078 SigGroupHead *sh = NULL;
1079 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1080 Signature *prev_sig = NULL;
1081
1082 if (de_ctx == NULL)
1083 return 0;
1084
1085 de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any "
1086 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
1087 "content:\"test2\"; content:\"test3\"; sid:1;)");
1088 if (de_ctx->sig_list == NULL) {
1089 result = 0;
1090 goto end;
1091 }
1092 prev_sig = de_ctx->sig_list;
1093
1094 prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any "
1095 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
1096 "content:\"test2\"; content:\"test3\"; sid:2;)");
1097 if (prev_sig->next == NULL) {
1098 result = 0;
1099 goto end;
1100 }
1101 prev_sig = prev_sig->next;
1102
1103 prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any "
1104 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
1105 "content:\"test2\"; content:\"test3\"; sid:3;)");
1106 if (prev_sig->next == NULL) {
1107 result = 0;
1108 goto end;
1109 }
1110 prev_sig = prev_sig->next;
1111
1112 prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any "
1113 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
1114 "content:\"test2\"; content:\"test3\"; sid:4;)");
1115 if (prev_sig->next == NULL) {
1116 result = 0;
1117 goto end;
1118 }
1119 prev_sig = prev_sig->next;
1120
1121 prev_sig->next = SigInit(de_ctx, "alert tcp any any -> any any "
1122 "(msg:\"SigGroupHead tests\"; content:\"test1\"; "
1123 "content:\"test2\"; content:\"test3\"; sid:5;)");
1124 if (prev_sig->next == NULL) {
1125 result = 0;
1126 goto end;
1127 }
1128 prev_sig = prev_sig->next;
1129
1130 SigAddressPrepareStage1(de_ctx);
1131
1132 SigGroupHeadAppendSig(de_ctx, &sh, de_ctx->sig_list);
1133 SigGroupHeadAppendSig(de_ctx, &sh, de_ctx->sig_list->next->next);
1134 SigGroupHeadAppendSig(de_ctx, &sh, de_ctx->sig_list->next->next->next->next);
1135
1136 SigGroupHeadSetSigCnt(sh, 4);
1137 SigGroupHeadBuildMatchArray(de_ctx, sh, 4);
1138
1139 result &= (sh->match_array[0] == de_ctx->sig_list);
1140 result &= (sh->match_array[1] == de_ctx->sig_list->next->next);
1141 result &= (sh->match_array[2] == de_ctx->sig_list->next->next->next->next);
1142
1143 SigGroupHeadFree(de_ctx, sh);
1144
1145 end:
1146 SigCleanSignatures(de_ctx);
1147 DetectEngineCtxFree(de_ctx);
1148 return result;
1149 }
1150
1151 /**
1152 * \test ICMP(?) sig grouping bug.
1153 */
SigGroupHeadTest10(void)1154 static int SigGroupHeadTest10(void)
1155 {
1156 int result = 0;
1157 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1158 Signature *s = NULL;
1159 Packet *p = NULL;
1160 DetectEngineThreadCtx *det_ctx = NULL;
1161 ThreadVars th_v;
1162
1163 memset(&th_v, 0, sizeof(ThreadVars));
1164
1165 p = UTHBuildPacketSrcDst(NULL, 0, IPPROTO_ICMP, "192.168.1.1", "1.2.3.4");
1166 p->icmpv4h->type = 5;
1167 p->icmpv4h->code = 1;
1168
1169 /* originally ip's were
1170 p.src.addr_data32[0] = 0xe08102d3;
1171 p.dst.addr_data32[0] = 0x3001a8c0;
1172 */
1173
1174 if (de_ctx == NULL)
1175 return 0;
1176
1177 s = DetectEngineAppendSig(de_ctx, "alert icmp 192.168.0.0/16 any -> any any (icode:>1; itype:11; sid:1; rev:1;)");
1178 if (s == NULL) {
1179 goto end;
1180 }
1181 s = DetectEngineAppendSig(de_ctx, "alert icmp any any -> 192.168.0.0/16 any (icode:1; itype:5; sid:2; rev:1;)");
1182 if (s == NULL) {
1183 goto end;
1184 }
1185
1186 SigGroupBuild(de_ctx);
1187 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1188
1189 AddressDebugPrint(&p->dst);
1190
1191 const SigGroupHead *sgh = SigMatchSignaturesGetSgh(de_ctx, p);
1192 if (sgh == NULL) {
1193 goto end;
1194 }
1195
1196 result = 1;
1197 end:
1198 SigCleanSignatures(de_ctx);
1199 DetectEngineCtxFree(de_ctx);
1200 UTHFreePackets(&p, 1);
1201 return result;
1202 }
1203 #endif
1204
SigGroupHeadRegisterTests(void)1205 void SigGroupHeadRegisterTests(void)
1206 {
1207 #ifdef UNITTESTS
1208 UtRegisterTest("SigGroupHeadTest03", SigGroupHeadTest03);
1209 UtRegisterTest("SigGroupHeadTest06", SigGroupHeadTest06);
1210 UtRegisterTest("SigGroupHeadTest07", SigGroupHeadTest07);
1211 UtRegisterTest("SigGroupHeadTest08", SigGroupHeadTest08);
1212 UtRegisterTest("SigGroupHeadTest09", SigGroupHeadTest09);
1213 UtRegisterTest("SigGroupHeadTest10", SigGroupHeadTest10);
1214 #endif
1215 }
1216