suricata
detect-bytemath.c
Go to the documentation of this file.
1/* Copyright (C) 2020-2022 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 Jeff Lucovsky <jeff@lucovsky.org>
22 */
23
24/*
25 * Refer to the Snort manual, section 3.5.34 for details.
26 */
27
28#include "suricata-common.h"
29#include "threads.h"
30#include "decode.h"
31
32#include "rust.h"
33#include "app-layer-parser.h"
34#include "app-layer-protos.h"
35
36#include "detect.h"
37#include "detect-parse.h"
38#include "detect-engine.h"
40#include "detect-engine-mpm.h"
41#include "detect-engine-state.h"
42#include "detect-engine-build.h"
43
44#include "detect-content.h"
45#include "detect-pcre.h"
46#include "detect-byte.h"
47#include "detect-bytemath.h"
48
49#include "flow.h"
50#include "flow-var.h"
51#include "flow-util.h"
52
53#include "util-byte.h"
54#include "util-debug.h"
55#include "util-unittest.h"
57#include "util-spm.h"
58
59static int DetectByteMathSetup(DetectEngineCtx *, Signature *, const char *);
60#ifdef UNITTESTS
61#define DETECT_BYTEMATH_ENDIAN_DEFAULT (uint8_t) BigEndian
62#define DETECT_BYTEMATH_BASE_DEFAULT (uint8_t) BaseDec
63
64static void DetectByteMathRegisterTests(void);
65#endif
66static void DetectByteMathFree(DetectEngineCtx *, void *);
67
68/**
69 * \brief Registers the keyword handlers for the "byte_math" keyword.
70 */
72{
73 sigmatch_table[DETECT_BYTEMATH].name = "byte_math";
75 sigmatch_table[DETECT_BYTEMATH].Setup = DetectByteMathSetup;
76 sigmatch_table[DETECT_BYTEMATH].Free = DetectByteMathFree;
77#ifdef UNITTESTS
78 sigmatch_table[DETECT_BYTEMATH].RegisterTests = DetectByteMathRegisterTests;
79#endif
80}
81
82static inline bool DetectByteMathValidateNbytesOnly(const DetectByteMathData *data, int32_t nbytes)
83{
84 return nbytes >= 1 &&
85 (((data->flags & DETECT_BYTEMATH_FLAG_STRING) && nbytes <= 10) || (nbytes <= 4));
86}
87
88int DetectByteMathDoMatch(DetectEngineThreadCtx *det_ctx, const DetectByteMathData *data,
89 const Signature *s, const uint8_t *payload, const uint32_t payload_len, uint8_t nbytes,
90 uint64_t rvalue, uint64_t *value, uint8_t endian)
91{
92 if (payload_len == 0) {
93 return 0;
94 }
95
96 if (!DetectByteMathValidateNbytesOnly(data, nbytes)) {
97 return 0;
98 }
99
100 const uint8_t *ptr;
101 int32_t len;
102 uint64_t val;
103 int extbytes;
104
105 /* Calculate the ptr value for the byte-math op and length remaining in
106 * the packet from that point.
107 */
108 if (data->flags & DETECT_BYTEMATH_FLAG_RELATIVE) {
109 SCLogDebug("relative, working with det_ctx->buffer_offset %" PRIu32 ", "
110 "data->offset %" PRIi32 "",
111 det_ctx->buffer_offset, data->offset);
112
113 ptr = payload + det_ctx->buffer_offset;
114 len = payload_len - det_ctx->buffer_offset;
115
116 ptr += data->offset;
117 len -= data->offset;
118
119 /* No match if there is no relative base */
120 if (len <= 0) {
121 return 0;
122 }
123 } else {
124 SCLogDebug("absolute, data->offset %" PRIi32 "", data->offset);
125
126 ptr = payload + data->offset;
127 len = payload_len - data->offset;
128 }
129
130 /* Validate that the to-be-extracted is within the packet */
131 if (ptr < payload || nbytes > len) {
132 SCLogDebug("Data not within payload pkt=%p, ptr=%p, len=%" PRIu32 ", nbytes=%d", payload,
133 ptr, len, nbytes);
134 return 0;
135 }
136
137 /* Extract the byte data */
138 if (data->flags & DETECT_BYTEMATH_FLAG_STRING) {
139 extbytes = ByteExtractStringUint64(&val, data->base, nbytes, (const char *)ptr);
140 if (extbytes <= 0) {
141 if (val == 0) {
142 SCLogDebug("No Numeric value");
143 return 0;
144 } else {
145 SCLogDebug("error extracting %d bytes of string data: %d", nbytes, extbytes);
146 return -1;
147 }
148 }
149 } else {
150 ByteEndian bme = endian;
151 int endianness = (bme == BigEndian) ? BYTE_BIG_ENDIAN : BYTE_LITTLE_ENDIAN;
152 extbytes = ByteExtractUint64(&val, endianness, nbytes, ptr);
153 if (extbytes != nbytes) {
154 SCLogDebug("error extracting %d bytes of numeric data: %d", nbytes, extbytes);
155 return 0;
156 }
157 }
158
159 DEBUG_VALIDATE_BUG_ON(extbytes > len);
160
161 ptr += extbytes;
162
163 switch (data->oper) {
164 case OperatorNone:
165 break;
166 case Addition:
167 val += rvalue;
168 break;
169 case Subtraction:
170 val -= rvalue;
171 break;
172 case Division:
173 if (rvalue == 0) {
174 SCLogDebug("avoiding division by zero");
175 return 0;
176 }
177 val /= rvalue;
178 break;
179 case Multiplication:
180 val *= rvalue;
181 break;
182 case LeftShift:
183 if (rvalue < 64) {
184 val <<= rvalue;
185 } else {
186 val = 0;
187 }
188 break;
189 case RightShift:
190 val >>= rvalue;
191 break;
192 }
193
194 det_ctx->buffer_offset = (uint32_t)(ptr - payload);
195
196 if (data->flags & DETECT_BYTEMATH_FLAG_BITMASK) {
197 val &= data->bitmask_val;
198 if (val && data->bitmask_shift_count) {
199 val = val >> data->bitmask_shift_count;
200 }
201 }
202
203 *value = val;
204 return 1;
205}
206
207/**
208 * \internal
209 * \brief Used to parse byte_math arg.
210 *
211 * \param arg The argument to parse.
212 * \param rvalue May be NULL. When non-null, will contain the variable
213 * name of rvalue (iff rvalue is not a scalar value)
214 *
215 * \retval bmd On success an instance containing the parsed data.
216 * On failure, NULL.
217 */
218static DetectByteMathData *DetectByteMathParse(
219 DetectEngineCtx *de_ctx, const char *arg, char **nbytes, char **rvalue)
220{
221 DetectByteMathData *bmd;
222 if ((bmd = SCByteMathParse(arg)) == NULL) {
223 SCLogError("invalid bytemath values");
224 return NULL;
225 }
226
227 if (bmd->nbytes_str) {
228 if (nbytes == NULL) {
229 SCLogError("byte_math supplied with "
230 "var name for nbytes. \"nbytes\" argument supplied to "
231 "this function must be non-NULL");
232 goto error;
233 }
234 *nbytes = SCStrdup(bmd->nbytes_str);
235 if (*nbytes == NULL) {
236 goto error;
237 }
238 }
239
240 if (bmd->rvalue_str) {
241 if (rvalue == NULL) {
242 SCLogError("byte_math supplied with "
243 "var name for rvalue. \"rvalue\" argument supplied to "
244 "this function must be non-NULL");
245 goto error;
246 }
247 *rvalue = SCStrdup(bmd->rvalue_str);
248 if (*rvalue == NULL) {
249 goto error;
250 }
251 }
252
253 if (bmd->flags & DETECT_BYTEMATH_FLAG_BITMASK) {
254 if (bmd->bitmask_val) {
255 uint32_t bmask = bmd->bitmask_val;
256 while (!(bmask & 0x1)){
257 bmask = bmask >> 1;
258 bmd->bitmask_shift_count++;
259 }
260 }
261 }
262
263 return bmd;
264
265 error:
266 if (bmd != NULL)
267 DetectByteMathFree(de_ctx, bmd);
268 return NULL;
269}
270
271/**
272 * \brief The setup function for the byte_math keyword for a signature.
273 *
274 * \param de_ctx Pointer to the detection engine context.
275 * \param s Pointer to signature for the current Signature being parsed
276 * from the rules.
277 * \param arg Pointer to the string holding the keyword value.
278 *
279 * \retval 0 On success.
280 * \retval -1 On failure.
281 */
282static int DetectByteMathSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
283{
284 SigMatch *prev_pm = NULL;
285 DetectByteMathData *data;
286 char *rvalue = NULL;
287 char *nbytes = NULL;
288 int ret = -1;
289
290 data = DetectByteMathParse(de_ctx, arg, &nbytes, &rvalue);
291 if (data == NULL)
292 goto error;
293
294 int sm_list;
296 if (DetectBufferGetActiveList(de_ctx, s) == -1)
297 goto error;
298
299 sm_list = s->init_data->list;
300
301 if (data->flags & DETECT_BYTEMATH_FLAG_RELATIVE) {
303 if (!prev_pm) {
304 SCLogError("relative specified without "
305 "previous pattern match");
306 goto error;
307 }
308 }
309 } else if (data->endian == EndianDCE) {
310 if (data->flags & DETECT_BYTEMATH_FLAG_RELATIVE) {
315 DETECT_ISDATAAT, -1);
316 if (prev_pm == NULL) {
317 sm_list = DETECT_SM_LIST_PMATCH;
318 } else {
319 sm_list = SigMatchListSMBelongsTo(s, prev_pm);
320 if (sm_list < 0)
321 goto error;
322 }
323 } else {
324 sm_list = DETECT_SM_LIST_PMATCH;
325 }
326
328 goto error;
329
330 } else if (data->flags & DETECT_BYTEMATH_FLAG_RELATIVE) {
334 DETECT_ISDATAAT, -1);
335 if (prev_pm == NULL) {
336 sm_list = DETECT_SM_LIST_PMATCH;
337 } else {
338 sm_list = SigMatchListSMBelongsTo(s, prev_pm);
339 if (sm_list < 0)
340 goto error;
341 }
342
343 } else {
344 sm_list = DETECT_SM_LIST_PMATCH;
345 }
346
347 if (data->endian == EndianDCE) {
349 goto error;
350
351 if ((data->flags & DETECT_BYTEMATH_FLAG_STRING) || (data->base == BaseDec) ||
352 (data->base == BaseHex) || (data->base == BaseOct)) {
353 SCLogError("Invalid option. "
354 "A bytemath keyword with dce holds other invalid modifiers.");
355 goto error;
356 }
357 }
358
359 if (nbytes != NULL) {
361 if (!DetectByteRetrieveSMVar(nbytes, s, sm_list, &index)) {
362 SCLogError("unknown byte_ keyword var seen in byte_math - %s", nbytes);
363 goto error;
364 }
365 data->nbytes = index;
366 data->flags |= DETECT_BYTEMATH_FLAG_NBYTES_VAR;
367 SCFree(nbytes);
368 nbytes = NULL;
369 }
370
371 if (rvalue != NULL) {
373 if (!DetectByteRetrieveSMVar(rvalue, s, sm_list, &index)) {
374 SCLogError("unknown byte_ keyword var seen in byte_math - %s", rvalue);
375 goto error;
376 }
377 data->rvalue = index;
378 data->flags |= DETECT_BYTEMATH_FLAG_RVALUE_VAR;
379 SCFree(rvalue);
380 rvalue = NULL;
381 }
382
383 SigMatch *prev_bmd_sm = DetectGetLastSMByListId(s, sm_list,
384 DETECT_BYTEMATH, -1);
385 if (prev_bmd_sm == NULL) {
386 data->local_id = 0;
387 } else {
388 data->local_id = ((DetectByteMathData *)prev_bmd_sm->ctx)->local_id + 1;
389 }
390 if (data->local_id > de_ctx->byte_extract_max_local_id) {
391 de_ctx->byte_extract_max_local_id = data->local_id;
392 }
393
394 if (SCSigMatchAppendSMToList(de_ctx, s, DETECT_BYTEMATH, (SigMatchCtx *)data, sm_list) ==
395 NULL) {
396 goto error;
397 }
398
399 if (!(data->flags & DETECT_BYTEMATH_FLAG_RELATIVE))
400 goto okay;
401
402 if (prev_pm == NULL)
403 goto okay;
404
405 if (prev_pm->type == DETECT_CONTENT) {
406 DetectContentData *cd = (DetectContentData *)prev_pm->ctx;
407 cd->flags |= DETECT_CONTENT_RELATIVE_NEXT;
408 } else if (prev_pm->type == DETECT_PCRE) {
409 DetectPcreData *pd = (DetectPcreData *)prev_pm->ctx;
410 pd->flags |= DETECT_PCRE_RELATIVE_NEXT;
411 }
412
413 okay:
414 return 0;
415
416 error:
417 if (rvalue)
418 SCFree(rvalue);
419 if (nbytes)
420 SCFree(nbytes);
421 DetectByteMathFree(de_ctx, data);
422 return ret;
423}
424
425/**
426 * \brief Used to free instances of DetectByteMathractData.
427 *
428 * \param ptr Instance of DetectByteMathData to be freed.
429 */
430static void DetectByteMathFree(DetectEngineCtx *de_ctx, void *ptr)
431{
432 SCByteMathFree(ptr);
433}
434
435/**
436 * \brief Lookup the SigMatch for a named byte_math variable.
437 *
438 * \param arg The name of the byte_math variable to lookup.
439 * \param s Pointer the signature to look in.
440 *
441 * \retval A pointer to the SigMatch if found, otherwise NULL.
442 */
443SigMatch *DetectByteMathRetrieveSMVar(const char *arg, int sm_list, const Signature *s)
444{
445 for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
446 SigMatch *sm = s->init_data->buffers[x].head;
447 while (sm != NULL) {
448 if (sm->type == DETECT_BYTEMATH) {
449 const DetectByteMathData *bmd = (const DetectByteMathData *)sm->ctx;
450 if (strcmp(bmd->result, arg) == 0) {
451 SCLogDebug("Retrieved SM for \"%s\"", arg);
452 return sm;
453 }
454 }
455 sm = sm->next;
456 }
457 }
458
459 for (int list = 0; list < DETECT_SM_LIST_MAX; list++) {
460 SigMatch *sm = s->init_data->smlists[list];
461 while (sm != NULL) {
462 // Make sure that the linked buffers ore on the same list
463 if (sm->type == DETECT_BYTEMATH && (sm_list == -1 || sm_list == list)) {
464 const DetectByteMathData *bmd = (const DetectByteMathData *)sm->ctx;
465 if (strcmp(bmd->result, arg) == 0) {
466 SCLogDebug("Retrieved SM for \"%s\"", arg);
467 return sm;
468 }
469 }
470 sm = sm->next;
471 }
472 }
473
474 return NULL;
475}
476
477/*************************************Unittests********************************/
478#ifdef UNITTESTS
479#include "detect-engine-alert.h"
480
481static int DetectByteMathParseTest01(void)
482{
483
484 DetectByteMathData *bmd = DetectByteMathParse(NULL,
485 "bytes 4, offset 2, oper +,"
486 "rvalue 10, result bar",
487 NULL, NULL);
488 FAIL_IF(bmd == NULL);
489
490 FAIL_IF_NOT(bmd->nbytes == 4);
491 FAIL_IF_NOT(bmd->offset == 2);
492 FAIL_IF_NOT(bmd->oper == Addition);
493 FAIL_IF_NOT(bmd->rvalue == 10);
494 FAIL_IF_NOT(strcmp(bmd->result, "bar") == 0);
497
498 DetectByteMathFree(NULL, bmd);
499
500 PASS;
501}
502
503static int DetectByteMathParseTest02(void)
504{
505 /* bytes value invalid */
506 DetectByteMathData *bmd = DetectByteMathParse(NULL,
507 "bytes 257, offset 2, oper +, "
508 "rvalue 39, result bar",
509 NULL, NULL);
510
511 FAIL_IF_NOT(bmd == NULL);
512
513 PASS;
514}
515
516static int DetectByteMathParseTest03(void)
517{
518 /* bytes value invalid */
519 DetectByteMathData *bmd = DetectByteMathParse(NULL,
520 "bytes 11, offset 2, oper +, "
521 "rvalue 39, result bar",
522 NULL, NULL);
523 FAIL_IF_NOT(bmd == NULL);
524
525 PASS;
526}
527
528static int DetectByteMathParseTest04(void)
529{
530 /* offset value invalid */
531 DetectByteMathData *bmd = DetectByteMathParse(NULL,
532 "bytes 4, offset 70000, oper +,"
533 " rvalue 39, result bar",
534 NULL, NULL);
535
536 FAIL_IF_NOT(bmd == NULL);
537
538 PASS;
539}
540
541static int DetectByteMathParseTest05(void)
542{
543 /* oper value invalid */
544 DetectByteMathData *bmd = DetectByteMathParse(NULL,
545 "bytes 11, offset 16, oper &,"
546 "rvalue 39, result bar",
547 NULL, NULL);
548 FAIL_IF_NOT(bmd == NULL);
549
550 PASS;
551}
552
553static int DetectByteMathParseTest06(void)
554{
555 uint8_t flags = DETECT_BYTEMATH_FLAG_RELATIVE;
556 char *rvalue = NULL;
557
558 DetectByteMathData *bmd = DetectByteMathParse(NULL,
559 "bytes 4, offset 0, oper +,"
560 "rvalue 248, result var, relative",
561 NULL, &rvalue);
562
563 FAIL_IF(bmd == NULL);
564 FAIL_IF_NOT(bmd->nbytes == 4);
565 FAIL_IF_NOT(bmd->offset == 0);
566 FAIL_IF_NOT(bmd->oper == Addition);
567 FAIL_IF_NOT(bmd->rvalue == 248);
568 FAIL_IF_NOT(strcmp(bmd->result, "var") == 0);
569 FAIL_IF_NOT(bmd->flags == flags);
572
573 DetectByteMathFree(NULL, bmd);
574
575 PASS;
576}
577
578static int DetectByteMathParseTest07(void)
579{
580 char *rvalue = NULL;
581
582 DetectByteMathData *bmd = DetectByteMathParse(NULL,
583 "bytes 4, offset 2, oper +,"
584 "rvalue foo, result bar",
585 NULL, &rvalue);
586 FAIL_IF_NOT(rvalue);
587 FAIL_IF_NOT(bmd->nbytes == 4);
588 FAIL_IF_NOT(bmd->offset == 2);
589 FAIL_IF_NOT(bmd->oper == Addition);
590 FAIL_IF_NOT(strcmp(rvalue, "foo") == 0);
591 FAIL_IF_NOT(strcmp(bmd->result, "bar") == 0);
594
595 DetectByteMathFree(NULL, bmd);
596
597 SCFree(rvalue);
598
599 PASS;
600}
601
602static int DetectByteMathParseTest08(void)
603{
604 /* ensure Parse checks the pointer value when rvalue is a var */
605 DetectByteMathData *bmd = DetectByteMathParse(NULL,
606 "bytes 4, offset 2, oper +,"
607 "rvalue foo, result bar",
608 NULL, NULL);
609 FAIL_IF_NOT(bmd == NULL);
610
611 PASS;
612}
613
614static int DetectByteMathParseTest09(void)
615{
616 uint8_t flags = DETECT_BYTEMATH_FLAG_RELATIVE;
617
618 DetectByteMathData *bmd = DetectByteMathParse(NULL,
619 "bytes 4, offset 2, oper +,"
620 "rvalue 39, result bar, relative",
621 NULL, NULL);
622 FAIL_IF(bmd == NULL);
623
624 FAIL_IF_NOT(bmd->nbytes == 4);
625 FAIL_IF_NOT(bmd->offset == 2);
626 FAIL_IF_NOT(bmd->oper == Addition);
627 FAIL_IF_NOT(bmd->rvalue == 39);
628 FAIL_IF_NOT(strcmp(bmd->result, "bar") == 0);
629 FAIL_IF_NOT(bmd->flags == flags);
632
633 DetectByteMathFree(NULL, bmd);
634
635 PASS;
636}
637
638static int DetectByteMathParseTest10(void)
639{
640 uint8_t flags = DETECT_BYTEMATH_FLAG_ENDIAN;
641
642 DetectByteMathData *bmd = DetectByteMathParse(NULL,
643 "bytes 4, offset 2, oper +,"
644 "rvalue 39, result bar, endian"
645 " big",
646 NULL, NULL);
647
648 FAIL_IF(bmd == NULL);
649 FAIL_IF_NOT(bmd->nbytes == 4);
650 FAIL_IF_NOT(bmd->offset == 2);
651 FAIL_IF_NOT(bmd->oper == Addition);
652 FAIL_IF_NOT(bmd->rvalue == 39);
653 FAIL_IF_NOT(strcmp(bmd->result, "bar") == 0);
654 FAIL_IF_NOT(bmd->flags == flags);
655 FAIL_IF_NOT(bmd->endian == BigEndian);
657
658 DetectByteMathFree(NULL, bmd);
659
660 PASS;
661}
662
663static int DetectByteMathParseTest11(void)
664{
665 uint8_t flags = DETECT_BYTEMATH_FLAG_ENDIAN;
666
667 DetectByteMathData *bmd = DetectByteMathParse(NULL,
668 "bytes 4, offset 2, oper +, "
669 "rvalue 39, result bar, dce",
670 NULL, NULL);
671
672 FAIL_IF(bmd == NULL);
673 FAIL_IF_NOT(bmd->nbytes == 4);
674 FAIL_IF_NOT(bmd->offset == 2);
675 FAIL_IF_NOT(bmd->oper == Addition);
676 FAIL_IF_NOT(bmd->rvalue == 39);
677 FAIL_IF_NOT(strcmp(bmd->result, "bar") == 0);
678 FAIL_IF_NOT(bmd->flags == flags);
679 FAIL_IF_NOT(bmd->endian == EndianDCE);
681
682 DetectByteMathFree(NULL, bmd);
683
684 PASS;
685}
686
687static int DetectByteMathParseTest12(void)
688{
689 uint8_t flags = DETECT_BYTEMATH_FLAG_RELATIVE | DETECT_BYTEMATH_FLAG_STRING;
690
691 DetectByteMathData *bmd = DetectByteMathParse(NULL,
692 "bytes 4, offset 2, oper +,"
693 "rvalue 39, result bar, "
694 "relative, string dec",
695 NULL, NULL);
696
697 FAIL_IF(bmd == NULL);
698 FAIL_IF_NOT(bmd->nbytes == 4);
699 FAIL_IF_NOT(bmd->offset == 2);
700 FAIL_IF_NOT(bmd->oper == Addition);
701 FAIL_IF_NOT(bmd->rvalue == 39);
702 FAIL_IF_NOT(strcmp(bmd->result, "bar") == 0);
703 FAIL_IF_NOT(bmd->flags == flags);
704 FAIL_IF_NOT(bmd->endian == BigEndian);
705 FAIL_IF_NOT(bmd->base == BaseDec);
706
707 DetectByteMathFree(NULL, bmd);
708
709 PASS;
710}
711
712static int DetectByteMathParseTest13(void)
713{
714 uint8_t flags = DETECT_BYTEMATH_FLAG_STRING |
715 DETECT_BYTEMATH_FLAG_RELATIVE |
716 DETECT_BYTEMATH_FLAG_BITMASK;
717
718 DetectByteMathData *bmd = DetectByteMathParse(NULL,
719 "bytes 4, offset 2, oper +, "
720 "rvalue 39, result bar, "
721 "relative, string dec, bitmask "
722 "0x8f40",
723 NULL, NULL);
724
725 FAIL_IF(bmd == NULL);
726 FAIL_IF_NOT(bmd->nbytes == 4);
727 FAIL_IF_NOT(bmd->offset == 2);
728 FAIL_IF_NOT(bmd->oper == Addition);
729 FAIL_IF_NOT(bmd->rvalue == 39);
730 FAIL_IF_NOT(strcmp(bmd->result, "bar") == 0);
731 FAIL_IF_NOT(bmd->bitmask_val == 0x8f40);
732 FAIL_IF_NOT(bmd->bitmask_shift_count == 6);
733 FAIL_IF_NOT(bmd->flags == flags);
734 FAIL_IF_NOT(bmd->endian == BigEndian);
735 FAIL_IF_NOT(bmd->base == BaseDec);
736
737 DetectByteMathFree(NULL, bmd);
738
739 PASS;
740}
741
742
743static int DetectByteMathParseTest14(void)
744{
745 /* incomplete */
746 DetectByteMathData *bmd = DetectByteMathParse(NULL,
747 "bytes 4, offset 2, oper +,"
748 "rvalue foo",
749 NULL, NULL);
750
751 FAIL_IF_NOT(bmd == NULL);
752
753 PASS;
754}
755
756static int DetectByteMathParseTest15(void)
757{
758
759 /* incomplete */
760 DetectByteMathData *bmd = DetectByteMathParse(NULL,
761 "bytes 4, offset 2, oper +, "
762 "result bar",
763 NULL, NULL);
764
765 FAIL_IF_NOT(bmd == NULL);
766
767 PASS;
768}
769
770static int DetectByteMathParseTest16(void)
771{
772 uint8_t flags = DETECT_BYTEMATH_FLAG_STRING | DETECT_BYTEMATH_FLAG_RELATIVE |
773 DETECT_BYTEMATH_FLAG_BITMASK;
774
775 DetectByteMathData *bmd = DetectByteMathParse(NULL,
776 "bytes 4, offset -2, oper +, "
777 "rvalue 39, result bar, "
778 "relative, string dec, bitmask "
779 "0x8f40",
780 NULL, NULL);
781
782 FAIL_IF(bmd == NULL);
783 FAIL_IF_NOT(bmd->nbytes == 4);
784 FAIL_IF_NOT(bmd->offset == -2);
785 FAIL_IF_NOT(bmd->oper == Addition);
786 FAIL_IF_NOT(bmd->rvalue == 39);
787 FAIL_IF_NOT(strcmp(bmd->result, "bar") == 0);
788 FAIL_IF_NOT(bmd->bitmask_val == 0x8f40);
789 FAIL_IF_NOT(bmd->bitmask_shift_count == 6);
790 FAIL_IF_NOT(bmd->flags == flags);
791 FAIL_IF_NOT(bmd->endian == BigEndian);
792 FAIL_IF_NOT(bmd->base == BaseDec);
793
794 DetectByteMathFree(NULL, bmd);
795
796 PASS;
797}
798
799static int DetectByteMathPacket01(void)
800{
801 uint8_t buf[] = { 0x38, 0x35, 0x6d, 0x00, 0x00, 0x01,
802 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
803 0x00, 0x00, 0x6d, 0x00, 0x01, 0x00 };
804 Flow f;
805 void *dns_state = NULL;
806 Packet *p = NULL;
807 Signature *s = NULL;
809 DetectEngineThreadCtx *det_ctx = NULL;
811
812 memset(&tv, 0, sizeof(ThreadVars));
813 memset(&f, 0, sizeof(Flow));
814
815 p = UTHBuildPacketReal(buf, sizeof(buf), IPPROTO_UDP,
816 "192.168.1.5", "192.168.1.1",
817 41424, 53);
818 FAIL_IF_NULL(p);
819
820 FLOW_INITIALIZE(&f);
821 f.flags |= FLOW_IPV4;
822 f.proto = IPPROTO_UDP;
824
825 p->flow = &f;
826 p->flags |= PKT_HAS_FLOW;
829
832
835
836 /*
837 * byte_extract: Extract 1 byte from offset 0 --> 0x0038
838 * byte_math: Extract 1 byte from offset 2 (0x35)
839 * Add 0x35 + 0x38 = 109 (0x6d)
840 * byte_test: Compare 2 bytes at offset 13 bytes from last
841 * match and compare with 0x6d
842 */
843 s = DetectEngineAppendSig(de_ctx, "alert udp any any -> any any "
844 "(byte_extract: 1, 0, extracted_val, relative;"
845 "byte_math: bytes 1, offset 1, oper +, rvalue extracted_val, result var;"
846 "byte_test: 2, =, var, 13;"
847 "msg:\"Byte extract and byte math with byte test verification\";"
848 "sid:1;)");
849 FAIL_IF_NULL(s);
850
851 /* this rule should not alert */
852 s = DetectEngineAppendSig(de_ctx, "alert udp any any -> any any "
853 "(byte_extract: 1, 0, extracted_val, relative;"
854 "byte_math: bytes 1, offset 1, oper +, rvalue extracted_val, result var;"
855 "byte_test: 2, !=, var, 13;"
856 "msg:\"Byte extract and byte math with byte test verification\";"
857 "sid:2;)");
858 FAIL_IF_NULL(s);
859
860 /*
861 * this rule should alert:
862 * compares offset 15 with var ... 1 (offset 15) < 0x6d (var)
863 */
864 s = DetectEngineAppendSig(de_ctx, "alert udp any any -> any any "
865 "(byte_extract: 1, 0, extracted_val, relative;"
866 "byte_math: bytes 1, offset 1, oper +, rvalue extracted_val, result var;"
867 "byte_test: 2, <, var, 15;"
868 "msg:\"Byte extract and byte math with byte test verification\";"
869 "sid:3;)");
870 FAIL_IF_NULL(s);
871
873 DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
874 FAIL_IF_NULL(det_ctx);
875
876 int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS,
877 STREAM_TOSERVER, buf, sizeof(buf));
878 FAIL_IF_NOT(r == 0);
879
880 dns_state = f.alstate;
881 FAIL_IF_NULL(dns_state);
882
883 /* do detect */
884 SigMatchSignatures(&tv, de_ctx, det_ctx, p);
885
886 /* ensure sids 1 & 3 alerted */
890
894
895 FLOW_DESTROY(&f);
896 UTHFreePacket(p);
897
898 PASS;
899}
900
901static int DetectByteMathPacket02(void)
902{
903 uint8_t buf[] = { 0x38, 0x35, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
904 0x00, 0x70, 0x00, 0x01, 0x00 };
905 Flow f;
906 void *dns_state = NULL;
907 Packet *p = NULL;
908 Signature *s = NULL;
910 DetectEngineThreadCtx *det_ctx = NULL;
912
913 memset(&tv, 0, sizeof(ThreadVars));
914 memset(&f, 0, sizeof(Flow));
915
916 p = UTHBuildPacketReal(buf, sizeof(buf), IPPROTO_UDP, "192.168.1.5", "192.168.1.1", 41424, 53);
917 FAIL_IF_NULL(p);
918
919 FLOW_INITIALIZE(&f);
920 f.flags |= FLOW_IPV4;
921 f.proto = IPPROTO_UDP;
923
924 p->flow = &f;
925 p->flags |= PKT_HAS_FLOW;
928
931
934
935 /*
936 * byte_extract: Extract 1 byte from offset 0 --> 0x38
937 * byte_math: Extract 1 byte from offset -1 (0x38)
938 * Add 0x38 + 0x38 = 112 (0x70)
939 * byte_test: Compare 2 bytes at offset 13 bytes from last
940 * match and compare with 0x70
941 */
943 "alert udp any any -> any any "
944 "(byte_extract: 1, 0, extracted_val, relative;"
945 "byte_math: bytes 1, offset -1, oper +, rvalue extracted_val, result var, relative;"
946 "byte_test: 2, =, var, 13;"
947 "msg:\"Byte extract and byte math with byte test verification\";"
948 "sid:1;)");
949 FAIL_IF_NULL(s);
950
951 /* this rule should not alert */
953 "alert udp any any -> any any "
954 "(byte_extract: 1, 0, extracted_val, relative;"
955 "byte_math: bytes 1, offset -1, oper +, rvalue extracted_val, result var, relative;"
956 "byte_test: 2, !=, var, 13;"
957 "msg:\"Byte extract and byte math with byte test verification\";"
958 "sid:2;)");
959 FAIL_IF_NULL(s);
960
961 /*
962 * this rule should alert:
963 * compares offset 15 with var ... 1 (offset 15) < 0x70 (var)
964 */
966 "alert udp any any -> any any "
967 "(byte_extract: 1, 0, extracted_val, relative;"
968 "byte_math: bytes 1, offset -1, oper +, rvalue extracted_val, result var, relative;"
969 "byte_test: 2, <, var, 15;"
970 "msg:\"Byte extract and byte math with byte test verification\";"
971 "sid:3;)");
972 FAIL_IF_NULL(s);
973
975 DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
976 FAIL_IF_NULL(det_ctx);
977
978 int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf, sizeof(buf));
979 FAIL_IF_NOT(r == 0);
980
981 dns_state = f.alstate;
982 FAIL_IF_NULL(dns_state);
983
984 /* do detect */
985 SigMatchSignatures(&tv, de_ctx, det_ctx, p);
986
987 /* ensure sids 1 & 3 alerted */
991
995
996 FLOW_DESTROY(&f);
997 UTHFreePacket(p);
998
999 PASS;
1000}
1001
1002static int DetectByteMathContext01(void)
1003{
1004 DetectEngineCtx *de_ctx = NULL;
1005 Signature *s = NULL;
1006 SigMatch *sm = NULL;
1007 DetectContentData *cd = NULL;
1008 DetectByteMathData *bmd = NULL;
1009
1011 FAIL_IF(de_ctx == NULL);
1012
1013 de_ctx->flags |= DE_QUIET;
1014 s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any "
1015 "(msg:\"Testing bytemath_body\"; "
1016 "content:\"|00 04 93 F3|\"; "
1017 "content:\"|00 00 00 07|\"; distance:4; within:4;"
1018 "byte_math:bytes 4, offset 0, oper +, rvalue "
1019 "248, result var, relative; sid:1;)");
1020
1021 FAIL_IF(de_ctx->sig_list == NULL);
1022
1024
1026 FAIL_IF(sm->type != DETECT_CONTENT);
1027 cd = (DetectContentData *)sm->ctx;
1028 FAIL_IF(cd->flags & DETECT_CONTENT_WITHIN);
1029 FAIL_IF(cd->flags & DETECT_CONTENT_DISTANCE);
1030 FAIL_IF(cd->content_len != 4);
1031
1032 sm = sm->next;
1033 FAIL_IF(sm->type != DETECT_CONTENT);
1034 sm = sm->next;
1035 FAIL_IF(sm->type != DETECT_BYTEMATH);
1036
1037 FAIL_IF(sm->ctx == NULL);
1038
1039 bmd = (DetectByteMathData *)sm->ctx;
1040 FAIL_IF_NOT(bmd->nbytes == 4);
1041 FAIL_IF_NOT(bmd->offset == 0);
1042 FAIL_IF_NOT(bmd->rvalue == 248);
1043 FAIL_IF_NOT(strcmp(bmd->result, "var") == 0);
1044 FAIL_IF_NOT(bmd->flags == DETECT_BYTEMATH_FLAG_RELATIVE);
1045 FAIL_IF_NOT(bmd->endian == BigEndian);
1046 FAIL_IF_NOT(bmd->oper == Addition);
1047 FAIL_IF_NOT(bmd->base == BaseDec);
1048
1050
1051 PASS;
1052}
1053
1054static void DetectByteMathRegisterTests(void)
1055{
1056 UtRegisterTest("DetectByteMathParseTest01", DetectByteMathParseTest01);
1057 UtRegisterTest("DetectByteMathParseTest02", DetectByteMathParseTest02);
1058 UtRegisterTest("DetectByteMathParseTest03", DetectByteMathParseTest03);
1059 UtRegisterTest("DetectByteMathParseTest04", DetectByteMathParseTest04);
1060 UtRegisterTest("DetectByteMathParseTest05", DetectByteMathParseTest05);
1061 UtRegisterTest("DetectByteMathParseTest06", DetectByteMathParseTest06);
1062 UtRegisterTest("DetectByteMathParseTest07", DetectByteMathParseTest07);
1063 UtRegisterTest("DetectByteMathParseTest08", DetectByteMathParseTest08);
1064 UtRegisterTest("DetectByteMathParseTest09", DetectByteMathParseTest09);
1065 UtRegisterTest("DetectByteMathParseTest10", DetectByteMathParseTest10);
1066 UtRegisterTest("DetectByteMathParseTest11", DetectByteMathParseTest11);
1067 UtRegisterTest("DetectByteMathParseTest12", DetectByteMathParseTest12);
1068 UtRegisterTest("DetectByteMathParseTest13", DetectByteMathParseTest13);
1069 UtRegisterTest("DetectByteMathParseTest14", DetectByteMathParseTest14);
1070 UtRegisterTest("DetectByteMathParseTest15", DetectByteMathParseTest15);
1071 UtRegisterTest("DetectByteMathParseTest16", DetectByteMathParseTest16);
1072 UtRegisterTest("DetectByteMathPacket01", DetectByteMathPacket01);
1073 UtRegisterTest("DetectByteMathPacket02", DetectByteMathPacket02);
1074 UtRegisterTest("DetectByteMathContext01", DetectByteMathContext01);
1075}
1076#endif /* UNITTESTS */
uint8_t len
AppLayerParserThreadCtx * AppLayerParserThreadCtxAlloc(void)
Gets a new app layer protocol's parser thread context.
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
Destroys the app layer parser thread context obtained using AppLayerParserThreadCtxAlloc().
int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, uint8_t flags, const uint8_t *input, uint32_t input_len)
@ ALPROTO_DCERPC
@ ALPROTO_DNS
uint8_t flags
Definition decode-gre.h:0
#define PKT_HAS_FLOW
Definition decode.h:1266
bool DetectByteRetrieveSMVar(const char *arg, const Signature *s, int sm_list, DetectByteIndexType *index)
Used to retrieve args from BM.
Definition detect-byte.c:41
uint8_t DetectByteIndexType
Definition detect-byte.h:28
void DetectBytemathRegister(void)
Registers the keyword handlers for the "byte_math" keyword.
int DetectByteMathDoMatch(DetectEngineThreadCtx *det_ctx, const DetectByteMathData *data, const Signature *s, const uint8_t *payload, const uint32_t payload_len, uint8_t nbytes, uint64_t rvalue, uint64_t *value, uint8_t endian)
#define DETECT_BYTEMATH_BASE_DEFAULT
#define DETECT_BYTEMATH_ENDIAN_DEFAULT
SigMatch * DetectByteMathRetrieveSMVar(const char *arg, int sm_list, const Signature *s)
Lookup the SigMatch for a named byte_math variable.
#define DETECT_CONTENT_RELATIVE_NEXT
#define DETECT_CONTENT_WITHIN
#define DETECT_CONTENT_DISTANCE
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
int DetectBufferGetActiveList(DetectEngineCtx *de_ctx, Signature *s)
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
@ DETECT_BYTE_EXTRACT
@ DETECT_BYTEMATH
@ DETECT_BYTETEST
@ DETECT_BYTEJUMP
@ DETECT_ISDATAAT
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.
Data structures and function prototypes for keeping state for the detection engine.
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
initialize thread specific detection engine context
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data)
SigMatch * DetectGetLastSMByListId(const Signature *s, int list_id,...)
Returns the sm with the largest index (added last) from the list passed to us as an id.
int SCDetectSignatureSetAppProto(Signature *s, AppProto alproto)
Signature * SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
Parses a signature and adds it to the Detection Engine Context.
SigMatch * SCSigMatchAppendSMToList(DetectEngineCtx *de_ctx, Signature *s, uint16_t type, SigMatchCtx *ctx, const int list)
Append a SigMatch to the list type.
SigMatch * DetectGetLastSMFromLists(const Signature *s,...)
Returns the sm with the largest index (added latest) from the lists passed to us.
int SigMatchListSMBelongsTo(const Signature *s, const SigMatch *key_sm)
SigTableElmt * sigmatch_table
#define DETECT_PCRE_RELATIVE_NEXT
Definition detect-pcre.h:34
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition detect.c:2420
#define DE_QUIET
Definition detect.h:330
#define DETECT_SM_LIST_NOTSET
Definition detect.h:144
@ DETECT_SM_LIST_PMATCH
Definition detect.h:119
@ DETECT_SM_LIST_MAX
Definition detect.h:135
uint8_t FlowGetProtoMapping(uint8_t proto)
Function to map the protocol to the defined FLOW_PROTO_* enumeration.
Definition flow-util.c:99
#define FLOW_INITIALIZE(f)
Definition flow-util.h:38
#define FLOW_DESTROY(f)
Definition flow-util.h:119
#define FLOW_PKT_TOSERVER
Definition flow.h:233
#define FLOW_IPV4
Definition flow.h:100
AppLayerParserThreadCtx * alp_tctx
ThreadVars * tv
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(expr)
Fail a test if expression evaluates to true.
uint16_t payload_len
main detection engine ctx
Definition detect.h:932
uint8_t mpm_matcher
Definition detect.h:935
uint8_t flags
Definition detect.h:934
Signature * sig_list
Definition detect.h:941
int32_t byte_extract_max_local_id
Definition detect.h:1010
Flow data structure.
Definition flow.h:356
uint8_t proto
Definition flow.h:378
uint32_t flags
Definition flow.h:421
AppProto alproto
application level protocol
Definition flow.h:450
void * alstate
Definition flow.h:479
uint8_t protomap
Definition flow.h:445
uint8_t flowflags
Definition decode.h:532
struct Flow_ * flow
Definition decode.h:546
uint32_t flags
Definition decode.h:544
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition detect.h:351
a single match condition for a signature
Definition detect.h:356
uint16_t type
Definition detect.h:357
struct SigMatch_ * next
Definition detect.h:360
SigMatchCtx * ctx
Definition detect.h:359
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition detect.h:1441
void(* Free)(DetectEngineCtx *, void *)
Definition detect.h:1446
void(* RegisterTests)(void)
Definition detect.h:1448
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition detect.h:1421
const char * name
Definition detect.h:1459
struct SigMatch_ * smlists[DETECT_SM_LIST_MAX]
Definition detect.h:642
struct SigMatch_ * smlists_tail[DETECT_SM_LIST_MAX]
Definition detect.h:644
SignatureInitDataBuffer * buffers
Definition detect.h:647
uint32_t buffer_index
Definition detect.h:648
Signature container.
Definition detect.h:668
SignatureInitData * init_data
Definition detect.h:747
Per thread variable structure.
Definition threadvars.h:58
int ByteExtractUint64(uint64_t *res, int e, uint16_t len, const uint8_t *bytes)
Definition util-byte.c:122
int ByteExtractStringUint64(uint64_t *res, int base, size_t len, const char *str)
Definition util-byte.c:234
#define BYTE_BIG_ENDIAN
Definition util-byte.h:29
#define BYTE_LITTLE_ENDIAN
Definition util-byte.h:30
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCLogError(...)
Macro used to log ERROR messages.
Definition util-debug.h:267
#define SCFree(p)
Definition util-mem.h:61
#define SCStrdup(s)
Definition util-mem.h:56
uint8_t mpm_default_matcher
Definition util-mpm.c:48
Packet * UTHBuildPacketReal(uint8_t *payload, uint16_t payload_len, uint8_t ipproto, const char *src, const char *dst, uint16_t sport, uint16_t dport)
UTHBuildPacketReal is a function that create tcp/udp packets for unittests specifying ip and port sou...
void UTHFreePacket(Packet *p)
UTHFreePacket: function to release the allocated data from UTHBuildPacket and the packet itself.
#define DEBUG_VALIDATE_BUG_ON(exp)